diff --git a/Build/ICSharpCode.SharpZipLib.nuspec b/Build/ICSharpCode.SharpZipLib.nuspec index d0fe50561..9b6e16fc2 100644 --- a/Build/ICSharpCode.SharpZipLib.nuspec +++ b/Build/ICSharpCode.SharpZipLib.nuspec @@ -2,7 +2,7 @@ ICSharpCode.SharpZipLib-dogfood - 0.87-dogfood + 1.0 SharpZipLib-dogfood IC#Code IC#Code @@ -13,24 +13,22 @@ http://icsharpcode.github.io/SharpZipLib/ http://icsharpcode.github.io/SharpZipLib/#license - Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team + Copyright © 2000-2016 SharpZipLib Contributors false - - - - Compression Library Zip GZip BZip2 Tar + + Compression Library Zip GZip BZip2 LZW Tar - - - - - - - - - + + + + + + + + + diff --git a/Build/run-appveyor-build.ps1 b/Build/run-appveyor-build.ps1 new file mode 100644 index 000000000..039a39ac9 --- /dev/null +++ b/Build/run-appveyor-build.ps1 @@ -0,0 +1,27 @@ +# Define build command. +$buildCmd = "C:\Program Files (x86)\MSBuild\14.0\bin\msbuild.exe"; +$buildArgs = @( + "ICSharpCode.SharpZipLib.sln" + "/l:C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll", + "/m", + "/p:UseSharedCompilation=false", + "/p:Configuration=Release", + "/p:Platform=Any CPU"); + +# If build is not a scheduled one, then simply build the project with MSBuild. +if ($env:APPVEYOR_SCHEDULED_BUILD -ne "True") { + & $buildCmd $buildArgs +# & nuget pack -OutputDirectory + return # exit script +} + +# Else, build project with Coverity Scan. +$publishCoverityExe = $env:APPVEYOR_BUILD_FOLDER + "\packages\PublishCoverity.0.11.0\tools\PublishCoverity.exe"; +"Building project with Coverity Scan..." +& cov-build --dir Documentation\cov-int $buildCmd $buildArgs; + +# Compress scan data. +& $publishCoverityExe compress -o Documentation\coverity.zip -i Documentation\cov-int; + +# Upload scan data. +& $publishCoverityExe publish -z Documentation\coverity.zip -r McNeight/SharpZipLib -t $env:Coverity_Token -e $env:Coverity_Email -d "AppVeyor scheduled build"; diff --git a/Build/run-nunit3-tests-debug.cmd b/Build/run-nunit3-tests-debug.cmd index 753b1a6e2..e3e51d42f 100644 --- a/Build/run-nunit3-tests-debug.cmd +++ b/Build/run-nunit3-tests-debug.cmd @@ -1 +1 @@ -..\packages\NUnit.ConsoleRunner.3.2.0\tools\nunit3-console.exe /framework:net-4.5 /result:..\Documentation\nunit3-test-results-debug.xml ..\bin\Debug\ICSharpCode.SharpZipLib.Tests.dll +packages\NUnit.ConsoleRunner.3.2.1\tools\nunit3-console.exe --framework=net-4.5 --domain=Single --testlist=ICSharpCode.SharpZipLib.Tests\PassingTests.txt --result=Documentation\nunit3-test-results-debug.xml bin\Debug\ICSharpCode.SharpZipLib.Tests.dll diff --git a/Build/run-nunit3-tests-release.cmd b/Build/run-nunit3-tests-release.cmd index f52a8ffde..7a5f6bedf 100644 --- a/Build/run-nunit3-tests-release.cmd +++ b/Build/run-nunit3-tests-release.cmd @@ -1 +1 @@ -..\packages\NUnit.ConsoleRunner.3.2.0\tools\nunit3-console.exe /framework:net-4.5 /result:..\Documentation\nunit3-test-results-release.xml ..\bin\Release\ICSharpCode.SharpZipLib.Tests.dll +packages\NUnit.ConsoleRunner.3.2.1\tools\nunit3-console.exe --framework=net-4.5 --domain=Single --testlist=ICSharpCode.SharpZipLib.Tests\PassingTests.txt --result=Documentation\nunit3-test-results-release.xml bin\Release\ICSharpCode.SharpZipLib.Tests.dll diff --git a/Build/run-opencover.cmd b/Build/run-opencover.cmd index ea47a8049..790f02c8b 100644 --- a/Build/run-opencover.cmd +++ b/Build/run-opencover.cmd @@ -1,2 +1 @@ -..\packages\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:run-nunit3-tests-release.cmd -register:user -filter:+[ICSharpCode.SharpZipLib]* -output:..\Documentation\opencover-results-release.xml -..\packages\ReportGenerator.2.4.4.0\tools\ReportGenerator.exe -reports:..\Documentation\opencover-results-release.xml -targetdir:..\Documentation\opencover +packages\OpenCover.4.6.519\tools\OpenCover.Console.exe -register:user -filter:+[ICSharpCode.SharpZipLib]* -target:Build\run-nunit3-tests-release.cmd -output:Documentation\opencover-results-release.xml diff --git a/Build/run-reportgenerator.cmd b/Build/run-reportgenerator.cmd new file mode 100644 index 000000000..7c1f0f852 --- /dev/null +++ b/Build/run-reportgenerator.cmd @@ -0,0 +1 @@ +packages\ReportGenerator.2.4.5.0\tools\ReportGenerator.exe -reports:Documentation\opencover-results-release.xml -targetdir:Documentation\opencover diff --git a/Documentation/nunit3-test-results-debug.xml b/Documentation/nunit3-test-results-debug.xml new file mode 100644 index 000000000..ffd4ea06d --- /dev/null +++ b/Documentation/nunit3-test-results-debug.xml @@ -0,0 +1,894 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Documentation/nunit3-test-results-release.xml b/Documentation/nunit3-test-results-release.xml index 06ce2dd4b..ccc3edc47 100644 --- a/Documentation/nunit3-test-results-release.xml +++ b/Documentation/nunit3-test-results-release.xml @@ -1,11 +1,149 @@  - - - - + + + + + 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 + + + + + - + @@ -13,888 +151,646 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - + - + - + - + - + - - - - - - - - + + + - - - - - + + + + + + + + + + + + + + + - - - - - - - - - + + + - + - - - + - + - + - - - + - - - - - - - - - + - + - + - + - - - - - - - - - - - - - - + + + - + - + - + - + - + - + - + - + - + - + - + - - - - - + - + - - - - - - + - - - - - + + + + + - - - - - - - - - + + + - - - - - - - - - - + - + - + - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - + + - + - + - + - + - + - + - + - + - + - + - - - - - + - - - - - + - - - - - - + - - - - - - + - + - + - + - + - + - + - + - + - + - - - - - + + + + + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - + + - - - + + + - + - + - - - - - - - - - - - + - - + + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - - - - - - - + + - - + + - + - + diff --git a/Documentation/opencover-results-release.xml b/Documentation/opencover-results-release.xml index 2abaed6cd..691c4525f 100644 --- a/Documentation/opencover-results-release.xml +++ b/Documentation/opencover-results-release.xml @@ -1,40 +1,40 @@ - + - + C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll - 2016-03-24T02:20:50.3825554Z + 2016-04-28T02:26:52.636468Z mscorlib - - C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\packages\NUnit.ConsoleRunner.3.2.0\tools\nunit3-console.exe - 2016-03-05T23:27:30Z + + 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-03-10T04:46:51.898274Z + 2016-04-27T06:31:03.8601995Z System - - C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\packages\NUnit.ConsoleRunner.3.2.0\tools\nunit.engine.api.dll - 2016-03-05T23:27:30Z + + 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.0\tools\nunit.engine.dll - 2016-03-05T23:27:30Z + + 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.0\tools\nunit.engine.dll - 2016-03-05T23:27:30Z + + 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 @@ -51,8 +51,8 @@ - C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\packages\NUnit.ConsoleRunner.3.2.0\tools\Mono.Cecil.dll - 2016-03-05T23:27:30Z + 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 @@ -68,33 +68,33 @@ System.Configuration - + C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll - 2016-03-24T02:20:50.3825554Z + 2016-04-28T02:26:52.636468Z mscorlib - - C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\packages\NUnit.ConsoleRunner.3.2.0\tools\nunit-agent.exe - 2016-03-05T23:27:30Z + + 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.0\tools\nunit.engine.dll - 2016-03-05T23:27:30Z + + 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.0\tools\nunit.engine.api.dll - 2016-03-05T23:27:30Z + + 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-03-10T04:46:51.898274Z + 2016-04-27T06:31:03.8601995Z System @@ -117,8 +117,8 @@ - C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\packages\NUnit.ConsoleRunner.3.2.0\tools\Mono.Cecil.dll - 2016-03-05T23:27:30Z + 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 @@ -128,15 +128,15 @@ System.Configuration - + C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\bin\Release\nunit.framework.dll - 2016-03-05T23:27:28Z + 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-03-10T04:46:51.898274Z + 2016-04-27T06:31:03.8601995Z System @@ -146,16 +146,16 @@ System.Web - + C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\bin\Release\ICSharpCode.SharpZipLib.Tests.dll - 2016-04-18T19:58:44.2823924Z + 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-04-18T15:32:37.0626596Z + 2016-05-17T23:07:43.011793Z ICSharpCode.SharpZipLib @@ -195,26 +195,27 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + @@ -232,11 +233,11 @@ System.Void ICSharpCode.SharpZipLib.SharpZipBaseException::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) - - + + - + @@ -244,11 +245,11 @@ System.Void ICSharpCode.SharpZipLib.SharpZipBaseException::.ctor() - - + + - + @@ -256,11 +257,11 @@ System.Void ICSharpCode.SharpZipLib.SharpZipBaseException::.ctor(System.String) - - + + - + @@ -268,11 +269,11 @@ System.Void ICSharpCode.SharpZipLib.SharpZipBaseException::.ctor(System.String,System.Exception) - - + + - + @@ -286,10 +287,10 @@ System.TimeSpan ICSharpCode.SharpZipLib.Zip.FastZipEvents::get_ProgressInterval() - + - + @@ -297,11 +298,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZipEvents::set_ProgressInterval(System.TimeSpan) - - + + - + @@ -325,19 +326,19 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.FastZipEvents::OnDirectoryFailure(System.String,System.Exception) - - - - - - - + + + + + + + - - + + - + @@ -345,19 +346,19 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.FastZipEvents::OnFileFailure(System.String,System.Exception) - - - - - - - + + + + + + + - - + + - + @@ -365,19 +366,19 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.FastZipEvents::OnProcessFile(System.String) - - - - - - - + + + + + + + - - + + - + @@ -385,19 +386,19 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.FastZipEvents::OnCompletedFile(System.String) - - - - - - - + + + + + + + - - + + - + @@ -405,19 +406,19 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.FastZipEvents::OnProcessDirectory(System.String,System.Boolean) - - - - - - - + + + + + + + - - + + - + @@ -425,15 +426,15 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZipEvents::.ctor() - + - + - + ICSharpCode.SharpZipLib.Zip.FastZip @@ -442,10 +443,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.FastZip::get_CreateEmptyDirectories() - + - + @@ -453,11 +454,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZip::set_CreateEmptyDirectories(System.Boolean) - - + + - + @@ -465,10 +466,10 @@ System.String ICSharpCode.SharpZipLib.Zip.FastZip::get_Password() - + - + @@ -476,11 +477,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZip::set_Password(System.String) - - + + - + @@ -488,10 +489,10 @@ ICSharpCode.SharpZipLib.Core.INameTransform ICSharpCode.SharpZipLib.Zip.FastZip::get_NameTransform() - + - + @@ -499,11 +500,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZip::set_NameTransform(ICSharpCode.SharpZipLib.Core.INameTransform) - - + + - + @@ -511,10 +512,10 @@ ICSharpCode.SharpZipLib.Zip.IEntryFactory ICSharpCode.SharpZipLib.Zip.FastZip::get_EntryFactory() - + - + @@ -522,17 +523,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZip::set_EntryFactory(ICSharpCode.SharpZipLib.Zip.IEntryFactory) - - - - - + + + + + - - + + - + @@ -540,10 +541,10 @@ ICSharpCode.SharpZipLib.Zip.UseZip64 ICSharpCode.SharpZipLib.Zip.FastZip::get_UseZip64() - + - + @@ -551,11 +552,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZip::set_UseZip64(ICSharpCode.SharpZipLib.Zip.UseZip64) - - + + - + @@ -563,10 +564,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.FastZip::get_RestoreDateTimeOnExtract() - + - + @@ -574,11 +575,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZip::set_RestoreDateTimeOnExtract(System.Boolean) - - + + - + @@ -586,10 +587,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.FastZip::get_RestoreAttributesOnExtract() - + - + @@ -597,11 +598,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZip::set_RestoreAttributesOnExtract(System.Boolean) - - + + - + @@ -609,13 +610,13 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZip::.ctor() - - - - + + + + - + @@ -623,14 +624,14 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZip::.ctor(ICSharpCode.SharpZipLib.Zip.FastZipEvents) - - - - - + + + + + - + @@ -638,23 +639,23 @@ 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) - - + + - + @@ -662,38 +663,38 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZip::CreateZip(System.IO.Stream,System.String,System.Boolean,System.String,System.String) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -701,11 +702,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZip::ExtractZip(System.String,System.String,System.String) - - + + - + @@ -713,12 +714,12 @@ 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) - - - + + + - + @@ -726,57 +727,57 @@ 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) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -784,64 +785,64 @@ 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) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -849,31 +850,31 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZip::AddFileContents(System.String,System.IO.Stream) - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -881,78 +882,78 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZip::ExtractFileEntry(ICSharpCode.SharpZipLib.Zip.ZipEntry,System.String) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -960,69 +961,69 @@ System.Void ICSharpCode.SharpZipLib.Zip.FastZip::ExtractEntry(ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1030,10 +1031,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.FastZip::MakeExternalAttributes(System.IO.FileInfo) - + - + @@ -1041,10 +1042,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.FastZip::NameIsValid(System.String) - + - + @@ -1053,25 +1054,25 @@ ICSharpCode.SharpZipLib.Zip.FastZip/ConfirmOverwriteDelegate - 100664486 + 100664489 System.Void ICSharpCode.SharpZipLib.Zip.FastZip/ConfirmOverwriteDelegate::.ctor(System.Object,System.IntPtr) - 100664487 + 100664490 System.Boolean ICSharpCode.SharpZipLib.Zip.FastZip/ConfirmOverwriteDelegate::Invoke(System.String) - 100664488 + 100664491 System.IAsyncResult ICSharpCode.SharpZipLib.Zip.FastZip/ConfirmOverwriteDelegate::BeginInvoke(System.String,System.AsyncCallback,System.Object) - 100664489 + 100664492 System.Boolean ICSharpCode.SharpZipLib.Zip.FastZip/ConfirmOverwriteDelegate::EndInvoke(System.IAsyncResult) @@ -1079,7 +1080,7 @@ - + ICSharpCode.SharpZipLib.Zip.WindowsNameTransform @@ -1088,10 +1089,10 @@ System.String ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::get_BaseDirectory() - + - + @@ -1099,16 +1100,16 @@ System.Void ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::set_BaseDirectory(System.String) - - - - + + + + - - + + - + @@ -1116,22 +1117,22 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::get_TrimIncomingPaths() - + - + - - + + 100663352 System.Void ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::set_TrimIncomingPaths(System.Boolean) - - + + - + @@ -1139,38 +1140,38 @@ System.Char ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::get_Replacement() - + - + - - + + 100663359 System.Void ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::set_Replacement(System.Char) - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - + @@ -1178,18 +1179,18 @@ System.Void ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::.ctor(System.String) - - - - - - + + + + + + - - + + - + @@ -1197,12 +1198,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::.ctor() - - - + + + - + @@ -1210,21 +1211,21 @@ System.String ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::TransformDirectory(System.String) - - - - - - - + + + + + + + - - - - + + + + - + @@ -1232,25 +1233,25 @@ System.String ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::TransformFile(System.String) - - - - - - - - - + + + + + + + + + - - - - - - + + + + + + - + @@ -1258,11 +1259,11 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::IsValidName(System.String) - - + + - + @@ -1270,72 +1271,72 @@ System.Void ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::.cctor() - - - - - - - - + + + + + + + + - + - - + + 100663357 System.String ICSharpCode.SharpZipLib.Zip.WindowsNameTransform::MakeValidName(System.String,System.Char) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1349,10 +1350,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipConstants::get_DefaultCodePage() - + - + @@ -1360,26 +1361,26 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipConstants::set_DefaultCodePage(System.Int32) - - - - + + + + - - - - - - - - - - - - + + + + + + + + + + + + - + @@ -1387,15 +1388,15 @@ System.String ICSharpCode.SharpZipLib.Zip.ZipConstants::ConvertToString(System.Byte[],System.Int32) - - - + + + - - + + - + @@ -1403,15 +1404,15 @@ System.String ICSharpCode.SharpZipLib.Zip.ZipConstants::ConvertToString(System.Byte[]) - - - + + + - - + + - + @@ -1419,19 +1420,19 @@ System.String ICSharpCode.SharpZipLib.Zip.ZipConstants::ConvertToStringExt(System.Int32,System.Byte[],System.Int32) - - - - - + + + + + - - - - + + + + - + @@ -1439,19 +1440,19 @@ System.String ICSharpCode.SharpZipLib.Zip.ZipConstants::ConvertToStringExt(System.Int32,System.Byte[]) - - - - - + + + + + - - - - + + + + - + @@ -1459,15 +1460,15 @@ System.Byte[] ICSharpCode.SharpZipLib.Zip.ZipConstants::ConvertToArray(System.String) - - - + + + - - + + - + @@ -1475,19 +1476,19 @@ System.Byte[] ICSharpCode.SharpZipLib.Zip.ZipConstants::ConvertToArray(System.Int32,System.String) - - - - - + + + + + - - - - + + + + - + @@ -1495,11 +1496,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipConstants::.ctor() - - + + - + @@ -1507,15 +1508,15 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipConstants::.cctor() - + - + - + ICSharpCode.SharpZipLib.Zip.ZipEntry @@ -1524,10 +1525,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_HasCrc() - + - + @@ -1535,10 +1536,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_IsCrypted() - + - + @@ -1546,17 +1547,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_IsCrypted(System.Boolean) - - - - - + + + + + - - + + - + @@ -1564,10 +1565,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_IsUnicodeText() - + - + @@ -1575,17 +1576,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_IsUnicodeText(System.Boolean) - - - - - + + + + + - - + + - + @@ -1593,10 +1594,10 @@ System.Byte ICSharpCode.SharpZipLib.Zip.ZipEntry::get_CryptoCheckValue() - + - + @@ -1604,11 +1605,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_CryptoCheckValue(System.Byte) - - + + - + @@ -1616,10 +1617,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_Flags() - + - + @@ -1627,11 +1628,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_Flags(System.Int32) - - + + - + @@ -1639,10 +1640,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_ZipFileIndex() - + - + @@ -1650,11 +1651,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_ZipFileIndex(System.Int64) - - + + - + @@ -1662,10 +1663,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_Offset() - + - + @@ -1673,11 +1674,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_Offset(System.Int64) - - + + - + @@ -1685,15 +1686,15 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_ExternalFileAttributes() - - - + + + - - + + - + @@ -1701,12 +1702,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_ExternalFileAttributes(System.Int32) - - - + + + - + @@ -1714,10 +1715,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_VersionMadeBy() - + - + @@ -1725,10 +1726,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_IsDOSEntry() - + - + @@ -1736,10 +1737,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_HostSystem() - + - + @@ -1747,12 +1748,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_HostSystem(System.Int32) - - - + + + - + @@ -1760,45 +1761,45 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_Version() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1806,13 +1807,13 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_CanDecompress() - + - - + + - + @@ -1820,23 +1821,23 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_LocalHeaderRequiresZip64() - - - - - - - + + + + + + + - - - - - - + + + + + + - + @@ -1844,10 +1845,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_CentralHeaderRequiresZip64() - + - + @@ -1855,15 +1856,15 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_DosTime() - - - + + + - - + + - + @@ -1871,67 +1872,61 @@ 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) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1939,10 +1934,10 @@ System.String ICSharpCode.SharpZipLib.Zip.ZipEntry::get_Name() - + - + @@ -1950,13 +1945,13 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_Size() - + - - + + - + @@ -1964,12 +1959,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_Size(System.Int64) - - - + + + - + @@ -1977,13 +1972,13 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_CompressedSize() - + - - + + - + @@ -1991,12 +1986,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_CompressedSize(System.Int64) - - - + + + - + @@ -2004,13 +1999,13 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_Crc() - + - - + + - + @@ -2018,17 +2013,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_Crc(System.Int64) - - - - - + + + + + - - + + - + @@ -2036,10 +2031,10 @@ ICSharpCode.SharpZipLib.Zip.CompressionMethod ICSharpCode.SharpZipLib.Zip.ZipEntry::get_CompressionMethod() - + - + @@ -2047,16 +2042,16 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_CompressionMethod(ICSharpCode.SharpZipLib.Zip.CompressionMethod) - - - - + + + + - - + + - + @@ -2064,13 +2059,13 @@ ICSharpCode.SharpZipLib.Zip.CompressionMethod ICSharpCode.SharpZipLib.Zip.ZipEntry::get_CompressionMethodForHeader() - + - - + + - + @@ -2078,10 +2073,10 @@ System.Byte[] ICSharpCode.SharpZipLib.Zip.ZipEntry::get_ExtraData() - + - + @@ -2089,22 +2084,22 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_ExtraData(System.Byte[]) - - - - - - - - + + + + + + + + - - - - + + + + - + @@ -2112,21 +2107,21 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_AESKeySize() - - - - - - + + + + + + - - - - - + + + + + - + @@ -2134,24 +2129,24 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_AESKeySize(System.Int32) - - - - - - - - + + + + + + + + - - - - - - + + + + + + - + @@ -2159,10 +2154,10 @@ System.Byte ICSharpCode.SharpZipLib.Zip.ZipEntry::get_AESEncryptionStrength() - + - + @@ -2170,10 +2165,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_AESSaltLen() - + - + @@ -2181,64 +2176,64 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntry::get_AESOverheadSize() - + - + - 100663423 + 100663424 System.String ICSharpCode.SharpZipLib.Zip.ZipEntry::get_Comment() - + - + - 100663424 + 100663425 System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::set_Comment(System.String) - - - - + + + + - - - - + + + + - + - 100663425 + 100663426 System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_IsDirectory() - - - + + + - + - 100663426 + 100663427 System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::get_IsFile() - + - + @@ -2246,11 +2241,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::.ctor(System.String) - - + + - + @@ -2258,11 +2253,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::.ctor(System.String,System.Int32) - - + + - + @@ -2270,74 +2265,75 @@ 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) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2345,16 +2341,16 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::HasDosAttributes(System.Int32) - - - - + + + + - - + + - + @@ -2362,11 +2358,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::ForceZip64() - - + + - + @@ -2374,567 +2370,555 @@ 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) + + + + + + + + + + + + + + + + + + + + + + + + - 100663422 + 100663423 System.Void ICSharpCode.SharpZipLib.Zip.ZipEntry::ProcessAESExtraData(ICSharpCode.SharpZipLib.Zip.ZipExtraData) - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - 100663427 + 100663428 System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::IsCompressionMethodSupported() - + - + - 100663428 + 100663429 System.Object ICSharpCode.SharpZipLib.Zip.ZipEntry::Clone() - - - - - + + + + + - - + + - + - 100663429 + 100663430 System.String ICSharpCode.SharpZipLib.Zip.ZipEntry::ToString() - + - + - 100663430 + 100663431 System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntry::IsCompressionMethodSupported(ICSharpCode.SharpZipLib.Zip.CompressionMethod) - + - + - - - 100663431 + + + 100663432 System.String ICSharpCode.SharpZipLib.Zip.ZipEntry::CleanName(System.String) - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - + - + ICSharpCode.SharpZipLib.Zip.ZipEntryFactory - 100663435 + 100663436 ICSharpCode.SharpZipLib.Core.INameTransform ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::get_NameTransform() - + - + - 100663436 + 100663437 System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::set_NameTransform(ICSharpCode.SharpZipLib.Core.INameTransform) - - - - - + + + + + - - + + - + - 100663437 + 100663438 ICSharpCode.SharpZipLib.Zip.ZipEntryFactory/TimeSetting ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::get_Setting() - + - + - 100663438 + 100663439 System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::set_Setting(ICSharpCode.SharpZipLib.Zip.ZipEntryFactory/TimeSetting) - - + + - + - 100663439 + 100663440 System.DateTime ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::get_FixedDateTime() - + - + - 100663440 + 100663441 System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::set_FixedDateTime(System.DateTime) - - - - + + + + - - + + - + - 100663441 + 100663442 System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::get_GetAttributes() - + - + - - - 100663442 + + + 100663443 System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::set_GetAttributes(System.Int32) - - + + - + - 100663443 + 100663444 System.Int32 ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::get_SetAttributes() - + - + - 100663444 + 100663445 System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::set_SetAttributes(System.Int32) - - + + - + - 100663445 + 100663446 System.Boolean ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::get_IsUnicodeText() - + - + - 100663446 + 100663447 System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::set_IsUnicodeText(System.Boolean) - - + + - + - 100663432 + 100663433 System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::.ctor() - - - - - + + + + + - + - 100663433 + 100663434 System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::.ctor(ICSharpCode.SharpZipLib.Zip.ZipEntryFactory/TimeSetting) - - - - - - + + + + + + - + - 100663434 + 100663435 System.Void ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::.ctor(System.DateTime) - - - - - - - + + + + + + + - + - 100663447 + 100663448 ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::MakeFileEntry(System.String) - + - + - 100663448 + 100663449 ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::MakeFileEntry(System.String,System.Boolean) - + - + - - - 100663449 + + + 100663450 ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::MakeFileEntry(System.String,System.String,System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - 100663450 + + + 100663451 ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::MakeDirectoryEntry(System.String) - + - + - - - 100663451 + + + 100663452 ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipEntryFactory::MakeDirectoryEntry(System.String,System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2944,51 +2928,51 @@ - 100663452 + 100663453 System.Void ICSharpCode.SharpZipLib.Zip.ZipException::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) - - + + - + - 100663453 + 100663454 System.Void ICSharpCode.SharpZipLib.Zip.ZipException::.ctor() - - + + - + - 100663454 + 100663455 System.Void ICSharpCode.SharpZipLib.Zip.ZipException::.ctor(System.String) - - + + - + - 100663455 + 100663456 System.Void ICSharpCode.SharpZipLib.Zip.ZipException::.ctor(System.String,System.Exception) - - + + - + @@ -2998,310 +2982,312 @@ - 100663460 + 100663461 System.Int16 ICSharpCode.SharpZipLib.Zip.RawTaggedData::get_TagID() - + - + - 100663461 + 100663462 System.Void ICSharpCode.SharpZipLib.Zip.RawTaggedData::set_TagID(System.Int16) - - + + - + - 100663464 + 100663465 System.Byte[] ICSharpCode.SharpZipLib.Zip.RawTaggedData::get_Data() - + - + - 100663465 + 100663466 System.Void ICSharpCode.SharpZipLib.Zip.RawTaggedData::set_Data(System.Byte[]) - - + + - + - 100663459 + 100663460 System.Void ICSharpCode.SharpZipLib.Zip.RawTaggedData::.ctor(System.Int16) - - - + + + - + - 100663462 + 100663463 System.Void ICSharpCode.SharpZipLib.Zip.RawTaggedData::SetData(System.Byte[],System.Int32,System.Int32) - - - - - + + + + + - - + + - + - 100663463 + 100663464 System.Byte[] ICSharpCode.SharpZipLib.Zip.RawTaggedData::GetData() - + - + - + ICSharpCode.SharpZipLib.Zip.ExtendedUnixData - 100663466 + 100663467 System.Int16 ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::get_TagID() - + - + - 100663470 + 100663471 System.DateTime ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::get_ModificationTime() - + - + - 100663471 + 100663472 System.Void ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::set_ModificationTime(System.DateTime) - - - - - + + + + + - - + + - + - 100663472 + 100663473 System.DateTime ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::get_AccessTime() - + - + - 100663473 + 100663474 System.Void ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::set_AccessTime(System.DateTime) - - - - - + + + + + - - + + - + - 100663474 + 100663475 System.DateTime ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::get_CreateTime() - + - + - 100663475 + 100663476 System.Void ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::set_CreateTime(System.DateTime) - - - - - + + + + + - - + + - + - 100663476 + 100663477 ICSharpCode.SharpZipLib.Zip.ExtendedUnixData/Flags ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::get_Include() - + - + - 100663477 + 100663478 System.Void ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::set_Include(ICSharpCode.SharpZipLib.Zip.ExtendedUnixData/Flags) - - + + - + - - - 100663467 + + + 100663468 System.Void ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::SetData(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100663468 + 100663469 System.Byte[] ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::GetData() - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100663469 + 100663470 System.Boolean ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::IsValidValue(System.DateTime) - + - + - 100663478 + 100663479 System.Void ICSharpCode.SharpZipLib.Zip.ExtendedUnixData::.ctor() - - - + + + - + @@ -3311,201 +3297,201 @@ - 100663479 + 100663480 System.Int16 ICSharpCode.SharpZipLib.Zip.NTTaggedData::get_TagID() - + - + - 100663483 + 100663484 System.DateTime ICSharpCode.SharpZipLib.Zip.NTTaggedData::get_LastModificationTime() - + - + - 100663484 + 100663485 System.Void ICSharpCode.SharpZipLib.Zip.NTTaggedData::set_LastModificationTime(System.DateTime) - - - - + + + + - - + + - + - 100663485 + 100663486 System.DateTime ICSharpCode.SharpZipLib.Zip.NTTaggedData::get_CreateTime() - + - + - 100663486 + 100663487 System.Void ICSharpCode.SharpZipLib.Zip.NTTaggedData::set_CreateTime(System.DateTime) - - - - + + + + - - + + - + - 100663487 + 100663488 System.DateTime ICSharpCode.SharpZipLib.Zip.NTTaggedData::get_LastAccessTime() - + - + - 100663488 + 100663489 System.Void ICSharpCode.SharpZipLib.Zip.NTTaggedData::set_LastAccessTime(System.DateTime) - - - - + + + + - - + + - + - 100663480 + 100663481 System.Void ICSharpCode.SharpZipLib.Zip.NTTaggedData::SetData(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100663481 + 100663482 System.Byte[] ICSharpCode.SharpZipLib.Zip.NTTaggedData::GetData() - - - - - - - - - - - + + + + + + + + + + + - + - 100663482 + 100663483 System.Boolean ICSharpCode.SharpZipLib.Zip.NTTaggedData::IsValidValue(System.DateTime) - - - - - - - + + + + + + + - + - 100663489 + 100663490 System.Void ICSharpCode.SharpZipLib.Zip.NTTaggedData::.ctor() - - - + + + - + - + ICSharpCode.SharpZipLib.Zip.ZipExtraData - 100663495 + 100663496 System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::get_Length() - + - + @@ -3513,10 +3499,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::get_ValueLength() - + - + @@ -3524,10 +3510,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::get_CurrentReadIndex() - + - + @@ -3535,141 +3521,118 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::get_UnreadCount() - - - + + + - - - - + + + + - + - 100663491 + 100663492 System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::.ctor() - - - + + + - + - 100663492 + 100663493 System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::.ctor(System.Byte[]) - - - - - - + + + + + + - - + + - + - 100663493 + 100663494 System.Byte[] ICSharpCode.SharpZipLib.Zip.ZipExtraData::GetEntryData() - - - + + + - - + + - + - 100663494 + 100663495 System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::Clear() - - - + + + - - - - + + + + - + - 100663496 - System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipExtraData::GetStreamForTag(System.Int32) - - - - - - - - - - - - - - - 100663497 - ICSharpCode.SharpZipLib.Zip.ITaggedData ICSharpCode.SharpZipLib.Zip.ZipExtraData::GetData(System.Int16) + System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipExtraData::GetStreamForTag(System.Int32) - - - - + + + + - - + + - + - - + + 100663498 - ICSharpCode.SharpZipLib.Zip.ITaggedData ICSharpCode.SharpZipLib.Zip.ZipExtraData::Create(System.Int16,System.Byte[],System.Int32,System.Int32) + T ICSharpCode.SharpZipLib.Zip.ZipExtraData::GetData() - - - - - - - - - + + + + + - - - - + + - + @@ -3677,33 +3640,33 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipExtraData::Find(System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3711,16 +3674,16 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddEntry(ICSharpCode.SharpZipLib.Zip.ITaggedData) - - - - + + + + - - + + - + @@ -3728,42 +3691,42 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddEntry(System.Int32,System.Byte[]) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3771,11 +3734,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::StartNewEntry() - - + + - + @@ -3783,13 +3746,13 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddNewEntry(System.Int32) - - - - + + + + - + @@ -3797,11 +3760,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddData(System.Byte) - - + + - + @@ -3809,16 +3772,16 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddData(System.Byte[]) - - - - + + + + - - + + - + @@ -3826,12 +3789,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddLeShort(System.Int32) - - - + + + - + @@ -3839,12 +3802,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddLeInt(System.Int32) - - - + + + - + @@ -3852,12 +3815,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::AddLeLong(System.Int64) - - - + + + - + @@ -3865,22 +3828,22 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipExtraData::Delete(System.Int32) - - - - - - - - - - + + + + + + + + + + - - + + - + @@ -3888,11 +3851,11 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipExtraData::ReadLong() - - + + - + @@ -3900,13 +3863,13 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::ReadInt() - - - - + + + + - + @@ -3914,13 +3877,13 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::ReadShort() - - - - + + + + - + @@ -3928,19 +3891,19 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::ReadByte() - - - - - + + + + + - - - - + + + + - + @@ -3948,12 +3911,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::Skip(System.Int32) - - - + + + - + @@ -3961,25 +3924,25 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::ReadCheck(System.Int32) - - - - - - - + + + + + + + - - - - - - - - + + + + + + + + - + @@ -3987,17 +3950,17 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipExtraData::ReadShortInternal() - - - - - + + + + + - - + + - + @@ -4005,13 +3968,13 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::SetShort(System.Int32&,System.Int32) - - - - + + + + - + @@ -4019,15 +3982,15 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipExtraData::Dispose() - - - + + + - - + + - + @@ -4041,10 +4004,10 @@ System.String ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs::get_FileName() - + - + @@ -4052,10 +4015,10 @@ System.Byte[] ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs::get_Key() - + - + @@ -4063,11 +4026,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs::set_Key(System.Byte[]) - - + + - + @@ -4075,12 +4038,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs::.ctor(System.String) - - - + + + - + @@ -4088,13 +4051,13 @@ System.Void ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs::.ctor(System.String,System.Byte[]) - - - - + + + + - + @@ -4108,10 +4071,10 @@ ICSharpCode.SharpZipLib.Zip.TestOperation ICSharpCode.SharpZipLib.Zip.TestStatus::get_Operation() - + - + @@ -4119,10 +4082,10 @@ ICSharpCode.SharpZipLib.Zip.ZipFile ICSharpCode.SharpZipLib.Zip.TestStatus::get_File() - + - + @@ -4130,10 +4093,10 @@ ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.TestStatus::get_Entry() - + - + @@ -4141,10 +4104,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.TestStatus::get_ErrorCount() - + - + @@ -4152,10 +4115,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.TestStatus::get_BytesTested() - + - + @@ -4163,10 +4126,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.TestStatus::get_EntryValid() - + - + @@ -4174,12 +4137,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.TestStatus::.ctor(ICSharpCode.SharpZipLib.Zip.ZipFile) - - - + + + - + @@ -4187,12 +4150,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.TestStatus::AddError() - - - + + + - + @@ -4200,11 +4163,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.TestStatus::SetOperation(ICSharpCode.SharpZipLib.Zip.TestOperation) - - + + - + @@ -4212,13 +4175,13 @@ System.Void ICSharpCode.SharpZipLib.Zip.TestStatus::SetEntry(ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - + + + + - + @@ -4226,11 +4189,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.TestStatus::SetBytesTested(System.Int64) - - + + - + @@ -4265,7 +4228,7 @@ - + ICSharpCode.SharpZipLib.Zip.ZipFile @@ -4274,10 +4237,10 @@ System.Byte[] ICSharpCode.SharpZipLib.Zip.ZipFile::get_Key() - + - + @@ -4285,11 +4248,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::set_Key(System.Byte[]) - - + + - + @@ -4297,18 +4260,18 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::set_Password(System.String) - - - - - - + + + + + + - - + + - + @@ -4316,10 +4279,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::get_HaveKeys() - + - + @@ -4327,10 +4290,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::get_IsStreamOwner() - + - + @@ -4338,11 +4301,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::set_IsStreamOwner(System.Boolean) - - + + - + @@ -4350,10 +4313,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::get_IsEmbeddedArchive() - + - + @@ -4361,10 +4324,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::get_IsNewArchive() - + - + @@ -4372,10 +4335,10 @@ System.String ICSharpCode.SharpZipLib.Zip.ZipFile::get_ZipFileComment() - + - + @@ -4383,10 +4346,10 @@ System.String ICSharpCode.SharpZipLib.Zip.ZipFile::get_Name() - + - + @@ -4394,10 +4357,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile::get_Size() - + - + @@ -4405,10 +4368,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile::get_Count() - + - + @@ -4416,10 +4379,10 @@ ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipFile::get_EntryByIndex(System.Int32) - + - + @@ -4427,10 +4390,10 @@ ICSharpCode.SharpZipLib.Core.INameTransform ICSharpCode.SharpZipLib.Zip.ZipFile::get_NameTransform() - + - + @@ -4438,11 +4401,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::set_NameTransform(ICSharpCode.SharpZipLib.Core.INameTransform) - - + + - + @@ -4450,10 +4413,10 @@ ICSharpCode.SharpZipLib.Zip.IEntryFactory ICSharpCode.SharpZipLib.Zip.ZipFile::get_EntryFactory() - + - + @@ -4461,17 +4424,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::set_EntryFactory(ICSharpCode.SharpZipLib.Zip.IEntryFactory) - - - - - + + + + + - - + + - + @@ -4479,10 +4442,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile::get_BufferSize() - + - + @@ -4490,20 +4453,20 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::set_BufferSize(System.Int32) - - - - - - + + + + + + - - - - + + + + - + @@ -4511,10 +4474,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::get_IsUpdating() - + - + @@ -4522,10 +4485,10 @@ ICSharpCode.SharpZipLib.Zip.UseZip64 ICSharpCode.SharpZipLib.Zip.ZipFile::get_UseZip64() - + - + @@ -4533,11 +4496,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::set_UseZip64(ICSharpCode.SharpZipLib.Zip.UseZip64) - - + + - + @@ -4545,17 +4508,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::OnKeysRequired(System.String) - - - - - + + + + + - - + + - + @@ -4563,27 +4526,27 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::.ctor(System.String) - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - + + - + @@ -4591,31 +4554,31 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::.ctor(System.IO.FileStream) - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4623,35 +4586,35 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::.ctor(System.IO.Stream) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4659,16 +4622,16 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::.ctor() - - - - - - - + + + + + + + - + @@ -4676,12 +4639,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Finalize() - - - + + + - + @@ -4689,12 +4652,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Close() - - - + + + - + @@ -4702,20 +4665,20 @@ ICSharpCode.SharpZipLib.Zip.ZipFile ICSharpCode.SharpZipLib.Zip.ZipFile::Create(System.String) - - - - - - - - + + + + + + + + - - + + - + @@ -4723,25 +4686,25 @@ ICSharpCode.SharpZipLib.Zip.ZipFile ICSharpCode.SharpZipLib.Zip.ZipFile::Create(System.IO.Stream) - - - - - - - - - + + + + + + + + + - - - - - - + + + + + + - + @@ -4749,15 +4712,15 @@ System.Collections.IEnumerator ICSharpCode.SharpZipLib.Zip.ZipFile::GetEnumerator() - - - + + + - - + + - + @@ -4765,24 +4728,24 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile::FindEntry(System.String,System.Boolean) - - - - - - - - + + + + + + + + - - - - - - + + + + + + - + @@ -4790,18 +4753,18 @@ ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipFile::GetEntry(System.String) - - - - + + + + - - - - + + + + - + @@ -4809,32 +4772,32 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipFile::GetInputStream(ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4842,34 +4805,34 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipFile::GetInputStream(System.Int64) - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4877,10 +4840,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::TestArchive(System.Boolean) - + - + @@ -4888,366 +4851,370 @@ 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) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5255,51 +5222,51 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::BeginUpdate(ICSharpCode.SharpZipLib.Zip.IArchiveStorage,ICSharpCode.SharpZipLib.Zip.IDynamicDataSource) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5307,11 +5274,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::BeginUpdate(ICSharpCode.SharpZipLib.Zip.IArchiveStorage) - - + + - + @@ -5319,17 +5286,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::BeginUpdate() - - - - - + + + + + - - + + - + @@ -5337,38 +5304,38 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CommitUpdate() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5376,11 +5343,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::AbortUpdate() - - + + - + @@ -5388,23 +5355,23 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::SetComment(System.String) - - - - - - - - - + + + + + + + + + - - - - + + + + - + @@ -5412,25 +5379,25 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::AddUpdate(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate) - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - + @@ -5438,29 +5405,29 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(System.String,ICSharpCode.SharpZipLib.Zip.CompressionMethod,System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -5468,24 +5435,24 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(System.String,ICSharpCode.SharpZipLib.Zip.CompressionMethod) - - - - - - - - - - + + + + + + + + + + - - - - + + + + - + @@ -5493,17 +5460,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(System.String) - - - - - + + + + + - - + + - + @@ -5511,21 +5478,21 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(System.String,System.String) - - - - - - - + + + + + + + - - - - + + + + - + @@ -5533,21 +5500,21 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(ICSharpCode.SharpZipLib.Zip.IStaticDataSource,System.String) - - - - - - - + + + + + + + - - - - + + + + - + @@ -5555,23 +5522,23 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(ICSharpCode.SharpZipLib.Zip.IStaticDataSource,System.String,ICSharpCode.SharpZipLib.Zip.CompressionMethod) - - - - - - - - - + + + + + + + + + - - - - + + + + - + @@ -5579,24 +5546,24 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(ICSharpCode.SharpZipLib.Zip.IStaticDataSource,System.String,ICSharpCode.SharpZipLib.Zip.CompressionMethod,System.Boolean) - - - - - - - - - - + + + + + + + + + + - - - - + + + + - + @@ -5604,23 +5571,23 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Add(ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - - - + + + + + + + - - - - - - + + + + + + - + @@ -5628,18 +5595,18 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::AddDirectory(System.String) - - - - - - + + + + + + - - + + - + @@ -5647,29 +5614,29 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile::Delete(System.String) - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -5677,24 +5644,24 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Delete(ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - - - - - - + + + + + + + + + + - - - - + + + + - + @@ -5702,12 +5669,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteLEShort(System.Int32) - - - + + + - + @@ -5715,12 +5682,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteLEUshort(System.UInt16) - - - + + + - + @@ -5728,12 +5695,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteLEInt(System.Int32) - - - + + + - + @@ -5741,12 +5708,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteLEUint(System.UInt32) - - - + + + - + @@ -5754,12 +5721,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteLeLong(System.Int64) - - - + + + - + @@ -5767,12 +5734,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteLEUlong(System.UInt64) - - - + + + - + @@ -5780,111 +5747,111 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteLocalEntryHeader(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5892,115 +5859,115 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile::WriteCentralDirectoryHeader(ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6008,19 +5975,19 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::PostUpdateCleanup() - - - - - - - + + + + + + + - - + + - + @@ -6028,14 +5995,14 @@ System.String ICSharpCode.SharpZipLib.Zip.ZipFile::GetTransformedFileName(System.String) - - + + - - + + - + @@ -6043,14 +6010,14 @@ System.String ICSharpCode.SharpZipLib.Zip.ZipFile::GetTransformedDirectoryName(System.String) - - + + - - + + - + @@ -6058,15 +6025,15 @@ System.Byte[] ICSharpCode.SharpZipLib.Zip.ZipFile::GetBuffer() - - - + + + - - + + - + @@ -6074,28 +6041,28 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CopyDescriptorBytes(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate,System.IO.Stream,System.IO.Stream) - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -6103,48 +6070,48 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CopyBytes(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate,System.IO.Stream,System.IO.Stream,System.Int64,System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6152,20 +6119,20 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile::GetDescriptorSize(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate) - - - - - - + + + + + + - - - - + + + + - + @@ -6173,29 +6140,29 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CopyDescriptorBytesDirect(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate,System.IO.Stream,System.Int64&,System.Int64) - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -6203,49 +6170,49 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CopyEntryDataDirect(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate,System.IO.Stream,System.Boolean,System.Int64&,System.Int64&) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6253,17 +6220,17 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile::FindExistingUpdate(ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - + + + + + - - + + - + @@ -6271,17 +6238,17 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile::FindExistingUpdate(System.String) - - - - - + + + + + - - + + - + @@ -6289,28 +6256,28 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipFile::GetOutputStream(ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -6318,49 +6285,49 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::AddEntry(ICSharpCode.SharpZipLib.Zip.ZipFile,ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6368,24 +6335,24 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::ModifyEntry(ICSharpCode.SharpZipLib.Zip.ZipFile,ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate) - - - - - - - - - - + + + + + + + + + + - - - - + + + + - + @@ -6393,38 +6360,38 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CopyEntryDirect(ICSharpCode.SharpZipLib.Zip.ZipFile,ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate,System.Int64&) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6432,22 +6399,22 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CopyEntry(ICSharpCode.SharpZipLib.Zip.ZipFile,ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate) - - - - - - - - - - + + + + + + + + + + - - + + - + @@ -6455,18 +6422,18 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Reopen(System.IO.Stream) - - - - - - + + + + + + - - + + - + @@ -6474,16 +6441,16 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Reopen() - - - - + + + + - - + + - + @@ -6491,49 +6458,49 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::UpdateCommentOnly() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6541,127 +6508,127 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::RunUpdates() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6669,15 +6636,15 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CheckUpdating() - - - + + + - - + + - + @@ -6685,11 +6652,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::System.IDisposable.Dispose() - - + + - + @@ -6697,25 +6664,25 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::DisposeInternal(System.Boolean) - - - - - - - - - + + + + + + + + + - - - - - - + + + + + + - + @@ -6723,11 +6690,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::Dispose(System.Boolean) - - + + - + @@ -6735,21 +6702,21 @@ System.UInt16 ICSharpCode.SharpZipLib.Zip.ZipFile::ReadLEUshort() - - - - - - - + + + + + + + - - - - + + + + - + @@ -6757,10 +6724,10 @@ System.UInt32 ICSharpCode.SharpZipLib.Zip.ZipFile::ReadLEUint() - + - + @@ -6768,10 +6735,10 @@ System.UInt64 ICSharpCode.SharpZipLib.Zip.ZipFile::ReadLEUlong() - + - + @@ -6779,12 +6746,12 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile::LocateBlockWithSignature(System.Int32,System.Int64,System.Int32,System.Int32) - - - + + + - + @@ -6792,140 +6759,140 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::ReadEntries() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6933,10 +6900,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile::LocateEntry(ICSharpCode.SharpZipLib.Zip.ZipEntry) - + - + @@ -6944,55 +6911,55 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipFile::CreateAndInitDecryptionStream(System.IO.Stream,ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -7000,32 +6967,32 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipFile::CreateAndInitEncryptionStream(System.IO.Stream,ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -7033,17 +7000,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::CheckClassicPassword(System.Security.Cryptography.CryptoStream,ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - + + + + + - - + + - + @@ -7051,15 +7018,15 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipFile::WriteEncryptionHeader(System.IO.Stream,System.Int64) - - - - - - + + + + + + - + @@ -7068,25 +7035,25 @@ ICSharpCode.SharpZipLib.Zip.ZipFile/KeysRequiredEventHandler - 100664490 + 100664493 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/KeysRequiredEventHandler::.ctor(System.Object,System.IntPtr) - 100664491 + 100664494 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/KeysRequiredEventHandler::Invoke(System.Object,ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs) - 100664492 + 100664495 System.IAsyncResult ICSharpCode.SharpZipLib.Zip.ZipFile/KeysRequiredEventHandler::BeginInvoke(System.Object,ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs,System.AsyncCallback,System.Object) - 100664493 + 100664496 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/KeysRequiredEventHandler::EndInvoke(System.IAsyncResult) @@ -7099,62 +7066,62 @@ - 100664494 + 100664497 System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile/UpdateComparer::Compare(System.Object,System.Object) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664495 + 100664498 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/UpdateComparer::.ctor() - + @@ -7164,268 +7131,268 @@ - 100664504 + 100664507 ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::get_Entry() - + - + - 100664505 + 100664508 ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::get_OutEntry() - - - + + + - - + + - + - 100664506 + 100664509 ICSharpCode.SharpZipLib.Zip.ZipFile/UpdateCommand ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::get_Command() - + - + - 100664507 + 100664510 System.String ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::get_Filename() - + - + - 100664508 + 100664511 System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::get_SizePatchOffset() - + - + - 100664509 + 100664512 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::set_SizePatchOffset(System.Int64) - - + + - + - 100664510 + 100664513 System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::get_CrcPatchOffset() - + - + - 100664511 + 100664514 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::set_CrcPatchOffset(System.Int64) - - + + - + - 100664512 + 100664515 System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::get_OffsetBasedSize() - + - + - 100664513 + 100664516 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::set_OffsetBasedSize(System.Int64) - - + + - + - 100664496 + 100664499 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(System.String,ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - - - - + + + + + + + + - + - 100664497 + 100664500 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(System.String,System.String,ICSharpCode.SharpZipLib.Zip.CompressionMethod) - - - - - - - - - + + + + + + + + + - + - 100664498 + 100664501 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(System.String,System.String) - - + + - + - 100664499 + 100664502 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(ICSharpCode.SharpZipLib.Zip.IStaticDataSource,System.String,ICSharpCode.SharpZipLib.Zip.CompressionMethod) - - - - - - - - - + + + + + + + + + - + - 100664500 + 100664503 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(ICSharpCode.SharpZipLib.Zip.IStaticDataSource,ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - - - - + + + + + + + + - + - 100664501 + 100664504 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(ICSharpCode.SharpZipLib.Zip.ZipEntry,ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - + + + + + - + - 100664502 + 100664505 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(ICSharpCode.SharpZipLib.Zip.ZipFile/UpdateCommand,ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - - - + + + + + + + - + - 100664503 + 100664506 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::.ctor(ICSharpCode.SharpZipLib.Zip.ZipEntry) - - + + - + - 100664514 + 100664517 System.IO.Stream ICSharpCode.SharpZipLib.Zip.ZipFile/ZipUpdate::GetSource() - - - - + + + + - - + + - + @@ -7435,127 +7402,127 @@ - 100664517 + 100664520 System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::get_IsSourceString() - + - + - 100664518 + 100664521 System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::get_RawLength() - - + + - + - 100664519 + 100664522 System.Byte[] ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::get_RawComment() - - + + - + - 100664515 + 100664518 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::.ctor(System.String) - - - - + + + + - + - 100664516 + 100664519 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::.ctor(System.Byte[]) - - - + + + - + - 100664520 + 100664523 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::Reset() - - - - - + + + + + - - + + - + - 100664521 + 100664524 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::MakeTextAvailable() - - - + + + - - + + - + - 100664522 + 100664525 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::MakeBytesAvailable() - - - + + + - - + + - + - 100664523 + 100664526 System.String ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString::op_Implicit(ICSharpCode.SharpZipLib.Zip.ZipFile/ZipString) - - + + - + @@ -7565,51 +7532,51 @@ - 100664525 + 100664528 System.Object ICSharpCode.SharpZipLib.Zip.ZipFile/ZipEntryEnumerator::get_Current() - + - + - 100664524 + 100664527 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipEntryEnumerator::.ctor(ICSharpCode.SharpZipLib.Zip.ZipEntry[]) - - - - + + + + - + - 100664526 + 100664529 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/ZipEntryEnumerator::Reset() - - + + - + - 100664527 + 100664530 System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/ZipEntryEnumerator::MoveNext() - + - + @@ -7619,385 +7586,388 @@ - 100664530 + 100664533 System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::get_CanRead() - + - + - 100664532 + 100664535 System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::get_CanWrite() - + - + - 100664533 + 100664536 System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::get_CanSeek() - + - + - 100664534 + 100664537 System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::get_Length() - + - + - 100664535 + 100664538 System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::get_Position() - + - + - 100664536 + 100664539 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::set_Position(System.Int64) - + - + - 100664528 + 100664531 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::.ctor(System.IO.Stream) - - - + + + - + - 100664529 + 100664532 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::Close() - + - + - 100664531 + 100664534 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::Flush() - - + + - + - 100664537 + 100664540 System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::Read(System.Byte[],System.Int32,System.Int32) - + - + - 100664538 + 100664541 System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::Seek(System.Int64,System.IO.SeekOrigin) - + - + - 100664539 + 100664542 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::SetLength(System.Int64) - + - + - 100664540 + 100664543 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/UncompressedStream::Write(System.Byte[],System.Int32,System.Int32) - - + + - + - + ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream - 100664549 + 100664552 System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::get_Position() - + - + - 100664550 + 100664553 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::set_Position(System.Int64) - - - - - - - + + + + + + + - - - - + + + + - + - 100664551 + 100664554 System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::get_Length() - + - + - 100664552 + 100664555 System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::get_CanWrite() - + - + - 100664553 + 100664556 System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::get_CanSeek() - + - + - 100664554 + 100664557 System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::get_CanRead() - + - + - 100664555 + 100664558 System.Boolean ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::get_CanTimeout() - + - + - 100664541 + 100664544 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::.ctor(ICSharpCode.SharpZipLib.Zip.ZipFile,System.Int64,System.Int64) - - - - - - - - + + + + + + + + - + - 100664542 + 100664545 System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::ReadByte() - - - - - - + + + + + + - - + + - + - 100664543 + 100664546 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::Close() - + - + - - - 100664544 + + + 100664547 System.Int32 ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::Read(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - 100664545 + 100664548 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::Write(System.Byte[],System.Int32,System.Int32) - + - + - 100664546 + 100664549 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::SetLength(System.Int64) - + - + - 100664547 + 100664550 System.Int64 ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::Seek(System.Int64,System.IO.SeekOrigin) - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - 100664548 + 100664551 System.Void ICSharpCode.SharpZipLib.Zip.ZipFile/PartialInputStream::Flush() - + - + @@ -8011,12 +7981,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.StaticDiskDataSource::.ctor(System.String) - - - + + + - + @@ -8024,10 +7994,10 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.StaticDiskDataSource::GetSource() - + - + @@ -8041,16 +8011,16 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.DynamicDiskDataSource::GetSource(ICSharpCode.SharpZipLib.Zip.ZipEntry,System.String) - - - - + + + + - - + + - + @@ -8058,7 +8028,7 @@ System.Void ICSharpCode.SharpZipLib.Zip.DynamicDiskDataSource::.ctor() - + @@ -8072,10 +8042,10 @@ ICSharpCode.SharpZipLib.Zip.FileUpdateMode ICSharpCode.SharpZipLib.Zip.BaseArchiveStorage::get_UpdateMode() - + - + @@ -8083,12 +8053,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.BaseArchiveStorage::.ctor(ICSharpCode.SharpZipLib.Zip.FileUpdateMode) - - - + + + - + @@ -8102,17 +8072,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::.ctor(ICSharpCode.SharpZipLib.Zip.ZipFile,ICSharpCode.SharpZipLib.Zip.FileUpdateMode) - - - - - + + + + + - - + + - + @@ -8120,11 +8090,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::.ctor(ICSharpCode.SharpZipLib.Zip.ZipFile) - - + + - + @@ -8132,19 +8102,19 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::GetTemporaryOutput() - - - - - - - + + + + + + + - - + + - + @@ -8152,33 +8122,33 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::ConvertTemporaryToFinal() - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -8186,14 +8156,14 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::MakeTemporaryCopy(System.IO.Stream) - - - - - + + + + + - + @@ -8201,23 +8171,23 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::OpenForDirectUpdate(System.IO.Stream) - - - - - - - + + + + + + + - - - - - - + + + + + + - + @@ -8225,15 +8195,15 @@ System.Void ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::Dispose() - - - + + + - - + + - + @@ -8241,38 +8211,38 @@ System.String ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage::GetTempFileName(System.String,System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -8286,10 +8256,10 @@ System.IO.MemoryStream ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::get_FinalStream() - + - + @@ -8297,11 +8267,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::.ctor() - - + + - + @@ -8309,11 +8279,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::.ctor(ICSharpCode.SharpZipLib.Zip.FileUpdateMode) - - + + - + @@ -8321,11 +8291,11 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::GetTemporaryOutput() - - + + - + @@ -8333,16 +8303,16 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::ConvertTemporaryToFinal() - - - - + + + + - - + + - + @@ -8350,13 +8320,13 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::MakeTemporaryCopy(System.IO.Stream) - - - - + + + + - + @@ -8364,25 +8334,25 @@ System.IO.Stream ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::OpenForDirectUpdate(System.IO.Stream) - - - - - - - - - + + + + + + + + + - - - - - - + + + + + + - + @@ -8390,15 +8360,15 @@ System.Void ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage::Dispose() - - - + + + - - + + - + @@ -8412,10 +8382,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.DescriptorData::get_CompressedSize() - + - + @@ -8423,11 +8393,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.DescriptorData::set_CompressedSize(System.Int64) - - + + - + @@ -8435,10 +8405,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.DescriptorData::get_Size() - + - + @@ -8446,11 +8416,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.DescriptorData::set_Size(System.Int64) - - + + - + @@ -8458,10 +8428,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.DescriptorData::get_Crc() - + - + @@ -8469,11 +8439,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.DescriptorData::set_Crc(System.Int64) - - + + - + @@ -8481,7 +8451,7 @@ System.Void ICSharpCode.SharpZipLib.Zip.DescriptorData::.ctor() - + @@ -8495,10 +8465,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.EntryPatchData::get_SizePatchOffset() - + - + @@ -8506,11 +8476,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.EntryPatchData::set_SizePatchOffset(System.Int64) - - + + - + @@ -8518,10 +8488,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.EntryPatchData::get_CrcPatchOffset() - + - + @@ -8529,11 +8499,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.EntryPatchData::set_CrcPatchOffset(System.Int64) - - + + - + @@ -8541,7 +8511,7 @@ System.Void ICSharpCode.SharpZipLib.Zip.EntryPatchData::.ctor() - + @@ -8555,10 +8525,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipHelperStream::get_IsStreamOwner() - + - + @@ -8566,11 +8536,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::set_IsStreamOwner(System.Boolean) - - + + - + @@ -8578,10 +8548,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipHelperStream::get_CanRead() - + - + @@ -8589,10 +8559,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipHelperStream::get_CanSeek() - + - + @@ -8600,10 +8570,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipHelperStream::get_CanTimeout() - + - + @@ -8611,10 +8581,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::get_Length() - + - + @@ -8622,10 +8592,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::get_Position() - + - + @@ -8633,11 +8603,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::set_Position(System.Int64) - - + + - + @@ -8645,10 +8615,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipHelperStream::get_CanWrite() - + - + @@ -8656,13 +8626,13 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::.ctor(System.String) - - - - + + + + - + @@ -8670,12 +8640,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::.ctor(System.IO.Stream) - - - + + + - + @@ -8683,11 +8653,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::Flush() - - + + - + @@ -8695,10 +8665,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::Seek(System.Int64,System.IO.SeekOrigin) - + - + @@ -8706,11 +8676,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::SetLength(System.Int64) - - + + - + @@ -8718,10 +8688,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::Read(System.Byte[],System.Int32,System.Int32) - + - + @@ -8729,11 +8699,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::Write(System.Byte[],System.Int32,System.Int32) - - + + - + @@ -8741,20 +8711,20 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::Close() - - - - - - + + + + + + - - - - + + + + - + @@ -8762,95 +8732,95 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteLocalHeader(ICSharpCode.SharpZipLib.Zip.ZipEntry,ICSharpCode.SharpZipLib.Zip.EntryPatchData) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -8858,25 +8828,25 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::LocateBlockWithSignature(System.Int32,System.Int64,System.Int32,System.Int32) - - - - - - - - - + + + + + + + + + - - - - - - + + + + + + - + @@ -8884,25 +8854,25 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteZip64EndOfCentralDirectory(System.Int64,System.Int64,System.Int64) - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + @@ -8910,54 +8880,54 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteEndOfCentralDirectory(System.Int64,System.Int64,System.Int64,System.Byte[]) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -8965,21 +8935,21 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::ReadLEShort() - - - - - - - + + + + + + + - - - - + + + + - + @@ -8987,10 +8957,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::ReadLEInt() - + - + @@ -8998,10 +8968,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::ReadLELong() - + - + @@ -9009,12 +8979,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteLEShort(System.Int32) - - - + + + - + @@ -9022,12 +8992,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteLEUshort(System.UInt16) - - - + + + - + @@ -9035,12 +9005,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteLEInt(System.Int32) - - - + + + - + @@ -9048,12 +9018,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteLEUint(System.UInt32) - - - + + + - + @@ -9061,12 +9031,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteLELong(System.Int64) - - - + + + - + @@ -9074,12 +9044,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteLEUlong(System.UInt64) - - - + + + - + @@ -9087,32 +9057,32 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipHelperStream::WriteDataDescriptor(ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -9120,30 +9090,30 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipHelperStream::ReadDataDescriptor(System.Boolean,ICSharpCode.SharpZipLib.Zip.DescriptorData) - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - + - + ICSharpCode.SharpZipLib.Zip.ZipInputStream @@ -9152,10 +9122,10 @@ System.String ICSharpCode.SharpZipLib.Zip.ZipInputStream::get_Password() - + - + @@ -9163,11 +9133,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream::set_Password(System.String) - - + + - + @@ -9175,10 +9145,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipInputStream::get_CanDecompressEntry() - + - + @@ -9186,13 +9156,13 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream::get_Available() - + - - + + - + @@ -9200,19 +9170,19 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.ZipInputStream::get_Length() - - - - - + + + + + - - - - + + + + - + @@ -9220,13 +9190,13 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream::.ctor(System.IO.Stream) - - - - + + + + - + @@ -9234,13 +9204,13 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream::.ctor(System.IO.Stream,System.Int32) - - - - + + + + - + @@ -9248,112 +9218,112 @@ ICSharpCode.SharpZipLib.Zip.ZipEntry ICSharpCode.SharpZipLib.Zip.ZipInputStream::GetNextEntry() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -9361,26 +9331,26 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream::ReadDataDescriptor() - - - - - - - - - - - - + + + + + + + + + + + + - - - - + + + + - + @@ -9388,31 +9358,31 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream::CompleteCloseEntry(System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -9420,68 +9390,68 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream::CloseEntry() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + 100663731 System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream::ReadByte() - - - - + + + + - - + + - + @@ -9489,10 +9459,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream::ReadingNotAvailable(System.Byte[],System.Int32,System.Int32) - + - + @@ -9500,66 +9470,66 @@ 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) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -9567,27 +9537,27 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream::Read(System.Byte[],System.Int32,System.Int32) - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - + @@ -9595,83 +9565,83 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream::BodyRead(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -9679,14 +9649,14 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream::Close() - - - - - + + + + + - + @@ -9695,25 +9665,25 @@ ICSharpCode.SharpZipLib.Zip.ZipInputStream/ReadDataHandler - 100664556 + 100664559 System.Void ICSharpCode.SharpZipLib.Zip.ZipInputStream/ReadDataHandler::.ctor(System.Object,System.IntPtr) - 100664557 + 100664560 System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream/ReadDataHandler::Invoke(System.Byte[],System.Int32,System.Int32) - 100664558 + 100664561 System.IAsyncResult ICSharpCode.SharpZipLib.Zip.ZipInputStream/ReadDataHandler::BeginInvoke(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object) - 100664559 + 100664562 System.Int32 ICSharpCode.SharpZipLib.Zip.ZipInputStream/ReadDataHandler::EndInvoke(System.IAsyncResult) @@ -9730,10 +9700,10 @@ System.String ICSharpCode.SharpZipLib.Zip.ZipNameTransform::get_TrimPrefix() - + - + @@ -9741,16 +9711,16 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipNameTransform::set_TrimPrefix(System.String) - - - - + + + + - - + + - + @@ -9758,11 +9728,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipNameTransform::.ctor() - - + + - + @@ -9770,12 +9740,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipNameTransform::.ctor(System.String) - - - + + + - + @@ -9783,23 +9753,23 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipNameTransform::.cctor() - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + @@ -9807,21 +9777,21 @@ System.String ICSharpCode.SharpZipLib.Zip.ZipNameTransform::TransformDirectory(System.String) - - - - - - - + + + + + + + - - - - + + + + - + @@ -9829,44 +9799,44 @@ System.String ICSharpCode.SharpZipLib.Zip.ZipNameTransform::TransformFile(System.String) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -9874,31 +9844,31 @@ System.String ICSharpCode.SharpZipLib.Zip.ZipNameTransform::MakeValidName(System.String,System.Char) - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -9906,21 +9876,21 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipNameTransform::IsValidName(System.String,System.Boolean) - - - - - - - + + + + + + + - - - - + + + + - + @@ -9928,11 +9898,11 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipNameTransform::IsValidName(System.String) - - + + - + @@ -9946,10 +9916,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.ZipOutputStream::get_IsFinished() - + - + @@ -9957,10 +9927,10 @@ ICSharpCode.SharpZipLib.Zip.UseZip64 ICSharpCode.SharpZipLib.Zip.ZipOutputStream::get_UseZip64() - + - + @@ -9968,11 +9938,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::set_UseZip64(ICSharpCode.SharpZipLib.Zip.UseZip64) - - + + - + @@ -9980,19 +9950,19 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::.ctor(System.IO.Stream) - - - - - - - - - - + + + + + + + + + + - + @@ -10000,19 +9970,19 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::.ctor(System.IO.Stream,System.Int32) - - - - - - - - - - + + + + + + + + + + - + @@ -10020,17 +9990,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::SetComment(System.String) - - - - - + + + + + - - + + - + @@ -10038,12 +10008,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::SetLevel(System.Int32) - - - + + + - + @@ -10051,10 +10021,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.ZipOutputStream::GetLevel() - + - + @@ -10062,12 +10032,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::WriteLeShort(System.Int32) - - - + + + - + @@ -10075,12 +10045,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::WriteLeInt(System.Int32) - - - + + + - + @@ -10088,12 +10058,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::WriteLeLong(System.Int64) - - - + + + - + @@ -10101,197 +10071,197 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::PutNextEntry(ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -10299,105 +10269,105 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::CloseEntry() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -10405,18 +10375,18 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::WriteEncryptionHeader(System.Int64) - - - - - - - - - + + + + + + + + + - + @@ -10424,16 +10394,16 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::AddExtraDataAES(ICSharpCode.SharpZipLib.Zip.ZipEntry,ICSharpCode.SharpZipLib.Zip.ZipExtraData) - - - - - - - + + + + + + + - + @@ -10441,13 +10411,13 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::WriteAESHeader(ICSharpCode.SharpZipLib.Zip.ZipEntry) - - - - + + + + - + @@ -10455,46 +10425,46 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::Write(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -10502,23 +10472,23 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::CopyAndEncrypt(System.Byte[],System.Int32,System.Int32) - - - - - - - - - + + + + + + + + + - - - - + + + + - + @@ -10526,127 +10496,127 @@ System.Void ICSharpCode.SharpZipLib.Zip.ZipOutputStream::Finish() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -10660,10 +10630,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Deflater::get_Adler() - + - + @@ -10671,10 +10641,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Deflater::get_TotalIn() - + - + @@ -10682,10 +10652,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Deflater::get_TotalOut() - + - + @@ -10693,10 +10663,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Deflater::get_IsFinished() - + - + @@ -10704,10 +10674,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Deflater::get_IsNeedingInput() - + - + @@ -10715,11 +10685,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::.ctor() - - + + - + @@ -10727,11 +10697,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::.ctor(System.Int32) - - + + - + @@ -10739,29 +10709,29 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::.ctor(System.Int32,System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -10769,17 +10739,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::Reset() - - - - - + + + + + - - + + - + @@ -10787,11 +10757,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::Flush() - - + + - + @@ -10799,11 +10769,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::Finish() - - + + - + @@ -10811,11 +10781,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::SetInput(System.Byte[]) - - + + - + @@ -10823,16 +10793,16 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::SetInput(System.Byte[],System.Int32,System.Int32) - - - - + + + + - - + + - + @@ -10840,27 +10810,27 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::SetLevel(System.Int32) - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - + @@ -10868,10 +10838,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Deflater::GetLevel() - + - + @@ -10879,11 +10849,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::SetStrategy(ICSharpCode.SharpZipLib.Zip.Compression.DeflateStrategy) - - + + - + @@ -10891,10 +10861,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Deflater::Deflate(System.Byte[]) - + - + @@ -10902,82 +10872,82 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Deflater::Deflate(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -10985,11 +10955,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::SetDictionary(System.Byte[]) - - + + - + @@ -10997,17 +10967,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Deflater::SetDictionary(System.Byte[],System.Int32,System.Int32) - - - - - + + + + + - - + + - + @@ -11021,15 +10991,15 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterConstants::.cctor() - - - - - - + + + + + + - + @@ -11043,10 +11013,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::get_Adler() - + - + @@ -11054,10 +11024,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::get_TotalIn() - + - + @@ -11065,10 +11035,10 @@ ICSharpCode.SharpZipLib.Zip.Compression.DeflateStrategy ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::get_Strategy() - + - + @@ -11076,11 +11046,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::set_Strategy(ICSharpCode.SharpZipLib.Zip.Compression.DeflateStrategy) - - + + - + @@ -11088,18 +11058,18 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::.ctor(ICSharpCode.SharpZipLib.Zip.Compression.DeflaterPending) - - - - - - - - - + + + + + + + + + - + @@ -11107,28 +11077,28 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::Deflate(System.Boolean,System.Boolean) - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -11136,37 +11106,37 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::SetInput(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11174,10 +11144,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::NeedsInput() - + - + @@ -11185,31 +11155,31 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::SetDictionary(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11217,30 +11187,30 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::Reset() - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -11248,11 +11218,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::ResetAdler() - - + + - + @@ -11260,54 +11230,54 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::SetLevel(System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11315,34 +11285,34 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::FillWindow() - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11350,11 +11320,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::UpdateHash() - - + + - + @@ -11362,14 +11332,14 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::InsertString() - - - - - + + + + + - + @@ -11377,33 +11347,33 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::SlideWindow() - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11411,77 +11381,77 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::FindLongestMatch(System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11489,32 +11459,32 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::DeflateStored(System.Boolean,System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11522,75 +11492,75 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::DeflateFast(System.Boolean,System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11598,100 +11568,100 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine::DeflateSlow(System.Boolean,System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11705,45 +11675,45 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::.cctor() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11751,17 +11721,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::.ctor(ICSharpCode.SharpZipLib.Zip.Compression.DeflaterPending) - - - - - - - - + + + + + + + + - + @@ -11769,15 +11739,15 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::Reset() - - - - - - + + + + + + - + @@ -11785,25 +11755,25 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::SendAllTrees(System.Int32) - - - - - - - - - - - - - + + + + + + + + + + + + + - - + + - + @@ -11811,40 +11781,40 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::CompressBlock() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11852,19 +11822,19 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::FlushStoredBlock(System.Byte[],System.Int32,System.Int32,System.Boolean) - - - - - - - + + + + + + + - - + + - + @@ -11872,69 +11842,69 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::FlushBlock(System.Byte[],System.Int32,System.Int32,System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11942,10 +11912,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::IsFull() - + - + @@ -11953,13 +11923,13 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::TallyLit(System.Int32) - - - - + + + + - + @@ -11967,27 +11937,27 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::TallyDist(System.Int32,System.Int32) - - - - - - - - - - - + + + + + + + + + + + - - - - - - + + + + + + - + @@ -11995,10 +11965,10 @@ System.Int16 ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::BitReverse(System.Int32) - + - + @@ -12006,21 +11976,21 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::Lcode(System.Int32) - - - - - - - + + + + + + + - - - - + + + + - + @@ -12028,481 +11998,481 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman::Dcode(System.Int32) - - - - - + + + + + - - + + - + - + ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree - 100664560 + 100664563 System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::.ctor(ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman,System.Int32,System.Int32,System.Int32) - - - - - - - + + + + + + + - + - 100664561 + 100664564 System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::Reset() - - - - - - - + + + + + + + - - + + - + - 100664562 + 100664565 System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::WriteSymbol(System.Int32) - - + + - + - 100664563 + 100664566 System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::CheckEmpty() - - - - - - - - + + + + + + + + - - - - + + + + - + - 100664564 + 100664567 System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::SetStaticCodes(System.Int16[],System.Byte[]) - - - + + + - + - 100664565 + 100664568 System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::BuildCodes() - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664566 + 100664569 System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::BuildTree() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664567 + 100664570 System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::GetEncodedLength() - - - - - - + + + + + + - - + + - + - 100664568 + 100664571 System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::CalcBLFreq(ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664569 + 100664572 System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::WriteTree(ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100664570 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664573 System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman/Tree::BuildLength(System.Int32[]) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -12516,11 +12486,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.DeflaterPending::.ctor() - - + + - + @@ -12534,10 +12504,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::get_IsNeedingInput() - + - + @@ -12545,10 +12515,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::get_IsNeedingDictionary() - + - + @@ -12556,10 +12526,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::get_IsFinished() - + - + @@ -12567,10 +12537,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Inflater::get_Adler() - + - + @@ -12578,10 +12548,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Inflater::get_TotalOut() - + - + @@ -12589,10 +12559,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Inflater::get_TotalIn() - + - + @@ -12600,10 +12570,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Inflater::get_RemainingInput() - + - + @@ -12611,11 +12581,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::.ctor() - - + + - + @@ -12623,19 +12593,19 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::.ctor(System.Boolean) - - - - - - - + + + + + + + - - + + - + @@ -12643,23 +12613,23 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::Reset() - - - - - - - - - - - + + + + + + + + + + + - - + + - + @@ -12667,33 +12637,33 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::DecodeHeader() - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -12701,22 +12671,22 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::DecodeDict() - - - - - - - - + + + + + + + + - - - - + + + + - + @@ -12724,83 +12694,83 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::DecodeHuffman() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -12808,27 +12778,27 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::DecodeChksum() - - - - - - - - - - - + + + + + + + + + + + - - - - - - + + + + + + - + @@ -12836,99 +12806,99 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Inflater::Decode() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -12936,11 +12906,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::SetDictionary(System.Byte[]) - - + + - + @@ -12948,35 +12918,35 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::SetDictionary(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -12984,11 +12954,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::SetInput(System.Byte[]) - - + + - + @@ -12996,12 +12966,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::SetInput(System.Byte[],System.Int32,System.Int32) - - - + + + - + @@ -13009,15 +12979,15 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Inflater::Inflate(System.Byte[]) - - - + + + - - + + - + @@ -13025,59 +12995,59 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Inflater::Inflate(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -13085,13 +13055,13 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Inflater::.cctor() - - - - + + + + - + @@ -13105,108 +13075,108 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader::Decode(ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -13214,12 +13184,12 @@ ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader::BuildLitLenTree() - - - + + + - + @@ -13227,12 +13197,12 @@ ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader::BuildDistTree() - - - + + + - + @@ -13240,7 +13210,7 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader::.ctor() - + @@ -13248,12 +13218,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader::.cctor() - - - + + + - + @@ -13267,40 +13237,40 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree::.cctor() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -13308,12 +13278,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree::.ctor(System.Byte[]) - - - + + + - + @@ -13321,84 +13291,84 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree::BuildTree(System.Byte[]) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -13406,46 +13376,46 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree::GetSymbol(ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -13459,10 +13429,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::get_BitCount() - + - + @@ -13470,10 +13440,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::get_IsFlushed() - + - + @@ -13481,11 +13451,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::.ctor() - - + + - + @@ -13493,12 +13463,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::.ctor(System.Int32) - - - + + + - + @@ -13506,11 +13476,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::Reset() - - + + - + @@ -13518,11 +13488,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::WriteByte(System.Int32) - - + + - + @@ -13530,12 +13500,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::WriteShort(System.Int32) - - - + + + - + @@ -13543,14 +13513,14 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::WriteInt(System.Int32) - - - - - + + + + + - + @@ -13558,12 +13528,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::WriteBlock(System.Byte[],System.Int32,System.Int32) - - - + + + - + @@ -13571,21 +13541,21 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::AlignToByte() - - - - - - - + + + + + + + - - - - + + + + - + @@ -13593,20 +13563,20 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::WriteBits(System.Int32,System.Int32) - - - - - - - - + + + + + + + + - - + + - + @@ -13614,12 +13584,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::WriteShortMSB(System.Int32) - - - + + + - + @@ -13627,27 +13597,27 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::Flush(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - + + + + - + @@ -13655,14 +13625,14 @@ System.Byte[] ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer::ToByteArray() - - - - - + + + + + - + @@ -13676,10 +13646,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_IsStreamOwner() - + - + @@ -13687,11 +13657,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::set_IsStreamOwner(System.Boolean) - - + + - + @@ -13699,10 +13669,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_CanPatchEntries() - + - + @@ -13710,10 +13680,10 @@ System.String ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_Password() - + - + @@ -13721,19 +13691,19 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::set_Password(System.String) - - - - - + + + + + - - - - + + + + - + @@ -13741,10 +13711,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_CanRead() - + - + @@ -13752,10 +13722,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_CanSeek() - + - + @@ -13763,10 +13733,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_CanWrite() - + - + @@ -13774,10 +13744,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_Length() - + - + @@ -13785,10 +13755,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::get_Position() - + - + @@ -13796,10 +13766,10 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::set_Position(System.Int64) - + - + @@ -13807,11 +13777,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::.ctor(System.IO.Stream) - - + + - + @@ -13819,11 +13789,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::.ctor(System.IO.Stream,ICSharpCode.SharpZipLib.Zip.Compression.Deflater) - - + + - + @@ -13831,32 +13801,32 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::.ctor(System.IO.Stream,ICSharpCode.SharpZipLib.Zip.Compression.Deflater,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -13864,38 +13834,38 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::Finish() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -13903,11 +13873,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::EncryptBlock(System.Byte[],System.Int32,System.Int32) - - + + - + @@ -13915,13 +13885,13 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::InitializePassword(System.String) - - - - + + + + - + @@ -13929,20 +13899,20 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::InitializeAESPassword(ICSharpCode.SharpZipLib.Zip.ZipEntry,System.String,System.Byte[]&,System.Byte[]&) - - - - - - - - + + + + + + + + - - + + - + @@ -13950,27 +13920,27 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::Deflate() - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - + @@ -13978,10 +13948,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::Seek(System.Int64,System.IO.SeekOrigin) - + - + @@ -13989,10 +13959,10 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::SetLength(System.Int64) - + - + @@ -14000,10 +13970,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::ReadByte() - + - + @@ -14011,10 +13981,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::Read(System.Byte[],System.Int32,System.Int32) - + - + @@ -14022,10 +13992,10 @@ System.IAsyncResult ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::BeginRead(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object) - + - + @@ -14033,10 +14003,10 @@ System.IAsyncResult ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::BeginWrite(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object) - + - + @@ -14044,13 +14014,13 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::Flush() - - - - + + + + - + @@ -14058,28 +14028,28 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::Close() - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -14087,15 +14057,15 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::GetAuthCodeIfAES() - - - + + + - - + + - + @@ -14103,13 +14073,13 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::WriteByte(System.Byte) - - - - + + + + - + @@ -14117,12 +14087,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream::Write(System.Byte[],System.Int32,System.Int32) - - - + + + - + @@ -14136,10 +14106,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::get_RawLength() - + - + @@ -14147,10 +14117,10 @@ System.Byte[] ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::get_RawData() - + - + @@ -14158,10 +14128,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::get_ClearTextLength() - + - + @@ -14169,10 +14139,10 @@ System.Byte[] ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::get_ClearText() - + - + @@ -14180,10 +14150,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::get_Available() - + - + @@ -14191,11 +14161,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::set_Available(System.Int32) - - + + - + @@ -14203,31 +14173,31 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::set_CryptoTransform(System.Security.Cryptography.ICryptoTransform) - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14235,11 +14205,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::.ctor(System.IO.Stream) - - + + - + @@ -14247,19 +14217,19 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::.ctor(System.IO.Stream,System.Int32) - - - - - - - + + + + + + + - - + + - + @@ -14267,16 +14237,16 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::SetInflaterInput(ICSharpCode.SharpZipLib.Zip.Compression.Inflater) - - - - + + + + - - + + - + @@ -14284,29 +14254,29 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::Fill() - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -14314,10 +14284,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::ReadRawBuffer(System.Byte[]) - + - + @@ -14325,33 +14295,33 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::ReadRawBuffer(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14359,33 +14329,33 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::ReadClearTextBuffer(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14393,21 +14363,21 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::ReadLeByte() - - - - - - - + + + + + + + - - - - + + + + - + @@ -14415,10 +14385,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::ReadLeShort() - + - + @@ -14426,10 +14396,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::ReadLeInt() - + - + @@ -14437,15 +14407,15 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer::ReadLeLong() - + - + - + ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream @@ -14454,10 +14424,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::get_IsStreamOwner() - + - + @@ -14465,11 +14435,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::set_IsStreamOwner(System.Boolean) - - + + - + @@ -14477,13 +14447,13 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::get_Available() - + - - + + - + @@ -14491,10 +14461,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::get_CanRead() - + - + @@ -14502,10 +14472,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::get_CanSeek() - + - + @@ -14513,10 +14483,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::get_CanWrite() - + - + @@ -14524,10 +14494,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::get_Length() - + - + @@ -14535,10 +14505,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::get_Position() - + - + @@ -14546,10 +14516,10 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::set_Position(System.Int64) - + - + @@ -14557,11 +14527,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::.ctor(System.IO.Stream) - - + + - + @@ -14569,11 +14539,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::.ctor(System.IO.Stream,ICSharpCode.SharpZipLib.Zip.Compression.Inflater) - - + + - + @@ -14581,28 +14551,28 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::.ctor(System.IO.Stream,ICSharpCode.SharpZipLib.Zip.Compression.Inflater,System.Int32) - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -14610,39 +14580,39 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::Skip(System.Int64) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14650,32 +14620,32 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::StopDecrypting() - - + + - + - - + + 100663923 System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::Fill() - - - - - - + + + + + + - - - - + + + + - + @@ -14683,11 +14653,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::Flush() - - + + - + @@ -14695,10 +14665,10 @@ System.Int64 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::Seek(System.Int64,System.IO.SeekOrigin) - + - + @@ -14706,10 +14676,10 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::SetLength(System.Int64) - + - + @@ -14717,10 +14687,10 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::Write(System.Byte[],System.Int32,System.Int32) - + - + @@ -14728,10 +14698,10 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::WriteByte(System.Byte) - + - + @@ -14739,10 +14709,10 @@ System.IAsyncResult ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::BeginWrite(System.Byte[],System.Int32,System.Int32,System.AsyncCallback,System.Object) - + - + @@ -14750,19 +14720,19 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::Close() - - - - - + + + + + - - - - + + + + - + @@ -14770,33 +14740,33 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream::Read(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14810,17 +14780,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::Write(System.Int32) - - - - - + + + + + - - + + - + @@ -14828,17 +14798,17 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::SlowRepeat(System.Int32,System.Int32,System.Int32) - - - - - + + + + + - - + + - + @@ -14846,34 +14816,34 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::Repeat(System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14881,25 +14851,25 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::CopyStored(ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator,System.Int32) - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - + @@ -14907,26 +14877,26 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::CopyDict(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - + + + + + + + + + + - - - - - - + + + + + + - + @@ -14934,10 +14904,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::GetFreeSpace() - + - + @@ -14945,10 +14915,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::GetAvailable() - + - + @@ -14956,32 +14926,32 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::CopyOutput(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14989,11 +14959,11 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::Reset() - - + + - + @@ -15001,10 +14971,10 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow::.ctor() - + - + @@ -15018,10 +14988,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::get_AvailableBits() - + - + @@ -15029,10 +14999,10 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::get_AvailableBytes() - + - + @@ -15040,10 +15010,10 @@ System.Boolean ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::get_IsNeedingInput() - + - + @@ -15051,20 +15021,20 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::PeekBits(System.Int32) - - - - - - + + + + + + - - - - + + + + - + @@ -15072,12 +15042,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::DropBits(System.Int32) - - - + + + - + @@ -15085,16 +15055,16 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::GetBits(System.Int32) - - - - + + + + - - + + - + @@ -15102,12 +15072,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::SkipToByteBoundary() - - - + + + - + @@ -15115,46 +15085,46 @@ System.Int32 ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::CopyBytes(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -15162,12 +15132,12 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::Reset() - - - + + + - + @@ -15175,42 +15145,42 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::SetInput(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -15218,7 +15188,7 @@ System.Void ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator::.ctor() - + @@ -15232,11 +15202,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.InvalidHeaderException::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) - - + + - + @@ -15244,11 +15214,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.InvalidHeaderException::.ctor() - - + + - + @@ -15256,11 +15226,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.InvalidHeaderException::.ctor(System.String) - - + + - + @@ -15268,11 +15238,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.InvalidHeaderException::.ctor(System.String,System.Exception) - - + + - + @@ -15307,7 +15277,7 @@ - + ICSharpCode.SharpZipLib.Tar.TarArchive @@ -15316,15 +15286,15 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarArchive::get_AsciiTranslate() - - - + + + - - + + - + @@ -15332,16 +15302,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::set_AsciiTranslate(System.Boolean) - - - - + + + + - - + + - + @@ -15349,15 +15319,15 @@ System.String ICSharpCode.SharpZipLib.Tar.TarArchive::get_PathPrefix() - - - + + + - - + + - + @@ -15365,16 +15335,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::set_PathPrefix(System.String) - - - - + + + + - - + + - + @@ -15382,15 +15352,15 @@ System.String ICSharpCode.SharpZipLib.Tar.TarArchive::get_RootPath() - - - + + + - - + + - + @@ -15398,16 +15368,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::set_RootPath(System.String) - - - - + + + + - - + + - + @@ -15415,15 +15385,15 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarArchive::get_ApplyUserInfoOverrides() - - - + + + - - + + - + @@ -15431,16 +15401,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::set_ApplyUserInfoOverrides(System.Boolean) - - - - + + + + - - + + - + @@ -15448,15 +15418,15 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarArchive::get_UserId() - - - + + + - - + + - + @@ -15464,15 +15434,15 @@ System.String ICSharpCode.SharpZipLib.Tar.TarArchive::get_UserName() - - - + + + - - + + - + @@ -15480,15 +15450,15 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarArchive::get_GroupId() - - - + + + - - + + - + @@ -15496,15 +15466,15 @@ System.String ICSharpCode.SharpZipLib.Tar.TarArchive::get_GroupName() - - - + + + - - + + - + @@ -15512,23 +15482,23 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarArchive::get_RecordSize() - - - - - - - + + + + + + + - - - - - - + + + + + + - + @@ -15536,17 +15506,17 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::set_IsStreamOwner(System.Boolean) - - - - - + + + + + - - + + - + @@ -15554,7 +15524,7 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::add_ProgressMessageEvent(ICSharpCode.SharpZipLib.Tar.ProgressMessageHandler) - + @@ -15562,7 +15532,7 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::remove_ProgressMessageEvent(ICSharpCode.SharpZipLib.Tar.ProgressMessageHandler) - + @@ -15570,16 +15540,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::OnProgressMessageEvent(ICSharpCode.SharpZipLib.Tar.TarEntry,System.String) - - - - + + + + - - + + - + @@ -15587,13 +15557,13 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::.ctor() - - - - + + + + - + @@ -15601,19 +15571,19 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::.ctor(ICSharpCode.SharpZipLib.Tar.TarInputStream) - - - - - - - + + + + + + + - - + + - + @@ -15621,19 +15591,19 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::.ctor(ICSharpCode.SharpZipLib.Tar.TarOutputStream) - - - - - - - + + + + + + + - - + + - + @@ -15641,22 +15611,22 @@ ICSharpCode.SharpZipLib.Tar.TarArchive ICSharpCode.SharpZipLib.Tar.TarArchive::CreateInputTarArchive(System.IO.Stream) - - - - - - - - + + + + + + + + - - - - + + + + - + @@ -15664,19 +15634,19 @@ ICSharpCode.SharpZipLib.Tar.TarArchive ICSharpCode.SharpZipLib.Tar.TarArchive::CreateInputTarArchive(System.IO.Stream,System.Int32) - - - - - + + + + + - - - - + + + + - + @@ -15684,22 +15654,22 @@ ICSharpCode.SharpZipLib.Tar.TarArchive ICSharpCode.SharpZipLib.Tar.TarArchive::CreateOutputTarArchive(System.IO.Stream) - - - - - - - - + + + + + + + + - - - - + + + + - + @@ -15707,19 +15677,19 @@ ICSharpCode.SharpZipLib.Tar.TarArchive ICSharpCode.SharpZipLib.Tar.TarArchive::CreateOutputTarArchive(System.IO.Stream,System.Int32) - - - - - + + + + + - - - - + + + + - + @@ -15727,16 +15697,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::SetKeepOldFiles(System.Boolean) - - - - + + + + - - + + - + @@ -15744,16 +15714,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::SetAsciiTranslation(System.Boolean) - - - - + + + + - - + + - + @@ -15761,20 +15731,20 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::SetUserInfo(System.Int32,System.String,System.Int32,System.String) - - - - - - - - + + + + + + + + - - + + - + @@ -15782,11 +15752,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::CloseArchive() - - + + - + @@ -15794,43 +15764,48 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::ListContents() - - - - - - - + + + + + + + - - - - + + + + - + - - + + 100663996 System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::ExtractContents(System.String) - - - - - - - + + + + + + + + - - - - + + + + + + + + - + @@ -15838,85 +15813,85 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::ExtractEntry(System.String,ICSharpCode.SharpZipLib.Tar.TarEntry) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -15924,30 +15899,30 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::WriteEntry(ICSharpCode.SharpZipLib.Tar.TarEntry,System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -15955,90 +15930,90 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::WriteEntryCore(ICSharpCode.SharpZipLib.Tar.TarEntry,System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -16046,12 +16021,12 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::Dispose() - - - + + + - + @@ -16059,27 +16034,27 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::Dispose(System.Boolean) - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - + @@ -16087,11 +16062,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::Close() - - + + - + @@ -16099,12 +16074,12 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::Finalize() - - - + + + - + @@ -16112,18 +16087,18 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarArchive::EnsureDirectoryExists(System.String) - - - - - - + + + + + + - - + + - + @@ -16131,38 +16106,38 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarArchive::IsBinary(System.String) - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + ICSharpCode.SharpZipLib.Tar.TarBuffer @@ -16171,10 +16146,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::get_RecordSize() - + - + @@ -16182,10 +16157,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::get_BlockFactor() - + - + @@ -16193,10 +16168,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::get_CurrentBlock() - + - + @@ -16204,10 +16179,10 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarBuffer::get_IsStreamOwner() - + - + @@ -16215,11 +16190,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::set_IsStreamOwner(System.Boolean) - - + + - + @@ -16227,10 +16202,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::get_CurrentRecord() - + - + @@ -16238,10 +16213,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::GetRecordSize() - + - + @@ -16249,10 +16224,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::GetBlockFactor() - + - + @@ -16260,14 +16235,14 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::.ctor() - - - - - + + + + + - + @@ -16275,15 +16250,15 @@ ICSharpCode.SharpZipLib.Tar.TarBuffer ICSharpCode.SharpZipLib.Tar.TarBuffer::CreateInputTarBuffer(System.IO.Stream) - - - + + + - - + + - + @@ -16291,23 +16266,23 @@ ICSharpCode.SharpZipLib.Tar.TarBuffer ICSharpCode.SharpZipLib.Tar.TarBuffer::CreateInputTarBuffer(System.IO.Stream,System.Int32) - - - - - - - - - + + + + + + + + + - - - - + + + + - + @@ -16315,15 +16290,15 @@ ICSharpCode.SharpZipLib.Tar.TarBuffer ICSharpCode.SharpZipLib.Tar.TarBuffer::CreateOutputTarBuffer(System.IO.Stream) - - - + + + - - + + - + @@ -16331,23 +16306,23 @@ ICSharpCode.SharpZipLib.Tar.TarBuffer ICSharpCode.SharpZipLib.Tar.TarBuffer::CreateOutputTarBuffer(System.IO.Stream,System.Int32) - - - - - - - - - + + + + + + + + + - - - - + + + + - + @@ -16355,22 +16330,22 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::Initialize(System.Int32) - - - - - - - - - - + + + + + + + + + + - - + + - + @@ -16378,28 +16353,28 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarBuffer::IsEOFBlock(System.Byte[]) - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -16407,28 +16382,28 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarBuffer::IsEndOfArchiveBlock(System.Byte[]) - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -16436,49 +16411,49 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::SkipBlock() - - - - - - - + + + + + + + - - - - - - + + + + + + - + - - + + 100664019 System.Byte[] ICSharpCode.SharpZipLib.Tar.TarBuffer::ReadBlock() - - - - - - - - - + + + + + + + + + - - - - - - + + + + + + - + @@ -16486,28 +16461,28 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarBuffer::ReadRecord() - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -16515,10 +16490,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::GetCurrentBlockNum() - + - + @@ -16526,10 +16501,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarBuffer::GetCurrentRecordNum() - + - + @@ -16537,30 +16512,30 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::WriteBlock(System.Byte[]) - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -16568,36 +16543,36 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::WriteBlock(System.Byte[],System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -16605,19 +16580,19 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::WriteRecord() - - - - - - - + + + + + + + - - + + - + @@ -16625,22 +16600,22 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::WriteFinalRecord() - - - - - - - - + + + + + + + + - - - - + + + + - + @@ -16648,34 +16623,34 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarBuffer::Close() - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + ICSharpCode.SharpZipLib.Tar.TarEntry @@ -16684,10 +16659,10 @@ ICSharpCode.SharpZipLib.Tar.TarHeader ICSharpCode.SharpZipLib.Tar.TarEntry::get_TarHeader() - + - + @@ -16695,10 +16670,10 @@ System.String ICSharpCode.SharpZipLib.Tar.TarEntry::get_Name() - + - + @@ -16706,11 +16681,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::set_Name(System.String) - - + + - + @@ -16718,22 +16693,22 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarEntry::get_UserId() - + - + - - + + 100664045 System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::set_UserId(System.Int32) - - + + - + @@ -16741,10 +16716,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarEntry::get_GroupId() - + - + @@ -16752,11 +16727,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::set_GroupId(System.Int32) - - + + - + @@ -16764,10 +16739,10 @@ System.String ICSharpCode.SharpZipLib.Tar.TarEntry::get_UserName() - + - + @@ -16775,11 +16750,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::set_UserName(System.String) - - + + - + @@ -16787,10 +16762,10 @@ System.String ICSharpCode.SharpZipLib.Tar.TarEntry::get_GroupName() - + - + @@ -16798,11 +16773,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::set_GroupName(System.String) - - + + - + @@ -16810,10 +16785,10 @@ System.DateTime ICSharpCode.SharpZipLib.Tar.TarEntry::get_ModTime() - + - + @@ -16821,11 +16796,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::set_ModTime(System.DateTime) - - + + - + @@ -16833,10 +16808,10 @@ System.String ICSharpCode.SharpZipLib.Tar.TarEntry::get_File() - + - + @@ -16844,10 +16819,10 @@ System.Int64 ICSharpCode.SharpZipLib.Tar.TarEntry::get_Size() - + - + @@ -16855,11 +16830,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::set_Size(System.Int64) - - + + - + @@ -16867,24 +16842,24 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarEntry::get_IsDirectory() - - - - - - + + + + + + - - - - - - - - + + + + + + + + - + @@ -16892,12 +16867,12 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::.ctor() - - - + + + - + @@ -16905,13 +16880,13 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::.ctor(System.Byte[]) - - - - + + + + - + @@ -16919,17 +16894,17 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::.ctor(ICSharpCode.SharpZipLib.Tar.TarHeader) - - - - - + + + + + - - + + - + @@ -16937,14 +16912,14 @@ System.Object ICSharpCode.SharpZipLib.Tar.TarEntry::Clone() - - - - - + + + + + - + @@ -16952,12 +16927,12 @@ ICSharpCode.SharpZipLib.Tar.TarEntry ICSharpCode.SharpZipLib.Tar.TarEntry::CreateTarEntry(System.String) - - - + + + - + @@ -16965,29 +16940,29 @@ ICSharpCode.SharpZipLib.Tar.TarEntry ICSharpCode.SharpZipLib.Tar.TarEntry::CreateEntryFromFile(System.String) - - - + + + - + - - + + 100664038 System.Boolean ICSharpCode.SharpZipLib.Tar.TarEntry::Equals(System.Object) - - - - + + + + - - + + - + @@ -16995,10 +16970,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarEntry::GetHashCode() - + - + @@ -17006,15 +16981,15 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarEntry::IsDescendent(ICSharpCode.SharpZipLib.Tar.TarEntry) - - - + + + - - + + - + @@ -17022,12 +16997,12 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::SetIds(System.Int32,System.Int32) - - - + + + - + @@ -17035,12 +17010,12 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::SetNames(System.String,System.String) - - - + + + - + @@ -17048,51 +17023,51 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::GetFileTarHeader(ICSharpCode.SharpZipLib.Tar.TarHeader,System.String) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -17100,25 +17075,25 @@ ICSharpCode.SharpZipLib.Tar.TarEntry[] ICSharpCode.SharpZipLib.Tar.TarEntry::GetDirectoryEntries() - - - - - - - - - + + + + + + + + + - - - - - - + + + + + + - + @@ -17126,11 +17101,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::WriteEntryHeader(System.Byte[]) - - + + - + @@ -17138,11 +17113,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::AdjustEntryName(System.Byte[],System.String) - - + + - + @@ -17150,36 +17125,36 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarEntry::NameTarHeader(ICSharpCode.SharpZipLib.Tar.TarHeader,System.String) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -17193,11 +17168,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarException::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) - - + + - + @@ -17205,11 +17180,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarException::.ctor() - - + + - + @@ -17217,11 +17192,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarException::.ctor(System.String) - - + + - + @@ -17229,16 +17204,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarException::.ctor(System.String,System.Exception) - - + + - + - + ICSharpCode.SharpZipLib.Tar.TarHeader @@ -17247,10 +17222,10 @@ System.String ICSharpCode.SharpZipLib.Tar.TarHeader::get_Name() - + - + @@ -17258,16 +17233,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_Name(System.String) - - - - + + + + - - + + - + @@ -17275,10 +17250,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::get_Mode() - + - + @@ -17286,11 +17261,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_Mode(System.Int32) - - + + - + @@ -17298,10 +17273,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::get_UserId() - + - + @@ -17309,11 +17284,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_UserId(System.Int32) - - + + - + @@ -17321,10 +17296,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::get_GroupId() - + - + @@ -17332,11 +17307,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_GroupId(System.Int32) - - + + - + @@ -17344,10 +17319,10 @@ System.Int64 ICSharpCode.SharpZipLib.Tar.TarHeader::get_Size() - + - + @@ -17355,16 +17330,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_Size(System.Int64) - - - - + + + + - - + + - + @@ -17372,10 +17347,10 @@ System.DateTime ICSharpCode.SharpZipLib.Tar.TarHeader::get_ModTime() - + - + @@ -17383,16 +17358,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_ModTime(System.DateTime) - - - - + + + + - - + + - + @@ -17400,10 +17375,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::get_Checksum() - + - + @@ -17411,10 +17386,10 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarHeader::get_IsChecksumValid() - + - + @@ -17422,10 +17397,10 @@ System.Byte ICSharpCode.SharpZipLib.Tar.TarHeader::get_TypeFlag() - + - + @@ -17433,11 +17408,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_TypeFlag(System.Byte) - - + + - + @@ -17445,10 +17420,10 @@ System.String ICSharpCode.SharpZipLib.Tar.TarHeader::get_LinkName() - + - + @@ -17456,16 +17431,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_LinkName(System.String) - - - - + + + + - - + + - + @@ -17473,10 +17448,10 @@ System.String ICSharpCode.SharpZipLib.Tar.TarHeader::get_Magic() - + - + @@ -17484,16 +17459,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_Magic(System.String) - - - - + + + + - - + + - + @@ -17501,10 +17476,10 @@ System.String ICSharpCode.SharpZipLib.Tar.TarHeader::get_Version() - + - + @@ -17512,16 +17487,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_Version(System.String) - - - - + + + + - - + + - + @@ -17529,10 +17504,10 @@ System.String ICSharpCode.SharpZipLib.Tar.TarHeader::get_UserName() - + - + @@ -17540,22 +17515,22 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_UserName(System.String) - - - - - - - - + + + + + + + + - - - - + + + + - + @@ -17563,10 +17538,10 @@ System.String ICSharpCode.SharpZipLib.Tar.TarHeader::get_GroupName() - + - + @@ -17574,17 +17549,17 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_GroupName(System.String) - - - - - + + + + + - - + + - + @@ -17592,10 +17567,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::get_DevMajor() - + - + @@ -17603,11 +17578,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_DevMajor(System.Int32) - - + + - + @@ -17615,10 +17590,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::get_DevMinor() - + - + @@ -17626,11 +17601,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::set_DevMinor(System.Int32) - - + + - + @@ -17638,20 +17613,20 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::.ctor() - - - - - - - - - - - + + + + + + + + + + + - + @@ -17659,10 +17634,10 @@ System.String ICSharpCode.SharpZipLib.Tar.TarHeader::GetName() - + - + @@ -17670,56 +17645,65 @@ System.Object ICSharpCode.SharpZipLib.Tar.TarHeader::Clone() - + - + - - + + 100664102 System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::ParseBuffer(System.Byte[]) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -17727,49 +17711,49 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::WriteHeader(System.Byte[]) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -17777,10 +17761,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetHashCode() - + - + @@ -17788,18 +17772,18 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarHeader::Equals(System.Object) - - - - - - + + + + + + - - + + - + @@ -17807,14 +17791,14 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::SetValueDefaults(System.Int32,System.String,System.Int32,System.String) - - - - - + + + + + - + @@ -17822,14 +17806,14 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::RestoreSetValues() - - - - - + + + + + - + @@ -17837,22 +17821,22 @@ System.Int64 ICSharpCode.SharpZipLib.Tar.TarHeader::ParseBinaryOrOctal(System.Byte[],System.Int32,System.Int32) - - - - - - - - + + + + + + + + - - - - + + + + - + @@ -17860,39 +17844,39 @@ System.Int64 ICSharpCode.SharpZipLib.Tar.TarHeader::ParseOctal(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -17900,37 +17884,37 @@ System.Text.StringBuilder ICSharpCode.SharpZipLib.Tar.TarHeader::ParseName(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -17938,52 +17922,52 @@ 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) - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -17991,19 +17975,19 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetNameBytes(System.Text.StringBuilder,System.Byte[],System.Int32,System.Int32) - - - - - + + + + + - - - - + + + + - + @@ -18011,19 +17995,19 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetNameBytes(System.String,System.Byte[],System.Int32,System.Int32) - - - - - + + + + + - - - - + + + + - + @@ -18031,27 +18015,27 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetAsciiBytes(System.String,System.Int32,System.Byte[],System.Int32,System.Int32) - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - + @@ -18059,35 +18043,35 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetOctalBytes(System.Int64,System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -18095,23 +18079,23 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetBinaryOrOctalBytes(System.Int64,System.Byte[],System.Int32,System.Int32) - - - - - - - - - + + + + + + + + + - - - - + + + + - + @@ -18119,11 +18103,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::GetCheckSumOctalBytes(System.Int64,System.Byte[],System.Int32,System.Int32) - - + + - + @@ -18131,18 +18115,18 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::ComputeCheckSum(System.Byte[]) - - - - - - + + + + + + - - + + - + @@ -18150,30 +18134,30 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::MakeCheckSum(System.Byte[]) - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -18181,10 +18165,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarHeader::GetCTime(System.DateTime) - + - + @@ -18192,15 +18176,15 @@ System.DateTime ICSharpCode.SharpZipLib.Tar.TarHeader::GetDateTimeFromCTime(System.Int64) - - - - - - + + + + + + - + @@ -18208,17 +18192,17 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarHeader::.cctor() - - - + + + - + - + ICSharpCode.SharpZipLib.Tar.TarInputStream @@ -18227,10 +18211,10 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarInputStream::get_IsStreamOwner() - + - + @@ -18238,11 +18222,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::set_IsStreamOwner(System.Boolean) - - + + - + @@ -18250,10 +18234,10 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarInputStream::get_CanRead() - + - + @@ -18261,10 +18245,10 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarInputStream::get_CanSeek() - + - + @@ -18272,10 +18256,10 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarInputStream::get_CanWrite() - + - + @@ -18283,10 +18267,10 @@ System.Int64 ICSharpCode.SharpZipLib.Tar.TarInputStream::get_Length() - + - + @@ -18294,10 +18278,10 @@ System.Int64 ICSharpCode.SharpZipLib.Tar.TarInputStream::get_Position() - + - + @@ -18305,10 +18289,10 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::set_Position(System.Int64) - + - + @@ -18316,10 +18300,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarInputStream::get_RecordSize() - + - + @@ -18327,10 +18311,10 @@ System.Int64 ICSharpCode.SharpZipLib.Tar.TarInputStream::get_Available() - + - + @@ -18338,10 +18322,10 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarInputStream::get_IsMarkSupported() - + - + @@ -18349,11 +18333,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::.ctor(System.IO.Stream) - - + + - + @@ -18361,13 +18345,13 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::.ctor(System.IO.Stream,System.Int32) - - - - + + + + - + @@ -18375,11 +18359,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::Flush() - - + + - + @@ -18387,10 +18371,10 @@ System.Int64 ICSharpCode.SharpZipLib.Tar.TarInputStream::Seek(System.Int64,System.IO.SeekOrigin) - + - + @@ -18398,10 +18382,10 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::SetLength(System.Int64) - + - + @@ -18409,10 +18393,10 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::Write(System.Byte[],System.Int32,System.Int32) - + - + @@ -18420,10 +18404,10 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::WriteByte(System.Byte) - + - + @@ -18431,85 +18415,85 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarInputStream::ReadByte() - - - - - + + + + + - - + + - + - - + + 100664140 System.Int32 ICSharpCode.SharpZipLib.Tar.TarInputStream::Read(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -18517,11 +18501,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::Close() - - + + - + @@ -18529,11 +18513,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::SetEntryFactory(ICSharpCode.SharpZipLib.Tar.TarInputStream/IEntryFactory) - - + + - + @@ -18541,10 +18525,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarInputStream::GetRecordSize() - + - + @@ -18552,24 +18536,24 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::Skip(System.Int64) - - - - - - - - + + + + + + + + - - - - - - + + + + + + - + @@ -18577,10 +18561,10 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::Mark(System.Int32) - + - + @@ -18588,118 +18572,122 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::Reset() - + - + - - + + 100664150 ICSharpCode.SharpZipLib.Tar.TarEntry ICSharpCode.SharpZipLib.Tar.TarInputStream::GetNextEntry() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -18707,36 +18695,36 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::CopyEntryContents(System.IO.Stream) - - - - - - + + + + + + - - + + - + - - + + 100664152 System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream::SkipToNextEntry() - - - - - + + + + + - - + + - + @@ -18746,49 +18734,49 @@ - 100664574 + 100664577 ICSharpCode.SharpZipLib.Tar.TarEntry ICSharpCode.SharpZipLib.Tar.TarInputStream/EntryFactoryAdapter::CreateEntry(System.String) - + - + - 100664575 + 100664578 ICSharpCode.SharpZipLib.Tar.TarEntry ICSharpCode.SharpZipLib.Tar.TarInputStream/EntryFactoryAdapter::CreateEntryFromFile(System.String) - + - + - 100664576 + 100664579 ICSharpCode.SharpZipLib.Tar.TarEntry ICSharpCode.SharpZipLib.Tar.TarInputStream/EntryFactoryAdapter::CreateEntry(System.Byte[]) - + - + - 100664577 + 100664580 System.Void ICSharpCode.SharpZipLib.Tar.TarInputStream/EntryFactoryAdapter::.ctor() - + - + ICSharpCode.SharpZipLib.Tar.TarOutputStream @@ -18797,10 +18785,10 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_IsStreamOwner() - + - + @@ -18808,11 +18796,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::set_IsStreamOwner(System.Boolean) - - + + - + @@ -18820,10 +18808,10 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_CanRead() - + - + @@ -18831,10 +18819,10 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_CanSeek() - + - + @@ -18842,10 +18830,10 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_CanWrite() - + - + @@ -18853,10 +18841,10 @@ System.Int64 ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_Length() - + - + @@ -18864,10 +18852,10 @@ System.Int64 ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_Position() - + - + @@ -18875,11 +18863,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::set_Position(System.Int64) - - + + - + @@ -18887,10 +18875,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_RecordSize() - + - + @@ -18898,10 +18886,10 @@ System.Boolean ICSharpCode.SharpZipLib.Tar.TarOutputStream::get_IsEntryOpen() - + - + @@ -18909,11 +18897,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::.ctor(System.IO.Stream) - - + + - + @@ -18921,20 +18909,20 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::.ctor(System.IO.Stream,System.Int32) - - - - - - - - + + + + + + + + - - + + - + @@ -18942,10 +18930,10 @@ System.Int64 ICSharpCode.SharpZipLib.Tar.TarOutputStream::Seek(System.Int64,System.IO.SeekOrigin) - + - + @@ -18953,11 +18941,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::SetLength(System.Int64) - - + + - + @@ -18965,10 +18953,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarOutputStream::ReadByte() - + - + @@ -18976,10 +18964,10 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarOutputStream::Read(System.Byte[],System.Int32,System.Int32) - + - + @@ -18987,11 +18975,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::Flush() - - + + - + @@ -18999,16 +18987,16 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::Finish() - - - - + + + + - - + + - + @@ -19016,17 +19004,17 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::Close() - - - - - + + + + + - - + + - + @@ -19034,54 +19022,55 @@ System.Int32 ICSharpCode.SharpZipLib.Tar.TarOutputStream::GetRecordSize() - + - + - - + + 100664173 System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::PutNextEntry(ICSharpCode.SharpZipLib.Tar.TarEntry) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -19089,23 +19078,23 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::CloseEntry() - - - - - - - - - + + + + + + + + + - - - - + + + + - + @@ -19113,11 +19102,11 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::WriteByte(System.Byte) - - + + - + @@ -19125,65 +19114,65 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::Write(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -19191,553 +19180,613 @@ System.Void ICSharpCode.SharpZipLib.Tar.TarOutputStream::WriteEofBlock() - - - + + + - + - ICSharpCode.SharpZipLib.LZW.LzwConstants + ICSharpCode.SharpZipLib.Lzw.LzwConstants 100664178 - System.Void ICSharpCode.SharpZipLib.LZW.LzwConstants::.ctor() + System.Void ICSharpCode.SharpZipLib.Lzw.LzwConstants::.ctor() - - + + - + - - ICSharpCode.SharpZipLib.LZW.LzwException + + ICSharpCode.SharpZipLib.Lzw.LzwException 100664179 - System.Void ICSharpCode.SharpZipLib.LZW.LzwException::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) + System.Void ICSharpCode.SharpZipLib.Lzw.LzwException::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) - - + + - + 100664180 - System.Void ICSharpCode.SharpZipLib.LZW.LzwException::.ctor() + System.Void ICSharpCode.SharpZipLib.Lzw.LzwException::.ctor() - - + + - + - - + + 100664181 - System.Void ICSharpCode.SharpZipLib.LZW.LzwException::.ctor(System.String) + System.Void ICSharpCode.SharpZipLib.Lzw.LzwException::.ctor(System.String) - - + + - + 100664182 - System.Void ICSharpCode.SharpZipLib.LZW.LzwException::.ctor(System.String,System.Exception) + System.Void ICSharpCode.SharpZipLib.Lzw.LzwException::.ctor(System.String,System.Exception) - - + + - + - - ICSharpCode.SharpZipLib.LZW.LzwInputStream + + ICSharpCode.SharpZipLib.Lzw.LzwInputStream 100664183 - System.Boolean ICSharpCode.SharpZipLib.LZW.LzwInputStream::get_IsStreamOwner() + System.Boolean ICSharpCode.SharpZipLib.Lzw.LzwInputStream::get_IsStreamOwner() - + - + - - + + 100664184 - System.Void ICSharpCode.SharpZipLib.LZW.LzwInputStream::set_IsStreamOwner(System.Boolean) + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::set_IsStreamOwner(System.Boolean) - - + + - + 100664191 - System.Boolean ICSharpCode.SharpZipLib.LZW.LzwInputStream::get_CanRead() + System.Boolean ICSharpCode.SharpZipLib.Lzw.LzwInputStream::get_CanRead() - + - + 100664192 - System.Boolean ICSharpCode.SharpZipLib.LZW.LzwInputStream::get_CanSeek() + System.Boolean ICSharpCode.SharpZipLib.Lzw.LzwInputStream::get_CanSeek() - + - + 100664193 - System.Boolean ICSharpCode.SharpZipLib.LZW.LzwInputStream::get_CanWrite() + System.Boolean ICSharpCode.SharpZipLib.Lzw.LzwInputStream::get_CanWrite() - + - + 100664194 - System.Int64 ICSharpCode.SharpZipLib.LZW.LzwInputStream::get_Length() + System.Int64 ICSharpCode.SharpZipLib.Lzw.LzwInputStream::get_Length() - + - + 100664195 - System.Int64 ICSharpCode.SharpZipLib.LZW.LzwInputStream::get_Position() + System.Int64 ICSharpCode.SharpZipLib.Lzw.LzwInputStream::get_Position() - + - + 100664196 - System.Void ICSharpCode.SharpZipLib.LZW.LzwInputStream::set_Position(System.Int64) + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::set_Position(System.Int64) - + - + - - + + 100664185 - System.Void ICSharpCode.SharpZipLib.LZW.LzwInputStream::.ctor(System.IO.Stream) + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::.ctor(System.IO.Stream) - - - - - - - + + + + + + + - + - - + + 100664186 - System.Int32 ICSharpCode.SharpZipLib.LZW.LzwInputStream::ReadByte() + System.Int32 ICSharpCode.SharpZipLib.Lzw.LzwInputStream::ReadByte() - - - - + + + + - - + + - + - - + + 100664187 - System.Int32 ICSharpCode.SharpZipLib.LZW.LzwInputStream::Read(System.Byte[],System.Int32,System.Int32) + System.Int32 ICSharpCode.SharpZipLib.Lzw.LzwInputStream::Read(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664188 - System.Int32 ICSharpCode.SharpZipLib.LZW.LzwInputStream::ResetBuf(System.Int32) + System.Int32 ICSharpCode.SharpZipLib.Lzw.LzwInputStream::ResetBuf(System.Int32) - - - - + + + + - + 100664189 - System.Void ICSharpCode.SharpZipLib.LZW.LzwInputStream::Fill() + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::Fill() - - - - + + + + - - + + - + - - + + 100664190 - System.Void ICSharpCode.SharpZipLib.LZW.LzwInputStream::ParseHeader() + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::ParseHeader() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664197 - System.Void ICSharpCode.SharpZipLib.LZW.LzwInputStream::Flush() + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::Flush() - - + + - + 100664198 - System.Int64 ICSharpCode.SharpZipLib.LZW.LzwInputStream::Seek(System.Int64,System.IO.SeekOrigin) + System.Int64 ICSharpCode.SharpZipLib.Lzw.LzwInputStream::Seek(System.Int64,System.IO.SeekOrigin) - + - + 100664199 - System.Void ICSharpCode.SharpZipLib.LZW.LzwInputStream::SetLength(System.Int64) + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::SetLength(System.Int64) - + - + 100664200 - System.Void ICSharpCode.SharpZipLib.LZW.LzwInputStream::Write(System.Byte[],System.Int32,System.Int32) + System.Void ICSharpCode.SharpZipLib.Lzw.LzwInputStream::Write(System.Byte[],System.Int32,System.Int32) - + - + 100664201 - System.Void ICSharpCode.SharpZipLib.LZW.LzwInputStream::WriteByte(System.Byte) + 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) + 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() + 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) + + + + + + + + + + + + - - - - + + + + + + - + @@ -19747,15 +19796,15 @@ - 100664204 + 100664206 System.Void ICSharpCode.SharpZipLib.GZip.GZipConstants::.ctor() - + - - + + - + @@ -19765,438 +19814,451 @@ - 100664205 + 100664207 System.Void ICSharpCode.SharpZipLib.GZip.GZipException::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) - + - - + + - + - 100664206 + 100664208 System.Void ICSharpCode.SharpZipLib.GZip.GZipException::.ctor() - + - - + + - + - 100664207 + 100664209 System.Void ICSharpCode.SharpZipLib.GZip.GZipException::.ctor(System.String) - + - - + + - + - 100664208 + 100664210 System.Void ICSharpCode.SharpZipLib.GZip.GZipException::.ctor(System.String,System.Exception) - + - - + + - + - + ICSharpCode.SharpZipLib.GZip.GZipInputStream - 100664209 + 100664211 System.Void ICSharpCode.SharpZipLib.GZip.GZipInputStream::.ctor(System.IO.Stream) - + - - + + - + - 100664210 + 100664212 System.Void ICSharpCode.SharpZipLib.GZip.GZipInputStream::.ctor(System.IO.Stream,System.Int32) - + - - + + - + - - - 100664211 + + + 100664213 System.Int32 ICSharpCode.SharpZipLib.GZip.GZipInputStream::Read(System.Byte[],System.Int32,System.Int32) - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100664212 + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664214 System.Boolean ICSharpCode.SharpZipLib.GZip.GZipInputStream::ReadHeader() - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100664213 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664215 System.Void ICSharpCode.SharpZipLib.GZip.GZipInputStream::ReadFooter() - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + ICSharpCode.SharpZipLib.GZip.GZipOutputStream - 100664214 + 100664216 System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::.ctor(System.IO.Stream) - + - - + + - + - 100664215 + 100664217 System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::.ctor(System.IO.Stream,System.Int32) - + + + + + + + + + + + + 100664218 + System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::Finalize() + - - - + + + - + - 100664216 + 100664219 System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::SetLevel(System.Int32) - + - - - - + + + + - - + + - + - 100664217 + 100664220 System.Int32 ICSharpCode.SharpZipLib.GZip.GZipOutputStream::GetLevel() - + - + - + - 100664218 + 100664221 System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::Write(System.Byte[],System.Int32,System.Int32) - + - - - - - - - + + + + + + + - - - - + + + + - + - 100664219 + 100664222 System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::Close() - + - - - - - - - - + + + + + + + + - - - - + + + + - + - 100664220 + 100664223 System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::Finish() - + - - - - - - - - - - + + + + + + + + + + - - - - + + + + - + - 100664221 + 100664224 System.Void ICSharpCode.SharpZipLib.GZip.GZipOutputStream::WriteHeader() - + - - - - - - + + + + + + - - + + - + @@ -20206,54 +20268,54 @@ - 100664222 + 100664225 System.Byte[] ICSharpCode.SharpZipLib.Encryption.PkzipClassic::GenerateKeys(System.Byte[]) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664223 + 100664226 System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassic::.ctor() - + @@ -20263,76 +20325,76 @@ - 100664224 + 100664227 System.Byte ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase::TransformByte() - + - - + + - + - 100664225 + 100664228 System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase::SetKeys(System.Byte[]) - + - - - - - - - - - + + + + + + + + + - - - - + + + + - + - 100664226 + 100664229 System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase::UpdateKeys(System.Byte) - + - - - - - + + + + + - + - 100664227 + 100664230 System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase::Reset() - + - - - - + + + + - + - 100664228 + 100664231 System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase::.ctor() - + @@ -20342,105 +20404,105 @@ - 100664232 + 100664235 System.Boolean ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::get_CanReuseTransform() - + - + - + - 100664233 + 100664236 System.Int32 ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::get_InputBlockSize() - + - + - + - 100664234 + 100664237 System.Int32 ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::get_OutputBlockSize() - + - + - + - 100664235 + 100664238 System.Boolean ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::get_CanTransformMultipleBlocks() - + - + - + - 100664229 + 100664232 System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::.ctor(System.Byte[]) - + - - - + + + - + - 100664230 + 100664233 System.Byte[] ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::TransformFinalBlock(System.Byte[],System.Int32,System.Int32) - + - - - + + + - + - 100664231 + 100664234 System.Int32 ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::TransformBlock(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32) - + - - - - - - - + + + + + + + - - + + - + - 100664236 + 100664239 System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform::Dispose() - + - - + + - + @@ -20450,105 +20512,105 @@ - 100664240 + 100664243 System.Boolean ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::get_CanReuseTransform() - + - + - + - 100664241 + 100664244 System.Int32 ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::get_InputBlockSize() - + - + - + - 100664242 + 100664245 System.Int32 ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::get_OutputBlockSize() - + - + - + - 100664243 + 100664246 System.Boolean ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::get_CanTransformMultipleBlocks() - + - + - + - 100664237 + 100664240 System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::.ctor(System.Byte[]) - + - - - + + + - + - 100664238 + 100664241 System.Byte[] ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::TransformFinalBlock(System.Byte[],System.Int32,System.Int32) - + - - - + + + - + - 100664239 + 100664242 System.Int32 ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::TransformBlock(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32) - + - - - - - - - + + + + + + + - - + + - + - 100664244 + 100664247 System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform::Dispose() - + - - + + - + @@ -20558,150 +20620,150 @@ - 100664245 + 100664248 System.Int32 ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::get_BlockSize() - + - + - + - 100664246 + 100664249 System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::set_BlockSize(System.Int32) - + - - - + + + - - + + - + - 100664247 + 100664250 System.Security.Cryptography.KeySizes[] ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::get_LegalKeySizes() - + - - - + + + - + - 100664249 + 100664252 System.Security.Cryptography.KeySizes[] ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::get_LegalBlockSizes() - + - - - + + + - + - 100664250 + 100664253 System.Byte[] ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::get_Key() - + - - - + + + - - + + - + - 100664251 + 100664254 System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::set_Key(System.Byte[]) - + - - - - - - + + + + + + - - - - + + + + - + - 100664248 + 100664251 System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::GenerateIV() - + - + - + - 100664252 + 100664255 System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::GenerateKey() - + - - - - + + + + - + - 100664253 + 100664256 System.Security.Cryptography.ICryptoTransform ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::CreateEncryptor(System.Byte[],System.Byte[]) - + - - + + - + - 100664254 + 100664257 System.Security.Cryptography.ICryptoTransform ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::CreateDecryptor(System.Byte[],System.Byte[]) - + - - + + - + - 100664255 + 100664258 System.Void ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged::.ctor() - + @@ -20711,100 +20773,100 @@ - 100664256 + 100664259 System.Void ICSharpCode.SharpZipLib.Encryption.ZipAESStream::.ctor(System.IO.Stream,ICSharpCode.SharpZipLib.Encryption.ZipAESTransform,System.Security.Cryptography.CryptoStreamMode) - + - - - - - - - - + + + + + + + + - - + + - + - 100664257 + 100664260 System.Int32 ICSharpCode.SharpZipLib.Encryption.ZipAESStream::Read(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664258 + 100664261 System.Void ICSharpCode.SharpZipLib.Encryption.ZipAESStream::Write(System.Byte[],System.Int32,System.Int32) - + - + - + @@ -20814,171 +20876,171 @@ - 100664261 + 100664264 System.Byte[] ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::get_PwdVerifier() - + - + - + - 100664264 + 100664267 System.Int32 ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::get_InputBlockSize() - + - + - + - 100664265 + 100664268 System.Int32 ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::get_OutputBlockSize() - + - + - + - 100664266 + 100664269 System.Boolean ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::get_CanTransformMultipleBlocks() - + - + - + - 100664267 + 100664270 System.Boolean ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::get_CanReuseTransform() - + - + - + - 100664259 + 100664262 System.Void ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::.ctor(System.String,System.Byte[],System.Int32,System.Boolean) - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664260 + 100664263 System.Int32 ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::TransformBlock(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32) - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664262 + 100664265 System.Byte[] ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::GetAuthCode() - + - - - - - + + + + + - - + + - + - 100664263 + 100664266 System.Byte[] ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::TransformFinalBlock(System.Byte[],System.Int32,System.Int32) - + - + - + - 100664268 + 100664271 System.Void ICSharpCode.SharpZipLib.Encryption.ZipAESTransform::Dispose() - + - - + + - + @@ -20988,51 +21050,51 @@ - 100664270 + 100664273 System.String ICSharpCode.SharpZipLib.Core.ScanEventArgs::get_Name() - + - + - + - 100664271 + 100664274 System.Boolean ICSharpCode.SharpZipLib.Core.ScanEventArgs::get_ContinueRunning() - + - + - + - 100664272 + 100664275 System.Void ICSharpCode.SharpZipLib.Core.ScanEventArgs::set_ContinueRunning(System.Boolean) - + - - + + - + - 100664269 + 100664272 System.Void ICSharpCode.SharpZipLib.Core.ScanEventArgs::.ctor(System.String) - + - - - - + + + + - + @@ -21042,93 +21104,93 @@ - 100664274 + 100664277 System.String ICSharpCode.SharpZipLib.Core.ProgressEventArgs::get_Name() - + - + - + - 100664275 + 100664278 System.Boolean ICSharpCode.SharpZipLib.Core.ProgressEventArgs::get_ContinueRunning() - + - + - + - 100664276 + 100664279 System.Void ICSharpCode.SharpZipLib.Core.ProgressEventArgs::set_ContinueRunning(System.Boolean) - + - - + + - + - 100664277 + 100664280 System.Single ICSharpCode.SharpZipLib.Core.ProgressEventArgs::get_PercentComplete() - + - - - - - + + + + + - - + + - + - 100664278 + 100664281 System.Int64 ICSharpCode.SharpZipLib.Core.ProgressEventArgs::get_Processed() - + - + - + - 100664279 + 100664282 System.Int64 ICSharpCode.SharpZipLib.Core.ProgressEventArgs::get_Target() - + - + - + - 100664273 + 100664276 System.Void ICSharpCode.SharpZipLib.Core.ProgressEventArgs::.ctor(System.String,System.Int64,System.Int64) - + - - - - - - + + + + + + - + @@ -21138,27 +21200,27 @@ - 100664281 + 100664284 System.Boolean ICSharpCode.SharpZipLib.Core.DirectoryEventArgs::get_HasMatchingFiles() - + - + - + - 100664280 + 100664283 System.Void ICSharpCode.SharpZipLib.Core.DirectoryEventArgs::.ctor(System.String,System.Boolean) - + - - - + + + - + @@ -21168,63 +21230,63 @@ - 100664283 + 100664286 System.String ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs::get_Name() - + - + - + - 100664284 + 100664287 System.Exception ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs::get_Exception() - + - + - + - 100664285 + 100664288 System.Boolean ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs::get_ContinueRunning() - + - + - + - 100664286 + 100664289 System.Void ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs::set_ContinueRunning(System.Boolean) - + - - + + - + - 100664282 + 100664285 System.Void ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs::.ctor(System.String,System.Exception) - + - - - - - + + + + + - + @@ -21233,25 +21295,25 @@ ICSharpCode.SharpZipLib.Core.ProcessFileHandler - 100664287 + 100664290 System.Void ICSharpCode.SharpZipLib.Core.ProcessFileHandler::.ctor(System.Object,System.IntPtr) - 100664288 + 100664291 System.Void ICSharpCode.SharpZipLib.Core.ProcessFileHandler::Invoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanEventArgs) - 100664289 + 100664292 System.IAsyncResult ICSharpCode.SharpZipLib.Core.ProcessFileHandler::BeginInvoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanEventArgs,System.AsyncCallback,System.Object) - 100664290 + 100664293 System.Void ICSharpCode.SharpZipLib.Core.ProcessFileHandler::EndInvoke(System.IAsyncResult) @@ -21263,25 +21325,25 @@ ICSharpCode.SharpZipLib.Core.ProgressHandler - 100664291 + 100664294 System.Void ICSharpCode.SharpZipLib.Core.ProgressHandler::.ctor(System.Object,System.IntPtr) - 100664292 + 100664295 System.Void ICSharpCode.SharpZipLib.Core.ProgressHandler::Invoke(System.Object,ICSharpCode.SharpZipLib.Core.ProgressEventArgs) - 100664293 + 100664296 System.IAsyncResult ICSharpCode.SharpZipLib.Core.ProgressHandler::BeginInvoke(System.Object,ICSharpCode.SharpZipLib.Core.ProgressEventArgs,System.AsyncCallback,System.Object) - 100664294 + 100664297 System.Void ICSharpCode.SharpZipLib.Core.ProgressHandler::EndInvoke(System.IAsyncResult) @@ -21293,25 +21355,25 @@ ICSharpCode.SharpZipLib.Core.CompletedFileHandler - 100664295 + 100664298 System.Void ICSharpCode.SharpZipLib.Core.CompletedFileHandler::.ctor(System.Object,System.IntPtr) - 100664296 + 100664299 System.Void ICSharpCode.SharpZipLib.Core.CompletedFileHandler::Invoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanEventArgs) - 100664297 + 100664300 System.IAsyncResult ICSharpCode.SharpZipLib.Core.CompletedFileHandler::BeginInvoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanEventArgs,System.AsyncCallback,System.Object) - 100664298 + 100664301 System.Void ICSharpCode.SharpZipLib.Core.CompletedFileHandler::EndInvoke(System.IAsyncResult) @@ -21323,25 +21385,25 @@ ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler - 100664299 + 100664302 System.Void ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler::.ctor(System.Object,System.IntPtr) - 100664300 + 100664303 System.Void ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler::Invoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs) - 100664301 + 100664304 System.IAsyncResult ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler::BeginInvoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs,System.AsyncCallback,System.Object) - 100664302 + 100664305 System.Void ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler::EndInvoke(System.IAsyncResult) @@ -21353,25 +21415,25 @@ ICSharpCode.SharpZipLib.Core.FileFailureHandler - 100664303 + 100664306 System.Void ICSharpCode.SharpZipLib.Core.FileFailureHandler::.ctor(System.Object,System.IntPtr) - 100664304 + 100664307 System.Void ICSharpCode.SharpZipLib.Core.FileFailureHandler::Invoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs) - 100664305 + 100664308 System.IAsyncResult ICSharpCode.SharpZipLib.Core.FileFailureHandler::BeginInvoke(System.Object,ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs,System.AsyncCallback,System.Object) - 100664306 + 100664309 System.Void ICSharpCode.SharpZipLib.Core.FileFailureHandler::EndInvoke(System.IAsyncResult) @@ -21379,265 +21441,265 @@ - + ICSharpCode.SharpZipLib.Core.FileSystemScanner - 100664307 + 100664310 System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::.ctor(System.String) - + - - - + + + - + - 100664308 + 100664311 System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::.ctor(System.String,System.String) - + - - - - + + + + - + - 100664309 + 100664312 System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::.ctor(ICSharpCode.SharpZipLib.Core.IScanFilter) - + - - - + + + - + - 100664310 + 100664313 System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::.ctor(ICSharpCode.SharpZipLib.Core.IScanFilter,ICSharpCode.SharpZipLib.Core.IScanFilter) - + - - - - + + + + - + - 100664311 + 100664314 System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::add_ProcessDirectory(System.EventHandler`1<ICSharpCode.SharpZipLib.Core.DirectoryEventArgs>) - + - 100664312 + 100664315 System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::remove_ProcessDirectory(System.EventHandler`1<ICSharpCode.SharpZipLib.Core.DirectoryEventArgs>) - + - - - 100664313 + + + 100664316 System.Boolean ICSharpCode.SharpZipLib.Core.FileSystemScanner::OnDirectoryFailure(System.String,System.Exception) - + - - - - - - - + + + + + + + - - + + - + - - - 100664314 + + + 100664317 System.Boolean ICSharpCode.SharpZipLib.Core.FileSystemScanner::OnFileFailure(System.String,System.Exception) - + - - - - - - - + + + + + + + - - + + - + - 100664315 + 100664318 System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::OnProcessFile(System.String) - + - - - - - - + + + + + + - - + + - + - 100664316 + 100664319 System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::OnCompleteFile(System.String) - + - - - - - - + + + + + + - - + + - + - 100664317 + 100664320 System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::OnProcessDirectory(System.String,System.Boolean) - + - - - - - - + + + + + + - - + + - + - 100664318 + 100664321 System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::Scan(System.String,System.Boolean) - + - - - + + + - + - - - 100664319 + + + 100664322 System.Void ICSharpCode.SharpZipLib.Core.FileSystemScanner::ScanDir(System.String,System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -21647,243 +21709,243 @@ - 100664323 + 100664326 System.Void ICSharpCode.SharpZipLib.Core.NameFilter::.ctor(System.String) - + - - - - - - + + + + + + - + - 100664324 + 100664327 System.Boolean ICSharpCode.SharpZipLib.Core.NameFilter::IsValidExpression(System.String) - + - - - - - - - + + + + + + + - + - 100664325 + 100664328 System.Boolean ICSharpCode.SharpZipLib.Core.NameFilter::IsValidFilterExpression(System.String) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664326 + 100664329 System.String[] ICSharpCode.SharpZipLib.Core.NameFilter::SplitQuoted(System.String) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664327 + 100664330 System.String ICSharpCode.SharpZipLib.Core.NameFilter::ToString() - + - + - + - 100664328 + 100664331 System.Boolean ICSharpCode.SharpZipLib.Core.NameFilter::IsIncluded(System.String) - + - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - + - 100664329 + 100664332 System.Boolean ICSharpCode.SharpZipLib.Core.NameFilter::IsExcluded(System.String) - + - - - - - - - - + + + + + + + + - - + + - + - 100664330 + 100664333 System.Boolean ICSharpCode.SharpZipLib.Core.NameFilter::IsMatch(System.String) - + - + - + - 100664331 + 100664334 System.Void ICSharpCode.SharpZipLib.Core.NameFilter::Compile() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -21893,36 +21955,36 @@ - 100664332 + 100664335 System.Void ICSharpCode.SharpZipLib.Core.PathFilter::.ctor(System.String) - + - - - + + + - + - 100664333 + 100664336 System.Boolean ICSharpCode.SharpZipLib.Core.PathFilter::IsMatch(System.String) - + - - - - - + + + + + - - - - + + + + - + @@ -21932,190 +21994,190 @@ - 100664338 + 100664341 System.Int64 ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::get_MinSize() - + - + - + - 100664339 + 100664342 System.Void ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::set_MinSize(System.Int64) - + - - - - + + + + - - - - + + + + - + - 100664340 + 100664343 System.Int64 ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::get_MaxSize() - + - + - + - 100664341 + 100664344 System.Void ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::set_MaxSize(System.Int64) - + - - - - + + + + - - - - + + + + - + - 100664342 + 100664345 System.DateTime ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::get_MinDate() - + - + - + - 100664343 + 100664346 System.Void ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::set_MinDate(System.DateTime) - + - - - - + + + + - - + + - + - 100664344 + 100664347 System.DateTime ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::get_MaxDate() - + - + - + - 100664345 + 100664348 System.Void ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::set_MaxDate(System.DateTime) - + - - - - + + + + - - + + - + - 100664334 + 100664337 System.Void ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::.ctor(System.String,System.Int64,System.Int64) - + - - - - - - - + + + + + + + - + - 100664335 + 100664338 System.Void ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::.ctor(System.String,System.DateTime,System.DateTime) - + - - - - - - - + + + + + + + - + - 100664336 + 100664339 System.Void ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::.ctor(System.String,System.Int64,System.Int64,System.DateTime,System.DateTime) - + - - - - - - - - - + + + + + + + + + - + - 100664337 + 100664340 System.Boolean ICSharpCode.SharpZipLib.Core.ExtendedPathFilter::IsMatch(System.String) - + - - - - - + + + + + - - + + - + @@ -22125,97 +22187,97 @@ - 100664348 + 100664351 System.Int64 ICSharpCode.SharpZipLib.Core.NameAndSizeFilter::get_MinSize() - + - + - + - 100664349 + 100664352 System.Void ICSharpCode.SharpZipLib.Core.NameAndSizeFilter::set_MinSize(System.Int64) - + - - - - + + + + - - - - + + + + - + - 100664350 + 100664353 System.Int64 ICSharpCode.SharpZipLib.Core.NameAndSizeFilter::get_MaxSize() - + - + - + - 100664351 + 100664354 System.Void ICSharpCode.SharpZipLib.Core.NameAndSizeFilter::set_MaxSize(System.Int64) - + - - - - + + + + - - - - + + + + - + - 100664346 + 100664349 System.Void ICSharpCode.SharpZipLib.Core.NameAndSizeFilter::.ctor(System.String,System.Int64,System.Int64) - + - - - - - + + + + + - + - 100664347 + 100664350 System.Boolean ICSharpCode.SharpZipLib.Core.NameAndSizeFilter::IsMatch(System.String) - + - - - - - - + + + + + + - - + + - + @@ -22225,195 +22287,195 @@ - 100664352 + 100664355 System.Void ICSharpCode.SharpZipLib.Core.StreamUtils::ReadFully(System.IO.Stream,System.Byte[]) - + - - + + - + - 100664353 + 100664356 System.Void ICSharpCode.SharpZipLib.Core.StreamUtils::ReadFully(System.IO.Stream,System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664354 + 100664357 System.Void ICSharpCode.SharpZipLib.Core.StreamUtils::Copy(System.IO.Stream,System.IO.Stream,System.Byte[]) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664355 + 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) - + - - + + - + - 100664356 + 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) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664357 + 100664360 System.Void ICSharpCode.SharpZipLib.Core.StreamUtils::.ctor() - + - - + + - + @@ -22423,458 +22485,468 @@ - 100664358 + 100664361 System.Void ICSharpCode.SharpZipLib.Core.WindowsPathUtils::.ctor() - + - - + + - + - 100664359 + 100664362 System.String ICSharpCode.SharpZipLib.Core.WindowsPathUtils::DropPathRoot(System.String) - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - ICSharpCode.SharpZipLib.Checksums.Adler32 + + ICSharpCode.SharpZipLib.Checksum.Adler32 - 100664360 - System.Int64 ICSharpCode.SharpZipLib.Checksums.Adler32::get_Value() - + 100664365 + System.Int64 ICSharpCode.SharpZipLib.Checksum.Adler32::get_Value() + - + - + - 100664361 - System.Void ICSharpCode.SharpZipLib.Checksums.Adler32::.ctor() - + 100664363 + System.Void ICSharpCode.SharpZipLib.Checksum.Adler32::.ctor() + - - - + + + - + - 100664362 - System.Void ICSharpCode.SharpZipLib.Checksums.Adler32::Reset() - + 100664364 + System.Void ICSharpCode.SharpZipLib.Checksum.Adler32::Reset() + - - + + - + - 100664363 - System.Void ICSharpCode.SharpZipLib.Checksums.Adler32::Update(System.Int32) - + 100664366 + System.Void ICSharpCode.SharpZipLib.Checksum.Adler32::Update(System.Int32) + - - - - - - + + + + + + - + - - - 100664364 - System.Void ICSharpCode.SharpZipLib.Checksums.Adler32::Update(System.Byte[]) - + + + 100664367 + System.Void ICSharpCode.SharpZipLib.Checksum.Adler32::Update(System.Byte[]) + - - - - + + + + - - + + - + - - - 100664365 - System.Void ICSharpCode.SharpZipLib.Checksums.Adler32::Update(System.Byte[],System.Int32,System.Int32) - + + + 100664368 + System.Void ICSharpCode.SharpZipLib.Checksum.Adler32::Update(System.Byte[],System.Int32,System.Int32) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664369 + System.Void ICSharpCode.SharpZipLib.Checksum.Adler32::.cctor() + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - ICSharpCode.SharpZipLib.Checksums.Crc32 + + ICSharpCode.SharpZipLib.Checksum.Crc32 - 100664367 - System.Int64 ICSharpCode.SharpZipLib.Checksums.Crc32::get_Value() - + 100664373 + System.Int64 ICSharpCode.SharpZipLib.Checksum.Crc32::get_Value() + - + - + - - - 100664368 - System.Void ICSharpCode.SharpZipLib.Checksums.Crc32::set_Value(System.Int64) - + + + 100664370 + System.UInt32 ICSharpCode.SharpZipLib.Checksum.Crc32::ComputeCrc32(System.UInt32,System.Byte) + - - + - + - - - 100664366 - System.UInt32 ICSharpCode.SharpZipLib.Checksums.Crc32::ComputeCrc32(System.UInt32,System.Byte) - + + + 100664371 + System.Void ICSharpCode.SharpZipLib.Checksum.Crc32::.ctor() + - + + + - + - 100664369 - System.Void ICSharpCode.SharpZipLib.Checksums.Crc32::Reset() - + 100664372 + System.Void ICSharpCode.SharpZipLib.Checksum.Crc32::Reset() + - - + + - + - - 100664370 - System.Void ICSharpCode.SharpZipLib.Checksums.Crc32::Update(System.Int32) - + + 100664374 + System.Void ICSharpCode.SharpZipLib.Checksum.Crc32::Update(System.Int32) + - - - - + + - + - - - 100664371 - System.Void ICSharpCode.SharpZipLib.Checksums.Crc32::Update(System.Byte[]) - + + + 100664375 + System.Void ICSharpCode.SharpZipLib.Checksum.Crc32::Update(System.Byte[]) + - - - - + + + + - - + + - + - - - 100664372 - System.Void ICSharpCode.SharpZipLib.Checksums.Crc32::Update(System.Byte[],System.Int32,System.Int32) - + + + 100664376 + System.Void ICSharpCode.SharpZipLib.Checksum.Crc32::Update(System.Byte[],System.Int32,System.Int32) + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100664373 - System.Void ICSharpCode.SharpZipLib.Checksums.Crc32::.ctor() - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - 100664374 - System.Void ICSharpCode.SharpZipLib.Checksums.Crc32::.cctor() - + + 100664377 + System.Void ICSharpCode.SharpZipLib.Checksum.Crc32::.cctor() + - + + + - + - - ICSharpCode.SharpZipLib.Checksums.StrangeCRC + + ICSharpCode.SharpZipLib.Checksum.BZip2Crc - 100664382 - System.Int64 ICSharpCode.SharpZipLib.Checksums.StrangeCRC::get_Value() - + 100664385 + System.Int64 ICSharpCode.SharpZipLib.Checksum.BZip2Crc::get_Value() + - + - + - 100664380 - System.Void ICSharpCode.SharpZipLib.Checksums.StrangeCRC::.ctor() - + 100664383 + System.Void ICSharpCode.SharpZipLib.Checksum.BZip2Crc::.ctor() + - - - + + + - + - 100664381 - System.Void ICSharpCode.SharpZipLib.Checksums.StrangeCRC::Reset() - + 100664384 + System.Void ICSharpCode.SharpZipLib.Checksum.BZip2Crc::Reset() + - - + + - + - - - 100664383 - System.Void ICSharpCode.SharpZipLib.Checksums.StrangeCRC::Update(System.Int32) - + + + 100664386 + System.Void ICSharpCode.SharpZipLib.Checksum.BZip2Crc::Update(System.Int32) + - - - - - + + - - - - - + + - - - 100664384 - System.Void ICSharpCode.SharpZipLib.Checksums.StrangeCRC::Update(System.Byte[]) - + + + 100664387 + System.Void ICSharpCode.SharpZipLib.Checksum.BZip2Crc::Update(System.Byte[]) + - - - - + + + + - - + + - + - - - 100664385 - System.Void ICSharpCode.SharpZipLib.Checksums.StrangeCRC::Update(System.Byte[],System.Int32,System.Int32) - + + + 100664388 + System.Void ICSharpCode.SharpZipLib.Checksum.BZip2Crc::Update(System.Byte[],System.Int32,System.Int32) + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - 100664386 - System.Void ICSharpCode.SharpZipLib.Checksums.StrangeCRC::.cctor() - + + 100664389 + System.Void ICSharpCode.SharpZipLib.Checksum.BZip2Crc::.cctor() + - + + + - + @@ -22884,57 +22956,57 @@ - 100664387 + 100664390 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2::Decompress(System.IO.Stream,System.IO.Stream,System.Boolean) - + - - - - - - - - - - + + + + + + + + + + - - - - - - + + + + + + - + - 100664388 + 100664391 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2::Compress(System.IO.Stream,System.IO.Stream,System.Boolean,System.Int32) - + - - - - - - - - - - + + + + + + + + + + - - - - - - + + + + + + - + @@ -22944,26 +23016,26 @@ - 100664389 + 100664392 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2Constants::.ctor() - + - - + + - + - 100664390 + 100664393 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2Constants::.cctor() - + - + - + @@ -22973,3182 +23045,3182 @@ - 100664391 + 100664394 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2Exception::.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) - + - - + + - + - 100664392 + 100664395 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2Exception::.ctor() - + - - + + - + - 100664393 + 100664396 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2Exception::.ctor(System.String) - + - - + + - + - 100664394 + 100664397 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2Exception::.ctor(System.String,System.Exception) - + - - + + - + - + ICSharpCode.SharpZipLib.BZip2.BZip2InputStream - 100664396 + 100664399 System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::get_IsStreamOwner() - + - + - + - 100664397 + 100664400 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::set_IsStreamOwner(System.Boolean) - + - - + + - + - 100664398 + 100664401 System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::get_CanRead() - + - + - + - 100664399 + 100664402 System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::get_CanSeek() - + - + - + - 100664400 + 100664403 System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::get_CanWrite() - + - + - + - 100664401 + 100664404 System.Int64 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::get_Length() - + - + - + - 100664402 + 100664405 System.Int64 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::get_Position() - + - + - + - 100664403 + 100664406 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::set_Position(System.Int64) - + - + - + - 100664395 + 100664398 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::.ctor(System.IO.Stream) - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664404 + 100664407 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::Flush() - + - - - + + + - - + + - + - 100664405 + 100664408 System.Int64 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::Seek(System.Int64,System.IO.SeekOrigin) - + - + - + - 100664406 + 100664409 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetLength(System.Int64) - + - + - + - 100664407 + 100664410 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::Write(System.Byte[],System.Int32,System.Int32) - + - + - + - 100664408 + 100664411 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::WriteByte(System.Byte) - + - + - + - - - 100664409 + + + 100664412 System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::Read(System.Byte[],System.Int32,System.Int32) - + - - - - - - - - - - + + + + + + + + + + - - - - - - + + + + + + - + - 100664410 + 100664413 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::Close() - + - - - + + + - - - - + + + + - + - - - 100664411 + + + 100664414 System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::ReadByte() - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - 100664412 + + + 100664415 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::MakeMaps() - + - - - - - - - - - + + + + + + + + + - - - - + + + + - + - 100664413 + 100664416 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::Initialize() - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100664414 + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664417 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::InitBlock() - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - 100664415 + + + 100664418 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::EndBlock() - + - - - - - - + + + + + + - - + + - + - 100664416 + 100664419 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::Complete() - + - - - - - + + + + + - - + + - + - 100664417 + 100664420 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::BsSetStream(System.IO.Stream) - + - - - - + + + + - + - 100664418 + 100664421 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::FillBuffer() - + - - - - - - - - - - - + + + + + + + + + + + - - + + - + - 100664419 + 100664422 System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::BsR(System.Int32) - + - - - - - + + + + + - - + + - + - 100664420 + 100664423 System.Char ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::BsGetUChar() - + - + - + - - - 100664421 + + + 100664424 System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::BsGetIntVS(System.Int32) - + - + - + - 100664422 + 100664425 System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::BsGetInt32() - + - - - - - + + + + + - + - - - 100664423 + + + 100664426 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::RecvDecodingTables() - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100664424 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664427 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::GetAndMoveToFrontDecode() - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664425 + 100664428 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetupBlock() - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664426 + 100664429 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetupRandPartA() - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100664427 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664430 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetupNoRandPartA() - + - - - - - - - - - - - - - + + + + + + + + + + + + + - - + + - + - 100664428 + 100664431 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetupRandPartB() - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664429 + 100664432 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetupRandPartC() - + - - - - - - - - - - + + + + + + + + + + - - + + - + - - - 100664430 + + + 100664433 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetupNoRandPartB() - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - 100664431 + 100664434 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetupNoRandPartC() - + - - - - - - - - - - + + + + + + + + + + - - + + - + - 100664432 + 100664435 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::SetDecompressStructureSizes(System.Int32) - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - 100664433 + 100664436 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::CompressedStreamEOF() - + - + - + - 100664434 + 100664437 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::BlockOverrun() - + - + - + - 100664435 + 100664438 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::BadBlockHeader() - + - + - + - 100664436 + 100664439 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2InputStream::CrcError() - + - + - + - - - 100664437 + + + 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 - 100664441 + 100664444 System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::get_IsStreamOwner() - + - + - + - 100664442 + 100664445 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::set_IsStreamOwner(System.Boolean) - + - - + + - + - 100664443 + 100664446 System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::get_CanRead() - + - + - + - 100664444 + 100664447 System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::get_CanSeek() - + - + - + - 100664445 + 100664448 System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::get_CanWrite() - + - + - + - 100664446 + 100664449 System.Int64 ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::get_Length() - + - + - + - 100664447 + 100664450 System.Int64 ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::get_Position() - + - + - + - 100664448 + 100664451 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::set_Position(System.Int64) - + - + - + - 100664458 + 100664461 System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::get_BytesWritten() - + - + - + - 100664438 + 100664441 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::.ctor(System.IO.Stream) - + - - + + - + - 100664439 + 100664442 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::.ctor(System.IO.Stream,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664440 + 100664443 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Finalize() - + - - - + + + - + - 100664449 + 100664452 System.Int64 ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Seek(System.Int64,System.IO.SeekOrigin) - + - + - + - 100664450 + 100664453 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::SetLength(System.Int64) - + - + - + - 100664451 + 100664454 System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::ReadByte() - + - + - + - 100664452 + 100664455 System.Int32 ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Read(System.Byte[],System.Int32,System.Int32) - + - + - + - - - 100664453 + + + 100664456 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Write(System.Byte[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100664454 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664457 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::WriteByte(System.Byte) - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664455 + 100664458 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Close() - + - - - + + + - + - - - 100664456 + + + 100664459 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::MakeMaps() - + - - - - - - - - - + + + + + + + + + - - - - + + + + - + - - - 100664457 + + + 100664460 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::WriteRun() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100664459 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664462 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Dispose(System.Boolean) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664460 + 100664463 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Flush() - + - - + + - + - 100664461 + 100664464 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Initialize() - + - - - - - - - - + + + + + + + + - + - 100664462 + 100664465 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::InitBlock() - + - - - - - - - - + + + + + + + + - - + + - + - - - 100664463 + + + 100664466 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::EndBlock() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664464 + 100664467 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::EndCompression() - + - - - - - - - - - + + + + + + + + + - + - 100664465 + 100664468 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::BsSetStream(System.IO.Stream) - + - - - - - + + + + + - + - 100664466 + 100664469 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::BsFinishedWithStream() - + - - - - - - - + + + + + + + - - + + - + - 100664467 + 100664470 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::BsW(System.Int32,System.Int32) - + - - - - - - - - - + + + + + + + + + - - + + - + - 100664468 + 100664471 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::BsPutUChar(System.Int32) - + - - + + - + - 100664469 + 100664472 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::BsPutint(System.Int32) - + - - - - - + + + + + - + - - - 100664470 + + + 100664473 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::BsPutIntVS(System.Int32,System.Int32) - + - - + + - + - - - 100664471 + + + 100664474 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::SendMTFValues() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - 100664472 + + + 100664475 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::MoveToFrontCodeAndSend() - + - - - - + + + + - + - - - 100664473 + + + 100664476 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::SimpleSort(System.Int32,System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664474 + 100664477 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Vswap(System.Int32,System.Int32,System.Int32) - + - - - - - - - - - + + + + + + + + + - - + + - + - - - 100664475 + + + 100664478 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::QSort3(System.Int32,System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100664476 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664479 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::MainSort() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664477 + 100664480 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::RandomiseBlock() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100664478 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664481 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::DoReversibleTransformation() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100664479 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100664482 System.Boolean ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::FullGtU(System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664480 + 100664483 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::AllocateCompressStructures() - + - - - - - - - - + + + + + + + + - - - - - - + + + + + + - + - - - 100664481 + + + 100664484 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::GenerateMTFValues() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 100664482 + 100664485 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Panic() - + - + - + - - - 100664483 + + + 100664486 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::HbMakeCodeLengths(System.Char[],System.Int32[],System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - 100664484 + + + 100664487 System.Void ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::HbAssignCodes(System.Int32[],System.Char[],System.Int32,System.Int32,System.Int32) - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - 100664485 + 100664488 System.Byte ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream::Med3(System.Byte,System.Byte,System.Byte) - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_Adler32.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_Adler32.htm index 1e39316a0..f7f340d3f 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_Adler32.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_Adler32.htm @@ -2,7 +2,7 @@ -ICSharpCode.SharpZipLib.Checksums.Adler32 - Coverage Report +ICSharpCode.SharpZipLib.Checksum.Adler32 - Coverage Report

Summary

@@ -12,272 +12,211 @@

Summary

-Class:ICSharpCode.SharpZipLib.Checksums.Adler32 +Class:ICSharpCode.SharpZipLib.Checksum.Adler32 Assembly:ICSharpCode.SharpZipLib -File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Checksums\Adler32.cs -Covered lines:25 -Uncovered lines:15 -Coverable lines:40 -Total lines:237 -Line coverage:62.5% -Branch coverage:61.1% +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(...)200
Update(...)979.1770.59
.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\Checksums\Adler32.cs

+

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

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1// Adler32.cs - Computes Adler32 data checksum of a data stream
 2// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team
 3//
 4// This file was translated from java, it was part of the GNU Classpath
 5// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
 6//
 7// This program is free software; you can redistribute it and/or
 8// modify it under the terms of the GNU General Public License
 9// as published by the Free Software Foundation; either version 2
 10// of the License, or (at your option) any later version.
 11//
 12// This program is distributed in the hope that it will be useful,
 13// but WITHOUT ANY WARRANTY; without even the implied warranty of
 14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15// GNU General Public License for more details.
 16//
 17// You should have received a copy of the GNU General Public License
 18// along with this program; if not, write to the Free Software
 19// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 20//
 21// Linking this library statically or dynamically with other modules is
 22// making a combined work based on this library.  Thus, the terms and
 23// conditions of the GNU General Public License cover the whole
 24// combination.
 25//
 26// As a special exception, the copyright holders of this library give you
 27// permission to link this library with independent modules to produce an
 28// executable, regardless of the license terms of these independent
 29// modules, and to copy and distribute the resulting executable under
 30// terms of your choice, provided that you also meet, for each linked
 31// independent module, the terms and conditions of the license of that
 32// module.  An independent module is a module which is not derived from
 33// or based on this library.  If you modify this library, you may extend
 34// this exception to your version of the library, but you are not
 35// obligated to do so.  If you do not wish to do so, delete this
 36// exception statement from your version.
 37
 38using System;
 39
 40namespace ICSharpCode.SharpZipLib.Checksums
 41{
 42
 43  /// <summary>
 44  /// Computes Adler32 checksum for a stream of data. An Adler32
 45  /// checksum is not as reliable as a CRC32 checksum, but a lot faster to
 46  /// compute.
 47  ///
 48  /// The specification for Adler32 may be found in RFC 1950.
 49  /// ZLIB Compressed Data Format Specification version 3.3)
 50  ///
 51  ///
 52  /// From that document:
 53  ///
 54  ///      "ADLER32 (Adler-32 checksum)
 55  ///       This contains a checksum value of the uncompressed data
 56  ///       (excluding any dictionary data) computed according to Adler-32
 57  ///       algorithm. This algorithm is a 32-bit extension and improvement
 58  ///       of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073
 59  ///       standard.
 60  ///
 61  ///       Adler-32 is composed of two sums accumulated per byte: s1 is
 62  ///       the sum of all bytes, s2 is the sum of all s1 values. Both sums
 63  ///       are done modulo 65521. s1 is initialized to 1, s2 to zero.  The
 64  ///       Adler-32 checksum is stored as s2*65536 + s1 in most-
 65  ///       significant-byte first (network) order."
 66  ///
 67  ///  "8.2. The Adler-32 algorithm
 68  ///
 69  ///    The Adler-32 algorithm is much faster than the CRC32 algorithm yet
 70  ///    still provides an extremely low probability of undetected errors.
 71  ///
 72  ///    The modulo on unsigned long accumulators can be delayed for 5552
 73  ///    bytes, so the modulo operation time is negligible.  If the bytes
 74  ///    are a, b, c, the second sum is 3a + 2b + c + 3, and so is position
 75  ///    and order sensitive, unlike the first sum, which is just a
 76  ///    checksum.  That 65521 is prime is important to avoid a possible
 77  ///    large class of two-byte errors that leave the check unchanged.
 78  ///    (The Fletcher checksum uses 255, which is not prime and which also
 79  ///    makes the Fletcher check insensitive to single byte changes 0 -
 80  ///    255.)
 81  ///
 82  ///    The sum s1 is initialized to 1 instead of zero to make the length
 83  ///    of the sequence part of s2, so that the length does not have to be
 84  ///    checked separately. (Any sequence of zeroes has a Fletcher
 85  ///    checksum of zero.)"
 86  /// </summary>
 87  /// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream"/>
 88  /// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream"/>
 89  public sealed class Adler32 : IChecksum
 90  {
 91    /// <summary>
 92    /// largest prime smaller than 65536
 93    /// </summary>
 94    const uint BASE = 65521;
 95
 96    /// <summary>
 97    /// Returns the Adler32 data checksum computed so far.
 98    /// </summary>
 99    public long Value {
 100      get {
 15101        return checksum;
 102      }
 103    }
 104
 105    /// <summary>
 106    /// Creates a new instance of the Adler32 class.
 107    /// The checksum starts off with a value of 1.
 108    /// </summary>
 720109    public Adler32()
 110    {
 720111      Reset();
 720112    }
 113
 114    /// <summary>
 115    /// Resets the Adler32 checksum to the initial value.
 116    /// </summary>
 117    public void Reset()
 118    {
 1165119      checksum = 1;
 1165120    }
 121
 122    /// <summary>
 123    /// Updates the checksum with a byte value.
 124    /// </summary>
 125    /// <param name="value">
 126    /// The data value to add. The high byte of the int is ignored.
 127    /// </param>
 128    public void Update(int value)
 129    {
 130      // We could make a length 1 byte array and call update again, but I
 131      // would rather not have that overhead
 0132      uint s1 = checksum & 0xFFFF;
 0133      uint s2 = checksum >> 16;
 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
 0135      s1 = (s1 + ((uint)value & 0xFF)) % BASE;
 0136      s2 = (s1 + s2) % BASE;
 137
 0138      checksum = (s2 << 16) + s1;
 0139    }
 140
 141    /// <summary>
 142    /// Updates the checksum with an array of bytes.
 143    /// </summary>
 144    /// <param name="buffer">
 145    /// The source of the data to update with.
 146    /// </param>
 147    public void Update(byte[] buffer)
 148    {
 0149       if ( buffer == null ) {
 0150        throw new ArgumentNullException(nameof(buffer));
 151      }
 152
 0153      Update(buffer, 0, buffer.Length);
 0154    }
 155
 156    /// <summary>
 157    /// Updates the checksum with the bytes taken from the array.
 158    /// </summary>
 159    /// <param name="buffer">
 160    /// an array of bytes
 161    /// </param>
 162    /// <param name="offset">
 163    /// the start of the data used for this update
 164    /// </param>
 165    /// <param name="count">
 166    /// the number of bytes to use for this update
 167    /// </param>
 168    public void Update(byte[] buffer, int offset, int count)
 169    {
 6243170       if (buffer == null) {
 0171        throw new ArgumentNullException(nameof(buffer));
 172      }
 173
 6243174       if (offset < 0) {
 175#if NETCF_1_0
 176        throw new ArgumentOutOfRangeException("offset");
 177#else
 0178        throw new ArgumentOutOfRangeException(nameof(offset), "cannot be negative");
 179#endif
 180      }
 181
 6243182       if ( count < 0 )
 183      {
 184#if NETCF_1_0
 185        throw new ArgumentOutOfRangeException("count");
 186#else
 0187        throw new ArgumentOutOfRangeException(nameof(count), "cannot be negative");
 188#endif
 189      }
 190
 6243191       if (offset >= buffer.Length)
 192      {
 193#if NETCF_1_0
 194        throw new ArgumentOutOfRangeException("offset");
 195#else
 0196        throw new ArgumentOutOfRangeException(nameof(offset), "not a valid index into buffer");
 197#endif
 198      }
 199
 6243200       if (offset + count > buffer.Length)
 201      {
 202#if NETCF_1_0
 203        throw new ArgumentOutOfRangeException("count");
 204#else
 0205        throw new ArgumentOutOfRangeException(nameof(count), "exceeds buffer size");
 206#endif
 207      }
 208
 209      //(By Per Bothner)
 6243210      uint s1 = checksum & 0xFFFF;
 6243211      uint s2 = checksum >> 16;
 212
 14027213       while (count > 0) {
 214        // We can defer the modulo operation:
 215        // s1 maximally grows from 65521 to 65521 + 255 * 3800
 216        // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31
 7784217        int n = 3800;
 7784218         if (n > count) {
 6243219          n = count;
 220        }
 7784221        count -= n;
 8556640222         while (--n >= 0) {
 8548856223          s1 = s1 + (uint)(buffer[offset++] & 0xff);
 8548856224          s2 = s2 + s1;
 225        }
 7784226        s1 %= BASE;
 7784227        s2 %= BASE;
 228      }
 229
 6243230      checksum = (s2 << 16) | s1;
 6243231    }
 232
 233    #region Instance Fields
 234    uint checksum;
 235    #endregion
 236  }
 237}
 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/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2.htm index 637b2ac46..80405d917 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:20 Coverable lines:20 -Total lines:105 +Total lines:66 Line coverage:0% Branch coverage:0% @@ -36,113 +36,74 @@

#LineLine coverage - 1// BZip2.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536// Suppress this in CF and 1.1, not needed. Static classes introduced in C# version 2.037#if !NETCF_2_0 && !NET_1_13839using System;40using System.IO;4142namespace ICSharpCode.SharpZipLib.BZip2 {4344  /// <summary>45  /// An example class to demonstrate compression and decompression of BZip2 streams.46  /// </summary>47  public static class BZip248  {49    /// <summary>50    /// Decompress the <paramref name="inStream">input</paramref> writing51    /// uncompressed data to the <paramref name="outStream">output stream</paramref>52    /// </summary>53    /// <param name="inStream">The readable stream containing data to decompress.</param>54    /// <param name="outStream">The output stream to receive the decompressed data.</param>55    /// <param name="isStreamOwner">Both streams are closed on completion if true.</param>56    public static void Decompress(Stream inStream, Stream outStream, bool isStreamOwner)57    { - 058       if (inStream == null || outStream == null) { - 059        throw new Exception("Null Stream");60      }6162      try { - 063        using (BZip2InputStream bzipInput = new BZip2InputStream(inStream)) { - 064          bzipInput.IsStreamOwner = isStreamOwner; - 065          Core.StreamUtils.Copy(bzipInput, outStream, new byte[4096]); - 066        }67      } finally { - 068         if (isStreamOwner) {69          // inStream is closed by the BZip2InputStream if stream owner - 070          outStream.Close();71        } - 072      } - 073    }7475    /// <summary>76    /// Compress the <paramref name="inStream">input stream</paramref> sending77    /// result data to <paramref name="outStream">output stream</paramref>78    /// </summary>79    /// <param name="inStream">The readable stream to compress.</param>80    /// <param name="outStream">The output stream to receive the compressed data.</param>81    /// <param name="isStreamOwner">Both streams are closed on completion if true.</param>82    /// <param name="level">Block size acts as compression level (1 to 9) with 1 giving83    /// the lowest compression and 9 the highest.</param>84    public static void Compress(Stream inStream, Stream outStream, bool isStreamOwner, int level)85    { - 086       if (inStream == null || outStream == null) { - 087        throw new Exception("Null Stream");88      }8990      try { - 091        using (BZip2OutputStream bzipOutput = new BZip2OutputStream(outStream, level)) { - 092          bzipOutput.IsStreamOwner = isStreamOwner; - 093          Core.StreamUtils.Copy(inStream, bzipOutput, new byte[4096]); - 094        }95      } finally { - 096         if (isStreamOwner) {97          // outStream is closed by the BZip2OutputStream if stream owner - 098          inStream.Close();99        } - 0100      } - 0101    }102103  }104}105#endif1using System;2using System.IO;34namespace ICSharpCode.SharpZipLib.BZip25{6  /// <summary>7  /// An example class to demonstrate compression and decompression of BZip2 streams.8  /// </summary>9  public static class BZip210  {11    /// <summary>12    /// Decompress the <paramref name="inStream">input</paramref> writing13    /// 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      }2324      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    }3637    /// <summary>38    /// Compress the <paramref name="inStream">input stream</paramref> sending39    /// 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 giving45    /// 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      }5152      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    }6465  }66} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2Constants.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2Constants.htm index a7d52f030..b07f50436 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2Constants.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2Constants.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:56 Coverable lines:56 -Total lines:197 +Total lines:121 Line coverage:0% @@ -35,205 +35,129 @@

#LineLine coverage - 1// BZip2Constants.cs2// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team3//4// This program is free software; you can redistribute it and/or5// modify it under the terms of the GNU General Public License6// as published by the Free Software Foundation; either version 27// of the License, or (at your option) any later version.8//9// This program is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.13//14// You should have received a copy of the GNU General Public License15// along with this program; if not, write to the Free Software16// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.17//18// Linking this library statically or dynamically with other modules is19// making a combined work based on this library.  Thus, the terms and20// conditions of the GNU General Public License cover the whole21// combination.22//23// As a special exception, the copyright holders of this library give you24// permission to link this library with independent modules to produce an25// executable, regardless of the license terms of these independent26// modules, and to copy and distribute the resulting executable under27// terms of your choice, provided that you also meet, for each linked28// independent module, the terms and conditions of the license of that29// module.  An independent module is a module which is not derived from30// or based on this library.  If you modify this library, you may extend31// this exception to your version of the library, but you are not32// obligated to do so.  If you do not wish to do so, delete this33// exception statement from your version.3435namespace ICSharpCode.SharpZipLib.BZip236{3738  /// <summary>39  /// Defines internal values for both compression and decompression40  /// </summary>41  internal sealed class BZip2Constants42  {43    /// <summary>44    /// Random numbers used to randomise repetitive blocks45    /// </summary> - 046    public readonly static int[] RandomNumbers = { - 047      619, 720, 127, 481, 931, 816, 813, 233, 566, 247, - 048      985, 724, 205, 454, 863, 491, 741, 242, 949, 214, - 049      733, 859, 335, 708, 621, 574,  73, 654, 730, 472, - 050      419, 436, 278, 496, 867, 210, 399, 680, 480,  51, - 051      878, 465, 811, 169, 869, 675, 611, 697, 867, 561, - 052      862, 687, 507, 283, 482, 129, 807, 591, 733, 623, - 053      150, 238,  59, 379, 684, 877, 625, 169, 643, 105, - 054      170, 607, 520, 932, 727, 476, 693, 425, 174, 647, - 055       73, 122, 335, 530, 442, 853, 695, 249, 445, 515, - 056      909, 545, 703, 919, 874, 474, 882, 500, 594, 612, - 057      641, 801, 220, 162, 819, 984, 589, 513, 495, 799, - 058      161, 604, 958, 533, 221, 400, 386, 867, 600, 782, - 059      382, 596, 414, 171, 516, 375, 682, 485, 911, 276, - 060       98, 553, 163, 354, 666, 933, 424, 341, 533, 870, - 061      227, 730, 475, 186, 263, 647, 537, 686, 600, 224, - 062      469,  68, 770, 919, 190, 373, 294, 822, 808, 206, - 063      184, 943, 795, 384, 383, 461, 404, 758, 839, 887, - 064      715,  67, 618, 276, 204, 918, 873, 777, 604, 560, - 065      951, 160, 578, 722,  79, 804,  96, 409, 713, 940, - 066      652, 934, 970, 447, 318, 353, 859, 672, 112, 785, - 067      645, 863, 803, 350, 139,  93, 354,  99, 820, 908, - 068      609, 772, 154, 274, 580, 184,  79, 626, 630, 742, - 069      653, 282, 762, 623, 680,  81, 927, 626, 789, 125, - 070      411, 521, 938, 300, 821,  78, 343, 175, 128, 250, - 071      170, 774, 972, 275, 999, 639, 495,  78, 352, 126, - 072      857, 956, 358, 619, 580, 124, 737, 594, 701, 612, - 073      669, 112, 134, 694, 363, 992, 809, 743, 168, 974, - 074      944, 375, 748,  52, 600, 747, 642, 182, 862,  81, - 075      344, 805, 988, 739, 511, 655, 814, 334, 249, 515, - 076      897, 955, 664, 981, 649, 113, 974, 459, 893, 228, - 077      433, 837, 553, 268, 926, 240, 102, 654, 459,  51, - 078      686, 754, 806, 760, 493, 403, 415, 394, 687, 700, - 079      946, 670, 656, 610, 738, 392, 760, 799, 887, 653, - 080      978, 321, 576, 617, 626, 502, 894, 679, 243, 440, - 081      680, 879, 194, 572, 640, 724, 926,  56, 204, 700, - 082      707, 151, 457, 449, 797, 195, 791, 558, 945, 679, - 083      297,  59,  87, 824, 713, 663, 412, 693, 342, 606, - 084      134, 108, 571, 364, 631, 212, 174, 643, 304, 329, - 085      343,  97, 430, 751, 497, 314, 983, 374, 822, 928, - 086      140, 206,  73, 263, 980, 736, 876, 478, 430, 305, - 087      170, 514, 364, 692, 829,  82, 855, 953, 676, 246, - 088      369, 970, 294, 750, 807, 827, 150, 790, 288, 923, - 089      804, 378, 215, 828, 592, 281, 565, 555, 710,  82, - 090      896, 831, 547, 261, 524, 462, 293, 465, 502,  56, - 091      661, 821, 976, 991, 658, 869, 905, 758, 745, 193, - 092      768, 550, 608, 933, 378, 286, 215, 979, 792, 961, - 093       61, 688, 793, 644, 986, 403, 106, 366, 905, 644, - 094      372, 567, 466, 434, 645, 210, 389, 550, 919, 135, - 095      780, 773, 635, 389, 707, 100, 626, 958, 165, 504, - 096      920, 176, 193, 713, 857, 265, 203,  50, 668, 108, - 097      645, 990, 626, 197, 510, 357, 358, 850, 858, 364, - 098      936, 638 - 099    };100101    /// <summary>102    /// When multiplied by compression parameter (1-9) gives the block size for compression103    /// 9 gives the best compression but uses the most memory.1namespace ICSharpCode.SharpZipLib.BZip22{3  /// <summary>4  /// Defines internal values for both compression and decompression5  /// </summary>6  internal sealed class BZip2Constants7  {8    /// <summary>9    /// Random numbers used to randomise repetitive blocks10    /// </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    };6566    /// <summary>67    /// When multiplied by compression parameter (1-9) gives the block size for compression68    /// 9 gives the best compression but uses the most memory.69    /// </summary>70    public const int BaseBlockSize = 100000;7172    /// <summary>73    /// Backend constant74    /// </summary>75    public const int MaximumAlphaSize = 258;7677    /// <summary>78    /// Backend constant79    /// </summary>80    public const int MaximumCodeLength = 23;8182    /// <summary>83    /// Backend constant84    /// </summary>85    public const int RunA = 0;8687    /// <summary>88    /// Backend constant89    /// </summary>90    public const int RunB = 1;9192    /// <summary>93    /// Backend constant94    /// </summary>95    public const int GroupCount = 6;9697    /// <summary>98    /// Backend constant99    /// </summary>100    public const int GroupSize = 50;101102    /// <summary>103    /// Backend constant  104    /// </summary>105    public const int BaseBlockSize = 100000;105    public const int NumberOfIterations = 4;  106  107    /// <summary>  108    /// Backend constant  109    /// </summary>110    public const int MaximumAlphaSize = 258;110    public const int MaximumSelectors = (2 + (900000 / GroupSize));  111  112    /// <summary>  113    /// Backend constant  114    /// </summary>115    public const int MaximumCodeLength = 23;115    public const int OvershootBytes = 20;  116117    /// <summary>118    /// Backend constant119    /// </summary>120    public const int RunA = 0;121122    /// <summary>123    /// Backend constant124    /// </summary>125    public const int RunB = 1;126127    /// <summary>128    /// Backend constant129    /// </summary>130    public const int GroupCount = 6;131132    /// <summary>133    /// Backend constant134    /// </summary>135    public const int GroupSize = 50;136137    /// <summary>138    /// Backend constant139    /// </summary>140    public const int NumberOfIterations = 4;141142    /// <summary>143    /// Backend constant144    /// </summary>145    public const int MaximumSelectors = (2 + (900000 / GroupSize));146147    /// <summary>148    /// Backend constant149    /// </summary>150    public const int OvershootBytes = 20;151 - 0152    private BZip2Constants()153    { - 0154    }155  }156}157158/* This file was derived from a file containing this license:159 *160 * This file is a part of bzip2 and/or libbzip2, a program and161 * library for lossless, block-sorting data compression.162 *163 * Copyright (C) 1996-1998 Julian R Seward.  All rights reserved.164 *165 * Redistribution and use in source and binary forms, with or without166 * modification, are permitted provided that the following conditions167 * are met:168 *169 * 1. Redistributions of source code must retain the above copyright170 * notice, this list of conditions and the following disclaimer.171 *172 * 2. The origin of this software must not be misrepresented; you must173 * not claim that you wrote the original software.  If you use this174 * software in a product, an acknowledgment in the product175 * documentation would be appreciated but is not required.176 *177 * 3. Altered source versions must be plainly marked as such, and must178 * not be misrepresented as being the original software.179 *180 * 4. The name of the author may not be used to endorse or promote181 * products derived from this software without specific prior written182 * permission.183 *184 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS185 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED186 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE187 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY188 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL189 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE190 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS191 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,192 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING193 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS194 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.195 *196 * Java version ported by Keiron Liddle, Aftex Software <keiron@aftexsw.com> 1999-2001197 */ + 0117    private BZip2Constants()118    { + 0119    }120  }121} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_StrangeCRC.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2Crc.htm similarity index 60% rename from Documentation/opencover/ICSharpCode.SharpZipLib_StrangeCRC.htm rename to Documentation/opencover/ICSharpCode.SharpZipLib_BZip2Crc.htm index 6ce2b4e3d..5777ac373 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_StrangeCRC.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2Crc.htm @@ -2,7 +2,7 @@ -ICSharpCode.SharpZipLib.Checksums.StrangeCRC - Coverage Report +ICSharpCode.SharpZipLib.Checksum.BZip2Crc - Coverage Report

Summary

@@ -12,244 +12,236 @@

Summary

-Class:ICSharpCode.SharpZipLib.Checksums.StrangeCRC +Class:ICSharpCode.SharpZipLib.Checksum.BZip2Crc Assembly:ICSharpCode.SharpZipLib -File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Checksums\StrangeCrc.cs -Covered lines:77 -Uncovered lines:15 -Coverable lines:92 -Total lines:208 -Line coverage:83.6% -Branch coverage:14.2% +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(...)2100100
Update(...)200
Update(...)600
.cctor()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\Checksums\StrangeCrc.cs

+

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

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1// StrangeCRC.cs - computes a crc used in the bziplib
 2//
 3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team
 4//
 5// This file was translated from java, it was part of the GNU Classpath
 6// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
 7//
 8// This program is free software; you can redistribute it and/or
 9// modify it under the terms of the GNU General Public License
 10// as published by the Free Software Foundation; either version 2
 11// of the License, or (at your option) any later version.
 12//
 13// This program is distributed in the hope that it will be useful,
 14// but WITHOUT ANY WARRANTY; without even the implied warranty of
 15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16// GNU General Public License for more details.
 17//
 18// You should have received a copy of the GNU General Public License
 19// along with this program; if not, write to the Free Software
 20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 21//
 22// Linking this library statically or dynamically with other modules is
 23// making a combined work based on this library.  Thus, the terms and
 24// conditions of the GNU General Public License cover the whole
 25// combination.
 26//
 27// As a special exception, the copyright holders of this library give you
 28// permission to link this library with independent modules to produce an
 29// executable, regardless of the license terms of these independent
 30// modules, and to copy and distribute the resulting executable under
 31// terms of your choice, provided that you also meet, for each linked
 32// independent module, the terms and conditions of the license of that
 33// module.  An independent module is a module which is not derived from
 34// or based on this library.  If you modify this library, you may extend
 35// this exception to your version of the library, but you are not
 36// obligated to do so.  If you do not wish to do so, delete this
 37// exception statement from your version.
 38
 39using System;
 40
 41namespace ICSharpCode.SharpZipLib.Checksums
 42{
 43  /// <summary>
 44  /// Bzip2 checksum algorithm
 45  /// </summary>
 46  public class StrangeCRC : IChecksum
 47  {
 148    readonly static uint[] crc32Table = {
 149      0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
 150      0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
 151      0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
 152      0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
 153      0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
 154      0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
 155      0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
 156      0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
 157      0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
 158      0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
 159      0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
 160      0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
 161      0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
 162      0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
 163      0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
 164      0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
 165      0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
 166      0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
 167      0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
 168      0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
 169      0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
 170      0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
 171      0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
 172      0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
 173      0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
 174      0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
 175      0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
 176      0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
 177      0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
 178      0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
 179      0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
 180      0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
 181      0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
 182      0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
 183      0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
 184      0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
 185      0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
 186      0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
 187      0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
 188      0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
 189      0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
 190      0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
 191      0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
 192      0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
 193      0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
 194      0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
 195      0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
 196      0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
 197      0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
 198      0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
 199      0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
 1100      0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
 1101      0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
 1102      0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
 1103      0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
 1104      0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
 1105      0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
 1106      0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
 1107      0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
 1108      0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
 1109      0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
 1110      0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
 1111      0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
 1112      0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
 1113    };
 114
 115    int globalCrc;
 116
 117    /// <summary>
 118    /// Initialise a default instance of <see cref="StrangeCRC"></see>
 119    /// </summary>
 4120    public StrangeCRC()
 121    {
 4122      Reset();
 4123    }
 124
 125    /// <summary>
 126    /// Reset the state of Crc.
 127    /// </summary>
 128    public void Reset()
 129    {
 7130      globalCrc = -1;
 7131    }
 132
 133    /// <summary>
 134    /// Get the current Crc value.
 135    /// </summary>
 136    public long Value {
 137      get {
 2138        return ~globalCrc;
 139      }
 140    }
 141
 142    /// <summary>
 143    /// Update the Crc value.
 144    /// </summary>
 145    /// <param name="value">data update is based on</param>
 146    public void Update(int value)
 147    {
 20002148      int temp = (globalCrc >> 24) ^ value;
 20002149       if (temp < 0) {
 10031150        temp = 256 + temp;
 151      }
 20002152      globalCrc = unchecked((int)((globalCrc << 8) ^ crc32Table[temp]));
 20002153    }
 154
 155    /// <summary>
 156    /// Update Crc based on a block of data
 157    /// </summary>
 158    /// <param name="buffer">The buffer containing data to update the crc with.</param>
 159    public void Update(byte[] buffer)
 160    {
 0161       if (buffer == null) {
 0162        throw new ArgumentNullException(nameof(buffer));
 163      }
 164
 0165      Update(buffer, 0, buffer.Length);
 0166    }
 167
 168    /// <summary>
 169    /// Update Crc based on a portion of a block of data
 170    /// </summary>
 171    /// <param name="buffer">block of data</param>
 172    /// <param name="offset">index of first byte to use</param>
 173    /// <param name="count">number of bytes to use</param>
 174    public void Update(byte[] buffer, int offset, int count)
 175    {
 0176       if (buffer == null) {
 0177        throw new ArgumentNullException(nameof(buffer));
 178      }
 179
 0180       if ( offset < 0 )
 181      {
 182#if NETCF_1_0
 183        throw new ArgumentOutOfRangeException("offset");
 184#else
 0185        throw new ArgumentOutOfRangeException(nameof(offset), "cannot be less than zero");
 186#endif
 187      }
 188
 0189       if ( count < 0 )
 190      {
 191#if NETCF_1_0
 192        throw new ArgumentOutOfRangeException("count");
 193#else
 0194        throw new ArgumentOutOfRangeException(nameof(count), "cannot be less than zero");
 195#endif
 196      }
 197
 0198       if ( offset + count > buffer.Length )
 199      {
 0200        throw new ArgumentOutOfRangeException(nameof(count));
 201      }
 202
 0203       for (int i = 0; i < count; ++i) {
 0204        Update(buffer[offset++]);
 205      }
 0206    }
 207  }
 208}
 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/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2Exception.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2Exception.htm index 594b7b55f..878f863cd 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2Exception.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2Exception.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:8 Coverable lines:8 -Total lines:90 +Total lines:48 Line coverage:0% @@ -37,98 +37,56 @@

#LineLine coverage - 1// BZip2.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;1using System;2using System.Runtime.Serialization;34namespace ICSharpCode.SharpZipLib.BZip25{6  /// <summary>7  /// BZip2Exception represents exceptions specific to BZip2 classes and code.8  /// </summary>9  [Serializable]10  public class BZip2Exception : SharpZipBaseException11  {12    /// <summary>13    /// Deserialization constructor14    /// </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    }2122    /// <summary>23    /// Initialise a new instance of <see cref="BZip2Exception" />.24    /// </summary> + 025    public BZip2Exception()26    { + 027    }2829    /// <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    }  3738#if !NETCF_1_0 && !NETCF_2_039using System.Runtime.Serialization;40#endif4142namespace ICSharpCode.SharpZipLib.BZip243{44  /// <summary>45  /// BZip2Exception represents exceptions specific to Bzip2 algorithm46  /// </summary>47#if !NETCF_1_0 && !NETCF_2_048  [Serializable]49#endif50  public class BZip2Exception : SharpZipBaseException51  {5253#if !NETCF_1_0 && !NETCF_2_054    /// <summary>55    /// Deserialization constructor56    /// </summary>57    /// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>58    /// <param name="context"><see cref="StreamingContext"/> for this constructor</param>59    protected BZip2Exception(SerializationInfo info, StreamingContext context) - 060      : base(info, context)6162    { - 063    }64#endif65    /// <summary>66    /// Initialise a new instance of BZip2Exception.67    /// </summary> - 068    public BZip2Exception()69    { - 070    }7172    /// <summary>73    /// Initialise a new instance of BZip2Exception with its message set to message.74    /// </summary>75    /// <param name="message">The message describing the error.</param> - 076    public BZip2Exception(string message) : base(message)77    { - 078    }7980    /// <summary>81    /// Initialise an instance of BZip2Exception82    /// </summary>83    /// <param name="message">A message describing the error.</param>84    /// <param name="exception">The exception that is the cause of the current exception.</param>85    public BZip2Exception(string message, Exception exception) - 086      : base(message, exception)87    { - 088    }89  }90}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/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2InputStream.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2InputStream.htm index 0a0182a94..b20003e80 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2InputStream.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2InputStream.htm @@ -15,12 +15,12 @@

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:308 -Uncovered lines:118 +Covered lines:111 +Uncovered lines:315 Coverable lines:426 -Total lines:1001 -Line coverage:72.3% -Branch coverage:65.2% +Total lines:909 +Line coverage:26% +Branch coverage:15.7%

Metrics

@@ -33,35 +33,35 @@

Metrics

SetLength(...)100 Write(...)100 WriteByte(...)100 -Read(...)49085.71 +Read(...)46057.14 Close()310060 -ReadByte()758.3336.36 -MakeMaps()310080 +ReadByte()716.6718.18 +MakeMaps()300 Initialize()68054.55 -InitBlock()1384.2160 -EndBlock()283.3366.67 +InitBlock()1347.3728 +EndBlock()200 Complete()28066.67 BsSetStream(...)1100100 FillBuffer()263.6466.67 BsR(...)2100100 BsGetUChar()1100100 -BsGetIntVS(...)1100100 +BsGetIntVS(...)100 BsGetInt32()1100100 -RecvDecodingTables()1894.6791.43 -GetAndMoveToFrontDecode()2691.9276.47 +RecvDecodingTables()1800 +GetAndMoveToFrontDecode()2600 SetupBlock()48485.71 SetupRandPartA()600 -SetupNoRandPartA()2100100 +SetupNoRandPartA()269.2366.67 SetupRandPartB()700 SetupRandPartC()200 -SetupNoRandPartB()362.580 +SetupNoRandPartB()300 SetupNoRandPartC()200 SetDecompressStructureSizes(...)677.7854.55 CompressedStreamEOF()100 BlockOverrun()100 BadBlockHeader()100 CrcError()100 -HbCreateDecodeTables(...)10100100 +HbCreateDecodeTables(...)1000

File(s)

@@ -69,1009 +69,917 @@

#LineLine coverage - 1// BZip2InputStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;37using System.IO;3839using ICSharpCode.SharpZipLib.Checksums;1using System;2using System.IO;3using ICSharpCode.SharpZipLib.Checksum;45namespace ICSharpCode.SharpZipLib.BZip26{7  /// <summary>8  /// An input stream that decompresses files in the BZip2 format9  /// </summary>10  public class BZip2InputStream : Stream11  {12    #region Constants13    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    #endregion21    #region Constructors22    /// <summary>23    /// Construct instance for reading from stream24    /// </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    }  4041namespace ICSharpCode.SharpZipLib.BZip242{4344  /// <summary>45  /// An input stream that decompresses files in the BZip2 format46  /// </summary>47  public class BZip2InputStream : Stream48  {49    #region Constants50    const int START_BLOCK_STATE = 1;51    const int RAND_PART_A_STATE = 2;52    const int RAND_PART_B_STATE = 3;53    const int RAND_PART_C_STATE = 4;54    const int NO_RAND_PART_A_STATE = 5;55    const int NO_RAND_PART_B_STATE = 6;56    const int NO_RAND_PART_C_STATE = 7;57    #endregion58    #region Constructors59    /// <summary>60    /// Construct instance for reading from stream61    /// </summary>62    /// <param name="stream">Data source</param> - 263    public BZip2InputStream(Stream stream)64    {65      // init arrays - 2866       for (int i = 0; i < BZip2Constants.GroupCount; ++i)67      { - 1268        limit[i] = new int[BZip2Constants.MaximumAlphaSize]; - 1269        baseArray[i]  = new int[BZip2Constants.MaximumAlphaSize]; - 1270        perm[i]  = new int[BZip2Constants.MaximumAlphaSize];71      }72 - 273      BsSetStream(stream); - 274      Initialize(); - 275      InitBlock(); - 276      SetupBlock(); - 277    }7879    #endregion8081    /// <summary>82    /// Get/set flag indicating ownership of underlying stream.83    /// When the flag is true <see cref="Close"></see> will close the underlying stream also.41    #endregion4243    /// <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    }515253    #region Stream Overrides54    /// <summary>55    /// Gets a value indicating if the stream supports reading56    /// </summary>57    public override bool CanRead {58      get { + 059        return baseStream.CanRead;60      }61    }6263    /// <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    }7172    /// <summary>73    /// Gets a value indicating whether the current stream supports writing.74    /// This property always returns false75    /// </summary>76    public override bool CanWrite {77      get { + 078        return false;79      }80    }8182    /// <summary>83    /// Gets the length in bytes of the stream.  84    /// </summary>85    public bool IsStreamOwner86    { - 287      get { return isStreamOwner; } - 088      set { isStreamOwner = value; }85    public override long Length {86      get { + 087        return baseStream.Length;88      }  89    }  909192    #region Stream Overrides93    /// <summary>94    /// Gets a value indicating if the stream supports reading95    /// </summary>96    public override bool CanRead97    {98      get { - 099        return baseStream.CanRead;100      }101    }102103    /// <summary>104    /// Gets a value indicating whether the current stream supports seeking.105    /// </summary>106    public override bool CanSeek {107      get { - 0108        return baseStream.CanSeek;109      }110    }111112    /// <summary>113    /// Gets a value indicating whether the current stream supports writing.114    /// This property always returns false115    /// </summary>116    public override bool CanWrite {117      get { - 0118        return false;119      }120    }121122    /// <summary>123    /// Gets the length in bytes of the stream.124    /// </summary>125    public override long Length {126      get { - 0127        return baseStream.Length;128      }129    }130131    /// <summary>132    /// Gets or sets the streams position.133    /// Setting the position is not supported and will throw a NotSupportException134    /// </summary>135    /// <exception cref="NotSupportedException">Any attempt to set the position</exception>136    public override long Position {137      get { - 0138        return baseStream.Position;139      }140      set { - 0141        throw new NotSupportedException("BZip2InputStream position cannot be set");142      }143    }144145    /// <summary>146    /// Flushes the stream.147    /// </summary>148    public override void Flush()149    { - 0150       if (baseStream != null) { - 0151        baseStream.Flush();152      } - 0153    }154155    /// <summary>156    /// Set the streams position.  This operation is not supported and will throw a NotSupportedException157    /// </summary>158    /// <param name="offset">A byte offset relative to the <paramref name="origin"/> parameter.</param>159    /// <param name="origin">A value of type <see cref="SeekOrigin"/> indicating the reference point used to obtain the 160    /// <returns>The new position of the stream.</returns>161    /// <exception cref="NotSupportedException">Any access</exception>162    public override long Seek(long offset, SeekOrigin origin)163    { - 0164      throw new NotSupportedException("BZip2InputStream Seek not supported");165    }166167    /// <summary>168    /// Sets the length of this stream to the given value.169    /// This operation is not supported and will throw a NotSupportedExceptionortedException170    /// </summary>171    /// <param name="value">The new length for the stream.</param>172    /// <exception cref="NotSupportedException">Any access</exception>173    public override void SetLength(long value)174    { - 0175      throw new NotSupportedException("BZip2InputStream SetLength not supported");176    }91    /// <summary>92    /// Gets or sets the streams position.93    /// Setting the position is not supported and will throw a NotSupportException94    /// </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    }104105    /// <summary>106    /// Flushes the stream.107    /// </summary>108    public override void Flush()109    { + 0110       if (baseStream != null) { + 0111        baseStream.Flush();112      } + 0113    }114115    /// <summary>116    /// Set the streams position.  This operation is not supported and will throw a NotSupportedException117    /// </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    }126127    /// <summary>128    /// Sets the length of this stream to the given value.129    /// This operation is not supported and will throw a NotSupportedExceptionortedException130    /// </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    }137138    /// <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 NotSupportedException141    /// </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    }150151    /// <summary>152    /// Writes a byte to the current position in the file stream.153    /// This operation is not supported and will throw a NotSupportedException154    /// </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    }161162    /// <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 less169    /// than the number of bytes requested if that number of bytes are not170    /// 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      }  177178    /// <summary>179    /// Writes a block of bytes to this stream using data from a buffer.180    /// This operation is not supported and will throw a NotSupportedException181    /// </summary>182    /// <param name="buffer">The buffer to source data from.</param>183    /// <param name="offset">The offset to start obtaining data from.</param>184    /// <param name="count">The number of bytes of data to write.</param>185    /// <exception cref="NotSupportedException">Any access</exception>186    public override void Write(byte[] buffer, int offset, int count)187    { - 0188      throw new NotSupportedException("BZip2InputStream Write not supported");189    }190191    /// <summary>192    /// Writes a byte to the current position in the file stream.193    /// This operation is not supported and will throw a NotSupportedException194    /// </summary>195    /// <param name="value">The value to write.</param>196    /// <exception cref="NotSupportedException">Any access</exception>197    public override void WriteByte(byte value)198    { - 0199      throw new NotSupportedException("BZip2InputStream WriteByte not supported");200    }201202    /// <summary>203    /// Read a sequence of bytes and advances the read position by one byte.204    /// </summary>205    /// <param name="buffer">Array of bytes to store values in</param>206    /// <param name="offset">Offset in array to begin storing data</param>207    /// <param name="count">The maximum number of bytes to read</param>208    /// <returns>The total number of bytes read into the buffer. This might be less209    /// than the number of bytes requested if that number of bytes are not210    /// currently available or zero if the end of the stream is reached.211    /// </returns>212    public override int Read(byte[] buffer, int offset, int count)213    { - 5214       if ( buffer == null )215      { - 0216        throw new ArgumentNullException(nameof(buffer));217      }218 - 20010219       for (int i = 0; i < count; ++i) { - 10003220        int rb = ReadByte(); - 10003221         if (rb == -1) { - 3222          return i;223        } - 10000224        buffer[offset + i] = (byte)rb; + 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    }187188    /// <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 position199    /// </summary>200    /// <returns>byte read or -1 on end of stream</returns>201    public override int ReadByte()202    { + 1203       if (streamEnd) { + 1204        return -1; // ok205      }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      } - 2226      return count; + 0226      return retChar;  227    }  228229    /// <summary>230    /// Closes the stream, releasing any associated resources.231    /// </summary>232    public override void Close()233    { - 2234       if ( IsStreamOwner && (baseStream != null) ) { - 2235        baseStream.Close();236      } - 2237    }238    /// <summary>239    /// Read a byte from stream advancing position240    /// </summary>241    /// <returns>byte read or -1 on end of stream</returns>242    public override int ReadByte()243    { - 10003244       if (streamEnd)245      { - 3246        return -1; // ok247      }248 - 10000249      int retChar = currentChar; - 10000250       switch (currentState)251      {252        case RAND_PART_B_STATE: - 0253          SetupRandPartB(); - 0254          break;255        case RAND_PART_C_STATE: - 0256          SetupRandPartC(); - 0257          break;258        case NO_RAND_PART_B_STATE: - 10000259          SetupNoRandPartB(); - 10000260          break;261        case NO_RAND_PART_C_STATE: - 0262          SetupNoRandPartC();263          break;264        case START_BLOCK_STATE:265        case NO_RAND_PART_A_STATE:266        case RAND_PART_A_STATE:267          break;268      } - 10000269      return retChar;270    }271272    #endregion229    #endregion230231    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    }242243    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    }259260    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      }  273274    void MakeMaps()275    { - 1276      nInUse = 0; - 514277       for (int i = 0; i < 256; ++i) { - 256278         if (inUse[i]) { - 256279          seqToUnseq[nInUse] = (byte)i; - 256280          unseqToSeq[i] = (byte)nInUse; - 256281          nInUse++;282        }283      } - 1284    } + 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();  285286    void Initialize()287    { - 2288      char magic1 = BsGetUChar(); - 2289      char magic2 = BsGetUChar();290 - 2291      char magic3 = BsGetUChar(); - 2292      char magic4 = BsGetUChar(); + 0286      mCrc.Reset(); + 0287      currentState = START_BLOCK_STATE; + 0288    }289290    void EndBlock()291    { + 0292      computedBlockCRC = (int)mCrc.Value;  293 - 2294       if (magic1 != 'B' || magic2 != 'Z' || magic3 != 'h' || magic4 < '1' || magic4 > '9') { - 0295        streamEnd = true; - 0296        return;294      // -- A bad CRC is considered a fatal error. -- + 0295       if (storedBlockCRC != computedBlockCRC) { + 0296        CrcError();  297      }  298 - 2299      SetDecompressStructureSizes(magic4 - '0'); - 2300      computedCombinedCRC = 0; - 2301    }302303    void InitBlock()304    { - 3305      char magic1 = BsGetUChar(); - 3306      char magic2 = BsGetUChar(); - 3307      char magic3 = BsGetUChar(); - 3308      char magic4 = BsGetUChar(); - 3309      char magic5 = BsGetUChar(); - 3310      char magic6 = BsGetUChar();311 - 3312       if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45 && magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) { - 2313        Complete(); - 2314        return;315      }316 - 1317       if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) { - 0318        BadBlockHeader(); - 0319        streamEnd = true; - 0320        return;321      }322 - 1323      storedBlockCRC  = BsGetInt32();299      // 1528150659 + 0300      computedCombinedCRC = ((computedCombinedCRC << 1) & 0xFFFFFFFF) | (computedCombinedCRC >> 31); + 0301      computedCombinedCRC = computedCombinedCRC ^ (uint)computedBlockCRC; + 0302    }303304    void Complete()305    { + 1306      storedCombinedCRC = BsGetInt32(); + 1307       if (storedCombinedCRC != (int)computedCombinedCRC) { + 0308        CrcError();309      }310 + 1311      streamEnd = true; + 1312    }313314    void BsSetStream(Stream stream)315    { + 1316      baseStream = stream; + 1317      bsLive = 0; + 1318      bsBuff = 0; + 1319    }320321    void FillBuffer()322    { + 14323      int thech = 0;  324 - 1325      blockRandomised = (BsR(1) == 1);326 - 1327      GetAndMoveToFrontDecode();328 - 1329      mCrc.Reset(); - 1330      currentState = START_BLOCK_STATE; - 1331    }332333    void EndBlock()334    { - 1335      computedBlockCRC = (int)mCrc.Value;336337      // -- A bad CRC is considered a fatal error. -- - 1338       if (storedBlockCRC != computedBlockCRC) { - 0339        CrcError();340      }341342      // 1528150659 - 1343      computedCombinedCRC = ((computedCombinedCRC << 1) & 0xFFFFFFFF) | (computedCombinedCRC >> 31); - 1344      computedCombinedCRC = computedCombinedCRC ^ (uint)computedBlockCRC; - 1345    }346347    void Complete()348    { - 2349      storedCombinedCRC = BsGetInt32(); - 2350       if (storedCombinedCRC != (int)computedCombinedCRC) { - 0351        CrcError();352      }353 - 2354      streamEnd = true; - 2355    }356357    void BsSetStream(Stream stream)358    { - 2359      baseStream = stream; - 2360      bsLive = 0; - 2361      bsBuff = 0; - 2362    }363364    void FillBuffer()365    { - 10531366      int thech = 0;367368      try { - 10531369        thech = baseStream.ReadByte(); - 10531370      } catch (Exception) { - 0371        CompressedStreamEOF(); - 0372      }373 - 10531374       if (thech == -1) { - 0375        CompressedStreamEOF();376      }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    }338339    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    }349350    char BsGetUChar()351    { + 10352      return (char)BsR(8);353    }354355    int BsGetIntVS(int numBits)356    { + 0357      return BsR(numBits);358    }359360    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    }368369    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 - 10531378      bsBuff = (bsBuff << 8) | (thech & 0xFF); - 10531379      bsLive += 8; - 10531380    }381382    int BsR(int n)383    { - 24370384       while (bsLive < n) { - 9182385        FillBuffer();386      }387 - 15188388      int v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1); - 15188389      bsLive -= n; - 15188390      return v;391    }392393    char BsGetUChar()394    { - 26395      return (char)BsR(8);396    }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;  397398    int BsGetIntVS(int numBits)399    { - 1400      return BsR(numBits);401    }402403    int BsGetInt32()404    { - 3405      int result = BsR(8); - 3406      result = (result << 8) | BsR(8); - 3407      result = (result << 8) | BsR(8); - 3408      result = (result << 8) | BsR(8); - 3409      return result;410    }411412    void RecvDecodingTables()413    { - 1414      char[][] len = new char[BZip2Constants.GroupCount][]; - 14415       for (int i = 0; i < BZip2Constants.GroupCount; ++i) { - 6416        len[i] = new char[BZip2Constants.MaximumAlphaSize];417      }418 - 1419      bool[] inUse16 = new bool[16];420421      //--- Receive the mapping table --- - 34422       for (int i = 0; i < 16; i++) { - 16423        inUse16[i] = (BsR(1) == 1);424      }425 - 34426       for (int i = 0; i < 16; i++) { - 16427         if (inUse16[i]) { - 544428           for (int j = 0; j < 16; j++) { - 256429            inUse[i * 16 + j] = (BsR(1) == 1);430          } - 16431        } else { - 0432           for (int j = 0; j < 16; j++) { - 0433            inUse[i * 16 + j] = false;434          }435        }436      }437 - 1438      MakeMaps(); - 1439      int alphaSize = nInUse + 2;440441      //--- Now the selectors --- - 1442      int nGroups    = BsR(3); - 1443      int nSelectors = BsR(15);444 - 404445       for (int i = 0; i < nSelectors; i++) { - 201446        int j = 0; - 729447         while (BsR(1) == 1) { - 528448          j++;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      }409410      //--- 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      }426427      //--- 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      }441442      //--- 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        } - 201450        selectorMtf[i] = (byte)j;451      }452453      //--- Undo the MTF values for the selectors. --- - 1454      byte[] pos = new byte[BZip2Constants.GroupCount]; - 14455       for (int v = 0; v < nGroups; v++) { - 6456        pos[v] = (byte)v;457      }458 - 404459       for (int i = 0; i < nSelectors; i++) { - 201460        int  v   = selectorMtf[i]; - 201461        byte tmp = pos[v]; - 729462         while (v > 0) { - 528463          pos[v] = pos[v - 1]; - 528464          v--;465        } - 201466        pos[0]      = tmp; - 201467        selector[i] = tmp;468      }469470      //--- Now the coding tables --- - 14471       for (int t = 0; t < nGroups; t++) { - 6472        int curr = BsR(5); - 3108473         for (int i = 0; i < alphaSize; i++) { - 2843474           while (BsR(1) == 1) { - 1295475             if (BsR(1) == 0) { - 654476              curr++; - 654477            } else { - 641478              curr--;479            }480          } - 1548481          len[t][i] = (char)curr;482        }483      }484485      //--- Create the Huffman decoding tables --- - 14486       for (int t = 0; t < nGroups; t++) { - 6487        int minLen = 32; - 6488        int maxLen = 0; - 3108489         for (int i = 0; i < alphaSize; i++) { - 1548490          maxLen = Math.Max(maxLen, len[t][i]); - 1548491          minLen = Math.Min(minLen, len[t][i]);492        } - 6493        HbCreateDecodeTables(limit[t], baseArray[t], perm[t], len[t], minLen, maxLen, alphaSize); - 6494        minLens[t] = minLen;495      } - 1496    }497498    void GetAndMoveToFrontDecode()499    { - 1500      byte[] yy = new byte[256];501      int nextSym;502 - 1503      int limitLast = BZip2Constants.BaseBlockSize * blockSize100k; - 1504      origPtr = BsGetIntVS(24);505 - 1506      RecvDecodingTables(); - 1507      int EOB = nInUse+1; - 1508      int groupNo = -1; - 1509      int groupPos = 0;510511      /*--512      Setting up the unzftab entries here is not strictly513      necessary, but it does save having to do it later514      in a separate pass, and so saves a block's worth of515      cache misses.516      --*/ - 514517       for (int i = 0; i <= 255; i++) { - 256518        unzftab[i] = 0;519      }520 - 514521       for (int i = 0; i <= 255; i++) { - 256522        yy[i] = (byte)i;523      }524 - 1525      last = -1; + 0450        HbCreateDecodeTables(limit[t], baseArray[t], perm[t], len[t], minLen, maxLen, alphaSize); + 0451        minLens[t] = minLen;452      } + 0453    }454455    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;467468      /*--469      Setting up the unzftab entries here is not strictly470      necessary, but it does save having to do it later471      in a separate pass, and so saves a block's worth of472      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]];511512      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 - 1527       if (groupPos == 0) { - 1528        groupNo++; - 1529        groupPos = BZip2Constants.GroupSize;530      }531 - 1532      groupPos--; - 1533      int zt = selector[groupNo]; - 1534      int zn = minLens[zt]; - 1535      int zvec = BsR(zn);536      int zj;537 - 2538       while (zvec > limit[zt][zn]) { - 1539         if (zn > 20) { // the longest code - 0540          throw new BZip2Exception("Bzip data error");541        } - 1542        zn++; - 1543         while (bsLive < 1) { - 0544          FillBuffer();545        } - 1546        zj = (bsBuff >> (bsLive-1)) & 1; - 1547        bsLive--; - 1548        zvec = (zvec << 1) | zj;549      } - 1550       if (zvec - baseArray[zt][zn] < 0 || zvec - baseArray[zt][zn] >= BZip2Constants.MaximumAlphaSize) { - 0551        throw new BZip2Exception("Bzip data error");552      } - 1553      nextSym = perm[zt][zvec - baseArray[zt][zn]];554555      while (true) { - 10001556         if (nextSym == EOB) {557          break;558        }559 - 10000560         if (nextSym == BZip2Constants.RunA || nextSym == BZip2Constants.RunB) { - 39561          int s = -1; - 39562          int n = 1;563          do { - 39564             if (nextSym == BZip2Constants.RunA) { - 39565              s += (0 + 1) * n; - 39566             } else if (nextSym == BZip2Constants.RunB) { - 0567              s += (1 + 1) * n;568            }569 - 39570            n <<= 1; + 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 - 39572             if (groupPos == 0) { - 1573              groupNo++; - 1574              groupPos = BZip2Constants.GroupSize;575            }576 - 39577            groupPos--;578 - 39579            zt = selector[groupNo]; - 39580            zn = minLens[zt]; - 39581            zvec = BsR(zn);582 - 86583             while (zvec > limit[zt][zn]) { - 47584              zn++; - 51585               while (bsLive < 1) { - 4586                FillBuffer();587              } - 47588              zj = (bsBuff >> (bsLive - 1)) & 1; - 47589              bsLive--; - 47590              zvec = (zvec << 1) | zj;591            } - 39592            nextSym = perm[zt][zvec - baseArray[zt][zn]]; - 39593           } while (nextSym == BZip2Constants.RunA || nextSym == BZip2Constants.RunB);594 - 39595          s++; - 39596          byte ch = seqToUnseq[yy[0]]; - 39597          unzftab[ch] += s;598 - 78599           while (s > 0) { - 39600            last++; - 39601            ll8[last] = ch; - 39602            s--;603          } + 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 - 39605           if (last >= limitLast) { - 0606            BlockOverrun();607          } - 0608          continue;609        } else { - 9961610          last++; - 9961611           if (last >= limitLast) { - 0612            BlockOverrun();613          }614 - 9961615          byte tmp = yy[nextSym - 1]; - 9961616          unzftab[seqToUnseq[tmp]]++; - 9961617          ll8[last] = seqToUnseq[tmp];618 - 2585304619           for (int j = nextSym-1; j > 0; --j) { - 1282691620            yy[j] = yy[j - 1];621          } - 9961622          yy[0] = tmp;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 - 9961624           if (groupPos == 0) { - 199625            groupNo++; - 199626            groupPos = BZip2Constants.GroupSize;627          }628 - 9961629          groupPos--; - 9961630          zt = selector[groupNo]; - 9961631          zn = minLens[zt]; - 9961632          zvec = BsR(zn); - 20183633           while (zvec > limit[zt][zn]) { - 10222634            zn++; - 11567635             while (bsLive < 1) { - 1345636              FillBuffer();637            } - 10222638            zj = (bsBuff >> (bsLive-1)) & 1; - 10222639            bsLive--; - 10222640            zvec = (zvec << 1) | zj;641          } - 9961642          nextSym = perm[zt][zvec - baseArray[zt][zn]]; - 9961643          continue;644        }645      } - 1646    }647648    void SetupBlock()649    { - 3650      int[] cftab = new int[257];651 - 3652      cftab[0] = 0; - 3653      Array.Copy(unzftab, 0, cftab, 1, 256);654 - 1542655       for (int i = 1; i <= 256; i++) { - 768656        cftab[i] += cftab[i - 1];657      }658 - 40008659       for (int i = 0; i <= last; i++) { - 20001660        byte ch = ll8[i]; - 20001661        tt[cftab[ch]] = i; - 20001662        cftab[ch]++; + 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    }638639    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      }664 - 3665      cftab = null;666 - 3667      tPos = tt[origPtr];668 - 3669      count = 0; - 3670      i2    = 0; - 3671      ch2   = 256;   /*-- not a char and not EOF --*/672 - 3673       if (blockRandomised) { - 0674        rNToGo = 0; - 0675        rTPos = 0; - 0676        SetupRandPartA(); - 0677      } else { - 3678        SetupNoRandPartA();679      } - 3680    }681682    void SetupRandPartA()683    { - 0684       if (i2 <= last) { - 0685        chPrev = ch2; - 0686        ch2  = ll8[tPos]; - 0687        tPos = tt[tPos]; - 0688         if (rNToGo == 0) { - 0689          rNToGo = BZip2Constants.RandomNumbers[rTPos]; - 0690          rTPos++; - 0691           if (rTPos == 512) { - 0692            rTPos = 0;693          }694        } - 0695        rNToGo--; - 0696         ch2 ^= (int)((rNToGo == 1) ? 1 : 0); - 0697        i2++;698 - 0699        currentChar  = ch2; - 0700        currentState = RAND_PART_B_STATE; - 0701        mCrc.Update(ch2); - 0702      } else { - 0703        EndBlock(); - 0704        InitBlock(); - 0705        SetupBlock();706      } - 0707    }708709    void SetupNoRandPartA()710    { - 10003711       if (i2 <= last) { - 10002712        chPrev = ch2; - 10002713        ch2  = ll8[tPos]; - 10002714        tPos = tt[tPos]; - 10002715        i2++;716 - 10002717        currentChar = ch2; - 10002718        currentState = NO_RAND_PART_B_STATE; - 10002719        mCrc.Update(ch2); - 10002720      } else { - 1721        EndBlock(); - 1722        InitBlock(); - 1723        SetupBlock();724      } - 1725    }726727    void SetupRandPartB()728    { - 0729       if (ch2 != chPrev) { - 0730        currentState = RAND_PART_A_STATE; - 0731        count = 1; - 0732        SetupRandPartA(); - 0733      } else { - 0734        count++; - 0735         if (count >= 4) { - 0736          z = ll8[tPos]; - 0737          tPos = tt[tPos]; - 0738           if (rNToGo == 0) { - 0739            rNToGo = BZip2Constants.RandomNumbers[rTPos]; - 0740            rTPos++; - 0741             if (rTPos == 512) { - 0742              rTPos = 0;743            }744          } - 0745          rNToGo--; - 0746           z ^= (byte)((rNToGo == 1) ? 1 : 0); - 0747          j2 = 0; - 0748          currentState = RAND_PART_C_STATE; - 0749          SetupRandPartC(); - 0750        } else { - 0751          currentState = RAND_PART_A_STATE; - 0752          SetupRandPartA();753        }754      } - 0755    }756757    void SetupRandPartC()758    { - 0759       if (j2 < (int)z) { - 0760        currentChar = ch2; - 0761        mCrc.Update(ch2); - 0762        j2++; - 0763      } else { - 0764        currentState = RAND_PART_A_STATE; - 0765        i2++; - 0766        count = 0; - 0767        SetupRandPartA();768      } - 0769    } + 0664    }665666    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    }683684    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    }713714    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    }727728    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    }748749    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    }762763    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;  770771    void SetupNoRandPartB()772    { - 10000773       if (ch2 != chPrev) { - 9962774        currentState = NO_RAND_PART_A_STATE; - 9962775        count = 1; - 9962776        SetupNoRandPartA(); - 9962777      } else { - 38778        count++; - 38779         if (count >= 4) { - 0780          z = ll8[tPos]; - 0781          tPos = tt[tPos]; - 0782          currentState = NO_RAND_PART_C_STATE; - 0783          j2 = 0; - 0784          SetupNoRandPartC(); - 0785        } else { - 38786          currentState = NO_RAND_PART_A_STATE; - 38787          SetupNoRandPartA();788        }789      } - 38790    }791792    void SetupNoRandPartC()793    { - 0794       if (j2 < (int)z) { - 0795        currentChar = ch2; - 0796        mCrc.Update(ch2); - 0797        j2++; - 0798      } else { - 0799        currentState = NO_RAND_PART_A_STATE; - 0800        i2++; - 0801        count = 0; - 0802        SetupNoRandPartA();803      } - 0804    }805806    void SetDecompressStructureSizes(int newSize100k)807    { - 2808       if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k && blockSize100k <= 9)) { - 0809        throw new BZip2Exception("Invalid block size");810      }811 - 2812      blockSize100k = newSize100k;813 - 2814       if (newSize100k == 0) { - 0815        return;816      }817 - 2818      int n = BZip2Constants.BaseBlockSize * newSize100k; - 2819      ll8 = new byte[n]; - 2820      tt  = new int[n]; - 2821    }822823    static void CompressedStreamEOF()824    { - 0825      throw new EndOfStreamException("BZip2 input stream end of compressed stream");826    }827828    static void BlockOverrun()829    { - 0830      throw new BZip2Exception("BZip2 input stream block overrun");831    }832833    static void BadBlockHeader()834    { - 0835      throw new BZip2Exception("BZip2 input stream bad block header");836    }837838    static void CrcError()839    { - 0840      throw new BZip2Exception("BZip2 input stream crc error");841    }842843    static void HbCreateDecodeTables(int[] limit, int[] baseArray, int[] perm, char[] length, int minLen, int maxLen, in844    { - 6845      int pp = 0;846 - 72847       for (int i = minLen; i <= maxLen; ++i)848      { - 15540849         for (int j = 0; j < alphaSize; ++j)850        { - 7740851           if (length[j] == i)852          { - 1548853            perm[pp] = j; - 1548854            ++pp;855          }856        }857      }858 - 288859       for (int i = 0; i < BZip2Constants.MaximumCodeLength; i++)860      { - 138861        baseArray[i] = 0;862      }863 - 3108864       for (int i = 0; i < alphaSize; i++)865      { - 1548866        ++baseArray[length[i] + 1];867      } + 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    }779780    static void CompressedStreamEOF()781    { + 0782      throw new EndOfStreamException("BZip2 input stream end of compressed stream");783    }784785    static void BlockOverrun()786    { + 0787      throw new BZip2Exception("BZip2 input stream block overrun");788    }789790    static void BadBlockHeader()791    { + 0792      throw new BZip2Exception("BZip2 input stream bad block header");793    }794795    static void CrcError()796    { + 0797      throw new BZip2Exception("BZip2 input stream crc error");798    }799800    static void HbCreateDecodeTables(int[] limit, int[] baseArray, int[] perm, char[] length, int minLen, int maxLen, in801    { + 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    }841842    #region Instance Fields843    /*--844    index of the last char in the block, so845    the block size == last + 1.846    --*/847    int last;848849    /*--850    index in zptr[] of original string after sorting.851    --*/852    int origPtr;853854    /*--855    always: in the range 0 .. 9.856    The current block size is 100000 * this number.857    --*/858    int blockSize100k;859860    bool blockRandomised;861862    int bsBuff;863    int bsLive; + 1864    IChecksum mCrc = new BZip2Crc();865 + 1866    bool[] inUse = new bool[256];867    int nInUse;  868 - 276869       for (int i = 1; i < BZip2Constants.MaximumCodeLength; i++)870      { - 132871        baseArray[i] += baseArray[i - 1];872      }873 - 288874       for (int i = 0; i < BZip2Constants.MaximumCodeLength; i++)875      { - 138876        limit[i] = 0;877      }878 - 6879      int vec = 0;880 - 72881       for (int i = minLen; i <= maxLen; i++)882      { - 30883        vec += (baseArray[i + 1] - baseArray[i]); - 30884        limit[i] = vec - 1; - 30885        vec <<= 1;886      }887 - 60888       for (int i = minLen + 1; i <= maxLen; i++)889      { - 24890        baseArray[i] = ((limit[i - 1] + 1) << 1) - baseArray[i];891      } - 6892    } + 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];874875    int[] tt;876    byte[] ll8;877878    /*--879    freq table collected to save a pass over the data880    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];888889    Stream baseStream;890    bool streamEnd;891 + 1892    int currentChar = -1;  893894    #region Instance Fields895    /*--896    index of the last char in the block, so897    the block size == last + 1.898    --*/899    int last;900901    /*--902    index in zptr[] of original string after sorting.903    --*/904    int origPtr;905906    /*--907    always: in the range 0 .. 9.908    The current block size is 100000 * this number.909    --*/910    int blockSize100k;911912    bool blockRandomised;913914    int bsBuff;915    int bsLive; - 2916    IChecksum mCrc = new StrangeCRC();917 - 2918    bool[] inUse = new bool[256];919    int    nInUse;920 - 2921    byte[] seqToUnseq = new byte[256]; - 2922    byte[] unseqToSeq = new byte[256];923 - 2924    byte[] selector    = new byte[BZip2Constants.MaximumSelectors]; - 2925    byte[] selectorMtf = new byte[BZip2Constants.MaximumSelectors];926927    int[] tt;928    byte[] ll8;929930    /*--931    freq table collected to save a pass over the data932    during decompression.933    --*/ - 2934    int[] unzftab = new int[256];935 - 2936    int[][] limit     = new int[BZip2Constants.GroupCount][]; - 2937    int[][] baseArray = new int[BZip2Constants.GroupCount][]; - 2938    int[][] perm      = new int[BZip2Constants.GroupCount][]; - 2939    int[] minLens     = new int[BZip2Constants.GroupCount];940941    Stream baseStream;942    bool   streamEnd;943 - 2944    int currentChar = -1;945 - 2946    int currentState = START_BLOCK_STATE;947948    int storedBlockCRC, storedCombinedCRC;949    int computedBlockCRC;950    uint computedCombinedCRC;951952    int count, chPrev, ch2;953    int tPos;954    int rNToGo;955    int rTPos;956    int i2, j2;957    byte z; - 2958    bool isStreamOwner = true;959    #endregion960  }961}962/* This file was derived from a file containing this license:963 *964 * This file is a part of bzip2 and/or libbzip2, a program and965 * library for lossless, block-sorting data compression.966 *967 * Copyright (C) 1996-1998 Julian R Seward.  All rights reserved.968 *969 * Redistribution and use in source and binary forms, with or without970 * modification, are permitted provided that the following conditions971 * are met:972 *973 * 1. Redistributions of source code must retain the above copyright974 * notice, this list of conditions and the following disclaimer.975 *976 * 2. The origin of this software must not be misrepresented; you must977 * not claim that you wrote the original software.  If you use this978 * software in a product, an acknowledgment in the product979 * documentation would be appreciated but is not required.980 *981 * 3. Altered source versions must be plainly marked as such, and must982 * not be misrepresented as being the original software.983 *984 * 4. The name of the author may not be used to endorse or promote985 * products derived from this software without specific prior written986 * permission.987 *988 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS989 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED990 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE991 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY992 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL993 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE994 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS995 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,996 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING997 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS998 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.999 *1000 * Java version ported by Keiron Liddle, Aftex Software <keiron@aftexsw.com> 1999-20011001 */ + 1894    int currentState = START_BLOCK_STATE;895896    int storedBlockCRC, storedCombinedCRC;897    int computedBlockCRC;898    uint computedCombinedCRC;899900    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    #endregion908  }909} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2OutputStream.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2OutputStream.htm index 60c0f8e12..6578a992a 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2OutputStream.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_BZip2OutputStream.htm @@ -15,12 +15,12 @@

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:616 -Uncovered lines:285 +Covered lines:107 +Uncovered lines:794 Coverable lines:901 -Total lines:1913 -Line coverage:68.3% -Branch coverage:66.2% +Total lines:1793 +Line coverage:11.8% +Branch coverage:3.6%

Metrics

@@ -34,37 +34,37 @@

Metrics

SetLength(...)100 ReadByte()100 Read(...)100 -Write(...)669.2363.64 -WriteByte(...)47585.71 +Write(...)600 +WriteByte(...)400 Close()1100100 -MakeMaps()310080 -WriteRun()757.8977.78 -Dispose(...)510066.67 +MakeMaps()300 +WriteRun()700 +Dispose(...)593.3355.56 Flush()1100100 Initialize()1100100 InitBlock()2100100 -EndBlock()38580 +EndBlock()31040 EndCompression()1100100 BsSetStream(...)1100100 BsFinishedWithStream()2100100 BsW(...)2100100 BsPutUChar(...)1100100 BsPutint(...)1100100 -BsPutIntVS(...)1100100 -SendMTFValues()6790.3684.21 -MoveToFrontCodeAndSend()1100100 -SimpleSort(...)1573.1758.62 +BsPutIntVS(...)100 +SendMTFValues()6700 +MoveToFrontCodeAndSend()100 +SimpleSort(...)1500 Vswap(...)200 -QSort3(...)1721.0527.59 -MainSort()3290.9888.52 +QSort3(...)1700 +MainSort()3200 RandomiseBlock()700 -DoReversibleTransformation()671.4363.64 -FullGtU(...)1811.4911.43 +DoReversibleTransformation()600 +FullGtU(...)1800 AllocateCompressStructures()410057.14 -GenerateMTFValues()1473.0259.26 +GenerateMTFValues()1400 Panic()100 -HbMakeCodeLengths(...)2390.1187.18 -HbAssignCodes(...)4100100 +HbMakeCodeLengths(...)2300 +HbAssignCodes(...)400 Med3(...)400 @@ -73,1921 +73,1801 @@

#LineLine coverage - 1// BZip2OutputStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;37using System.IO;3839using ICSharpCode.SharpZipLib.Checksums;4041namespace ICSharpCode.SharpZipLib.BZip242{1using System;2using System.IO;3using ICSharpCode.SharpZipLib.Checksum;45namespace ICSharpCode.SharpZipLib.BZip26{7  /// <summary>8  /// An output stream that compresses into the BZip2 format9  /// including file header chars into another stream.10  /// </summary>11  public class BZip2OutputStream : Stream12  {13    #region Constants14    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;2021    /*--22    If you are ever unlucky/improbable enough23    to get a stack overflow whilst sorting,24    increase the following constant and try25    again.  In practice I have never seen the26    stack go above 27 elems, so the following27    limit seems very generous.28    --*/29    const int QSORT_STACK_SIZE = 1000;3031    /*--32    Knuth's increments seem to work better33    than Incerpi-Sedgewick here.  Possibly34    because the number of elems to sort is35    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  4344  // TODO: Update to BZip2 1.0.1, 1.0.24546  /// <summary>47  /// An output stream that compresses into the BZip2 format48  /// including file header chars into another stream.49  /// </summary>50  public class BZip2OutputStream : Stream51  {52    #region Constants53    const int SETMASK       = (1 << 21);54    const int CLEARMASK     = (~SETMASK);55    const int GREATER_ICOST = 15;56    const int LESSER_ICOST = 0;57    const int SMALL_THRESH = 20;58    const int DEPTH_THRESH = 10;5960    /*--61    If you are ever unlucky/improbable enough62    to get a stack overflow whilst sorting,63    increase the following constant and try64    again.  In practice I have never seen the65    stack go above 27 elems, so the following66    limit seems very generous.67    --*/68    const int QSORT_STACK_SIZE = 1000;6970    /*--71    Knuth's increments seem to work better72    than Incerpi-Sedgewick here.  Possibly73    because the number of elems to sort is74    usually small, typically <= 20.75    --*/ - 276    readonly int[] increments = { - 277                          1, 4, 13, 40, 121, 364, 1093, 3280, - 278                          9841, 29524, 88573, 265720, - 279                          797161, 2391484 - 280                        };81    #endregion8283    #region Constructors84    /// <summary>85    /// Construct a default output stream with maximum block size44    #region Constructors45    /// <summary>46    /// Construct a default output stream with maximum block size47    /// </summary>48    /// <param name="stream">The stream to write BZip data onto.</param> + 149    public BZip2OutputStream(Stream stream) : this(stream, 9)50    { + 151    }5253    /// <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 giving61    /// 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    #endregion8182    #region Destructor83    /// <summary>84    /// Ensures that resources are freed and other cleanup operations85    /// are performed when the garbage collector reclaims the BZip2OutputStream.  86    /// </summary>87    /// <param name="stream">The stream to write BZip data onto.</param> - 288    public BZip2OutputStream(Stream stream) : this(stream, 9)89    { - 290    }9192    /// <summary>93    /// Initialise a new instance of the <see cref="BZip2OutputStream"></see>94    /// for the specified stream, using the given blocksize.95    /// </summary>96    /// <param name="stream">The stream to write compressed data to.</param>97    /// <param name="blockSize">The block size to use.</param>98    /// <remarks>99    /// Valid block sizes are in the range 1..9, with 1 giving100    /// the lowest compression and 9 the highest.101    /// </remarks> - 2102    public BZip2OutputStream(Stream stream, int blockSize)103    { - 2104      BsSetStream(stream);105 - 2106      workFactor = 50; - 2107       if (blockSize > 9) { - 0108        blockSize = 9;109      }110 - 2111       if (blockSize < 1) { - 0112        blockSize = 1;113      } - 2114      blockSize100k = blockSize; - 2115      AllocateCompressStructures(); - 2116      Initialize(); - 2117      InitBlock(); - 2118    }119    #endregion120121    #region Destructor87    ~BZip2OutputStream()88    { + 089      Dispose(false); + 090    }91    #endregion9293    /// <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    }101102103    #region Stream overrides104    /// <summary>105    /// Gets a value indicating whether the current stream supports reading106    /// </summary>107    public override bool CanRead {108      get { + 0109        return false;110      }111    }112113    /// <summary>114    /// Gets a value indicating whether the current stream supports seeking115    /// </summary>116    public override bool CanSeek {117      get { + 0118        return false;119      }120    }121  122    /// <summary>123    /// Ensures that resources are freed and other cleanup operations124    /// are performed when the garbage collector reclaims the BZip2OutputStream.125    /// </summary>126    ~BZip2OutputStream()127    { - 0128      Dispose(false); - 0129    }130    #endregion131132    /// <summary>133    /// Get/set flag indicating ownership of underlying stream.134    /// When the flag is true <see cref="Close"></see> will close the underlying stream also.135    /// </summary>136    public bool IsStreamOwner137    { - 2138      get { return isStreamOwner; } - 0139      set { isStreamOwner = value; }140    }141142143    #region Stream overrides144    /// <summary>145    /// Gets a value indicating whether the current stream supports reading146    /// </summary>147    public override bool CanRead148    {149      get { - 0150        return false;151      }152    }153154    /// <summary>155    /// Gets a value indicating whether the current stream supports seeking156    /// </summary>157    public override bool CanSeek {158      get { - 0159        return false;160      }123    /// Gets a value indicating whether the current stream supports writing124    /// </summary>125    public override bool CanWrite {126      get { + 0127        return baseStream.CanWrite;128      }129    }130131    /// <summary>132    /// Gets the length in bytes of the stream133    /// </summary>134    public override long Length {135      get { + 0136        return baseStream.Length;137      }138    }139140    /// <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    }151152    /// <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    /// Gets a value indicating whether the current stream supports writing164    /// Sets the length of this stream to the given value.  165    /// </summary>166    public override bool CanWrite {167      get { - 0168        return baseStream.CanWrite;169      }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    /// Gets the length in bytes of the stream173    /// Read a byte from the stream advancing the position.  174    /// </summary>175    public override long Length {176      get { - 0177        return baseStream.Length;178      }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    /// Gets or sets the current position of this stream.182    /// Read a block of bytes  183    /// </summary>184    public override long Position {185      get { - 0186        return baseStream.Position;187      }188      set { - 0189        throw new NotSupportedException("BZip2OutputStream position cannot be set");190      }191    }192193    /// <summary>194    /// Sets the current position of this stream to the given value.195    /// </summary>196    /// <param name="offset">The point relative to the offset from which to being seeking.</param>197    /// <param name="origin">The reference point from which to begin seeking.</param>198    /// <returns>The new position in the stream.</returns>199    public override long Seek(long offset, SeekOrigin origin)200    { - 0201      throw new NotSupportedException("BZip2OutputStream Seek not supported");202    }203204    /// <summary>205    /// Sets the length of this stream to the given value.206    /// </summary>207    /// <param name="value">The new stream length.</param>208    public override void SetLength(long value)209    { - 0210      throw new NotSupportedException("BZip2OutputStream SetLength not supported");211    }212213    /// <summary>214    /// Read a byte from the stream advancing the position.215    /// </summary>216    /// <returns>The byte read cast to an int; -1 if end of stream.</returns>217    public override int ReadByte()218    { - 0219      throw new NotSupportedException("BZip2OutputStream ReadByte not supported");220    }221222    /// <summary>223    /// Read a block of bytes224    /// </summary>225    /// <param name="buffer">The buffer to read into.</param>226    /// <param name="offset">The offset in the buffer to start storing data at.</param>227    /// <param name="count">The maximum number of bytes to read.</param>228    /// <returns>The total number of bytes read. This might be less than the number of bytes229    /// requested if that number of bytes are not currently available, or zero230    /// if the end of the stream is reached.</returns>231    public override int Read(byte[] buffer, int offset, int count)232    { - 0233      throw new NotSupportedException("BZip2OutputStream Read not supported");234    }235236    /// <summary>237    /// Write a block of bytes to the stream238    /// </summary>239    /// <param name="buffer">The buffer containing data to write.</param>240    /// <param name="offset">The offset of the first byte to write.</param>241    /// <param name="count">The number of bytes to write.</param>242    public override void Write(byte[] buffer, int offset, int count)243    { - 1244       if ( buffer == null ) { - 0245        throw new ArgumentNullException(nameof(buffer));246      }247 - 1248       if ( offset < 0 )249      { - 0250        throw new ArgumentOutOfRangeException(nameof(offset));251      }252 - 1253       if ( count < 0 )254      { - 0255        throw new ArgumentOutOfRangeException(nameof(count));256      }257 - 1258       if ( buffer.Length - offset < count )259      { - 0260        throw new ArgumentException("Offset/count out of range");261      }262 - 20002263       for (int i = 0; i < count; ++i) { - 10000264        WriteByte(buffer[offset + i]);265      } - 1266    }267268    /// <summary>269    /// Write a byte to the stream.270    /// </summary>271    /// <param name="value">The byte to write to the stream.</param>272    public override void WriteByte(byte value)273    { - 10000274      int b = (256 + value) % 256; - 10000275       if (currentChar != -1) { - 9999276         if (currentChar == b) { - 38277          runLength++; - 38278           if (runLength > 254) { - 0279            WriteRun(); - 0280            currentChar = -1; - 0281            runLength = 0;282          } - 0283        } else { - 9961284          WriteRun(); - 9961285          runLength = 1; - 9961286          currentChar = b;287        } - 9961288      } else { - 1289        currentChar = b; - 1290        runLength++;291      } - 39292    }293294    /// <summary>295    /// End the current block and end compression.296    /// Close the stream and free any resources297    /// </summary>298    public override void Close()299    { - 2300      Dispose(true); - 2301      GC.SuppressFinalize(this); - 2302    }303304    #endregion305    void MakeMaps()306    { - 1307      nInUse = 0; - 514308       for (int i = 0; i < 256; i++) { - 256309         if (inUse[i]) { - 256310          seqToUnseq[nInUse] = (char)i; - 256311          unseqToSeq[i] = (char)nInUse; - 256312          nInUse++;313        }314      } - 1315    }316317    /// <summary>318    /// Get the number of bytes written to output.319    /// </summary>320    void WriteRun()321    { - 9962322       if (last < allowableBlockSize) { - 9962323        inUse[currentChar] = true; - 39924324         for (int i = 0; i < runLength; i++) { - 10000325          mCrc.Update(currentChar);326        }327 - 9962328         switch (runLength) {329          case 1: - 9925330            last++; - 9925331            block[last + 1] = (byte)currentChar; - 9925332            break;333          case 2: - 36334            last++; - 36335            block[last + 1] = (byte)currentChar; - 36336            last++; - 36337            block[last + 1] = (byte)currentChar; - 36338            break;339          case 3: - 1340            last++; - 1341            block[last + 1] = (byte)currentChar; - 1342            last++; - 1343            block[last + 1] = (byte)currentChar; - 1344            last++; - 1345            block[last + 1] = (byte)currentChar; - 1346            break;347          default: - 0348            inUse[runLength - 4] = true; - 0349            last++; - 0350            block[last + 1] = (byte)currentChar; - 0351            last++; - 0352            block[last + 1] = (byte)currentChar; - 0353            last++; - 0354            block[last + 1] = (byte)currentChar; - 0355            last++; - 0356            block[last + 1] = (byte)currentChar; - 0357            last++; - 0358            block[last + 1] = (byte)(runLength - 4); - 0359            break;360        }361      } else { - 0362        EndBlock(); - 0363        InitBlock(); - 0364        WriteRun();365      } - 0366    }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 bytes188    /// requested if that number of bytes are not currently available, or zero189    /// 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    }194195    /// <summary>196    /// Write a block of bytes to the stream197    /// </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    }223224    /// <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    }249250    /// <summary>251    /// End the current block and end compression.252    /// Close the stream and free any resources253    /// </summary>254    public override void Close()255    { + 1256      Dispose(true); + 1257      GC.SuppressFinalize(this); + 1258    }259260    #endregion261    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    }272273    /// <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    }323324    /// <summary>325    /// Get the number of bytes written to the output.326    /// </summary>327    public int BytesWritten { + 0328      get { return bytesOut; }329    }330331    /// <summary>332    /// Releases the unmanaged resources used by the <see cref="BZip2OutputStream"/> and optionally releases the managed333    /// </summary>334    /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged re335    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    }359360    /// <summary>361    /// Flush output buffers362    /// </summary>363    public override void Flush()364    { + 1365      baseStream.Flush(); + 1366    }  367368    /// <summary>369    /// Get the number of bytes written to the output.370    /// </summary>371    public int BytesWritten372    { - 0373      get { return bytesOut; }374    }375376    /// <summary>377    /// Releases the unmanaged resources used by the <see cref="BZip2OutputStream"/> and optionally releases the managed378    /// </summary>379    /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged re380#if NET_1_0 || NET_1_1 || NETCF_1_0381    protected virtual void Dispose(bool disposing)382#else383    override protected void Dispose(bool disposing)384#endif385    {386      try {387#if !NET_1_0 && !NET_1_1 && !NETCF_1_0 - 2388        base.Dispose(disposing);389#endif - 2390         if( !disposed_ ) { - 2391          disposed_=true;392 - 2393           if( runLength>0 ) { - 1394            WriteRun();395          }396 - 2397          currentChar=-1; - 2398          EndBlock(); - 2399          EndCompression(); - 2400          Flush();401        } - 2402      }403      finally { - 2404         if ( disposing ) { - 2405           if ( IsStreamOwner ) { - 2406            baseStream.Close();407          }408        } - 2409      } - 2410    }368    void Initialize()369    { + 1370      bytesOut = 0; + 1371      nBlocksRandomised = 0;372373      /*--- 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    }385386    void InitBlock()387    { + 1388      mCrc.Reset(); + 1389      last = -1;390 + 514391       for (int i = 0; i < 256; i++) { + 256392        inUse[i] = false;393      }394395      /*--- 20 is just a paranoia constant ---*/ + 1396      allowableBlockSize = BZip2Constants.BaseBlockSize * blockSize100k - 20; + 1397    }398399    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;408409      /*-- sort the block and establish position of original string --*/ + 0410      DoReversibleTransformation();  411412    /// <summary>413    /// Flush output buffers414    /// </summary>415    public override void Flush()416    { - 2417      baseStream.Flush(); - 2418    }419420    void Initialize()421    { - 2422      bytesOut = 0; - 2423      nBlocksRandomised = 0;424425      /*--- Write header `magic' bytes indicating file-format == huffmanised,426      followed by a digit indicating blockSize100k.427      ---*/428 - 2429      BsPutUChar('B'); - 2430      BsPutUChar('Z');412      /*--413      A 6-byte block header, the value chosen arbitrarily414      as 0x314159265359 :-).  A 32 bit value does not really415      give a strong enough guarantee that the value will not416      appear by chance in the compressed datastream.  Worst-case417      probability of this event, for a 900k block, is about418      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 from423      damaged files.424      --*/ + 0425      BsPutUChar(0x31); + 0426      BsPutUChar(0x41); + 0427      BsPutUChar(0x59); + 0428      BsPutUChar(0x26); + 0429      BsPutUChar(0x53); + 0430      BsPutUChar(0x59);  431 - 2432      BsPutUChar('h'); - 2433      BsPutUChar('0' + blockSize100k);434 - 2435      combinedCRC = 0; - 2436    }437438    void InitBlock()439    { - 2440      mCrc.Reset(); - 2441      last = -1;442 - 1028443       for (int i = 0; i < 256; i++) { - 512444        inUse[i] = false;445      }446447      /*--- 20 is just a paranoia constant ---*/ - 2448      allowableBlockSize = BZip2Constants.BaseBlockSize * blockSize100k - 20; - 2449    }450451    void EndBlock()452    { - 2453       if (last < 0) {       // dont do anything for empty files, (makes empty files compatible with original Bzip) - 1454        return;455      }456 - 1457      blockCRC = unchecked((uint)mCrc.Value); - 1458      combinedCRC = (combinedCRC << 1) | (combinedCRC >> 31); - 1459      combinedCRC ^= blockCRC;460461      /*-- sort the block and establish position of original string --*/ - 1462      DoReversibleTransformation();463464      /*--465      A 6-byte block header, the value chosen arbitrarily466      as 0x314159265359 :-).  A 32 bit value does not really467      give a strong enough guarantee that the value will not468      appear by chance in the compressed datastream.  Worst-case469      probability of this event, for a 900k block, is about470      2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits.471      For a compressed file of size 100Gb -- about 100000 blocks --472      only a 48-bit marker will do.  NB: normal compression/473      decompression do *not* rely on these statistical properties.474      They are only important when trying to recover blocks from475      damaged files.476      --*/ - 1477      BsPutUChar(0x31); - 1478      BsPutUChar(0x41); - 1479      BsPutUChar(0x59); - 1480      BsPutUChar(0x26); - 1481      BsPutUChar(0x53); - 1482      BsPutUChar(0x59);483484      /*-- Now the block's CRC, so it is in a known place. --*/485      unchecked { - 1486        BsPutint((int)blockCRC);487      }488489      /*-- Now a single bit indicating randomisation. --*/ - 1490       if (blockRandomised) { - 0491        BsW(1,1); - 0492        nBlocksRandomised++; - 0493      } else { - 1494        BsW(1,0);495      }496497      /*-- Finally, block's contents proper. --*/ - 1498      MoveToFrontCodeAndSend(); - 1499    }500501    void EndCompression()502    {503      /*--504      Now another magic 48-bit number, 0x177245385090, to505      indicate the end of the last block.  (sqrt(pi), if506      you want to know.  I did want to use e, but it contains507      too much repetition -- 27 18 28 18 28 46 -- for me508      to feel statistically comfortable.  Call me paranoid.)509      --*/ - 2510      BsPutUChar(0x17); - 2511      BsPutUChar(0x72); - 2512      BsPutUChar(0x45); - 2513      BsPutUChar(0x38); - 2514      BsPutUChar(0x50); - 2515      BsPutUChar(0x90);432      /*-- Now the block's CRC, so it is in a known place. --*/433      unchecked { + 0434        BsPutint((int)blockCRC);435      }436437      /*-- Now a single bit indicating randomisation. --*/ + 0438       if (blockRandomised) { + 0439        BsW(1, 1); + 0440        nBlocksRandomised++; + 0441      } else { + 0442        BsW(1, 0);443      }444445      /*-- Finally, block's contents proper. --*/ + 0446      MoveToFrontCodeAndSend(); + 0447    }448449    void EndCompression()450    {451      /*--452      Now another magic 48-bit number, 0x177245385090, to453      indicate the end of the last block.  (sqrt(pi), if454      you want to know.  I did want to use e, but it contains455      too much repetition -- 27 18 28 18 28 46 -- for me456      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);464465      unchecked { + 1466        BsPutint((int)combinedCRC);467      }468 + 1469      BsFinishedWithStream(); + 1470    }471472    void BsSetStream(Stream stream)473    { + 1474      baseStream = stream; + 1475      bsLive = 0; + 1476      bsBuff = 0; + 1477      bytesOut = 0; + 1478    }479480    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    }490491    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    }503504    void BsPutUChar(int c)505    { + 10506      BsW(8, c); + 10507    }508509    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    }  516517      unchecked { - 2518        BsPutint((int)combinedCRC);519      }520 - 2521      BsFinishedWithStream(); - 2522    }523524    void BsSetStream(Stream stream)525    { - 2526      baseStream = stream; - 2527      bsLive = 0; - 2528      bsBuff = 0; - 2529      bytesOut = 0; - 2530    }531532    void BsFinishedWithStream()533    { - 5534       while (bsLive > 0)535      { - 3536        int ch = (bsBuff >> 24); - 3537        baseStream.WriteByte((byte)ch); // write 8-bit - 3538        bsBuff <<= 8; - 3539        bsLive -= 8; - 3540        bytesOut++;541      } - 2542    }543544    void BsW(int n, int v)545    { - 24421546       while (bsLive >= 8) { - 10528547        int ch = (bsBuff >> 24); - 10528548        unchecked{baseStream.WriteByte((byte)ch);} // write 8-bit - 10528549        bsBuff <<= 8; - 10528550        bsLive -= 8; - 10528551        ++bytesOut;552      } - 13893553      bsBuff |= (v << (32 - bsLive - n)); - 13893554      bsLive += n; - 13893555    }517    void BsPutIntVS(int numBits, int c)518    { + 0519      BsW(numBits, c); + 0520    }521522    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      }528529      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      }539540      /*--- 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      }  556557    void BsPutUChar(int c)558    { - 26559      BsW(8, c); - 26560    }561562    void BsPutint(int u)563    { - 3564      BsW(8, (u >> 24) & 0xFF); - 3565      BsW(8, (u >> 16) & 0xFF); - 3566      BsW(8, (u >>  8) & 0xFF); - 3567      BsW(8,  u        & 0xFF); - 3568    }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        }  569570    void BsPutIntVS(int numBits, int c)571    { - 1572      BsW(numBits, c); - 1573    } + 0570         if (ge > gs && nPart != nGroups && nPart != 1 && ((nGroups - nPart) % 2 == 1)) { + 0571          aFreq -= mtfFreq[ge]; + 0572          ge--;573        }  574575    void SendMTFValues()576    { - 1577      char[][] len = new char[BZip2Constants.GroupCount][]; - 14578       for (int i = 0; i < BZip2Constants.GroupCount; ++i) { - 6579        len[i] = new char[BZip2Constants.MaximumAlphaSize];580      }581582      int gs, ge, totc, bt, bc, iter; - 1583      int nSelectors = 0, alphaSize, minLen, maxLen, selCtr;584      int nGroups;585 - 1586      alphaSize = nInUse + 2; - 14587       for (int t = 0; t < BZip2Constants.GroupCount; t++) { - 3108588         for (int v = 0; v < alphaSize; v++) { - 1548589          len[t][v] = (char)GREATER_ICOST;590        } + 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      }  592593      /*--- Decide how many coding tables to use ---*/ - 1594       if (nMTF <= 0) { - 0595        Panic();596      }597 - 1598       if (nMTF < 200) { - 0599        nGroups = 2; - 1600       } else if (nMTF < 600) { - 0601        nGroups = 3; - 1602       } else if (nMTF < 1200) { - 0603        nGroups = 4; - 1604       } else if (nMTF < 2400) { - 0605        nGroups = 5; - 0606      } else { - 1607        nGroups = 6;608      }609610      /*--- Generate an initial set of coding tables ---*/ - 1611      int nPart = nGroups; - 1612      int remF  = nMTF; - 1613      gs = 0; - 7614       while (nPart > 0) { - 6615        int tFreq = remF / nPart; - 6616        int aFreq = 0; - 6617        ge = gs - 1; - 266618         while (aFreq < tFreq && ge < alphaSize - 1) { - 260619          ge++; - 260620          aFreq += mtfFreq[ge];621        }622 - 6623         if (ge > gs && nPart != nGroups && nPart != 1 && ((nGroups - nPart) % 2 == 1)) { - 2624          aFreq -= mtfFreq[ge]; - 2625          ge--;626        }627 - 3108628         for (int v = 0; v < alphaSize; v++) { - 1548629           if (v >= gs && v <= ge) { - 258630            len[nPart - 1][v] = (char)LESSER_ICOST; - 258631          } else { - 1290632            len[nPart - 1][v] = (char)GREATER_ICOST;633          }634        }635 - 6636        nPart--; - 6637        gs = ge + 1; - 6638        remF -= aFreq;639      }640 - 1641      int[][] rfreq = new int[BZip2Constants.GroupCount][]; - 14642       for (int i = 0; i < BZip2Constants.GroupCount; ++i) { - 6643        rfreq[i] = new int[BZip2Constants.MaximumAlphaSize];644      }645 - 1646      int[] fave = new int[BZip2Constants.GroupCount]; - 1647      short[] cost = new short[BZip2Constants.GroupCount];648      /*---649      Iterate up to N_ITERS times to improve the tables.650      ---*/ - 10651       for (iter = 0; iter < BZip2Constants.NumberOfIterations; ++iter) { - 56652         for (int t = 0; t < nGroups; ++t) { - 24653          fave[t] = 0;654        }655 - 56656         for (int t = 0; t < nGroups; ++t) { - 12432657           for (int v = 0; v < alphaSize; ++v) { - 6192658            rfreq[t][v] = 0;659          }660        }661 - 4662        nSelectors = 0; - 4663        totc = 0; - 4664        gs   = 0; - 804665        while (true) {666          /*--- Set group start & end marks. --*/ - 808667           if (gs >= nMTF) {668            break;669          } - 804670          ge = gs + BZip2Constants.GroupSize - 1; - 804671           if (ge >= nMTF) { - 4672            ge = nMTF - 1;673          }674675          /*--676          Calculate the cost of this group as coded677          by each of the coding tables.678          --*/ - 11256679           for (int t = 0; t < nGroups; t++) { - 4824680            cost[t] = 0;681          }682 - 804683           if (nGroups == 6) {684            short cost0, cost1, cost2, cost3, cost4, cost5; - 804685            cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0; - 81616686             for (int i = gs; i <= ge; ++i) { - 40004687              short icv = szptr[i]; - 40004688              cost0 += (short)len[0][icv]; - 40004689              cost1 += (short)len[1][icv]; - 40004690              cost2 += (short)len[2][icv]; - 40004691              cost3 += (short)len[3][icv]; - 40004692              cost4 += (short)len[4][icv]; - 40004693              cost5 += (short)len[5][icv];694            } - 804695            cost[0] = cost0; - 804696            cost[1] = cost1; - 804697            cost[2] = cost2; - 804698            cost[3] = cost3; - 804699            cost[4] = cost4; - 804700            cost[5] = cost5; - 804701          } else { - 0702             for (int i = gs; i <= ge; ++i) { - 0703              short icv = szptr[i]; - 0704               for (int t = 0; t < nGroups; t++) { - 0705                cost[t] += (short)len[t][icv];706              }707            }708          }709710          /*--711          Find the coding table which is best for this group,712          and record its identity in the selector table.713          --*/ - 804714          bc = 999999999; - 804715          bt = -1; - 11256716           for (int t = 0; t < nGroups; ++t) { - 4824717             if (cost[t] < bc) { - 1899718              bc = cost[t]; - 1899719              bt = t;720            }721          } - 804722          totc += bc; - 804723          fave[bt]++; - 804724          selector[nSelectors] = (char)bt; - 804725          nSelectors++;726727          /*--728          Increment the symbol frequencies for the selected table.729          --*/ - 81616730           for (int i = gs; i <= ge; ++i) { - 40004731            ++rfreq[bt][szptr[i]];732          }733 - 804734          gs = ge+1;735        }736737        /*--738        Recompute the tables based on the accumulated frequencies.739        --*/ - 56740         for (int t = 0; t < nGroups; ++t) { - 24741          HbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20);742        }743      }744 - 1745      rfreq = null; - 1746      fave = null; - 1747      cost = null;748 - 1749       if (!(nGroups < 8)) { - 0750        Panic(); + 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          }621622          /*--623          Calculate the cost of this group as coded624          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          }656657          /*--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++;673674          /*--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        }683684        /*--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      }703704      /*--- 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      }731732      /*--- 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 - 1753       if (!(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZip2Constants.GroupSize)))) { - 0754        Panic();755      }756757      /*--- Compute MTF values for the selectors. ---*/ - 1758      char[] pos = new char[BZip2Constants.GroupCount];759      char ll_i, tmp2, tmp;760 - 14761       for (int i = 0; i < nGroups; i++) { - 6762        pos[i] = (char)i;763      }764 - 404765       for (int i = 0; i < nSelectors; i++) { - 201766        ll_i = selector[i]; - 201767        int j = 0; - 201768        tmp = pos[j]; - 729769         while (ll_i != tmp) { - 528770          j++; - 528771          tmp2 = tmp; - 528772          tmp = pos[j]; - 528773          pos[j] = tmp2;774        } - 201775        pos[0] = tmp; - 201776        selectorMtf[i] = (char)j;777      }778 - 1779      int[][] code = new int[BZip2Constants.GroupCount][];780 - 14781       for (int i = 0; i < BZip2Constants.GroupCount; ++i) { - 6782        code[i] = new int[BZip2Constants.MaximumAlphaSize];783      }784785      /*--- Assign actual codes for the tables. --*/ - 14786       for (int t = 0; t < nGroups; t++) { - 6787        minLen = 32; - 6788        maxLen = 0; - 3108789         for (int i = 0; i < alphaSize; i++) { - 1548790           if (len[t][i] > maxLen) { - 13791            maxLen = len[t][i];792          } - 1548793           if (len[t][i] < minLen) { - 14794            minLen = len[t][i];795          }796        } - 6797         if (maxLen > 20) { - 0798          Panic();799        } - 6800         if (minLen < 1) { - 0801          Panic();802        } - 6803        HbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize);804      }805806      /*--- Transmit the mapping table. ---*/ - 1807      bool[] inUse16 = new bool[16]; - 34808       for (int i = 0; i < 16; ++i) { - 16809        inUse16[i] = false; - 544810         for (int j = 0; j < 16; ++j) { - 256811           if (inUse[i * 16 + j]) { - 256812            inUse16[i] = true;813          }814        }815      }816 - 34817       for (int i = 0; i < 16; ++i) { - 16818         if (inUse16[i]) { - 16819          BsW(1,1); - 16820        } else { - 0821          BsW(1,0);822        }823      }824 - 34825       for (int i = 0; i < 16; ++i) { - 16826         if (inUse16[i]) { - 544827           for (int j = 0; j < 16; ++j) { - 256828             if (inUse[i * 16 + j]) { - 256829              BsW(1,1); - 256830            } else { - 0831              BsW(1,0);832            }833          }834        }835      }836837      /*--- Now the selectors. ---*/ - 1838      BsW(3, nGroups); - 1839      BsW(15, nSelectors); - 404840       for (int i = 0; i < nSelectors; ++i) { - 1458841         for (int j = 0; j < selectorMtf[i]; ++j) { - 528842          BsW(1,1);843        } - 201844        BsW(1,0);845      }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      }783784      /*--- 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      }793794      /*--- 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      }810811      /*--- 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    }834835    void MoveToFrontCodeAndSend()836    { + 0837      BsPutIntVS(24, origPtr); + 0838      GenerateMTFValues(); + 0839      SendMTFValues(); + 0840    }841842    void SimpleSort(int lo, int hi, int d)843    {844      int i, j, h, bigN, hp;845      int v;  846847      /*--- Now the coding tables. ---*/ - 14848       for (int t = 0; t < nGroups; ++t) { - 6849        int curr = len[t][0]; - 6850        BsW(5, curr); - 3108851         for (int i = 0; i < alphaSize; ++i) { - 2202852           while (curr < len[t][i]) { - 654853            BsW(2, 2); - 654854            curr++; /* 10 */855          } - 2189856           while (curr > len[t][i]) { - 641857            BsW(2, 3); - 641858            curr--; /* 11 */859          } - 1548860          BsW (1, 0);861        }862      }863864      /*--- And finally, the block data proper ---*/ - 1865      selCtr = 0; - 1866      gs = 0; - 201867      while (true) { - 202868         if (gs >= nMTF) {869          break;870        } - 201871        ge = gs + BZip2Constants.GroupSize - 1; - 201872         if (ge >= nMTF) { - 1873          ge = nMTF - 1;874        }875 - 20404876         for (int i = gs; i <= ge; i++) { - 10001877          BsW(len[selector[selCtr]][szptr[i]], code[selector[selCtr]][szptr[i]]);878        }879 - 201880        gs = ge + 1; - 201881        ++selCtr;882      } - 1883       if (!(selCtr == nSelectors)) { - 0884        Panic();885      } - 1886    }887888    void MoveToFrontCodeAndSend ()889    { - 1890      BsPutIntVS(24, origPtr); - 1891      GenerateMTFValues(); - 1892      SendMTFValues(); - 1893    }894895    void SimpleSort(int lo, int hi, int d)896    {897      int i, j, h, bigN, hp;898      int v;899 - 353900      bigN = hi - lo + 1; - 353901       if (bigN < 2) { - 0902        return;903      }904 - 353905      hp = 0; - 706906       while (increments[hp] < bigN) { - 353907        hp++;908      } - 353909      hp--;910 - 1059911       for (; hp >= 0; hp--) { - 353912        h = increments[hp];913 - 353914        i = lo + h;915        while (true) {916          /*-- copy 1 --*/ - 353917           if (i > hi)918            break; - 353919          v = zptr[i]; - 353920          j = i; - 353921           while (FullGtU(zptr[j-h]+d, v+d)) { - 171922            zptr[j] = zptr[j-h]; - 171923            j = j - h; - 171924             if (j <= (lo + h - 1))925              break;926          } - 353927          zptr[j] = v; - 353928          i++;929930          /*-- copy 2 --*/ - 353931           if (i > hi) {932            break;933          } - 24934          v = zptr[i]; - 24935          j = i; - 40936           while (FullGtU ( zptr[j-h]+d, v+d )) { - 22937            zptr[j] = zptr[j-h]; - 22938            j = j - h; - 22939             if (j <= (lo + h - 1)) {940              break;941            }942          } - 24943          zptr[j] = v; - 24944          i++;945946          /*-- copy 3 --*/ - 24947           if (i > hi) {948            break;949          } - 0950          v = zptr[i]; - 0951          j = i; - 0952           while (FullGtU ( zptr[j-h]+d, v+d)) { - 0953            zptr[j] = zptr[j-h]; - 0954            j = j - h; - 0955             if (j <= (lo + h - 1)) {956              break;957            }958          } - 0959          zptr[j] = v; - 0960          i++;961 - 0962           if (workDone > workLimit && firstAttempt) { - 0963            return;964          }965        }966      } - 353967    }968969    void Vswap(int p1, int p2, int n )970    { - 0971      int temp = 0; - 0972       while (n > 0) { - 0973        temp = zptr[p1]; - 0974        zptr[p1] = zptr[p2]; - 0975        zptr[p2] = temp; - 0976        p1++; - 0977        p2++; - 0978        n--;979      } - 0980    }981982    void QSort3(int loSt, int hiSt, int dSt)983    {984      int unLo, unHi, ltLo, gtHi, med, n, m;985      int lo, hi, d;986 - 353987      StackElement[] stack = new StackElement[QSORT_STACK_SIZE];988 - 353989      int sp = 0;990 - 353991      stack[sp].ll = loSt; - 353992      stack[sp].hh = hiSt; - 353993      stack[sp].dd = dSt; - 353994      sp++;995 - 706996       while (sp > 0) { - 353997         if (sp >= QSORT_STACK_SIZE) { - 0998          Panic();999        }1000 - 3531001        sp--; - 3531002        lo = stack[sp].ll; - 3531003        hi = stack[sp].hh; - 3531004        d = stack[sp].dd;1005 - 3531006         if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) { - 3531007          SimpleSort(lo, hi, d); - 3531008           if (workDone > workLimit && firstAttempt) { - 01009            return;1010          }1011          continue;1012        }1013 - 01014        med = Med3(block[zptr[lo] + d + 1], - 01015               block[zptr[hi            ] + d + 1], - 01016               block[zptr[(lo + hi) >> 1] + d + 1]);1017 - 01018        unLo = ltLo = lo; - 01019        unHi = gtHi = hi;1020 - 01021        while (true) { - 01022          while (true) { - 01023             if (unLo > unHi) {1024              break;1025            } - 01026            n = ((int)block[zptr[unLo]+d + 1]) - med; - 01027             if (n == 0) { - 01028              int temp = zptr[unLo]; - 01029              zptr[unLo] = zptr[ltLo]; - 01030              zptr[ltLo] = temp; - 01031              ltLo++; - 01032              unLo++; - 01033              continue;1034            } - 01035             if (n >  0) {1036              break;1037            } - 01038            unLo++;1039          } + 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++;876877          /*-- 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++;892893          /*-- 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    }915916    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    }928929    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          }10101011          { + 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          while (true) { - 01042             if (unLo > unHi) {1043              break;1044            } - 01045            n = ((int)block[zptr[unHi]+d + 1]) - med; - 01046             if (n == 0) { - 01047              int temp = zptr[unHi]; - 01048              zptr[unHi] = zptr[gtHi]; - 01049              zptr[gtHi] = temp; - 01050              gtHi--; - 01051              unHi--; - 01052              continue;1053            } - 01054             if (n <  0) {1055              break;1056            } - 01057            unHi--;1058          }1059 - 01060           if (unLo > unHi) {1061            break;1062          }10631064          { - 01065            int temp = zptr[unLo]; - 01066            zptr[unLo] = zptr[unHi]; - 01067            zptr[unHi] = temp; - 01068            unLo++; - 01069            unHi--;1070          }1071        }1072 - 01073         if (gtHi < ltLo) { - 01074          stack[sp].ll = lo; - 01075          stack[sp].hh = hi; - 01076          stack[sp].dd = d+1; - 01077          sp++; - 01078          continue;1079        }1080 - 01081        n = ((ltLo-lo) < (unLo-ltLo)) ? (ltLo-lo) : (unLo-ltLo); - 01082        Vswap(lo, unLo-n, n); - 01083        m = ((hi-gtHi) < (gtHi-unHi)) ? (hi-gtHi) : (gtHi-unHi); - 01084        Vswap(unLo, hi-m+1, m);1085 - 01086        n = lo + unLo - ltLo - 1; - 01087        m = hi - (gtHi - unHi) + 1;1088 - 01089        stack[sp].ll = lo; - 01090        stack[sp].hh = n; - 01091        stack[sp].dd = d; - 01092        sp++;1093 - 01094        stack[sp].ll = n + 1; - 01095        stack[sp].hh = m - 1; - 01096        stack[sp].dd = d+1; - 01097        sp++;1098 - 01099        stack[sp].ll = m; - 01100        stack[sp].hh = hi; - 01101        stack[sp].dd = d; - 01102        sp++;1103      } - 3531104    }11051106    void MainSort()1107    {1108      int i, j, ss, sb; - 11109      int[] runningOrder = new int[256]; - 11110      int[] copy = new int[256]; - 11111      bool[] bigDone = new bool[256];1112      int c1, c2;1113      int numQSorted;11141115      /*--1116      In the various block-sized structures, live data runs1117      from 0 to last+NUM_OVERSHOOT_BYTES inclusive.  First,1118      set up the overshoot area for block.1119      --*/11201121      //   if (verbosity >= 4) fprintf ( stderr, "        sort initialise ...\n" ); - 421122       for (i = 0; i < BZip2Constants.OvershootBytes; i++) { - 201123        block[last + i + 2] = block[(i % (last + 1)) + 1];1124      } - 200421125       for (i = 0; i <= last + BZip2Constants.OvershootBytes; i++) { - 100201126        quadrant[i] = 0;1127      }1128 - 11129      block[0] = (byte)(block[last + 1]);1130 - 11131       if (last < 4000) {1132        /*--1133        Use simpleSort(), since the full sorting mechanism1134        has quite a large constant overhead.1135        --*/ - 01136         for (i = 0; i <= last; i++) { - 01137          zptr[i] = i;1138        } - 01139        firstAttempt = false; - 01140        workDone = workLimit = 0; - 01141        SimpleSort(0, last, 0); - 01142      } else { - 11143        numQSorted = 0; - 5141144         for (i = 0; i <= 255; i++) { - 2561145          bigDone[i] = false;1146        } - 1310761147         for (i = 0; i <= 65536; i++) { - 655371148          ftab[i] = 0;1149        }1150 - 11151        c1 = block[0]; - 200021152         for (i = 0; i <= last; i++) { - 100001153          c2 = block[i + 1]; - 100001154          ftab[(c1 << 8) + c2]++; - 100001155          c1 = c2;1156        } + 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    }10521053    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;10611062      /*--1063      In the various block-sized structures, live data runs1064      from 0 to last+NUM_OVERSHOOT_BYTES inclusive.  First,1065      set up the overshoot area for block.1066      --*/10671068      //   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 mechanism1081        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;11211122        /*--1123        Now ftab contains the first loc of every small bucket.1124        Calculate the running order, from smallest to largest1125        big bucket.1126        --*/1127 + 01128         for (i = 0; i <= 255; i++) { + 01129          runningOrder[i] = i;1130        }11311132        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);11521153        /*--1154        The main sorting loop.1155        --*/ + 01156         for (i = 0; i <= 255; i++) {  1157 - 1310741158         for (i = 1; i <= 65536; i++) { - 655361159          ftab[i] += ftab[i - 1];1160        }1161 - 11162        c1 = block[1]; - 200001163         for (i = 0; i < last; i++) { - 99991164          c2 = block[i + 2]; - 99991165          j = (c1 << 8) + c2; - 99991166          c1 = c2; - 99991167          ftab[j]--; - 99991168          zptr[ftab[j]] = i;1169        }1170 - 11171        j = ((block[last + 1]) << 8) + (block[1]); - 11172        ftab[j]--; - 11173        zptr[ftab[j]] = last;11741175        /*--1176        Now ftab contains the first loc of every small bucket.1177        Calculate the running order, from smallest to largest1178        big bucket.1179        --*/1180 - 5141181         for (i = 0; i <= 255; i++) { - 2561182          runningOrder[i] = i;1183        }11841185        int vv; - 11186        int h = 1;1187        do { - 51188          h = 3 * h + 1; - 51189         } while (h <= 256);1190        do { - 51191          h = h / 3; - 22121192           for (i = h; i <= 255; i++) { - 11011193            vv = runningOrder[i]; - 11011194            j = i; - 20721195             while ((ftab[((runningOrder[j-h])+1) << 8] - ftab[(runningOrder[j-h]) << 8]) > (ftab[((vv)+1) << 8] - ftab[( - 10811196              runningOrder[j] = runningOrder[j-h]; - 10811197              j = j - h; - 10811198               if (j <= (h - 1)) {1199                break;1200              }1201            } - 11011202            runningOrder[j] = vv;1203          } - 51204         } while (h != 1);12051206        /*--1207        The main sorting loop.1208        --*/ - 5141209         for (i = 0; i <= 255; i++) {12101211          /*--1212          Process big buckets, starting with the least full.1213          --*/ - 2561214          ss = runningOrder[i];12151216          /*--1217          Complete the big bucket [ss] by quicksorting1218          any unsorted small buckets [ss, j].  Hopefully1219          previous pointer-scanning phases have already1220          completed many of the small buckets [ss, j], so1221          we don't have to sort them at all.1158          /*--1159          Process big buckets, starting with the least full.1160          --*/ + 01161          ss = runningOrder[i];11621163          /*--1164          Complete the big bucket [ss] by quicksorting1165          any unsorted small buckets [ss, j].  Hopefully1166          previous pointer-scanning phases have already1167          completed many of the small buckets [ss, j], so1168          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          }11851186          /*--1187          The ss big bucket is now done.  Record this fact,1188          and update the quadrant descriptors.  Remember to1189          update quadrants in the overshoot area too, if1190          necessary.  The "if (i < 255)" test merely skips1191          this updating for the last bucket processed, since1192          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          }12181219          /*--1220          Now scan this big bucket so as to synthesise the1221          sorted order for small buckets [t, ss] for all t != ss.  1222          --*/ - 1315841223           for (j = 0; j <= 255; j++) { - 655361224            sb = (ss << 8) + j; - 655361225             if(!((ftab[sb] & SETMASK) == SETMASK)) { - 328961226              int lo = ftab[sb] & CLEARMASK; - 328961227              int hi = (ftab[sb+1] & CLEARMASK) - 1; - 328961228               if (hi > lo) { - 3531229                QSort3(lo, hi, 2); - 3531230                numQSorted += (hi - lo + 1); - 3531231                 if (workDone > workLimit && firstAttempt) { - 01232                  return;1233                }1234              } - 328961235              ftab[sb] |= SETMASK;1236            } + 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          }12381239          /*--1240          The ss big bucket is now done.  Record this fact,1241          and update the quadrant descriptors.  Remember to1242          update quadrants in the overshoot area too, if1243          necessary.  The "if (i < 255)" test merely skips1244          this updating for the last bucket processed, since1245          updating for the last bucket is pointless.1246          --*/ - 2561247          bigDone[ss] = true;1248 - 2561249           if (i < 255) { - 2551250            int bbStart  = ftab[ss << 8] & CLEARMASK; - 2551251            int bbSize   = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; - 2551252            int shifts   = 0;1253 - 2551254             while ((bbSize >> shifts) > 65534) { - 01255              shifts++;1256            }1257 - 203981258             for (j = 0; j < bbSize; j++) { - 99441259              int a2update = zptr[bbStart + j]; - 99441260              int qVal = (j >> shifts); - 99441261              quadrant[a2update] = qVal; - 99441262               if (a2update < BZip2Constants.OvershootBytes) { - 201263                quadrant[a2update + last + 1] = qVal;1264              }1265            }1266 - 2551267             if (!(((bbSize-1) >> shifts) <= 65535)) { - 01268              Panic();1269            }1270          }12711272          /*--1273          Now scan this big bucket so as to synthesise the1274          sorted order for small buckets [t, ss] for all t != ss.1275          --*/ - 1315841276           for (j = 0; j <= 255; j++) { - 655361277            copy[j] = ftab[(j << 8) + ss] & CLEARMASK;1278          }1279 - 205121280           for (j = ftab[ss << 8] & CLEARMASK; j < (ftab[(ss+1) << 8] & CLEARMASK); j++) { - 100001281            c1 = block[zptr[j]]; - 100001282             if (!bigDone[c1]) { - 49591283              zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1; - 49591284              copy[c1] ++;1285            }1286          }1287 - 1315841288           for (j = 0; j <= 255; j++) { - 655361289            ftab[(j << 8) + ss] |= SETMASK;1290          }1291        }1292      } - 11293    }12941295    void RandomiseBlock()1296    {1297      int i; - 01298      int rNToGo = 0; - 01299      int rTPos  = 0; - 01300       for (i = 0; i < 256; i++) { - 01301        inUse[i] = false;1302      }1238        }1239      } + 01240    }12411242    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    }12671268    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    }12971298    bool FullGtU(int i1, int i2)1299    {1300      int k;1301      byte c1, c2;1302      int s1, s2;  1303 - 01304       for (i = 0; i <= last; i++) { - 01305         if (rNToGo == 0) { - 01306          rNToGo = (int)BZip2Constants.RandomNumbers[rTPos]; - 01307          rTPos++; - 01308           if (rTPos == 512) { - 01309            rTPos = 0;1310          }1311        } - 01312        rNToGo--; - 01313         block[i + 1] ^= (byte)((rNToGo == 1) ? 1 : 0);1314        // handle 16 bit signed numbers - 01315        block[i + 1] &= 0xFF;1316 - 01317        inUse[block[i + 1]] = true;1318      } - 01319    }13201321    void DoReversibleTransformation()1322    { - 11323      workLimit = workFactor * last; - 11324      workDone = 0; - 11325      blockRandomised = false; - 11326      firstAttempt = true; + 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 - 11328      MainSort();1329 - 11330       if (workDone > workLimit && firstAttempt) { - 01331        RandomiseBlock(); - 01332        workLimit = workDone = 0; - 01333        blockRandomised = true; - 01334        firstAttempt = false; - 01335        MainSort();1336      }1337 - 11338      origPtr = -1; - 134401339       for (int i = 0; i <= last; i++) { - 67201340         if (zptr[i] == 0) { - 11341          origPtr = i; - 11342          break;1343        }1344      }1345 - 11346       if (origPtr == -1) { - 01347        Panic(); + 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      } - 11349    }13501351    bool FullGtU(int i1, int i2)1352    {1353      int k;1354      byte c1, c2;1355      int s1, s2;1356 - 3931357      c1 = block[i1 + 1]; - 3931358      c2 = block[i2 + 1]; - 3931359       if (c1 != c2) { - 3911360        return c1 > c2;1361      } - 21362      i1++; - 21363      i2++;1364 - 21365      c1 = block[i1 + 1]; - 21366      c2 = block[i2 + 1]; - 21367       if (c1 != c2) { - 21368        return c1 > c2;1369      } - 01370      i1++; - 01371      i2++;1372 - 01373      c1 = block[i1 + 1]; - 01374      c2 = block[i2 + 1]; - 01375       if (c1 != c2) { - 01376        return c1 > c2;1377      } - 01378      i1++; - 01379      i2++; + 01349      i1++; + 01350      i2++;1351 + 01352      k = last + 1;13531354      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      i1++; - 01387      i2++;1388 - 01389      c1 = block[i1 + 1]; - 01390      c2 = block[i2 + 1]; - 01391       if (c1 != c2) { - 01392        return c1 > c2;1393      } - 01394      i1++; - 01395      i2++;1396 - 01397      c1 = block[i1 + 1]; - 01398      c2 = block[i2 + 1]; - 01399       if (c1 != c2) { - 01400        return c1 > c2;1401      } - 01402      i1++; - 01403      i2++;1404 - 01405      k = last + 1; + 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++;  14061407      do { - 01408        c1 = block[i1 + 1]; - 01409        c2 = block[i2 + 1]; - 01410         if (c1 != c2) { - 01411          return c1 > c2;1412        } - 01413        s1 = quadrant[i1]; - 01414        s2 = quadrant[i2]; - 01415         if (s1 != s2) { - 01416          return s1 > s2;1417        } - 01418        i1++; - 01419        i2++;1420 - 01421        c1 = block[i1 + 1]; - 01422        c2 = block[i2 + 1]; - 01423         if (c1 != c2) { - 01424          return c1 > c2;1425        } - 01426        s1 = quadrant[i1]; - 01427        s2 = quadrant[i2]; - 01428         if (s1 != s2) { - 01429          return s1 > s2;1430        } - 01431        i1++; - 01432        i2++;1433 - 01434        c1 = block[i1 + 1]; - 01435        c2 = block[i2 + 1]; - 01436         if (c1 != c2) { - 01437          return c1 > c2;1438        } - 01439        s1 = quadrant[i1]; - 01440        s2 = quadrant[i2]; - 01441         if (s1 != s2) { - 01442          return s1 > s2;1443        } - 01444        i1++; - 01445        i2++;1446 - 01447        c1 = block[i1 + 1]; - 01448        c2 = block[i2 + 1]; - 01449         if (c1 != c2) { - 01450          return c1 > c2;1451        } - 01452        s1 = quadrant[i1]; - 01453        s2 = quadrant[i2]; - 01454         if (s1 != s2) { - 01455          return s1 > s2;1456        } - 01457        i1++; - 01458        i2++;1459 - 01460         if (i1 > last) { - 01461          i1 -= last; - 01462          i1--;1463        } - 01464         if (i2 > last) { - 01465          i2 -= last; - 01466          i2--;1467        } + 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    }14221423    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      }14351436      /*1437      The back end needs a place to store the MTF values1438      whilst it calculates the coding tables.  We could1439      put them in the zptr array.  However, these values1440      will fit in a short, so we overlay szptr at the1441      start of zptr, in the hope of reducing the number1442      of cache misses induced by the multiple traversals1443      of the MTF values when calculating coding tables.1444      Seems to improve compression speed by about 1%.1445      */1446      //  szptr = zptr;14471448 + 11449      szptr = new short[2 * n]; + 11450    }14511452    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        k -= 4; - 01470        ++workDone; - 01471       } while (k >= 0);1472 - 01473      return false;1474    } + 01469      wr = 0; + 01470      zPend = 0; + 01471       for (i = 0; i < nInUse; i++) { + 01472        yy[i] = (char)i;1473      }1474  14751476    void AllocateCompressStructures()1477    { - 21478      int n = BZip2Constants.BaseBlockSize * blockSize100k; - 21479      block = new byte[(n + 1 + BZip2Constants.OvershootBytes)]; - 21480      quadrant = new int[(n + BZip2Constants.OvershootBytes)]; - 21481      zptr = new int[n]; - 21482      ftab = new int[65537];1483 - 21484       if (block == null || quadrant == null || zptr == null  || ftab == null) {1485        //    int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537;1486        //    compressOutOfMemory ( totalDraw, n );1487      }14881489      /*1490      The back end needs a place to store the MTF values1491      whilst it calculates the coding tables.  We could1492      put them in the zptr array.  However, these values1493      will fit in a short, so we overlay szptr at the1494      start of zptr, in the hope of reducing the number1495      of cache misses induced by the multiple traversals1496      of the MTF values when calculating coding tables.1497      Seems to improve compression speed by about 1%.1498      */1499      //  szptr = zptr;15001501 - 21502      szptr = new short[2 * n]; - 21503    }15041505    void GenerateMTFValues()1506    { - 11507      char[] yy = new char[256];1508      int  i, j;1509      char tmp;1510      char tmp2;1511      int zPend;1512      int wr;1513      int EOB;1514 - 11515      MakeMaps(); - 11516      EOB = nInUse+1;1517 - 5181518       for (i = 0; i <= EOB; i++) { - 2581519        mtfFreq[i] = 0; + 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 - 11522      wr = 0; - 11523      zPend = 0; - 5141524       for (i = 0; i < nInUse; i++) { - 2561525        yy[i] = (char) i;1526      }15271528 - 200021529       for (i = 0; i <= last; i++) {1530        char ll_i;1531 - 100001532        ll_i = unseqToSeq[block[zptr[i]]];1533 - 100001534        j = 0; - 100001535        tmp = yy[j]; - 12926911536         while (ll_i != tmp) { - 12826911537          j++; - 12826911538          tmp2 = tmp; - 12826911539          tmp = yy[j]; - 12826911540          yy[j] = tmp2; + 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        } - 100001542        yy[0] = tmp;1542      }  1543 - 100001544         if (j == 0) { - 391545          zPend++; - 391546        } else { - 99611547           if (zPend > 0) { - 391548            zPend--; - 01549            while (true) { - 391550               switch (zPend % 2) {1551                case 0: - 391552                  szptr[wr] = (short)BZip2Constants.RunA; - 391553                  wr++; - 391554                  mtfFreq[BZip2Constants.RunA]++; - 391555                  break;1556                case 1: - 01557                  szptr[wr] = (short)BZip2Constants.RunB; - 01558                  wr++; - 01559                  mtfFreq[BZip2Constants.RunB]++;1560                  break;1561              } - 391562               if (zPend < 2) {1563                break;1564              } - 01565              zPend = (zPend - 2) / 2;1566            } - 391567            zPend = 0;1568          } - 99611569          szptr[wr] = (short)(j + 1); - 99611570          wr++; - 99611571          mtfFreq[j + 1]++;1572        }1573      }1574 - 11575       if (zPend > 0) { - 01576        zPend--; - 01577        while (true) { - 01578           switch (zPend % 2) {1579            case 0: - 01580              szptr[wr] = (short)BZip2Constants.RunA; - 01581              wr++; - 01582              mtfFreq[BZip2Constants.RunA]++; - 01583              break;1584            case 1: - 01585              szptr[wr] = (short)BZip2Constants.RunB; - 01586              wr++; - 01587              mtfFreq[BZip2Constants.RunB]++;1588              break;1589          } - 01590           if (zPend < 2) {1591            break;1592          } - 01593          zPend = (zPend - 2) / 2;1594        }1595      } + 01544      szptr[wr] = (short)EOB; + 01545      wr++; + 01546      mtfFreq[EOB]++;1547 + 01548      nMTF = wr; + 01549    }15501551    static void Panic()1552    { + 01553      throw new BZip2Exception("BZip2 output stream panic");1554    }15551556    static void HbMakeCodeLengths(char[] len, int[] freq, int alphaSize, int maxLen)1557    {1558      /*--1559      Nodes and heap entries run from 1.  Entry 01560      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 - 11597      szptr[wr] = (short)EOB; - 11598      wr++; - 11599      mtfFreq[EOB]++;1600 - 11601      nMTF = wr; - 11602    }16031604    static void Panic()1605    { - 01606      throw new BZip2Exception("BZip2 output stream panic");1607    }16081609    static void HbMakeCodeLengths(char[] len, int[] freq, int alphaSize, int maxLen)1610    {1611      /*--1612      Nodes and heap entries run from 1.  Entry 01613      for both the heap and nodes is a sentinel.1614      --*/1615      int nNodes, nHeap, n1, n2, j, k;1616      bool  tooLong;1617 - 241618      int[] heap   = new int[BZip2Constants.MaximumAlphaSize + 2]; - 241619      int[] weight = new int[BZip2Constants.MaximumAlphaSize * 2]; - 241620      int[] parent = new int[BZip2Constants.MaximumAlphaSize * 2];1621 - 124321622       for (int i = 0; i < alphaSize; ++i)1623      { - 61921624        weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;1625      }1626 - 01627      while (true)1628      { - 241629        nNodes = alphaSize; - 241630        nHeap = 0;1631 - 241632        heap[0] = 0; - 241633        weight[0] = 0; - 241634        parent[0] = -2;1635 - 124321636         for (int i = 1; i <= alphaSize; ++i)1637        { - 61921638          parent[i] = -1; - 61921639          nHeap++; - 61921640          heap[nHeap] = i; - 61921641          int zz = nHeap; - 61921642          int tmp = heap[zz]; - 120581643           while (weight[tmp] < weight[heap[zz >> 1]])1644          { - 58661645            heap[zz] = heap[zz >> 1]; - 58661646            zz >>= 1;1647          } - 61921648          heap[zz] = tmp;1649        } - 241650         if (!(nHeap < (BZip2Constants.MaximumAlphaSize+2)))1651        { - 01652          Panic();1653        }1654 - 61921655         while (nHeap > 1)1656        { - 61681657          n1 = heap[1]; - 61681658          heap[1] = heap[nHeap]; - 61681659          nHeap--; - 61681660          int zz = 1; - 61681661          int yy = 0; - 61681662          int tmp = heap[zz]; - 342431663          while (true)1664          { - 404111665            yy = zz << 1; - 404111666             if (yy > nHeap)1667            {1668              break;1669            } - 346031670             if (yy < nHeap &&  weight[heap[yy+1]] < weight[heap[yy]])1671            { - 156441672              yy++;1673            } - 346031674             if (weight[tmp] < weight[heap[yy]])1675            {1676              break;1677            }1678 - 342431679            heap[zz] = heap[yy]; - 342431680            zz = yy;1681          } - 61681682          heap[zz] = tmp; - 61681683          n2 = heap[1]; - 61681684          heap[1] = heap[nHeap]; - 61681685          nHeap--;1686 - 61681687          zz = 1; - 61681688          yy = 0; - 61681689          tmp = heap[zz]; - 329131690          while (true)1691          { - 390811692            yy = zz << 1; - 390811693             if (yy > nHeap)1694            {1695              break;1696            } - 341941697             if (yy < nHeap && weight[heap[yy+1]] < weight[heap[yy]])1698            { - 156711699              yy++;1700            } - 341941701             if (weight[tmp] < weight[heap[yy]])1702            {1703              break;1704            } - 329131705            heap[zz] = heap[yy]; - 329131706            zz = yy;1707          } - 61681708          heap[zz] = tmp; - 61681709          nNodes++; - 61681710          parent[n1] = parent[n2] = nNodes;1711 - 61681712          weight[nNodes] = (int)((weight[n1] & 0xffffff00) + (weight[n2] & 0xffffff00)) | - 61681713            (int)(1 + (((weight[n1] & 0x000000ff) > (weight[n2] & 0x000000ff)) ? (weight[n1] & 0x000000ff) : (weight[n2]1714 - 61681715          parent[nNodes] = -1; - 61681716          nHeap++; - 61681717          heap[nHeap] = nNodes;1718 - 61681719          zz  = nHeap; - 61681720          tmp = heap[zz]; - 65991721           while (weight[tmp] < weight[heap[zz >> 1]])1722          { - 4311723            heap[zz] = heap[zz >> 1]; - 4311724            zz >>= 1;1725          } - 61681726          heap[zz] = tmp;1727        } - 241728         if (!(nNodes < (BZip2Constants.MaximumAlphaSize * 2)))1729        { - 01730          Panic();1731        }1732 - 241733        tooLong = false; - 124321734         for (int i = 1; i <= alphaSize; ++i)1735        { - 61921736          j = 0; - 61921737          k = i; - 571051738           while (parent[k] >= 0)1739          { - 509131740            k = parent[k]; - 509131741            j++;1742          } - 61921743          len[i - 1] = (char)j; - 61921744          tooLong |= j > maxLen;1745        }1746 - 241747         if (!tooLong)1748        {1749          break;1750        }1751 - 01752         for (int i = 1; i < alphaSize; ++i)1753        { - 01754          j = weight[i] >> 8; - 01755          j = 1 + (j / 2); - 01756          weight[i] = j << 8;1757        }1758      } - 241759    } + 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    }16871688    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    }17011702    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    }17201721    struct StackElement1722    {1723      public int ll;1724      public int hh;1725      public int dd;1726    }17271728    #region Instance Fields + 11729    bool isStreamOwner = true;17301731    /*--1732    index of the last char in the block, so1733    the block size == last + 1.1734    --*/1735    int last;17361737    /*--1738    index in zptr[] of original string after sorting.1739    --*/1740    int origPtr;17411742    /*--1743    always: in the range 0 .. 9.1744    The current block size is 100000 * this number.1745    --*/1746    int blockSize100k;17471748    bool blockRandomised;17491750    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];  17601761    static void HbAssignCodes (int[] code, char[] length, int minLen, int maxLen, int alphaSize)1762    { - 61763      int vec = 0; - 721764       for (int n = minLen; n <= maxLen; ++n)1765      { - 155401766         for (int i = 0; i < alphaSize; ++i)1767        { - 77401768           if (length[i] == n)1769          { - 15481770            code[i] = vec; - 15481771            ++vec;1772          }1773        } - 301774        vec <<= 1;1775      } - 61776    }17771778    static byte Med3(byte a, byte b, byte c )1779    {1780      byte t; - 01781       if (a > b)1782      { - 01783        t = a; - 01784        a = b; - 01785        b = t;1786      } - 01787       if (b > c)1788      { - 01789        t = b; - 01790        b = c; - 01791        c = t;1792      } - 01793       if (a > b)1794      { - 01795        b = a;1796      } - 01797      return b;1798    }17991800    struct StackElement1801    {1802      public int ll;1803      public int hh;1804      public int dd;1805    }18061807    #region Instance Fields - 21808    bool isStreamOwner = true;18091810    /*--1811    index of the last char in the block, so1812    the block size == last + 1.1813    --*/1814    int last;18151816    /*--1817    index in zptr[] of original string after sorting.1818    --*/1819    int origPtr;18201821    /*--1822    always: in the range 0 .. 9.1823    The current block size is 100000 * this number.1824    --*/1825    int blockSize100k;18261827    bool blockRandomised;18281829    int bytesOut;1830    int bsBuff;1831    int bsLive; - 21832    IChecksum mCrc = new StrangeCRC();1833 - 21834    bool[] inUse = new bool[256];1835    int nInUse;1836 - 21837    char[] seqToUnseq = new char[256]; - 21838    char[] unseqToSeq = new char[256];1839 - 21840    char[] selector = new char[BZip2Constants.MaximumSelectors]; - 21841    char[] selectorMtf = new char[BZip2Constants.MaximumSelectors];18421843    byte[]  block;1844    int[]   quadrant;1845    int[]   zptr;1846    short[] szptr;1847    int[]   ftab;18481849    int nMTF;1850 - 21851    int[] mtfFreq = new int[BZip2Constants.MaximumAlphaSize];18521853    /*1854    * Used when sorting.  If too many long comparisons1855    * happen, we stop sorting, randomise the block1856    * slightly, and try again.1857    */1858    int workFactor;1859    int workDone;1860    int workLimit;1861    bool firstAttempt;1862    int nBlocksRandomised;1863 - 21864    int currentChar = -1;1865    int runLength;1866    uint blockCRC, combinedCRC;1867    int allowableBlockSize;1868    Stream baseStream;1869    bool disposed_;1870    #endregion1871  }1872}18731874/* This file was derived from a file containing this license:1875 *1876 * This file is a part of bzip2 and/or libbzip2, a program and1877 * library for lossless, block-sorting data compression.1878 *1879 * Copyright (C) 1996-1998 Julian R Seward.  All rights reserved.1880 *1881 * Redistribution and use in source and binary forms, with or without1882 * modification, are permitted provided that the following conditions1883 * are met:1884 *1885 * 1. Redistributions of source code must retain the above copyright1886 * notice, this list of conditions and the following disclaimer.1887 *1888 * 2. The origin of this software must not be misrepresented; you must1889 * not claim that you wrote the original software.  If you use this1890 * software in a product, an acknowledgment in the product1891 * documentation would be appreciated but is not required.1892 *1893 * 3. Altered source versions must be plainly marked as such, and must1894 * not be misrepresented as being the original software.1895 *1896 * 4. The name of the author may not be used to endorse or promote1897 * products derived from this software without specific prior written1898 * permission.1899 *1900 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS1901 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED1902 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE1903 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY1904 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL1905 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE1906 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS1907 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,1908 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING1909 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS1910 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.1911 *1912 * Java version ported by Keiron Liddle, Aftex Software <keiron@aftexsw.com> 1999-20011913 */ + 11761    char[] selector = new char[BZip2Constants.MaximumSelectors]; + 11762    char[] selectorMtf = new char[BZip2Constants.MaximumSelectors];17631764    byte[] block;1765    int[] quadrant;1766    int[] zptr;1767    short[] szptr;1768    int[] ftab;17691770    int nMTF;1771 + 11772    int[] mtfFreq = new int[BZip2Constants.MaximumAlphaSize];17731774    /*1775    * Used when sorting.  If too many long comparisons1776    * happen, we stop sorting, randomise the block1777    * 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    #endregion1792  }1793} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_BaseArchiveStorage.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_BaseArchiveStorage.htm index f6cbd6b93..fc090fd6d 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_BaseArchiveStorage.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_BaseArchiveStorage.htm @@ -18,7 +18,7 @@

Summary

Covered lines:4 Uncovered lines:0 Coverable lines:4 -Total lines:4476 +Total lines:4263 Line coverage:100% @@ -34,4484 +34,4271 @@

#LineLine coverage - 1// ZipFile.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  2009-12-22  Z-1649  Added AES support41//  2010-03-02  Z-1650  Fixed updating ODT archives in memory. Exposed exceptions in updating.42//  2010-05-25  Z-1663  Fixed exception when testing local header compressed size of -143//  2012-11-29  Z-1684  Fixed ZipFile.Add(string fileName, string entryName) losing the file TimeStamp4445using System;46using System.Collections;47using System.IO;48using System.Text;49using System.Globalization;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;1213namespace ICSharpCode.SharpZipLib.Zip14{15  #region Keys Required Event Args16  /// <summary>17  /// Arguments used with KeysRequiredEvent18  /// </summary>19  public class KeysRequiredEventArgs : EventArgs20  {21    #region Constructors22    /// <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    }3031    /// <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    }4142    #endregion43    #region Properties44    /// <summary>45    /// Gets the name of the file for which keys are required.46    /// </summary>47    public string FileName {48      get { return fileName; }49    }  5051#if !NETCF_1_052using System.Security.Cryptography;53using ICSharpCode.SharpZipLib.Encryption;54#endif5556using ICSharpCode.SharpZipLib.Core;57using ICSharpCode.SharpZipLib.Checksums;58using ICSharpCode.SharpZipLib.Zip.Compression.Streams;59using ICSharpCode.SharpZipLib.Zip.Compression;6061namespace ICSharpCode.SharpZipLib.Zip62{63  #region Keys Required Event Args64  /// <summary>65  /// Arguments used with KeysRequiredEvent66  /// </summary>67  public class KeysRequiredEventArgs : EventArgs68  {69    #region Constructors70    /// <summary>71    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>72    /// </summary>73    /// <param name="name">The name of the file for which keys are required.</param>74    public KeysRequiredEventArgs(string name)75    {76      fileName = name;77    }7879    /// <summary>80    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>81    /// </summary>82    /// <param name="name">The name of the file for which keys are required.</param>83    /// <param name="keyValue">The current key value.</param>84    public KeysRequiredEventArgs(string name, byte[] keyValue)85    {86      fileName = name;87      key = keyValue;88    }8990    #endregion91    #region Properties92    /// <summary>93    /// Gets the name of the file for which keys are required.94    /// </summary>95    public string FileName96    {97      get { return fileName; }98    }99100    /// <summary>101    /// Gets or sets the key value102    /// </summary>103    public byte[] Key104    {105      get { return key; }106      set { key = value; }107    }108    #endregion109110    #region Instance Fields111    string fileName;112    byte[] key;113    #endregion114  }115  #endregion116117  #region Test Definitions118  /// <summary>119  /// The strategy to apply to testing.120  /// </summary>121  public enum TestStrategy122  {123    /// <summary>124    /// Find the first error only.125    /// </summary>126    FindFirstError,51    /// <summary>52    /// Gets or sets the key value53    /// </summary>54    public byte[] Key {55      get { return key; }56      set { key = value; }57    }58    #endregion5960    #region Instance Fields61    string fileName;62    byte[] key;63    #endregion64  }65  #endregion6667  #region Test Definitions68  /// <summary>69  /// The strategy to apply to testing.70  /// </summary>71  public enum TestStrategy72  {73    /// <summary>74    /// Find the first error only.75    /// </summary>76    FindFirstError,77    /// <summary>78    /// Find all possible errors.79    /// </summary>80    FindAllErrors,81  }8283  /// <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 TestOperation88  {89    /// <summary>90    /// Setting up testing.91    /// </summary>92    Initialising,9394    /// <summary>95    /// Testing an individual entries header96    /// </summary>97    EntryHeader,9899    /// <summary>100    /// Testing an individual entries data101    /// </summary>102    EntryData,103104    /// <summary>105    /// Testing an individual entry has completed.106    /// </summary>107    EntryComplete,108109    /// <summary>110    /// Running miscellaneous tests111    /// </summary>112    MiscellaneousTests,113114    /// <summary>115    /// Testing is complete116    /// </summary>117    Complete,118  }119120  /// <summary>121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.122  /// </summary>123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>124  public class TestStatus125  {126    #region Constructors  127    /// <summary>128    /// Find all possible errors.128    /// Initialise a new instance of <see cref="TestStatus"/>  129    /// </summary>130    FindAllErrors,131  }132133  /// <summary>134  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.135  /// </summary>136  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>137  public enum TestOperation138  {130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>131    public TestStatus(ZipFile file)132    {133      file_ = file;134    }135    #endregion136137    #region Properties138  139    /// <summary>140    /// Setting up testing.140    /// Get the current <see cref="TestOperation"/> in progress.  141    /// </summary>142    Initialising,143144    /// <summary>145    /// Testing an individual entries header146    /// </summary>147    EntryHeader,148149    /// <summary>150    /// Testing an individual entries data151    /// </summary>152    EntryData,153154    /// <summary>155    /// Testing an individual entry has completed.156    /// </summary>157    EntryComplete,158159    /// <summary>160    /// Running miscellaneous tests161    /// </summary>162    MiscellaneousTests,163164    /// <summary>165    /// Testing is complete166    /// </summary>167    Complete,168  }169170  /// <summary>171  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.172  /// </summary>173  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>174  public class TestStatus175  {176    #region Constructors177    /// <summary>178    /// Initialise a new instance of <see cref="TestStatus"/>179    /// </summary>180    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>181    public TestStatus(ZipFile file)182    {183      file_ = file;184    }185    #endregion186187    #region Properties142    public TestOperation Operation {143      get { return operation_; }144    }145146    /// <summary>147    /// Get the <see cref="ZipFile"/> this status is applicable to.148    /// </summary>149    public ZipFile File {150      get { return file_; }151    }152153    /// <summary>154    /// Get the current/last entry tested.155    /// </summary>156    public ZipEntry Entry {157      get { return entry_; }158    }159160    /// <summary>161    /// Get the number of errors detected so far.162    /// </summary>163    public int ErrorCount {164      get { return errorCount_; }165    }166167    /// <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    }173174    /// <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    #endregion181182    #region Internal API183    internal void AddError()184    {185      errorCount_++;186      entryValid_ = false;187    }  188189    /// <summary>190    /// Get the current <see cref="TestOperation"/> in progress.191    /// </summary>192    public TestOperation Operation193    {194      get { return operation_; }195    }196197    /// <summary>198    /// Get the <see cref="ZipFile"/> this status is applicable to.199    /// </summary>200    public ZipFile File201    {202      get { return file_; }203    }204205    /// <summary>206    /// Get the current/last entry tested.207    /// </summary>208    public ZipEntry Entry209    {210      get { return entry_; }211    }212213    /// <summary>214    /// Get the number of errors detected so far.215    /// </summary>216    public int ErrorCount217    {218      get { return errorCount_; }219    }220221    /// <summary>222    /// Get the number of bytes tested so far for the current entry.223    /// </summary>224    public long BytesTested225    {226      get { return bytesTested_; }227    }228229    /// <summary>230    /// Get a value indicating wether the last entry test was valid.231    /// </summary>232    public bool EntryValid233    {234      get { return entryValid_; }235    }236    #endregion237238    #region Internal API239    internal void AddError()240    {241      errorCount_++;242      entryValid_ = false;243    }244245    internal void SetOperation(TestOperation operation)246    {247      operation_ = operation;248    }249250    internal void SetEntry(ZipEntry entry)251    {252      entry_ = entry;253      entryValid_ = true;254      bytesTested_ = 0;255    }256257    internal void SetBytesTested(long value)258    {259      bytesTested_ = value;260    }261    #endregion262263    #region Instance Fields264    ZipFile file_;265    ZipEntry entry_;266    bool entryValid_;267    int errorCount_;268    long bytesTested_;269    TestOperation operation_;270    #endregion271  }272273  /// <summary>274  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if275  /// </summary>276  /// <remarks>If the message is non-null an error has occured.  If the message is null277  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>278  public delegate void ZipTestResultHandler(TestStatus status, string message);279  #endregion280281  #region Update Definitions282  /// <summary>283  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.284  /// </summary>285  public enum FileUpdateMode286  {287    /// <summary>288    /// Perform all updates on temporary files ensuring that the original file is saved.289    /// </summary>290    Safe,291    /// <summary>292    /// Update the archive directly, which is faster but less safe.293    /// </summary>294    Direct,295  }296  #endregion189    internal void SetOperation(TestOperation operation)190    {191      operation_ = operation;192    }193194    internal void SetEntry(ZipEntry entry)195    {196      entry_ = entry;197      entryValid_ = true;198      bytesTested_ = 0;199    }200201    internal void SetBytesTested(long value)202    {203      bytesTested_ = value;204    }205    #endregion206207    #region Instance Fields208    ZipFile file_;209    ZipEntry entry_;210    bool entryValid_;211    int errorCount_;212    long bytesTested_;213    TestOperation operation_;214    #endregion215  }216217  /// <summary>218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if219  /// </summary>220  /// <remarks>If the message is non-null an error has occured.  If the message is null221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>222  public delegate void ZipTestResultHandler(TestStatus status, string message);223  #endregion224225  #region Update Definitions226  /// <summary>227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.228  /// </summary>229  public enum FileUpdateMode230  {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  #endregion241242  #region ZipFile Class243  /// <summary>244  /// This class represents a Zip archive.  You can ask for the contained245  /// entries, or get an input stream for a file entry.  The entry is246  /// 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 arbitrary251  /// entries in different threads.252  /// <br/>253  /// <br/>Author of the original java version : Jochen Hoenicke254  /// </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 MainClass265  /// {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, IDisposable287  {288    #region KeyHandling289290    /// <summary>291    /// Delegate for handling keys/password setting during compresion/decompression.292    /// </summary>293    public delegate void KeysRequiredEventHandler(294      object sender,295      KeysRequiredEventArgs e296    );  297298  #region ZipFile Class299  /// <summary>300  /// This class represents a Zip archive.  You can ask for the contained301  /// entries, or get an input stream for a file entry.  The entry is302  /// automatically decompressed.303  ///304  /// You can also update the archive adding or deleting entries.305  ///306  /// This class is thread safe for input:  You can open input streams for arbitrary307  /// entries in different threads.308  /// <br/>309  /// <br/>Author of the original java version : Jochen Hoenicke310  /// </summary>311  /// <example>312  /// <code>313  /// using System;314  /// using System.Text;315  /// using System.Collections;316  /// using System.IO;317  ///318  /// using ICSharpCode.SharpZipLib.Zip;319  ///320  /// class MainClass321  /// {322  ///   static public void Main(string[] args)323  ///   {324  ///     using (ZipFile zFile = new ZipFile(args[0])) {325  ///       Console.WriteLine("Listing of : " + zFile.Name);326  ///       Console.WriteLine("");327  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");328  ///       Console.WriteLine("--------  --------  --------  ------  ---------");329  ///       foreach (ZipEntry e in zFile) {330  ///         if ( e.IsFile ) {331  ///           DateTime d = e.DateTime;332  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,333  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),334  ///             e.Name);335  ///         }336  ///       }337  ///     }338  ///   }339  /// }340  /// </code>341  /// </example>342  public class ZipFile : IEnumerable, IDisposable343  {344    #region KeyHandling345346    /// <summary>347    /// Delegate for handling keys/password setting during compresion/decompression.348    /// </summary>349    public delegate void KeysRequiredEventHandler(350      object sender,351      KeysRequiredEventArgs e352    );353354    /// <summary>355    /// Event handler for handling encryption keys.356    /// </summary>357    public KeysRequiredEventHandler KeysRequired;358359    /// <summary>360    /// Handles getting of encryption keys when required.361    /// </summary>362    /// <param name="fileName">The file for which encryption keys are required.</param>363    void OnKeysRequired(string fileName)364    {365      if (KeysRequired != null) {366        var krea = new KeysRequiredEventArgs(fileName, key);367        KeysRequired(this, krea);368        key = krea.Key;369      }370    }371372    /// <summary>373    /// Get/set the encryption key value.374    /// </summary>375    byte[] Key376    {377      get { return key; }378      set { key = value; }379    }380381#if !NETCF_1_0382    /// <summary>383    /// Password to be used for encrypting/decrypting files.384    /// </summary>385    /// <remarks>Set to null if no password is required.</remarks>386    public string Password387    {388      set389      {390        if ( string.IsNullOrEmpty(value)) {391          key = null;392        }393        else {394          rawPassword_ = value;395          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));396        }298    /// <summary>299    /// Event handler for handling encryption keys.300    /// </summary>301    public KeysRequiredEventHandler KeysRequired;302303    /// <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    }315316    /// <summary>317    /// Get/set the encryption key value.318    /// </summary>319    byte[] Key {320      get { return key; }321      set { key = value; }322    }323324    /// <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    }338339    /// <summary>340    /// Get a value indicating wether encryption keys are currently available.341    /// </summary>342    bool HaveKeys {343      get { return key != null; }344    }345    #endregion346347    #region Constructors348    /// <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 occurs355    /// </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      }364365      name_ = name;366367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);368      isStreamOwner = true;369370      try {371        ReadEntries();372      } catch {373        DisposeInternal(true);374        throw;375      }376    }377378    /// <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      }394395      if (!file.CanSeek) {396        throw new ArgumentException("Stream is not seekable", nameof(file));  397      }398    }399#endif400401    /// <summary>402    /// Get a value indicating wether encryption keys are currently available.403    /// </summary>404    bool HaveKeys405    {406      get { return key != null; }407    }408    #endregion409410    #region Constructors398399      baseStream_ = file;400      name_ = file.Name;401      isStreamOwner = true;402403      try {404        ReadEntries();405      } catch {406        DisposeInternal(true);407        throw;408      }409    }410  411    /// <summary>412    /// Opens a Zip file with the given name for reading.412    /// Opens a Zip file reading the given <see cref="Stream"/>.  413    /// </summary>414    /// <param name="name">The name of the file to open.</param>415    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>416    /// <exception cref="IOException">417    /// An i/o error occurs418    /// </exception>419    /// <exception cref="ZipException">420    /// The file doesn't contain a valid zip archive.421    /// </exception>422    public ZipFile(string name)423    {424      if ( name == null ) {425        throw new ArgumentNullException(nameof(name));426      }427428      name_ = name;429430      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);431      isStreamOwner = true;414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>415    /// <exception cref="IOException">416    /// An i/o error occurs417    /// </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      }  432433      try {434        ReadEntries();433      if (!stream.CanSeek) {434        throw new ArgumentException("Stream is not seekable", nameof(stream));  435      }436      catch {437        DisposeInternal(true);438        throw;439      }440    }441442    /// <summary>443    /// Opens a Zip file reading the given <see cref="FileStream"/>.444    /// </summary>445    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>446    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>447    /// <exception cref="IOException">448    /// An i/o error occurs.449    /// </exception>450    /// <exception cref="ZipException">451    /// The file doesn't contain a valid zip archive.452    /// </exception>453    public ZipFile(FileStream file)454    {455      if ( file == null ) {456        throw new ArgumentNullException(nameof(file));457      }458459      if ( !file.CanSeek ) {460        throw new ArgumentException("Stream is not seekable", nameof(file));461      }462463      baseStream_  = file;464      name_ = file.Name;465      isStreamOwner = true;466467      try {468        ReadEntries();469      }470      catch {471        DisposeInternal(true);472        throw;473      }474    }475476    /// <summary>477    /// Opens a Zip file reading the given <see cref="Stream"/>.478    /// </summary>479    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>480    /// <exception cref="IOException">481    /// An i/o error occurs482    /// </exception>483    /// <exception cref="ZipException">484    /// The stream doesn't contain a valid zip archive.<br/>485    /// </exception>486    /// <exception cref="ArgumentException">487    /// The <see cref="Stream">stream</see> doesnt support seeking.488    /// </exception>489    /// <exception cref="ArgumentNullException">490    /// The <see cref="Stream">stream</see> argument is null.491    /// </exception>492    public ZipFile(Stream stream)493    {494      if ( stream == null ) {495        throw new ArgumentNullException(nameof(stream));496      }497498      if ( !stream.CanSeek ) {499        throw new ArgumentException("Stream is not seekable", nameof(stream));500      }501502      baseStream_  = stream;503      isStreamOwner = true;504505      if ( baseStream_.Length > 0 ) {506        try {507          ReadEntries();508        }509        catch {510          DisposeInternal(true);511          throw;512        }513      } else {514        entries_ = new ZipEntry[0];515        isNewArchive_ = true;516      }517    }518519    /// <summary>520    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.521    /// </summary>522    internal ZipFile()523    {524      entries_ = new ZipEntry[0];525      isNewArchive_ = true;526    }527528    #endregion529530    #region Destructors and Closing531    /// <summary>532    /// Finalize this instance.533    /// </summary>534    ~ZipFile()535    {536      Dispose(false);537    }538436437      baseStream_ = stream;438      isStreamOwner = true;439440      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    }452453    /// <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    }461462    #endregion463464    #region Destructors and Closing465    /// <summary>466    /// Finalize this instance.467    /// </summary>468    ~ZipFile()469    {470      Dispose(false);471    }472473    /// <summary>474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying475    /// 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    }485486    #endregion487488    #region Creators489    /// <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      }500501      FileStream fs = File.Create(fileName);502503      var result = new ZipFile();504      result.name_ = fileName;505      result.baseStream_ = fs;506      result.isStreamOwner = true;507      return result;508    }509510    /// <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      }522523      if (!outStream.CanWrite) {524        throw new ArgumentException("Stream is not writeable", nameof(outStream));525      }526527      if (!outStream.CanSeek) {528        throw new ArgumentException("Stream is not seekable", nameof(outStream));529      }530531      var result = new ZipFile();532      result.baseStream_ = outStream;533      return result;534    }535536    #endregion537538    #region Properties  539    /// <summary>540    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying541    /// Once closed, no further instance methods should be called.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    /// <exception cref="System.IO.IOException">544    /// An i/o error occurs.545    /// </exception>546    public void Close()547    {548      DisposeInternal(true);549      GC.SuppressFinalize(this);550    }551552    #endregion553554    #region Creators555    /// <summary>556    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.557    /// </summary>558    /// <param name="fileName">The name of the archive to create.</param>559    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>560    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>561    public static ZipFile Create(string fileName)562    {563      if ( fileName == null ) {564        throw new ArgumentNullException(nameof(fileName));565      }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    }550551    /// <summary>552    /// Get a value indicating wether553    /// this archive is embedded in another file or not.554    /// </summary>555    public bool IsEmbeddedArchive {556      // Not strictly correct in all circumstances currently557      get { return offsetOfFirstEntry > 0; }558    }559560    /// <summary>561    /// Get a value indicating that this archive is a new one.562    /// </summary>563    public bool IsNewArchive {564      get { return isNewArchive_; }565    }  566567      FileStream fs = File.Create(fileName);568569      var result = new ZipFile();570      result.name_ = fileName;571      result.baseStream_ = fs;572      result.isStreamOwner = true;573      return result;574    }575576    /// <summary>577    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.578    /// </summary>579    /// <param name="outStream">The stream providing data storage.</param>580    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>581    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>582    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>583    public static ZipFile Create(Stream outStream)584    {585      if ( outStream == null ) {586        throw new ArgumentNullException(nameof(outStream));587      }588589      if ( !outStream.CanWrite ) {590        throw new ArgumentException("Stream is not writeable", nameof(outStream));567    /// <summary>568    /// Gets the comment for the zip file.569    /// </summary>570    public string ZipFileComment {571      get { return comment_; }572    }573574    /// <summary>575    /// Gets the name of this zip file.576    /// </summary>577    public string Name {578      get { return name_; }579    }580581    /// <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      }592593      if ( !outStream.CanSeek ) {594        throw new ArgumentException("Stream is not seekable", nameof(outStream));595      }596597      var result = new ZipFile();598      result.baseStream_ = outStream;599      return result;600    }601602    #endregion603604    #region Properties605    /// <summary>606    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.607    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.608    /// </summary>609    /// <remarks>610    /// The default value is true in all cases.611    /// </remarks>612    public bool IsStreamOwner613    {614      get { return isStreamOwner; }615      set { isStreamOwner = value; }616    }617618    /// <summary>619    /// Get a value indicating wether620    /// this archive is embedded in another file or not.621    /// </summary>622    public bool IsEmbeddedArchive623    {624      // Not strictly correct in all circumstances currently625      get { return offsetOfFirstEntry > 0; }626    }627628    /// <summary>629    /// Get a value indicating that this archive is a new one.630    /// </summary>631    public bool IsNewArchive632    {633      get { return isNewArchive_; }634    }635636    /// <summary>637    /// Gets the comment for the zip file.638    /// </summary>639    public string ZipFileComment640    {641      get { return comment_; }642    }643644    /// <summary>645    /// Gets the name of this zip file.646    /// </summary>647    public string Name648    {649      get { return name_; }650    }651652    /// <summary>653    /// Gets the number of entries in this zip file.654    /// </summary>655    /// <exception cref="InvalidOperationException">656    /// The Zip file has been closed.657    /// </exception>658    [Obsolete("Use the Count property instead")]659    public int Size660    {661      get662      {663        return entries_.Length;664      }665    }666667    /// <summary>668    /// Get the number of entries contained in this <see cref="ZipFile"/>.669    /// </summary>670    public long Count671    {672      get673      {674        return entries_.Length;675      }676    }677678    /// <summary>679    /// Indexer property for ZipEntries680    /// </summary>681    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]682    public ZipEntry this[int index]683    {684      get {685        return (ZipEntry) entries_[index].Clone();686      }687    }688689    #endregion690691    #region Input Handling692    /// <summary>693    /// Gets an enumerator for the Zip entries in this Zip file.694    /// </summary>695    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>696    /// <exception cref="ObjectDisposedException">697    /// The Zip file has been closed.698    /// </exception>699    public IEnumerator GetEnumerator()700    {701      if (isDisposed_) {702        throw new ObjectDisposedException("ZipFile");703      }704705      return new ZipEntryEnumerator(entries_);706    }707708    /// <summary>709    /// Return the index of the entry with a matching name710    /// </summary>711    /// <param name="name">Entry name to find</param>712    /// <param name="ignoreCase">If true the comparison is case insensitive</param>713    /// <returns>The index position of the matching entry or -1 if not found</returns>714    /// <exception cref="ObjectDisposedException">715    /// The Zip file has been closed.716    /// </exception>717    public int FindEntry(string name, bool ignoreCase)718    {719      if (isDisposed_) {720        throw new ObjectDisposedException("ZipFile");721      }722723      // TODO: This will be slow as the next ice age for huge archives!724      for (int i = 0; i < entries_.Length; i++) {725        if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {726          return i;727        }728      }729      return -1;730    }731732    /// <summary>733    /// Searches for a zip entry in this archive with the given name.734    /// String comparisons are case insensitive735    /// </summary>736    /// <param name="name">737    /// The name to find. May contain directory components separated by slashes ('/').738    /// </param>739    /// <returns>740    /// A clone of the zip entry, or null if no entry with that name exists.741    /// </returns>742    /// <exception cref="ObjectDisposedException">743    /// The Zip file has been closed.744    /// </exception>745    public ZipEntry GetEntry(string name)746    {747      if (isDisposed_) {748        throw new ObjectDisposedException("ZipFile");749      }750751      int index = FindEntry(name, true);752      return (index >= 0) ? (ZipEntry) entries_[index].Clone() : null;753    }754755    /// <summary>756    /// Gets an input stream for reading the given zip entry data in an uncompressed form.757    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().758    /// </summary>759    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>760    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>761    /// <exception cref="ObjectDisposedException">762    /// The ZipFile has already been closed763    /// </exception>764    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">765    /// The compression method for the entry is unknown766    /// </exception>767    /// <exception cref="IndexOutOfRangeException">768    /// The entry is not found in the ZipFile769    /// </exception>770    public Stream GetInputStream(ZipEntry entry)771    {772      if ( entry == null ) {773        throw new ArgumentNullException(nameof(entry));774      }775776      if ( isDisposed_ ) {777        throw new ObjectDisposedException("ZipFile");778      }779780      long index = entry.ZipFileIndex;781      if ( (index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name) ) {782        index = FindEntry(entry.Name, true);783        if (index < 0) {784          throw new ZipException("Entry cannot be found");785        }786      }787      return GetInputStream(index);788    }789790    /// <summary>791    /// Creates an input stream reading a zip entry792    /// </summary>793    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>794    /// <returns>795    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>796    /// </returns>797    /// <exception cref="ObjectDisposedException">798    /// The ZipFile has already been closed799    /// </exception>800    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">801    /// The compression method for the entry is unknown802    /// </exception>803    /// <exception cref="IndexOutOfRangeException">804    /// The entry is not found in the ZipFile805    /// </exception>806    public Stream GetInputStream(long entryIndex)807    {808      if ( isDisposed_ ) {809        throw new ObjectDisposedException("ZipFile");810      }592    }593594    /// <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    }602603    /// <summary>604    /// Indexer property for ZipEntries605    /// </summary>606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]607    public ZipEntry this[int index] {608      get {609        return (ZipEntry)entries_[index].Clone();610      }611    }612613    #endregion614615    #region Input Handling616    /// <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      }628629      return new ZipEntryEnumerator(entries_);630    }631632    /// <summary>633    /// Return the index of the entry with a matching name634    /// </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      }646647      // 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    }655656    /// <summary>657    /// Searches for a zip entry in this archive with the given name.658    /// String comparisons are case insensitive659    /// </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      }674675      int index = FindEntry(name, true);676      return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;677    }678679    /// <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 closed687    /// </exception>688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">689    /// The compression method for the entry is unknown690    /// </exception>691    /// <exception cref="IndexOutOfRangeException">692    /// The entry is not found in the ZipFile693    /// </exception>694    public Stream GetInputStream(ZipEntry entry)695    {696      if (entry == null) {697        throw new ArgumentNullException(nameof(entry));698      }699700      if (isDisposed_) {701        throw new ObjectDisposedException("ZipFile");702      }703704      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    }713714    /// <summary>715    /// Creates an input stream reading a zip entry716    /// </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 closed723    /// </exception>724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">725    /// The compression method for the entry is unknown726    /// </exception>727    /// <exception cref="IndexOutOfRangeException">728    /// The entry is not found in the ZipFile729    /// </exception>730    public Stream GetInputStream(long entryIndex)731    {732      if (isDisposed_) {733        throw new ObjectDisposedException("ZipFile");734      }735736      long start = LocateEntry(entries_[entryIndex]);737      CompressionMethod method = entries_[entryIndex].CompressionMethod;738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);739740      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      }746747      switch (method) {748        case CompressionMethod.Stored:749          // read as is.750          break;751752        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;756757        default:758          throw new ZipException("Unsupported compression method " + method);759      }760761      return result;762    }763764    #endregion765766    #region Archive Testing767    /// <summary>768    /// Test an archive for integrity/validity769    /// </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    }777778    /// <summary>779    /// Test an archive for integrity/validity780    /// </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      }791792      var status = new TestStatus(this);793794      if (resultHandler != null) {795        resultHandler(status, null);796      }797798      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;799800      bool testing = true;801802      try {803        int entryIndex = 0;804805        while (testing && (entryIndex < Count)) {806          if (resultHandler != null) {807            status.SetEntry(this[entryIndex]);808            status.SetOperation(TestOperation.EntryHeader);809            resultHandler(status, null);810          }  811812      long start = LocateEntry(entries_[entryIndex]);813      CompressionMethod method = entries_[entryIndex].CompressionMethod;814      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);815816      if (entries_[entryIndex].IsCrypted == true) {817#if NETCF_1_0818        throw new ZipException("decryption not supported for Compact Framework 1.0");819#else820        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);821        if (result == null) {822          throw new ZipException("Unable to decrypt this entry");823        }824#endif825      }826827      switch (method) {828        case CompressionMethod.Stored:829          // read as is.830          break;831832        case CompressionMethod.Deflated:833          // No need to worry about ownership and closing as underlying stream close does nothing.834          result = new InflaterInputStream(result, new Inflater(true));835          break;836837        default:838          throw new ZipException("Unsupported compression method " + method);839      }812          try {813            TestLocalHeader(this[entryIndex], test);814          } catch (ZipException ex) {815            status.AddError();816817            if (resultHandler != null) {818              resultHandler(status,819                string.Format("Exception during test - '{0}'", ex.Message));820            }821822            testing &= strategy != TestStrategy.FindFirstError;823          }824825          if (testing && testData && this[entryIndex].IsFile) {826            if (resultHandler != null) {827              status.SetOperation(TestOperation.EntryData);828              resultHandler(status, null);829            }830831            var crc = new Crc32();832833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {834835              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);  840841      return result;842    }843844    #endregion845846    #region Archive Testing847    /// <summary>848    /// Test an archive for integrity/validity849    /// </summary>850    /// <param name="testData">Perform low level data Crc check</param>851    /// <returns>true if all tests pass, false otherwise</returns>852    /// <remarks>Testing will terminate on the first error found.</remarks>853    public bool TestArchive(bool testData)854    {855      return TestArchive(testData, TestStrategy.FindFirstError, null);856    }857858    /// <summary>859    /// Test an archive for integrity/validity860    /// </summary>861    /// <param name="testData">Perform low level data Crc check</param>862    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>863    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>864    /// <returns>true if all tests pass, false otherwise</returns>865    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>866    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)867    {868      if (isDisposed_) {869        throw new ObjectDisposedException("ZipFile");870      }871872      var status = new TestStatus(this);873874      if ( resultHandler != null ) {875        resultHandler(status, null);876      }877878      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;879880      bool testing = true;841                if (resultHandler != null) {842                  totalBytes += bytesRead;843                  status.SetBytesTested(totalBytes);844                  resultHandler(status, null);845                }846              }847            }848849            if (this[entryIndex].Crc != crc.Value) {850              status.AddError();851852              if (resultHandler != null) {853                resultHandler(status, "CRC mismatch");854              }855856              testing &= strategy != TestStrategy.FindFirstError;857            }858859            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              }866867              if (this[entryIndex].CompressedSize != data.CompressedSize) {868                status.AddError();869              }870871              if (this[entryIndex].Size != data.Size) {872                status.AddError();873              }874            }875          }876877          if (resultHandler != null) {878            status.SetOperation(TestOperation.EntryComplete);879            resultHandler(status, null);880          }  881882      try {883        int entryIndex = 0;882          entryIndex += 1;883        }  884885        while ( testing && (entryIndex < Count) ) {886          if ( resultHandler != null ) {887            status.SetEntry(this[entryIndex]);888            status.SetOperation(TestOperation.EntryHeader);889            resultHandler(status, null);890          }891892          try  {893            TestLocalHeader(this[entryIndex], test);894          }895          catch(ZipException ex) {896            status.AddError();897898            if ( resultHandler != null ) {899              resultHandler(status,900                string.Format("Exception during test - '{0}'", ex.Message));901            }902903            testing &= strategy != TestStrategy.FindFirstError;904          }885        if (resultHandler != null) {886          status.SetOperation(TestOperation.MiscellaneousTests);887          resultHandler(status, null);888        }889890        // TODO: the 'Corrina Johns' test where local headers are missing from891        // the central directory.  They are therefore invisible to many archivers.892      } catch (Exception ex) {893        status.AddError();894895        if (resultHandler != null) {896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));897        }898      }899900      if (resultHandler != null) {901        status.SetOperation(TestOperation.Complete);902        status.SetEntry(null);903        resultHandler(status, null);904      }  905906          if ( testing && testData && this[entryIndex].IsFile ) {907            if ( resultHandler != null ) {908              status.SetOperation(TestOperation.EntryData);909              resultHandler(status, null);910            }911912                        var crc = new Crc32();913914                        using (Stream entryStream = this.GetInputStream(this[entryIndex]))915                        {916917                            byte[] buffer = new byte[4096];918                            long totalBytes = 0;919                            int bytesRead;920                            while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0)921                            {922                                crc.Update(buffer, 0, bytesRead);923924                                if (resultHandler != null)925                                {926                                    totalBytes += bytesRead;927                                    status.SetBytesTested(totalBytes);928                                    resultHandler(status, null);929                                }930                            }931                        }932933            if (this[entryIndex].Crc != crc.Value) {934              status.AddError();935936              if ( resultHandler != null ) {937                resultHandler(status, "CRC mismatch");938              }939940              testing &= strategy != TestStrategy.FindFirstError;941            }942943            if (( this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0 ) {944              var helper = new ZipHelperStream(baseStream_);945              var data = new DescriptorData();946              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);947              if (this[entryIndex].Crc != data.Crc) {948                status.AddError();949              }950951              if (this[entryIndex].CompressedSize != data.CompressedSize) {952                status.AddError();953              }954955              if (this[entryIndex].Size != data.Size) {956                status.AddError();957              }958            }959          }960961          if ( resultHandler != null ) {962            status.SetOperation(TestOperation.EntryComplete);963            resultHandler(status, null);964          }965966          entryIndex += 1;967        }968969        if ( resultHandler != null ) {970          status.SetOperation(TestOperation.MiscellaneousTests);971          resultHandler(status, null);972        }973974        // TODO: the 'Corrina Johns' test where local headers are missing from975        // the central directory.  They are therefore invisible to many archivers.976      }977      catch (Exception ex) {978        status.AddError();906      return (status.ErrorCount == 0);907    }908909    [Flags]910    enum HeaderTest911    {912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted913      Header = 0x02,     // Check that this header contents are valid914    }915916    /// <summary>917    /// Test a local header against that provided from the central directory918    /// </summary>919    /// <param name="entry">920    /// The entry to test against921    /// </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;929930        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        }934935        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();945946        byte[] nameData = new byte[storedNameLength];947        StreamUtils.ReadFully(baseStream_, nameData);948949        byte[] extraData = new byte[extraDataLength];950        StreamUtils.ReadFully(baseStream_, extraData);951952        var localExtraData = new ZipExtraData(extraData);953954        // Extra data / zip64 checks955        if (localExtraData.Find(1)) {956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64957          // and size or compressedSize = MaxValue, due to rogue creators.958959          size = localExtraData.ReadLong();960          compressedSize = localExtraData.ReadLong();961962          if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {963            // These may be valid if patched later964            if ((size != -1) && (size != entry.Size)) {965              throw new ZipException("Size invalid for descriptor");966            }967968            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        }  979980        if ( resultHandler != null ) {981          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));982        }983      }984985      if ( resultHandler != null ) {986        status.SetOperation(TestOperation.Complete);987        status.SetEntry(null);988        resultHandler(status, null);989      }980        if (testData) {981          if (entry.IsFile) {982            if (!entry.IsCompressionMethodSupported()) {983              throw new ZipException("Compression method not supported");984            }985986            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})", extract989            }  990991      return (status.ErrorCount == 0);992    }993994    [Flags]995    enum HeaderTest996    {997      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted998      Header  = 0x02,     // Check that this header contents are valid999    }10001001    /// <summary>1002    /// Test a local header against that provided from the central directory1003    /// </summary>1004    /// <param name="entry">1005    /// The entry to test against1006    /// </param>1007    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>1008    /// <returns>The offset of the entries data in the file</returns>1009    long TestLocalHeader(ZipEntry entry, HeaderTest tests)1010    {1011      lock(baseStream_)1012      {1013        bool testHeader = (tests & HeaderTest.Header) != 0;1014        bool testData = (tests & HeaderTest.Extract) != 0;10151016        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);1017        if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {1018          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)1019        }10201021        var extractVersion = ( short ) (ReadLEUshort() & 0x00ff);1022        var localFlags = ( short )ReadLEUshort();1023        var compressionMethod = ( short )ReadLEUshort();1024        var fileTime = ( short )ReadLEUshort();1025        var fileDate = ( short )ReadLEUshort();1026        uint crcValue = ReadLEUint();1027        long compressedSize = ReadLEUint();1028        long size = ReadLEUint();1029        int storedNameLength = ReadLEUshort();1030        int extraDataLength = ReadLEUshort();10311032        byte[] nameData = new byte[storedNameLength];1033        StreamUtils.ReadFully(baseStream_, nameData);10341035        byte[] extraData = new byte[extraDataLength];1036        StreamUtils.ReadFully(baseStream_, extraData);991            if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance992              throw new ZipException("The library does not support the zip version required to extract this entry");993            }994          }995        }996997        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})", extractVersi1015          }10161017          // Local entry flags dont have reserved bit set on.1018          if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R1019            throw new ZipException("Reserved bit flags cannot be set.");1020          }10211022          // Encryption requires extract version >= 201023          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          }10261027          // 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            }10321033            if (extractVersion < 50) {1034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({01035            }1036          }  10371038        var localExtraData = new ZipExtraData(extraData);10391040        // Extra data / zip64 checks1041        if (localExtraData.Find(1))1042        {1043          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip641044          // and size or compressedSize = MaxValue, due to rogue creators.10451046          size = localExtraData.ReadLong();1047          compressedSize = localExtraData.ReadLong();10481049                    if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0)1050                    {1051                        // These may be valid if patched later1052                        if ( (size != -1) && (size != entry.Size)) {1053                            throw new ZipException("Size invalid for descriptor");1054                        }10551056                        if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {1057                            throw new ZipException("Compressed size invalid for descriptor");1058                        }1059                    }1060                }1061        else1062        {1063          // No zip64 extra data but entry requires it.1064          if ((extractVersion >= ZipConstants.VersionZip64) &&1065            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue)))1066          {1067            throw new ZipException("Required Zip64 extended information missing");1038          // Patched entries require extract version >= 271039          if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {1040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));1041          }10421043          // Central header flags match local entry flags.1044          if (localFlags != entry.Flags) {1045            throw new ZipException("Central header/local header flags mismatch");1046          }10471048          // Central header compression method matches local entry1049          if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {1050            throw new ZipException("Central header/local header compression method mismatch");1051          }10521053          if (entry.Version != extractVersion) {1054            throw new ZipException("Extract version mismatch");1055          }10561057          // Strong encryption and extract version match1058          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          }10631064          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        }10701071        if ( testData ) {1072          if ( entry.IsFile ) {1073            if ( !entry.IsCompressionMethodSupported() ) {1074              throw new ZipException("Compression method not supported");1075            }10761077            if ( (extractVersion > ZipConstants.VersionMadeBy)1078              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)) ) {1079              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract1080            }10811082            if ( (localFlags & ( int )(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enha1083              throw new ZipException("The library does not support the zip version required to extract this entry");1084            }1085          }1086        }10871088                if (testHeader)1089                {1090                    if ((extractVersion <= 63) &&  // Ignore later versions as we dont know about them..1091                        (extractVersion != 10) &&1092                        (extractVersion != 11) &&1093                        (extractVersion != 20) &&1094                        (extractVersion != 21) &&1095                        (extractVersion != 25) &&1096                        (extractVersion != 27) &&1097                        (extractVersion != 45) &&1098                        (extractVersion != 46) &&1099                        (extractVersion != 50) &&1100                        (extractVersion != 51) &&1101                        (extractVersion != 52) &&1102                        (extractVersion != 61) &&1103                        (extractVersion != 62) &&1104                        (extractVersion != 63)1105                        )1106                    {1107                        throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", 1108                    }11091110                    // Local entry flags dont have reserved bit set on.1111                    if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | General1112                    {1113                        throw new ZipException("Reserved bit flags cannot be set.");1114                    }11151116                    // Encryption requires extract version >= 201117                    if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20))1118                    {1119                        throw new ZipException(string.Format("Version required to extract this entry is too low for encr1120                    }11211122                    // Strong encryption requires encryption flag to be set and extract version >= 50.1123                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1124                    {1125                        if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0)1126                        {1127                            throw new ZipException("Strong encryption flag set but encryption flag is not set");1128                        }10691070          if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {1071            if (crcValue != (uint)entry.Crc) {1072              throw new ZipException("Central header/local header crc mismatch");1073            }1074          }10751076          // Crc valid for empty entry.1077          // This will also apply to streamed entries where size isnt known and the header cant be patched1078          if ((size == 0) && (compressedSize == 0)) {1079            if (crcValue != 0) {1080              throw new ZipException("Invalid CRC for empty entry");1081            }1082          }10831084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably1086          if (entry.Name.Length > storedNameLength) {1087            throw new ZipException("File name length mismatch");1088          }10891090          // Name data has already been read convert it and compare.1091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);10921093          // Central directory and local entry name match1094          if (localName != entry.Name) {1095            throw new ZipException("Central header and local header file name mismatch");1096          }10971098          // Directories have zero actual size but can have compressed size1099          if (entry.IsDirectory) {1100            if (size > 0) {1101              throw new ZipException("Directory cannot have size");1102            }11031104            // 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 bytes1112              // 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 bytes1114              throw new ZipException("Directory compressed size invalid");1115            }1116          }11171118          if (!ZipNameTransform.IsValidName(localName, true)) {1119            throw new ZipException("Name is invalid");1120          }1121        }11221123        // Tests that apply to both data and header.11241125        // 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)) {  11291130                        if (extractVersion < 50)1131                        {1132                            throw new ZipException(string.Format("Version required to extract this entry is too low for 1133                        }1134                    }11351136                    // Patched entries require extract version >= 271137                    if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27))1138                    {1139                        throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractV1140                    }11411142                    // Central header flags match local entry flags.1143                    if (localFlags != entry.Flags)1144                    {1145                        throw new ZipException("Central header/local header flags mismatch");1146                    }11471148                    // Central header compression method matches local entry1149                    if (entry.CompressionMethod != (CompressionMethod)compressionMethod)1150                    {1151                        throw new ZipException("Central header/local header compression method mismatch");1152                    }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          }11361137          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        }11441145        int extraLength = storedNameLength + extraDataLength;1146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;1147      }1148    }11491150    #endregion11511152    #region Updating  11531154                    if (entry.Version != extractVersion)1155                    {1156                        throw new ZipException("Extract version mismatch");1157                    }11581159                    // Strong encryption and extract version match1160                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1161                    {1162                        if (extractVersion < 62)1163                        {1164                            throw new ZipException("Strong encryption flag set but version not high enough");1165                        }1166                    }11671168                    if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0)1169                    {1170                        if ((fileTime != 0) || (fileDate != 0))1171                        {1172                            throw new ZipException("Header masked set but date/time values non-zero");1173                        }1174                    }11751176                    if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0)1177                    {1178                        if (crcValue != (uint)entry.Crc)1179                        {1180                            throw new ZipException("Central header/local header crc mismatch");1181                        }1182                    }11831184                    // Crc valid for empty entry.1185                    // This will also apply to streamed entries where size isnt known and the header cant be patched1186                    if ((size == 0) && (compressedSize == 0))1187                    {1188                        if (crcValue != 0)1189                        {1190                            throw new ZipException("Invalid CRC for empty entry");1191                        }1192                    }11931194                    // TODO: make test more correct...  can't compare lengths as was done originally as this can fail fo1195                    // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntr1196                    if (entry.Name.Length > storedNameLength)1197                    {1198                        throw new ZipException("File name length mismatch");1199                    }12001201                    // Name data has already been read convert it and compare.1202                    string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);12031204                    // Central directory and local entry name match1205                    if (localName != entry.Name)1206                    {1207                        throw new ZipException("Central header and local header file name mismatch");1208                    }12091210                    // Directories have zero actual size but can have compressed size1211                    if (entry.IsDirectory)1212                    {1213                        if (size > 0)1214                        {1215                            throw new ZipException("Directory cannot have size");1216                        }12171218                        // There may be other cases where the compressed size can be greater than this?1219                        // If so until details are known we will be strict.1220                        if (entry.IsCrypted)1221                        {1222                            if (compressedSize > ZipConstants.CryptoHeaderSize + 2)1223                            {1224                                throw new ZipException("Directory compressed size invalid");1225                            }1226                        }1227                        else if (compressedSize > 2)1228                        {1229                            // When not compressed the directory size can validly be 2 bytes1230                            // if the true size wasnt known when data was originally being written.1231                            // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes1232                            throw new ZipException("Directory compressed size invalid");1233                        }1234                    }12351236                    if (!ZipNameTransform.IsValidName(localName, true))1237                    {1238                        throw new ZipException("Name is invalid");1239                    }1240                }12411242        // Tests that apply to both data and header.1154    const int DefaultBufferSize = 4096;11551156    /// <summary>1157    /// The kind of update to apply.1158    /// </summary>1159    enum UpdateCommand1160    {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    }11651166    #region Properties1167    /// <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      }11741175      set {1176        updateEntryFactory_.NameTransform = value;1177      }1178    }11791180    /// <summary>1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1182    /// during updates.1183    /// </summary>1184    public IEntryFactory EntryFactory {1185      get {1186        return updateEntryFactory_;1187      }11881189      set {1190        if (value == null) {1191          updateEntryFactory_ = new ZipEntryFactory();1192        } else {1193          updateEntryFactory_ = value;1194        }1195      }1196    }11971198    /// <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        }12071208        if (bufferSize_ != value) {1209          bufferSize_ = value;1210          copyBuffer_ = null;1211        }1212      }1213    }12141215    /// <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    }12211222    /// <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    }12291230    #endregion12311232    #region Immediate updating1233    //    TBD: Direct form of updating1234    //1235    //    public void Update(IEntryMatcher deleteMatcher)1236    //    {1237    //    }1238    //1239    //    public void Update(IScanner addScanner)1240    //    {1241    //    }1242    #endregion  12431244        // Size can be verified only if it is known in the local header.1245        // it will always be known in the central header.1246        if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||1247          ((size > 0) || (compressedSize > 0))) {12481249          if (size != entry.Size) {1250            throw new ZipException(1251              string.Format("Size mismatch between central header({0}) and local header({1})",1252                entry.Size, size));1253          }12541255          if (compressedSize != entry.CompressedSize &&1256            compressedSize != 0xFFFFFFFF && compressedSize != -1) {1257            throw new ZipException(1258              string.Format("Compressed size mismatch between central header({0}) and local header({1})",1259              entry.CompressedSize, compressedSize));1260          }1261        }1244    #region Deferred Updating1245    /// <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.</p1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1250    /// <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      }12581259      if (dataSource == null) {1260        throw new ArgumentNullException(nameof(dataSource));1261      }  12621263        int extraLength = storedNameLength + extraDataLength;1264        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;1263      if (isDisposed_) {1264        throw new ObjectDisposedException("ZipFile");  1265      }1266    }12671268    #endregion12691270    #region Updating12711272    const int DefaultBufferSize = 4096;12661267      if (IsEmbeddedArchive) {1268        throw new ZipException("Cannot update embedded/SFX archives");1269      }12701271      archiveStorage_ = archiveStorage;1272      updateDataSource_ = dataSource;  12731274    /// <summary>1275    /// The kind of update to apply.1276    /// </summary>1277    enum UpdateCommand1278    {1279      Copy,       // Copy original file contents.1280      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.1281      Add,        // Add a new file to the archive.1282    }1274      // NOTE: the baseStream_ may not currently support writing or seeking.12751276      updateIndex_ = new Hashtable();12771278      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      }  12831284    #region Properties1285    /// <summary>1286    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.1287    /// </summary>1288    public INameTransform NameTransform1289    {1290      get {1291        return updateEntryFactory_.NameTransform;1292      }12931294      set {1295        updateEntryFactory_.NameTransform = value;1296      }1297    }12981299    /// <summary>1300    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1301    /// during updates.1302    /// </summary>1303    public IEntryFactory EntryFactory1304    {1305      get {1306        return updateEntryFactory_;1307      }13081309      set {1310        if (value == null) {1311          updateEntryFactory_ = new ZipEntryFactory();1312        }1313        else {1314          updateEntryFactory_ = value;1315        }1316      }1317    }13181319    /// <summary>1320    /// Get /set the buffer size to be used when updating this zip file.1321    /// </summary>1322    public int BufferSize1323    {1324      get { return bufferSize_; }1325      set {1326        if ( value < 1024 ) {1327#if NETCF_1_01328          throw new ArgumentOutOfRangeException("value");1329#else1330          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");1331#endif1332        }13331334        if ( bufferSize_ != value ) {1335          bufferSize_ = value;1336          copyBuffer_ = null;1337        }1338      }1339    }1284      // We must sort by offset before using offset's calculated sizes1285      updates_.Sort(new UpdateComparer());12861287      int idx = 0;1288      foreach (ZipUpdate update in updates_) {1289        //If last entry, there is no next entry offset to use1290        if (idx == updates_.Count - 1)1291          break;12921293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;1294        idx++;1295      }1296      updateCount_ = updates_.Count;12971298      contentsEdited_ = false;1299      commentEdited_ = false;1300      newComment_ = null;1301    }13021303    /// <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    }13111312    /// <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    }13261327    /// <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      }13381339      CheckUpdating();  13401341    /// <summary>1342    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.1343    /// </summary>1344    public bool IsUpdating1345    {1346      get { return updates_ != null; }1347    }13481349    /// <summary>1350    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.1351    /// </summary>1352    public UseZip64 UseZip641353    {1354      get { return useZip64_; }1355      set { useZip64_ = value; }1356    }13571358    #endregion13591360    #region Immediate updating1361//    TBD: Direct form of updating1362//1363//    public void Update(IEntryMatcher deleteMatcher)1364//    {1365//    }1366//1367//    public void Update(IScanner addScanner)1368//    {1369//    }1370    #endregion13711372    #region Deferred Updating1373    /// <summary>1374    /// Begin updating this <see cref="ZipFile"/> archive.1375    /// </summary>1376    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p1377    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1341      try {1342        updateIndex_.Clear();1343        updateIndex_ = null;13441345        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        }13581359      } finally {1360        PostUpdateCleanup();1361      }1362    }13631364    /// <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    }13731374    /// <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    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>1380    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1381    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)1382    {1383      if ( archiveStorage == null ) {1384        throw new ArgumentNullException(nameof(archiveStorage));1385      }1379    public void SetComment(string comment)1380    {1381      if (isDisposed_) {1382        throw new ObjectDisposedException("ZipFile");1383      }13841385      CheckUpdating();  13861387      if ( dataSource == null ) {1388        throw new ArgumentNullException(nameof(dataSource));1389      }13901391      if ( isDisposed_ ) {1392        throw new ObjectDisposedException("ZipFile");1393      }13941395      if ( IsEmbeddedArchive ) {1396        throw new ZipException ("Cannot update embedded/SFX archives");1397      }1387      newComment_ = new ZipString(comment);13881389      if (newComment_.RawLength > 0xffff) {1390        newComment_ = null;1391        throw new ZipException("Comment length exceeds maximum - 65535");1392      }13931394      // We dont take account of the original and current comment appearing to be the same1395      // as encoding may be different.1396      commentEdited_ = true;1397    }  13981399      archiveStorage_ = archiveStorage;1400      updateDataSource_ = dataSource;14011402      // NOTE: the baseStream_ may not currently support writing or seeking.14031404      updateIndex_ = new Hashtable();14051406      updates_ = new ArrayList(entries_.Length);1407      foreach(ZipEntry entry in entries_) {1408        int index = updates_.Add(new ZipUpdate(entry));1409        updateIndex_.Add(entry.Name, index);1410      }14111412      // We must sort by offset before using offset's calculated sizes1413      updates_.Sort(new UpdateComparer());14141415      int idx = 0;1416      foreach (ZipUpdate update in updates_) {1417        //If last entry, there is no next entry offset to use1418        if (idx == updates_.Count - 1)1419          break;14201421        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;1422        idx++;1423      }1424      updateCount_ = updates_.Count;14251426      contentsEdited_ = false;1427      commentEdited_ = false;1428      newComment_ = null;1429    }14301431    /// <summary>1432    /// Begin updating to this <see cref="ZipFile"/> archive.1433    /// </summary>1434    /// <param name="archiveStorage">The storage to use during the update.</param>1435    public void BeginUpdate(IArchiveStorage archiveStorage)1436    {1437      BeginUpdate(archiveStorage, new DynamicDiskDataSource());1438    }14391440    /// <summary>1441    /// Begin updating this <see cref="ZipFile"/> archive.1442    /// </summary>1443    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>1444    /// <seealso cref="CommitUpdate"></seealso>1445    /// <seealso cref="AbortUpdate"></seealso>1446    public void BeginUpdate()1447    {1448      if ( Name == null ) {1449        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());1450      }1451      else {1452        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());1453      }1399    #endregion14001401    #region Adding Entries14021403    void AddUpdate(ZipUpdate update)1404    {1405      contentsEdited_ = true;14061407      int index = FindExistingUpdate(update.Entry.Name);14081409      if (index >= 0) {1410        if (updates_[index] == null) {1411          updateCount_ += 1;1412        }14131414        // 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    }14221423    /// <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      }14371438      if (isDisposed_) {1439        throw new ObjectDisposedException("ZipFile");1440      }14411442      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1444      }14451446      CheckUpdating();1447      contentsEdited_ = true;14481449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1450      entry.IsUnicodeText = useUnicodeText;1451      entry.CompressionMethod = compressionMethod;14521453      AddUpdate(new ZipUpdate(fileName, entry));  1454    }  1455  1456    /// <summary>1457    /// Commit current updates, updating this archive.1457    /// Add a new entry to the archive.  1458    /// </summary>1459    /// <seealso cref="BeginUpdate()"></seealso>1460    /// <seealso cref="AbortUpdate"></seealso>1461    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1462    public void CommitUpdate()1463    {1464      if ( isDisposed_ ) {1465        throw new ObjectDisposedException("ZipFile");1466      }14671468      CheckUpdating();14691470      try {1471        updateIndex_.Clear();1472        updateIndex_=null;14731474        if( contentsEdited_ ) {1475          RunUpdates();1476        }1477        else if( commentEdited_ ) {1478          UpdateCommentOnly();1479        }1480        else {1481          // Create an empty archive if none existed originally.1482          if( entries_.Length==0 ) {1483            byte[] theComment=(newComment_!=null)?newComment_.RawComment:ZipConstants.ConvertToArray(comment_);1484            using( ZipHelperStream zhs=new ZipHelperStream(baseStream_) ) {1485              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);1486            }1487          }1488        }14891459    /// <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      }14681469      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1471      }14721473      CheckUpdating();1474      contentsEdited_ = true;14751476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1477      entry.CompressionMethod = compressionMethod;1478      AddUpdate(new ZipUpdate(fileName, entry));1479    }14801481    /// <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      finally {1492        PostUpdateCleanup();1493      }14911492      CheckUpdating();1493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));  1494    }  1495  1496    /// <summary>1497    /// Abort updating leaving the archive unchanged.1497    /// Add a file to the archive.  1498    /// </summary>1499    /// <seealso cref="BeginUpdate()"></seealso>1500    /// <seealso cref="CommitUpdate"></seealso>1501    public void AbortUpdate()1502    {1503      PostUpdateCleanup();1504    }15051506    /// <summary>1507    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.1508    /// </summary>1509    /// <param name="comment">The comment to record.</param>1510    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1511    public void SetComment(string comment)1512    {1513      if ( isDisposed_ ) {1514        throw new ObjectDisposedException("ZipFile");1515      }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      }15071508      if (entryName == null) {1509        throw new ArgumentNullException(nameof(entryName));1510      }15111512      CheckUpdating();1513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));1514    }1515  15161517      CheckUpdating();15181519      newComment_ = new ZipString(comment);15201521      if ( newComment_.RawLength  > 0xffff ) {1522        newComment_ = null;1523        throw new ZipException("Comment length exceeds maximum - 65535");1524      }15251526      // We dont take account of the original and current comment appearing to be the same1527      // as encoding may be different.1528      commentEdited_ = true;1529    }15301531    #endregion15321533    #region Adding Entries15341535    void AddUpdate(ZipUpdate update)1536    {1537      contentsEdited_ = true;15381539      int index = FindExistingUpdate(update.Entry.Name);15401541      if (index >= 0) {1542        if ( updates_[index] == null ) {1543          updateCount_ += 1;1544        }15451546        // Direct replacement is faster than delete and add.1547        updates_[index] = update;1548      }1549      else {1550        index = updates_.Add(update);1551        updateCount_ += 1;1552        updateIndex_.Add(update.Entry.Name, index);1553      }1554    }15551556    /// <summary>1557    /// Add a new entry to the archive.1558    /// </summary>1559    /// <param name="fileName">The name of the file to add.</param>1560    /// <param name="compressionMethod">The compression method to use.</param>1561    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>1562    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1563    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1564    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>1565    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText )1566    {1567      if (fileName == null) {1568        throw new ArgumentNullException(nameof(fileName));1569      }15701571      if ( isDisposed_ ) {1572        throw new ObjectDisposedException("ZipFile");1573      }15741575      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1576        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1577      }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      }15271528      if (entryName == null) {1529        throw new ArgumentNullException(nameof(entryName));1530      }15311532      CheckUpdating();1533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));1534    }15351536    /// <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      }15471548      if (entryName == null) {1549        throw new ArgumentNullException(nameof(entryName));1550      }15511552      CheckUpdating();15531554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1555      entry.CompressionMethod = compressionMethod;15561557      AddUpdate(new ZipUpdate(dataSource, entry));1558    }15591560    /// <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 useUnicode1568    {1569      if (dataSource == null) {1570        throw new ArgumentNullException(nameof(dataSource));1571      }15721573      if (entryName == null) {1574        throw new ArgumentNullException(nameof(entryName));1575      }15761577      CheckUpdating();  15781579      CheckUpdating();1580      contentsEdited_ = true;15811582      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1583      entry.IsUnicodeText = useUnicodeText;1584      entry.CompressionMethod = compressionMethod;1579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1580      entry.IsUnicodeText = useUnicodeText;1581      entry.CompressionMethod = compressionMethod;15821583      AddUpdate(new ZipUpdate(dataSource, entry));1584    }  15851586      AddUpdate(new ZipUpdate(fileName, entry));1587    }15881589    /// <summary>1590    /// Add a new entry to the archive.1591    /// </summary>1592    /// <param name="fileName">The name of the file to add.</param>1593    /// <param name="compressionMethod">The compression method to use.</param>1594    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>1595    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>1596    public void Add(string fileName, CompressionMethod compressionMethod)1597    {1598      if ( fileName == null ) {1599        throw new ArgumentNullException(nameof(fileName));1600      }16011602      if ( !ZipEntry.IsCompressionMethodSupported(compressionMethod) ) {1603        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1604      }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      }15961597      CheckUpdating();15981599      if ((entry.Size != 0) || (entry.CompressedSize != 0)) {1600        throw new ZipException("Entry cannot have any data");1601      }16021603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));1604    }  16051606      CheckUpdating();1607      contentsEdited_ = true;16081609      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1610      entry.CompressionMethod = compressionMethod;1611      AddUpdate(new ZipUpdate(fileName, entry));1612    }16131614    /// <summary>1615    /// Add a file to the archive.1616    /// </summary>1617    /// <param name="fileName">The name of the file to add.</param>1618    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1619    public void Add(string fileName)1620    {1621      if ( fileName == null ) {1622        throw new ArgumentNullException(nameof(fileName));1623      }16241625      CheckUpdating();1626      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));1627    }16281629    /// <summary>1630    /// Add a file to the archive.1631    /// </summary>1632    /// <param name="fileName">The name of the file to add.</param>1633    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>1634    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1635    public void Add(string fileName, string entryName)1636    {1637      if (fileName == null) {1638        throw new ArgumentNullException(nameof(fileName));1639      }16401641      if ( entryName == null ) {1642        throw new ArgumentNullException(nameof(entryName));1643      }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      }16151616      CheckUpdating();16171618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);1619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));1620    }16211622    #endregion16231624    #region Modifying Entries1625    /* 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          }16331634          if ( updated == null ) {1635            throw new ArgumentNullException("updated");1636          }16371638          CheckUpdating();1639          contentsEdited_ = true;1640          updates_.Add(new ZipUpdate(original, updated));1641        }1642    */1643    #endregion  16441645      CheckUpdating();1646      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));1647    }164816491650    /// <summary>1651    /// Add a file entry with data.1652    /// </summary>1653    /// <param name="dataSource">The source of the data for this entry.</param>1654    /// <param name="entryName">The name to give to the entry.</param>1655    public void Add(IStaticDataSource dataSource, string entryName)1656    {1657      if ( dataSource == null ) {1658        throw new ArgumentNullException(nameof(dataSource));1659      }16601661      if ( entryName == null ) {1662        throw new ArgumentNullException(nameof(entryName));1663      }16641665      CheckUpdating();1666      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));1667    }16681669    /// <summary>1670    /// Add a file entry with data.1671    /// </summary>1672    /// <param name="dataSource">The source of the data for this entry.</param>1673    /// <param name="entryName">The name to give to the entry.</param>1674    /// <param name="compressionMethod">The compression method to use.</param>1675    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)1676    {1677      if ( dataSource == null ) {1678        throw new ArgumentNullException(nameof(dataSource));1679      }16801681      if ( entryName == null ) {1682        throw new ArgumentNullException(nameof(entryName));1683      }16841685      CheckUpdating();16861687      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1688      entry.CompressionMethod = compressionMethod;16891690      AddUpdate(new ZipUpdate(dataSource, entry));1691    }16921693    /// <summary>1694    /// Add a file entry with data.1695    /// </summary>1696    /// <param name="dataSource">The source of the data for this entry.</param>1697    /// <param name="entryName">The name to give to the entry.</param>1698    /// <param name="compressionMethod">The compression method to use.</param>1699    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>1700    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode1701    {1702      if (dataSource == null) {1703        throw new ArgumentNullException(nameof(dataSource));1704      }17051706      if ( entryName == null ) {1707        throw new ArgumentNullException(nameof(entryName));1708      }17091710      CheckUpdating();17111712      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1713      entry.IsUnicodeText = useUnicodeText;1714      entry.CompressionMethod = compressionMethod;17151716      AddUpdate(new ZipUpdate(dataSource, entry));1717    }17181719    /// <summary>1720    /// Add a <see cref="ZipEntry"/> that contains no data.1721    /// </summary>1722    /// <param name="entry">The entry to add.</param>1723    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>1724    public void Add(ZipEntry entry)1725    {1726      if ( entry == null ) {1727        throw new ArgumentNullException(nameof(entry));1728      }17291730      CheckUpdating();1645    #region Deleting Entries1646    /// <summary>1647    /// Delete an entry by name1648    /// </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      }16561657      CheckUpdating();16581659      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    }16711672    /// <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      }16811682      CheckUpdating();16831684      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    }16931694    #endregion16951696    #region Update Support16971698    #region Writing Values/Headers1699    void WriteLEShort(int value)1700    {1701      baseStream_.WriteByte((byte)(value & 0xff));1702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));1703    }17041705    /// <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    }17131714    /// <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    }17221723    /// <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    }  17311732      if ( (entry.Size != 0) || (entry.CompressedSize != 0) ) {1733        throw new ZipException("Entry cannot have any data");1734      }17351736      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));1737    }17381739    /// <summary>1740    /// Add a directory entry to the archive.1741    /// </summary>1742    /// <param name="directoryName">The directory to add.</param>1743    public void AddDirectory(string directoryName)1744    {1745      if ( directoryName == null ) {1746        throw new ArgumentNullException(nameof(directoryName));1747      }17481749      CheckUpdating();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    }17401741    void WriteLEUlong(ulong value)1742    {1743      WriteLEUint((uint)(value & 0xffffffff));1744      WriteLEUint((uint)(value >> 32));1745    }17461747    void WriteLocalEntryHeader(ZipUpdate update)1748    {1749      ZipEntry entry = update.OutEntry;  17501751      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);1752      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));1753    }17541755    #endregion17561757    #region Modifying Entries1758/* Modify not yet ready for public consumption.1759   Direct modification of an entry should not overwrite original data before its read.1760   Safe mode is trivial in this sense.1761    public void Modify(ZipEntry original, ZipEntry updated)1762    {1763      if ( original == null ) {1764        throw new ArgumentNullException("original");1765      }1751      // TODO: Local offset will require adjusting for multi-disk zip files.1752      entry.Offset = baseStream_.Position;17531754      // 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        }  17661767      if ( updated == null ) {1768        throw new ArgumentNullException("updated");1769      }17701771      CheckUpdating();1772      contentsEdited_ = true;1773      updates_.Add(new ZipUpdate(original, updated));1774    }1775*/1776    #endregion17771778    #region Deleting Entries1779    /// <summary>1780    /// Delete an entry by name1781    /// </summary>1782    /// <param name="fileName">The filename to delete</param>1783    /// <returns>True if the entry was found and deleted; false otherwise.</returns>1784    public bool Delete(string fileName)1785    {1786      if ( fileName == null ) {1787        throw new ArgumentNullException(nameof(fileName));1788      }17891790      CheckUpdating();17911792      bool result = false;1793      int index = FindExistingUpdate(fileName);1794      if ( (index >= 0) && (updates_[index] != null) ) {1795        result = true;1796        contentsEdited_ = true;1797        updates_[index] = null;1798        updateCount_ -= 1;1799      }1800      else {1801        throw new ZipException("Cannot find entry to delete");1802      }1803      return result;1804    }18051806    /// <summary>1807    /// Delete a <see cref="ZipEntry"/> from the archive.1808    /// </summary>1809    /// <param name="entry">The entry to delete.</param>1810    public void Delete(ZipEntry entry)1811    {1812      if ( entry == null ) {1813        throw new ArgumentNullException(nameof(entry));1814      }18151816      CheckUpdating();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        }17751776        switch (useZip64_) {1777          case UseZip64.Dynamic:1778            if (entry.Size < 0) {1779              entry.ForceZip64();1780            }1781            break;17821783          case UseZip64.On:1784            entry.ForceZip64();1785            break;17861787          case UseZip64.Off:1788            // Do nothing.  The entry itself may be using Zip64 independantly.1789            break;1790        }1791      }17921793      // Write the local file header1794      WriteLEInt(ZipConstants.LocalHeaderSignature);17951796      WriteLEShort(entry.Version);1797      WriteLEShort(entry.Flags);17981799      WriteLEShort((byte)entry.CompressionMethod);1800      WriteLEInt((int)entry.DosTime);18011802      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      }18091810      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        }  18171818      int index = FindExistingUpdate(entry);1819      if ( index >= 0 ) {1820        contentsEdited_ = true;1821        updates_[index] = null;1822        updateCount_ -= 1;1823      }1824      else {1825        throw new ZipException("Cannot find entry to delete");1818        WriteLEInt((int)entry.CompressedSize);1819        WriteLEInt((int)entry.Size);1820      }18211822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);18231824      if (name.Length > 0xFFFF) {1825        throw new ZipException("Entry name too long.");  1826      }1827    }18281829    #endregion18301831    #region Update Support18271828      var ed = new ZipExtraData(entry.ExtraData);18291830      if (entry.LocalHeaderRequiresZip64) {1831        ed.StartNewEntry();  18321833    #region Writing Values/Headers1834    void WriteLEShort(int value)1835    {1836      baseStream_.WriteByte(( byte )(value & 0xff));1837      baseStream_.WriteByte(( byte )((value >> 8) & 0xff));1838    }18391840    /// <summary>1841    /// Write an unsigned short in little endian byte order.1842    /// </summary>1843    void WriteLEUshort(ushort value)1844    {1845      baseStream_.WriteByte(( byte )(value & 0xff));1846      baseStream_.WriteByte(( byte )(value >> 8));1847    }18481849    /// <summary>1850    /// Write an int in little endian byte order.1851    /// </summary>1852    void WriteLEInt(int value)1853    {1854      WriteLEShort(value & 0xffff);1855      WriteLEShort(value >> 16);1856    }18571858    /// <summary>1859    /// Write an unsigned int in little endian byte order.1860    /// </summary>1861    void WriteLEUint(uint value)1862    {1863      WriteLEUshort((ushort)(value & 0xffff));1864      WriteLEUshort((ushort)(value >> 16));1865    }18661867    /// <summary>1868    /// Write a long in little endian byte order.1869    /// </summary>1870    void WriteLeLong(long value)1871    {1872      WriteLEInt(( int )(value & 0xffffffff));1873      WriteLEInt(( int )(value >> 32));1874    }18751876    void WriteLEUlong(ulong value)1877    {1878      WriteLEUint(( uint )(value & 0xffffffff));1879      WriteLEUint(( uint )(value >> 32));1880    }18811882    void WriteLocalEntryHeader(ZipUpdate update)1883    {1884      ZipEntry entry = update.OutEntry;18851886      // TODO: Local offset will require adjusting for multi-disk zip files.1887      entry.Offset = baseStream_.Position;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      }18411842      entry.ExtraData = ed.GetEntryData();18431844      WriteLEShort(name.Length);1845      WriteLEShort(entry.ExtraData.Length);18461847      if (name.Length > 0) {1848        baseStream_.Write(name, 0, name.Length);1849      }18501851      if (entry.LocalHeaderRequiresZip64) {1852        if (!ed.Find(1)) {1853          throw new ZipException("Internal error cannot find extra data");1854        }18551856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1857      }18581859      if (entry.ExtraData.Length > 0) {1860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);1861      }1862    }18631864    int WriteCentralDirectoryHeader(ZipEntry entry)1865    {1866      if (entry.CompressedSize < 0) {1867        throw new ZipException("Attempt to write central directory entry with unknown csize");1868      }18691870      if (entry.Size < 0) {1871        throw new ZipException("Attempt to write central directory entry with unknown size");1872      }18731874      if (entry.Crc < 0) {1875        throw new ZipException("Attempt to write central directory entry with unknown crc");1876      }18771878      // Write the central file header1879      WriteLEInt(ZipConstants.CentralHeaderSignature);18801881      // Version made by1882      WriteLEShort(ZipConstants.VersionMadeBy);18831884      // Version required to extract1885      WriteLEShort(entry.Version);18861887      WriteLEShort(entry.Flags);  18881889      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.1890      if (update.Command != UpdateCommand.Copy) {1891        if (entry.CompressionMethod == CompressionMethod.Deflated) {1892          if (entry.Size == 0) {1893            // No need to compress - no data.1894            entry.CompressedSize = entry.Size;1895            entry.Crc = 0;1896            entry.CompressionMethod = CompressionMethod.Stored;1897          }1898        }1899        else if (entry.CompressionMethod == CompressionMethod.Stored) {1900          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;1901        }19021903        if (HaveKeys) {1904          entry.IsCrypted = true;1905          if (entry.Crc < 0) {1906            entry.Flags |= (int)GeneralBitFlags.Descriptor;1907          }1908        }1909        else {1910          entry.IsCrypted = false;1911        }1889      unchecked {1890        WriteLEShort((byte)entry.CompressionMethod);1891        WriteLEInt((int)entry.DosTime);1892        WriteLEInt((int)entry.Crc);1893      }18941895      if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {1896        WriteLEInt(-1);1897      } else {1898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));1899      }19001901      if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {1902        WriteLEInt(-1);1903      } else {1904        WriteLEInt((int)entry.Size);1905      }19061907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);19081909      if (name.Length > 0xFFFF) {1910        throw new ZipException("Entry name is too long.");1911      }  19121913        switch (useZip64_) {1914          case UseZip64.Dynamic:1915            if (entry.Size < 0) {1916              entry.ForceZip64();1917            }1918            break;19191920          case UseZip64.On:1921            entry.ForceZip64();1922            break;19231924          case UseZip64.Off:1925            // Do nothing.  The entry itself may be using Zip64 independantly.1926            break;1913      WriteLEShort(name.Length);19141915      // Central header extra data is different to local header version so regenerate.1916      var ed = new ZipExtraData(entry.ExtraData);19171918      if (entry.CentralHeaderRequiresZip64) {1919        ed.StartNewEntry();19201921        if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {1922          ed.AddLeLong(entry.Size);1923        }19241925        if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {1926          ed.AddLeLong(entry.CompressedSize);  1927        }1928      }19291930      // Write the local file header1931      WriteLEInt(ZipConstants.LocalHeaderSignature);19281929        if (entry.Offset >= 0xffffffff) {1930          ed.AddLeLong(entry.Offset);1931        }  19321933      WriteLEShort(entry.Version);1934      WriteLEShort(entry.Flags);19351936      WriteLEShort((byte)entry.CompressionMethod);1937      WriteLEInt(( int )entry.DosTime);19381939      if ( !entry.HasCrc ) {1940        // Note patch address for updating CRC later.1941        update.CrcPatchOffset = baseStream_.Position;1942        WriteLEInt(( int )0);1943      }1944      else {1945        WriteLEInt(unchecked(( int )entry.Crc));1946      }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      }19391940      byte[] centralExtraData = ed.GetEntryData();19411942      WriteLEShort(centralExtraData.Length);1943      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);19441945      WriteLEShort(0);    // disk number1946      WriteLEShort(0);    // internal file attributes  19471948      if (entry.LocalHeaderRequiresZip64) {1949        WriteLEInt(-1);1950        WriteLEInt(-1);1951      }1952      else {1953        if ( (entry.CompressedSize < 0) || (entry.Size < 0) ) {1954          update.SizePatchOffset = baseStream_.Position;1955        }19561957        WriteLEInt(( int )entry.CompressedSize);1958        WriteLEInt(( int )entry.Size);1959      }19601961      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);19621963      if ( name.Length > 0xFFFF ) {1964        throw new ZipException("Entry name too long.");1965      }19661967      var ed = new ZipExtraData(entry.ExtraData);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      }19581959      if (entry.Offset >= 0xffffffff) {1960        WriteLEUint(0xffffffff);1961      } else {1962        WriteLEUint((uint)(int)entry.Offset);1963      }19641965      if (name.Length > 0) {1966        baseStream_.Write(name, 0, name.Length);1967      }  19681969      if ( entry.LocalHeaderRequiresZip64 ) {1970        ed.StartNewEntry();19711972        // Local entry header always includes size and compressed size.1973        // NOTE the order of these fields is reversed when compared to the normal headers!1974        ed.AddLeLong(entry.Size);1975        ed.AddLeLong(entry.CompressedSize);1976        ed.AddNewEntry(1);1969      if (centralExtraData.Length > 0) {1970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);1971      }19721973      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];19741975      if (rawComment.Length > 0) {1976        baseStream_.Write(rawComment, 0, rawComment.Length);  1977      }1978      else {1979        ed.Delete(1);1980      }19811982      entry.ExtraData = ed.GetEntryData();19831984      WriteLEShort(name.Length);1985      WriteLEShort(entry.ExtraData.Length);19861987      if ( name.Length > 0 ) {1988        baseStream_.Write(name, 0, name.Length);1989      }19901991      if ( entry.LocalHeaderRequiresZip64 ) {1992        if ( !ed.Find(1) ) {1993          throw new ZipException("Internal error cannot find extra data");1994        }19951996        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1997      }19981999      if ( entry.ExtraData.Length > 0 ) {2000        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);2001      }2002    }20032004    int WriteCentralDirectoryHeader(ZipEntry entry)2005    {2006      if ( entry.CompressedSize < 0 ) {2007        throw new ZipException("Attempt to write central directory entry with unknown csize");2008      }20092010      if ( entry.Size < 0 ) {2011        throw new ZipException("Attempt to write central directory entry with unknown size");2012      }20132014      if ( entry.Crc < 0 ) {2015        throw new ZipException("Attempt to write central directory entry with unknown crc");2016      }20172018      // Write the central file header2019      WriteLEInt(ZipConstants.CentralHeaderSignature);20202021      // Version made by2022      WriteLEShort(ZipConstants.VersionMadeBy);20232024      // Version required to extract2025      WriteLEShort(entry.Version);19781979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;1980    }1981    #endregion19821983    void PostUpdateCleanup()1984    {1985      updateDataSource_ = null;1986      updates_ = null;1987      updateIndex_ = null;19881989      if (archiveStorage_ != null) {1990        archiveStorage_.Dispose();1991        archiveStorage_ = null;1992      }1993    }19941995    string GetTransformedFileName(string name)1996    {1997      INameTransform transform = NameTransform;1998      return (transform != null) ?1999        transform.TransformFile(name) :2000        name;2001    }20022003    string GetTransformedDirectoryName(string name)2004    {2005      INameTransform transform = NameTransform;2006      return (transform != null) ?2007        transform.TransformDirectory(name) :2008        name;2009    }20102011    /// <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    }20222023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2024    {2025      int bytesToCopy = GetDescriptorSize(update);  20262027      WriteLEShort(entry.Flags);20282029      unchecked {2030        WriteLEShort((byte)entry.CompressionMethod);2031        WriteLEInt((int)entry.DosTime);2032        WriteLEInt((int)entry.Crc);2033      }20342035      if ( (entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff) ) {2036        WriteLEInt(-1);2037      }2038      else {2039        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));2040      }20412042      if ( (entry.IsZip64Forced()) || (entry.Size >= 0xffffffff) ) {2043        WriteLEInt(-1);2044      }2045      else {2046        WriteLEInt((int)entry.Size);2047      }20482049      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);2027      if (bytesToCopy > 0) {2028        byte[] buffer = GetBuffer();20292030        while (bytesToCopy > 0) {2031          int readSize = Math.Min(buffer.Length, bytesToCopy);20322033          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    }20432044    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      }  20502051      if ( name.Length > 0xFFFF ) {2052        throw new ZipException("Entry name is too long.");2053      }2051      // NOTE: Compressed size is updated elsewhere.2052      var crc = new Crc32();2053      byte[] buffer = GetBuffer();  20542055      WriteLEShort(name.Length);20562057      // Central header extra data is different to local header version so regenerate.2058      var ed = new ZipExtraData(entry.ExtraData);20592060      if ( entry.CentralHeaderRequiresZip64 ) {2061        ed.StartNewEntry();20622063        if ( (entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On) )2064        {2065          ed.AddLeLong(entry.Size);2066        }20672068        if ( (entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On) )2069        {2070          ed.AddLeLong(entry.CompressedSize);2071        }20722073        if ( entry.Offset >= 0xffffffff ) {2074          ed.AddLeLong(entry.Offset);2075        }20762077        // Number of disk on which this file starts isnt supported and is never written here.2078        ed.AddNewEntry(1);2079      }2080      else {2081        // Should have already be done when local header was added.2082        ed.Delete(1);2083      }20842085      byte[] centralExtraData = ed.GetEntryData();2055      long targetBytes = bytesToCopy;2056      long totalBytesRead = 0;20572058      int bytesRead;2059      do {2060        int readSize = buffer.Length;20612062        if (bytesToCopy < readSize) {2063          readSize = (int)bytesToCopy;2064        }20652066        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));20772078      if (totalBytesRead != targetBytes) {2079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2080      }20812082      if (updateCrc) {2083        update.OutEntry.Crc = crc.Value;2084      }2085    }  20862087      WriteLEShort(centralExtraData.Length);2088      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);20892090      WriteLEShort(0);  // disk number2091      WriteLEShort(0);  // internal file attributes20922093      // External file attributes...2094      if ( entry.ExternalFileAttributes != -1 ) {2095        WriteLEInt(entry.ExternalFileAttributes);2096      }2097      else {2098        if ( entry.IsDirectory ) {2099          WriteLEUint(16);2100        }2101        else {2102          WriteLEUint(0);2103        }2104      }21052106      if ( entry.Offset >= 0xffffffff ) {2107        WriteLEUint(0xffffffff);2108      }2109      else {2110        WriteLEUint((uint)(int)entry.Offset);2111      }21122113      if ( name.Length > 0 ) {2114        baseStream_.Write(name, 0, name.Length);2115      }21162117      if ( centralExtraData.Length > 0 ) {2118        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);2119      }21202121      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];21222123      if ( rawComment.Length > 0 ) {2124        baseStream_.Write(rawComment, 0, rawComment.Length);2125      }21262127      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;2128    }2129    #endregion21302131    void PostUpdateCleanup()2132    {2133            updateDataSource_ = null;2134            updates_ = null;2135            updateIndex_ = null;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    }21032104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2105    {2106      int bytesToCopy = GetDescriptorSize(update);21072108      while (bytesToCopy > 0) {2109        var readSize = (int)bytesToCopy;2110        byte[] buffer = GetBuffer();21112112        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    }21252126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2127    {2128      long bytesToCopy = update.Entry.CompressedSize;21292130      // NOTE: Compressed size is updated elsewhere.2131      var crc = new Crc32();2132      byte[] buffer = GetBuffer();21332134      long targetBytes = bytesToCopy;2135      long totalBytesRead = 0;  21362137            if (archiveStorage_ != null)2138            {2139        archiveStorage_.Dispose();2140        archiveStorage_=null;2141      }2142    }21432144    string GetTransformedFileName(string name)2145    {2146            INameTransform transform = NameTransform;2147      return (transform != null) ?2148        transform.TransformFile(name) :2149        name;2150    }21512152    string GetTransformedDirectoryName(string name)2153    {2154            INameTransform transform = NameTransform;2155            return (transform != null) ?2156        transform.TransformDirectory(name) :2157        name;2158    }21592160    /// <summary>2161    /// Get a raw memory buffer.2162    /// </summary>2163    /// <returns>Returns a raw memory buffer.</returns>2164    byte[] GetBuffer()2165    {2166      if ( copyBuffer_ == null ) {2167        copyBuffer_ = new byte[bufferSize_];2137      int bytesRead;2138      do {2139        int readSize = buffer.Length;21402141        if (bytesToCopy < readSize) {2142          readSize = (int)bytesToCopy;2143        }21442145        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);21532154          destinationPosition += bytesRead;2155          sourcePosition += bytesRead;2156          bytesToCopy -= bytesRead;2157          totalBytesRead += bytesRead;2158        }2159      }2160      while ((bytesRead > 0) && (bytesToCopy > 0));21612162      if (totalBytesRead != targetBytes) {2163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2164      }21652166      if (updateCrc) {2167        update.OutEntry.Crc = crc.Value;  2168      }2169      return copyBuffer_;2170    }21712172    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2173    {2174      int bytesToCopy = GetDescriptorSize(update);2169    }21702171    int FindExistingUpdate(ZipEntry entry)2172    {2173      int result = -1;2174      string convertedName = GetTransformedFileName(entry.Name);  21752176      if ( bytesToCopy > 0 ) {2177        byte[] buffer = GetBuffer();21782179        while ( bytesToCopy > 0 ) {2180          int readSize = Math.Min(buffer.Length, bytesToCopy);21812182          int bytesRead = source.Read(buffer, 0, readSize);2183          if ( bytesRead > 0 ) {2184            dest.Write(buffer, 0, bytesRead);2185            bytesToCopy -= bytesRead;2186          }2187          else {2188            throw new ZipException("Unxpected end of stream");2189          }2190        }2191      }2192    }21932194    void CopyBytes(ZipUpdate update, Stream destination, Stream source,2195      long bytesToCopy, bool updateCrc)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 useful2181            // 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    }21942195    int FindExistingUpdate(string fileName)  2196    {2197      if ( destination == source ) {2198        throw new InvalidOperationException("Destination and source are the same");2199      }2197      int result = -1;21982199      string convertedName = GetTransformedFileName(fileName);  22002201      // NOTE: Compressed size is updated elsewhere.2202      var crc = new Crc32();2203      byte[] buffer = GetBuffer();2201      if (updateIndex_.ContainsKey(convertedName)) {2202        result = (int)updateIndex_[convertedName];2203      }  22042205      long targetBytes = bytesToCopy;2206      long totalBytesRead = 0;22072208      int bytesRead;2209      do {2210        int readSize = buffer.Length;22112212        if ( bytesToCopy < readSize ) {2213          readSize = (int)bytesToCopy;2214        }22152216        bytesRead = source.Read(buffer, 0, readSize);2217        if ( bytesRead > 0 ) {2218          if ( updateCrc ) {2219            crc.Update(buffer, 0, bytesRead);2220          }2221          destination.Write(buffer, 0, bytesRead);2222          bytesToCopy -= bytesRead;2223          totalBytesRead += bytesRead;2224        }2225      }2226      while ( (bytesRead > 0) && (bytesToCopy > 0) );22272228      if ( totalBytesRead != targetBytes ) {2229        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2230      }22312232      if ( updateCrc ) {2233        update.OutEntry.Crc = crc.Value;2234      }2235    }22362237    /// <summary>2238    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.2239    /// </summary>2240    /// <param name="update">The update to get the size for.</param>2241    /// <returns>The descriptor size, zero if there isnt one.</returns>2242    int GetDescriptorSize(ZipUpdate update)2243    {2244      int result = 0;2245      if ( (update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {2246        result = ZipConstants.DataDescriptorSize - 4;2247        if ( update.Entry.LocalHeaderRequiresZip64 ) {2248          result = ZipConstants.Zip64DataDescriptorSize - 4;2249        }2250      }2251      return result;2252    }2205      /*2206            // This is slow like the coming of the next ice age but takes less storage and may be useful2207            // 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       */22162217      return result;2218    }22192220    /// <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_;22282229      if (entry.IsCrypted == true) {2230        result = CreateAndInitEncryptionStream(result, entry);2231      }22322233      switch (entry.CompressionMethod) {2234        case CompressionMethod.Stored:2235          result = new UncompressedStream(result);2236          break;22372238        case CompressionMethod.Deflated:2239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));2240          dos.IsStreamOwner = false;2241          result = dos;2242          break;22432244        default:2245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2246      }2247      return result;2248    }22492250    void AddEntry(ZipFile workFile, ZipUpdate update)2251    {2252      Stream source = null;  22532254    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2255    {2256      int bytesToCopy = GetDescriptorSize(update);22572258      while ( bytesToCopy > 0 ) {2259        var readSize = (int)bytesToCopy;2260        byte[] buffer = GetBuffer();2254      if (update.Entry.IsFile) {2255        source = update.GetSource();22562257        if (source == null) {2258          source = updateDataSource_.GetSource(update.Entry, update.Filename);2259        }2260      }  22612262        stream.Position = sourcePosition;2263        int bytesRead = stream.Read(buffer, 0, readSize);2264        if ( bytesRead > 0 ) {2265          stream.Position = destinationPosition;2266          stream.Write(buffer, 0, bytesRead);2267          bytesToCopy -= bytesRead;2268          destinationPosition += bytesRead;2269          sourcePosition += bytesRead;2270        }2271        else {2272          throw new ZipException("Unxpected end of stream");2273        }2274      }2275    }22762277    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2278    {2279      long bytesToCopy = update.Entry.CompressedSize;22802281      // NOTE: Compressed size is updated elsewhere.2282      var crc = new Crc32();2283      byte[] buffer = GetBuffer();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          }22732274          workFile.WriteLocalEntryHeader(update);22752276          long dataStart = workFile.baseStream_.Position;22772278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {2279            CopyBytes(update, output, source, sourceStreamLength, true);2280          }22812282          long dataEnd = workFile.baseStream_.Position;2283          update.OutEntry.CompressedSize = dataEnd - dataStart;  22842285      long targetBytes = bytesToCopy;2286      long totalBytesRead = 0;22872288      int bytesRead;2289      do2290      {2291        int readSize = buffer.Length;22922293        if ( bytesToCopy < readSize ) {2294          readSize = (int)bytesToCopy;2295        }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      }22942295    }  22962297        stream.Position = sourcePosition;2298        bytesRead = stream.Read(buffer, 0, readSize);2299        if ( bytesRead > 0 ) {2300          if ( updateCrc ) {2301            crc.Update(buffer, 0, bytesRead);2302          }2303          stream.Position = destinationPosition;2304          stream.Write(buffer, 0, bytesRead);23052306          destinationPosition += bytesRead;2307          sourcePosition += bytesRead;2308          bytesToCopy -= bytesRead;2309          totalBytesRead += bytesRead;2310        }2311      }2312      while ( (bytesRead > 0) && (bytesToCopy > 0) );23132314      if ( totalBytesRead != targetBytes ) {2315        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2316      }23172318      if ( updateCrc ) {2319        update.OutEntry.Crc = crc.Value;2320      }2321    }23222323    int FindExistingUpdate(ZipEntry entry)2324    {2325      int result = -1;2326      string convertedName = GetTransformedFileName(entry.Name);23272328      if (updateIndex_.ContainsKey(convertedName)) {2329        result = (int)updateIndex_[convertedName];2330      }2331/*2332      // This is slow like the coming of the next ice age but takes less storage and may be useful2333      // for CF?2334      for (int index = 0; index < updates_.Count; ++index)2335      {2336        ZipUpdate zu = ( ZipUpdate )updates_[index];2337        if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&2338          (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {2339          result = index;2340          break;2341        }2342      }2343 */2344      return result;2345    }23462347    int FindExistingUpdate(string fileName)2348    {2349      int result = -1;23502351      string convertedName = GetTransformedFileName(fileName);23522353      if (updateIndex_.ContainsKey(convertedName)) {2354        result = (int)updateIndex_[convertedName];2355      }23562357/*2358      // This is slow like the coming of the next ice age but takes less storage and may be useful2359      // for CF?2360      for ( int index = 0; index < updates_.Count; ++index ) {2361        if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,2362          true, CultureInfo.InvariantCulture) == 0 ) {2363          result = index;2364          break;2365        }2366      }2367 */23682369      return result;2370    }23712372    /// <summary>2373    /// Get an output stream for the specified <see cref="ZipEntry"/>2374    /// </summary>2375    /// <param name="entry">The entry to get an output stream for.</param>2376    /// <returns>The output stream obtained for the entry.</returns>2377    Stream GetOutputStream(ZipEntry entry)2378    {2379      Stream result = baseStream_;2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)2298    {2299      workFile.WriteLocalEntryHeader(update);2300      long dataStart = workFile.baseStream_.Position;23012302      // 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      }23102311      long dataEnd = workFile.baseStream_.Position;2312      update.Entry.CompressedSize = dataEnd - dataStart;2313    }23142315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2316    {2317      bool skipOver = false || update.Entry.Offset == destinationPosition;23182319      if (!skipOver) {2320        baseStream_.Position = destinationPosition;2321        workFile.WriteLocalEntryHeader(update);2322        destinationPosition = baseStream_.Position;2323      }23242325      long sourcePosition = 0;23262327      const int NameLengthOffset = 26;23282329      // TODO: Add base for SFX friendly handling2330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;23312332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23332334      // 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();23382339      sourcePosition = baseStream_.Position + nameLength + extraLength;23402341      if (skipOver) {2342        if (update.OffsetBasedSize != -1)2343          destinationPosition += update.OffsetBasedSize;2344        else2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2346          // WinZip produces a warning on these entries:2347          // "caution: value of lrec.csize (compressed size) changed from ..."2348          destinationPosition +=2349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size2350            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    }23582359    void CopyEntry(ZipFile workFile, ZipUpdate update)2360    {2361      workFile.WriteLocalEntryHeader(update);23622363      if (update.Entry.CompressedSize > 0) {2364        const int NameLengthOffset = 26;23652366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;23672368        // TODO: This wont work for SFX files!2369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23702371        uint nameLength = ReadLEUshort();2372        uint extraLength = ReadLEUshort();23732374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);23752376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2377      }2378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);2379    }  23802381      if ( entry.IsCrypted == true ) {2382#if NETCF_1_02383        throw new ZipException("Encryption not supported for Compact Framework 1.0");2384#else2385        result = CreateAndInitEncryptionStream(result, entry);2386#endif2387      }23882389      switch ( entry.CompressionMethod ) {2390        case CompressionMethod.Stored:2391          result = new UncompressedStream(result);2392          break;23932394        case CompressionMethod.Deflated:2395          var dos = new DeflaterOutputStream(result, new Deflater(9, true));2396          dos.IsStreamOwner = false;2397          result = dos;2398          break;23992400        default:2401          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2402      }2403      return result;2404    }24052406    void AddEntry(ZipFile workFile, ZipUpdate update)2407    {2408      Stream source = null;24092410      if ( update.Entry.IsFile ) {2411        source = update.GetSource();24122413        if ( source == null ) {2414          source = updateDataSource_.GetSource(update.Entry, update.Filename);2415        }2416      }24172418      if ( source != null ) {2419        using ( source ) {2420          long sourceStreamLength = source.Length;2421          if ( update.OutEntry.Size < 0 ) {2422            update.OutEntry.Size = sourceStreamLength;2423          }2424          else {2425            // Check for errant entries.2426            if ( update.OutEntry.Size != sourceStreamLength ) {2427              throw new ZipException("Entry size/stream size mismatch");2428            }2429          }24302431          workFile.WriteLocalEntryHeader(update);24322433          long dataStart = workFile.baseStream_.Position;24342435          using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {2436            CopyBytes(update, output, source, sourceStreamLength, true);2437          }24382439          long dataEnd = workFile.baseStream_.Position;2440          update.OutEntry.CompressedSize = dataEnd - dataStart;24412442          if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor)2443          {2444            var helper = new ZipHelperStream(workFile.baseStream_);2445            helper.WriteDataDescriptor(update.OutEntry);2446          }2447        }2381    void Reopen(Stream source)2382    {2383      if (source == null) {2384        throw new ZipException("Failed to reopen archive - no source");2385      }23862387      isNewArchive_ = false;2388      baseStream_ = source;2389      ReadEntries();2390    }23912392    void Reopen()2393    {2394      if (Name == null) {2395        throw new InvalidOperationException("Name is not known cannot Reopen");2396      }23972398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));2399    }24002401    void UpdateCommentOnly()2402    {2403      long baseLength = baseStream_.Length;24042405      ZipHelperStream updateFile = null;24062407      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {2408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);2409        updateFile = new ZipHelperStream(copyStream);2410        updateFile.IsStreamOwner = true;24112412        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 doesnt2418          // 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.24212422          // 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      }24312432      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        }24392440        const int CentralHeaderCommentSizeOffset = 16;2441        updateFile.Position += CentralHeaderCommentSizeOffset;24422443        byte[] rawComment = newComment_.RawComment;24442445        updateFile.WriteLEShort(rawComment.Length);2446        updateFile.Write(rawComment, 0, rawComment.Length);2447        updateFile.SetLength(updateFile.Position);  2448      }2449      else {2450        workFile.WriteLocalEntryHeader(update);2451        update.OutEntry.CompressedSize = 0;2452      }24532454    }24552456    void ModifyEntry(ZipFile workFile, ZipUpdate update)2457    {2458      workFile.WriteLocalEntryHeader(update);2459      long dataStart = workFile.baseStream_.Position;24602461      // TODO: This is slow if the changes don't effect the data!!2462      if ( update.Entry.IsFile && (update.Filename != null) ) {2463        using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {2464          using ( Stream source = this.GetInputStream(update.Entry) ) {2465            CopyBytes(update, output, source, source.Length, true);2466          }2467        }2468      }24692470      long dataEnd = workFile.baseStream_.Position;2471      update.Entry.CompressedSize = dataEnd - dataStart;2472    }24732474    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2475    {2476      bool skipOver = false || update.Entry.Offset == destinationPosition;24492450      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {2451        Reopen(archiveStorage_.ConvertTemporaryToFinal());2452      } else {2453        ReadEntries();2454      }2455    }24562457    /// <summary>2458    /// Class used to sort updates.2459    /// </summary>2460    class UpdateComparer : IComparer2461    {2462      /// <summary>2463      /// Compares two objects and returns a value indicating whether one is2464      /// 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;24752476        int result;  24772478      if ( !skipOver ) {2479        baseStream_.Position = destinationPosition;2480        workFile.WriteLocalEntryHeader(update);2481        destinationPosition = baseStream_.Position;2482      }24832484      long sourcePosition = 0;24852486      const int NameLengthOffset = 26;24872488      // TODO: Add base for SFX friendly handling2489      long entryDataOffset = update.Entry.Offset + NameLengthOffset;24902491      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);24922493      // Clumsy way of handling retrieving the original name and extra data length for now.2494      // TODO: Stop re-reading name and data length in CopyEntryDirect.2495      uint nameLength = ReadLEUshort();2496      uint extraLength = ReadLEUshort();24972498      sourcePosition = baseStream_.Position + nameLength + extraLength;24992500      if (skipOver) {2501        if (update.OffsetBasedSize != -1)2502          destinationPosition += update.OffsetBasedSize;2503        else2504          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2505          // WinZip produces a warning on these entries:2506          // "caution: value of lrec.csize (compressed size) changed from ..."2507          destinationPosition +=2508            (sourcePosition - entryDataOffset) + NameLengthOffset +  // Header size2509            update.Entry.CompressedSize + GetDescriptorSize(update);2510      }2511      else {2512        if ( update.Entry.CompressedSize > 0 ) {2513          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition );2514        }2515        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);2516      }2517    }25182519    void CopyEntry(ZipFile workFile, ZipUpdate update)2520    {2521      workFile.WriteLocalEntryHeader(update);25222523      if ( update.Entry.CompressedSize > 0 ) {2524        const int NameLengthOffset = 26;25252526        long entryDataOffset = update.Entry.Offset + NameLengthOffset;25272528        // TODO: This wont work for SFX files!2529        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);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;24892490          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    }25052506    void RunUpdates()2507    {2508      long sizeEntries = 0;2509      long endOfStream = 0;2510      bool directUpdate = false;2511      long destinationPosition = 0; // NOT SFX friendly25122513      ZipFile workFile;25142515      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;25232524        // 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;  25302531        uint nameLength = ReadLEUshort();2532        uint extraLength = ReadLEUshort();25332534        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);2531        if (key != null) {2532          workFile.key = (byte[])key.Clone();2533        }2534      }  25352536        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2537      }2538      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);2539    }25402541    void Reopen(Stream source)2542    {2543      if ( source == null ) {2544        throw new ZipException("Failed to reopen archive - no source");2545      }25462547      isNewArchive_ = false;2548      baseStream_ = source;2549      ReadEntries();2550    }25512552    void Reopen()2553    {2554      if (Name == null) {2555        throw new InvalidOperationException("Name is not known cannot Reopen");2556      }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;25472548              case UpdateCommand.Modify:2549                // TODO: Direct modifying of an entry will take some legwork.2550                ModifyEntry(workFile, update);2551                break;25522553              case UpdateCommand.Add:2554                if (!IsNewArchive && directUpdate) {2555                  workFile.baseStream_.Position = destinationPosition;2556                }  25572558      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));2559    }25602561    void UpdateCommentOnly()2562    {2563      long baseLength = baseStream_.Length;25642565      ZipHelperStream updateFile = null;25662567      if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {2568        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);2569        updateFile = new ZipHelperStream(copyStream);2570        updateFile.IsStreamOwner = true;2558                AddEntry(workFile, update);25592560                if (directUpdate) {2561                  destinationPosition = workFile.baseStream_.Position;2562                }2563                break;2564            }2565          }2566        }25672568        if (!IsNewArchive && directUpdate) {2569          workFile.baseStream_.Position = destinationPosition;2570        }  25712572        baseStream_.Close();2573        baseStream_ = null;2574      }2575      else {2576        if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {2577          // TODO: archiveStorage wasnt originally intended for this use.2578          // Need to revisit this to tidy up handling as archive storage currently doesnt2579          // handle the original stream well.2580          // The problem is when using an existing zip archive with an in memory archive storage.2581          // The open stream wont support writing but the memory storage should open the same file not an in memory one.25822583          // Need to tidy up the archive storage interface and contract basically.2584          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);2585          updateFile = new ZipHelperStream(baseStream_);2586        }2587        else {2588          baseStream_.Close();2589          baseStream_ = null;2590          updateFile = new ZipHelperStream(Name);2591        }2592      }25932594      using ( updateFile ) {2595        long locatedCentralDirOffset =2596          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,2597                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);2598        if ( locatedCentralDirOffset < 0 ) {2599          throw new ZipException("Cannot find central directory");2600        }26012602        const int CentralHeaderCommentSizeOffset = 16;2603        updateFile.Position += CentralHeaderCommentSizeOffset;26042605        byte[] rawComment = newComment_.RawComment;26062607        updateFile.WriteLEShort(rawComment.Length);2608        updateFile.Write(rawComment, 0, rawComment.Length);2609        updateFile.SetLength(updateFile.Position);2610      }26112612      if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {2613        Reopen(archiveStorage_.ConvertTemporaryToFinal());2614      }2615      else {2616        ReadEntries();2617      }2618    }26192620    /// <summary>2621    /// Class used to sort updates.2622    /// </summary>2623    class UpdateComparer : IComparer2624    {2625      /// <summary>2626      /// Compares two objects and returns a value indicating whether one is2627      /// less than, equal to or greater than the other.2628      /// </summary>2629      /// <param name="x">First object to compare</param>2630      /// <param name="y">Second object to compare.</param>2631      /// <returns>Compare result.</returns>2632      public int Compare(2633        object x,2634        object y)2635      {2636        var zx = x as ZipUpdate;2637        var zy = y as ZipUpdate;26382639        int result;26402641        if (zx == null) {2642          if (zy == null) {2643            result = 0;2644          }2645          else {2646            result = -1;2647          }2648        }2649        else if (zy == null) {2650          result = 1;2651        }2652        else {2653          int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;2654          int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;26552656          result = xCmdValue - yCmdValue;2657          if (result == 0) {2658            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;2659            if (offsetDiff < 0) {2660              result = -1;2661            }2662            else if (offsetDiff == 0) {2663              result = 0;2664            }2665            else {2666              result = 1;2667            }2668          }2669        }2670        return result;2671      }2672    }26732674    void RunUpdates()2675    {2676      long sizeEntries = 0;2677      long endOfStream = 0;2678      bool directUpdate = false;2679      long destinationPosition = 0; // NOT SFX friendly26802681      ZipFile workFile;2572        long centralDirOffset = workFile.baseStream_.Position;25732574        foreach (ZipUpdate update in updates_) {2575          if (update != null) {2576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2577          }2578        }25792580        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        }25842585        endOfStream = workFile.baseStream_.Position;25862587        // 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            }25962597            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      }26162617      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    }26272628    void CheckUpdating()2629    {2630      if (updates_ == null) {2631        throw new InvalidOperationException("BeginUpdate has not been called");2632      }2633    }26342635    #endregion26362637    #region ZipUpdate class2638    /// <summary>2639    /// Represents a pending update to a Zip file.2640    /// </summary>2641    class ZipUpdate2642    {2643      #region Constructors2644      public ZipUpdate(string fileName, ZipEntry entry)2645      {2646        command_ = UpdateCommand.Add;2647        entry_ = entry;2648        filename_ = fileName;2649      }26502651      [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      }26592660      [Obsolete]2661      public ZipUpdate(string fileName, string entryName)2662        : this(fileName, entryName, CompressionMethod.Deflated)2663      {2664        // Do nothing.2665      }26662667      [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      }26752676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2677      {2678        command_ = UpdateCommand.Add;2679        entry_ = entry;2680        dataSource_ = dataSource;2681      }  26822683      if ( IsNewArchive ) {2684        workFile = this;2685        workFile.baseStream_.Position = 0;2686        directUpdate = true;2687      }2688      else if ( archiveStorage_.UpdateMode == FileUpdateMode.Direct ) {2689        workFile = this;2690        workFile.baseStream_.Position = 0;2691        directUpdate = true;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      }  26922693        // Sort the updates by offset within copies/modifies, then adds.2694        // This ensures that data required by copies will not be overwritten.2695        updates_.Sort(new UpdateComparer());2696      }2697      else {2698        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());2699        workFile.UseZip64 = UseZip64;27002701        if (key != null) {2702          workFile.key = (byte[])key.Clone();2703        }2704      }27052706      try {2707        foreach ( ZipUpdate update in updates_ ) {2708          if (update != null) {2709            switch (update.Command) {2710              case UpdateCommand.Copy:2711                if (directUpdate) {2712                  CopyEntryDirect(workFile, update, ref destinationPosition);2713                }2714                else {2715                  CopyEntry(workFile, update);2716                }2717                break;2693      public ZipUpdate(UpdateCommand command, ZipEntry entry)2694      {2695        command_ = command;2696        entry_ = (ZipEntry)entry.Clone();2697      }269826992700      /// <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      #endregion27102711      /// <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      }  27182719              case UpdateCommand.Modify:2720                // TODO: Direct modifying of an entry will take some legwork.2721                ModifyEntry(workFile, update);2722                break;27232724              case UpdateCommand.Add:2725                if (!IsNewArchive && directUpdate) {2726                  workFile.baseStream_.Position = destinationPosition;2727                }27282729                AddEntry(workFile, update);27302731                if (directUpdate) {2732                  destinationPosition = workFile.baseStream_.Position;2733                }2734                break;2735            }2736          }2737        }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          }27272728          return outEntry_;2729        }2730      }27312732      /// <summary>2733      /// Get the command for this update.2734      /// </summary>2735      public UpdateCommand Command {2736        get { return command_; }2737      }  27382739        if ( !IsNewArchive && directUpdate ) {2740          workFile.baseStream_.Position = destinationPosition;2741        }27422743        long centralDirOffset = workFile.baseStream_.Position;27442745        foreach ( ZipUpdate update in updates_ ) {2746          if (update != null) {2747            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2748          }2749        }27502751        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);2752        using ( ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_) ) {2753          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);2754        }27552756        endOfStream = workFile.baseStream_.Position;27572758        // And now patch entries...2759        foreach ( ZipUpdate update in updates_ ) {2760          if (update != null)2761          {2762            // If the size of the entry is zero leave the crc as 0 as well.2763            // The calculated crc will be all bits on...2764            if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {2765              workFile.baseStream_.Position = update.CrcPatchOffset;2766              workFile.WriteLEInt((int)update.OutEntry.Crc);2767            }27682769            if (update.SizePatchOffset > 0) {2770              workFile.baseStream_.Position = update.SizePatchOffset;2771              if (update.OutEntry.LocalHeaderRequiresZip64) {2772                workFile.WriteLeLong(update.OutEntry.Size);2773                workFile.WriteLeLong(update.OutEntry.CompressedSize);2774              }2775              else {2776                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);2777                workFile.WriteLEInt((int)update.OutEntry.Size);2778              }2779            }2780          }2781        }2782      }2783      catch {2784        workFile.Close();2785        if (!directUpdate && (workFile.Name != null)) {2786          File.Delete(workFile.Name);2787        }2788        throw;2789      }27902791      if (directUpdate) {2792        workFile.baseStream_.SetLength(endOfStream);2793        workFile.baseStream_.Flush();2794        isNewArchive_ = false;2795        ReadEntries();2796      }2797      else {2798        baseStream_.Close();2799        Reopen(archiveStorage_.ConvertTemporaryToFinal());2800      }2801    }28022803    void CheckUpdating()2804    {2805      if ( updates_ == null ) {2806        throw new InvalidOperationException("BeginUpdate has not been called");2807      }2808    }28092810    #endregion28112812    #region ZipUpdate class2813    /// <summary>2814    /// Represents a pending update to a Zip file.2815    /// </summary>2816    class ZipUpdate2817    {2818      #region Constructors2819      public ZipUpdate(string fileName, ZipEntry entry)2820      {2821        command_ = UpdateCommand.Add;2822        entry_ = entry;2823        filename_ = fileName;2824      }28252826      [Obsolete]2827      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)2828      {2829        command_ = UpdateCommand.Add;2830        entry_ = new ZipEntry(entryName);2831        entry_.CompressionMethod = compressionMethod;2832        filename_ = fileName;2833      }28342835      [Obsolete]2836      public ZipUpdate(string fileName, string entryName)2837        : this(fileName, entryName, CompressionMethod.Deflated)2838      {2839        // Do nothing.2840      }28412842      [Obsolete]2843      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)2844      {2845        command_ = UpdateCommand.Add;2846        entry_ = new ZipEntry(entryName);2847        entry_.CompressionMethod = compressionMethod;2848        dataSource_ = dataSource;2849      }28502851      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2852      {2853        command_ = UpdateCommand.Add;2854        entry_ = entry;2855        dataSource_ = dataSource;2856      }28572858      public ZipUpdate(ZipEntry original, ZipEntry updated)2859      {2860        throw new ZipException("Modify not currently supported");2861      /*2862        command_ = UpdateCommand.Modify;2863        entry_ = ( ZipEntry )original.Clone();2864        outEntry_ = ( ZipEntry )updated.Clone();2865      */2866      }28672868      public ZipUpdate(UpdateCommand command, ZipEntry entry)2869      {2870        command_ = command;2871        entry_ = ( ZipEntry )entry.Clone();2872      }28732739      /// <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      }27452746      /// <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      }27532754      /// <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      }27612762      /// <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      }27702771      public Stream GetSource()2772      {2773        Stream result = null;2774        if (dataSource_ != null) {2775          result = dataSource_.GetSource();2776        }27772778        return result;2779      }27802781      #region Instance Fields2782      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      #endregion2791    }27922793    #endregion2794    #endregion27952796    #region Disposing27972798    #region IDisposable Members2799    void IDisposable.Dispose()2800    {2801      Close();2802    }2803    #endregion28042805    void DisposeInternal(bool disposing)2806    {2807      if (!isDisposed_) {2808        isDisposed_ = true;2809        entries_ = new ZipEntry[0];28102811        if (IsStreamOwner && (baseStream_ != null)) {2812          lock (baseStream_) {2813            baseStream_.Close();2814          }2815        }28162817        PostUpdateCleanup();2818      }2819    }28202821    /// <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    }28302831    #endregion28322833    #region Internal routines2834    #region Reading2835    /// <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 prematurely2841    /// </exception>2842    ushort ReadLEUshort()2843    {2844      int data1 = baseStream_.ReadByte();28452846      if (data1 < 0) {2847        throw new EndOfStreamException("End of stream");2848      }28492850      int data2 = baseStream_.ReadByte();28512852      if (data2 < 0) {2853        throw new EndOfStreamException("End of stream");2854      }285528562857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));2858    }28592860    /// <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 prematurely2869    /// </exception>2870    uint ReadLEUint()2871    {2872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));2873    }  28742875      /// <summary>2876      /// Copy an existing entry.2877      /// </summary>2878      /// <param name="entry">The existing entry to copy.</param>2879      public ZipUpdate(ZipEntry entry)2880        : this(UpdateCommand.Copy, entry)2881      {2882        // Do nothing.2883      }2884      #endregion28852886      /// <summary>2887      /// Get the <see cref="ZipEntry"/> for this update.2888      /// </summary>2889      /// <remarks>This is the source or original entry.</remarks>2890      public ZipEntry Entry2891      {2892        get { return entry_; }2893      }28942895      /// <summary>2896      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.2897      /// </summary>2898      public ZipEntry OutEntry2899      {2900        get {2901          if ( outEntry_ == null ) {2902            outEntry_ = (ZipEntry)entry_.Clone();2903          }29042905          return outEntry_;2906        }2907      }2875    ulong ReadLEUlong()2876    {2877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);2878    }28792880    #endregion2881    // 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    }28882889    /// <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 found2897    /// </exception>2898    void ReadEntries()2899    {2900      // Search for the End Of Central Directory.  When a zip comment is2901      // present the directory will start earlier2902      //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 files2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then2906      // this could be invalid.2907      // Could also speed this up by reading memory in larger blocks.  29082909      /// <summary>2910      /// Get the command for this update.2911      /// </summary>2912      public UpdateCommand Command2913      {2914        get { return command_; }2915      }29162917      /// <summary>2918      /// Get the filename if any for this update.  Null if none exists.2919      /// </summary>2920      public string Filename2921      {2922        get { return filename_; }2923      }29242925      /// <summary>2926      /// Get/set the location of the size patch for this update.2927      /// </summary>2928      public long SizePatchOffset2929      {2930        get { return sizePatchOffset_; }2931        set { sizePatchOffset_ = value; }2932      }29332934      /// <summary>2935      /// Get /set the location of the crc patch for this update.2936      /// </summary>2937      public long CrcPatchOffset2938      {2939        get { return crcPatchOffset_; }2940        set { crcPatchOffset_ = value; }2941      }29422943      /// <summary>2944      /// Get/set the size calculated by offset.2945      /// Specifically, the difference between this and next entry's starting offset.2946      /// </summary>2947      public long OffsetBasedSize2948      {2949        get { return _offsetBasedSize; }2950        set { _offsetBasedSize = value; }2951      }29522953      public Stream GetSource()2954      {2955        Stream result = null;2956        if ( dataSource_ != null ) {2957          result = dataSource_.GetSource();2958        }29592960        return result;2961      }29622963      #region Instance Fields2964      ZipEntry entry_;2965      ZipEntry outEntry_;2966      UpdateCommand command_;2967      IStaticDataSource dataSource_;2968      string filename_;2969      long sizePatchOffset_ = -1;2970      long crcPatchOffset_ = -1;2971      long _offsetBasedSize = -1;2972      #endregion2973    }29742975    #endregion2976    #endregion29772978    #region Disposing29792980    #region IDisposable Members2981    void IDisposable.Dispose()2982    {2983      Close();2984    }2985    #endregion29862987    void DisposeInternal(bool disposing)2988    {2989      if ( !isDisposed_ ) {2990        isDisposed_ = true;2991        entries_ = new ZipEntry[0];29922993        if ( IsStreamOwner && (baseStream_ != null) ) {2994          lock(baseStream_) {2995            baseStream_.Close();2996          }2997        }2909      if (baseStream_.CanSeek == false) {2910        throw new ZipException("ZipFile stream must be seekable");2911      }29122913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,2914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);29152916      if (locatedEndOfCentralDir < 0) {2917        throw new ZipException("Cannot find central directory");2918      }29192920      // Read end of central directory record2921      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();29282929      if (commentSize > 0) {2930        byte[] comment = new byte[commentSize];29312932        StreamUtils.ReadFully(baseStream_, comment);2933        comment_ = ZipConstants.ConvertToString(comment);2934      } else {2935        comment_ = string.Empty;2936      }29372938      bool isZip64 = false;29392940      // 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;29482949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 2950        if (offset < 0) {2951          throw new ZipException("Cannot find Zip64 locator");2952        }29532954        // number of the disk with the start of the zip64 end of central directory 4 bytes2955        // relative offset of the zip64 end of central directory record 8 bytes2956        // total number of disks 4 bytes2957        ReadLEUint(); // startDisk64 is not currently used2958        ulong offset64 = ReadLEUlong();2959        uint totalDisks = ReadLEUint();29602961        baseStream_.Position = (long)offset64;2962        long sig64 = ReadLEUint();29632964        if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {2965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));2966        }29672968        // 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();29782979        // NOTE: zip64 extensible data sector (variable size) is ignored.2980      }29812982      entries_ = new ZipEntry[entriesForThisDisk];29832984      // SFX/embedded support, find the offset of the first entry vis the start of the stream2985      // 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 offsets2988      // 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      }29962997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);  29982999        PostUpdateCleanup();3000      }3001    }30023003    /// <summary>3004    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.3005    /// </summary>3006    /// <param name="disposing">true to release both managed and unmanaged resources;3007    /// false to release only unmanaged resources.</param>3008    protected virtual void Dispose(bool disposing)3009    {3010      DisposeInternal(disposing);3011    }30123013    #endregion30143015    #region Internal routines3016    #region Reading3017    /// <summary>3018    /// Read an unsigned short in little endian byte order.3019    /// </summary>3020    /// <returns>Returns the value read.</returns>3021    /// <exception cref="EndOfStreamException">3022    /// The stream ends prematurely3023    /// </exception>3024    ushort ReadLEUshort()3025    {3026      int data1 = baseStream_.ReadByte();30273028      if ( data1 < 0 ) {3029        throw new EndOfStreamException("End of stream");3030      }30313032      int data2 = baseStream_.ReadByte();30333034      if ( data2 < 0 ) {3035        throw new EndOfStreamException("End of stream");3036      }303730383039      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));3040    }30413042    /// <summary>3043    /// Read a uint in little endian byte order.3044    /// </summary>3045    /// <returns>Returns the value read.</returns>3046    /// <exception cref="IOException">3047    /// An i/o error occurs.3048    /// </exception>3049    /// <exception cref="System.IO.EndOfStreamException">3050    /// The file ends prematurely3051    /// </exception>3052    uint ReadLEUint()3053    {3054      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));3055    }30563057    ulong ReadLEUlong()3058    {3059      return ReadLEUint() | ((ulong)ReadLEUint() << 32);3060    }30613062    #endregion3063    // NOTE this returns the offset of the first byte after the signature.3064    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)3065    {3066      using ( ZipHelperStream les = new ZipHelperStream(baseStream_) ) {3067        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);3068      }3069    }30703071    /// <summary>3072    /// Search for and read the central directory of a zip file filling the entries array.3073    /// </summary>3074    /// <exception cref="System.IO.IOException">3075    /// An i/o error occurs.3076    /// </exception>3077    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3078    /// The central directory is malformed or cannot be found3079    /// </exception>3080    void ReadEntries()3081    {3082      // Search for the End Of Central Directory.  When a zip comment is3083      // present the directory will start earlier3084      //3085      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.3086      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files3087      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then3088      // this could be invalid.3089      // Could also speed this up by reading memory in larger blocks.2999      for (ulong i = 0; i < entriesForThisDisk; i++) {3000        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {3001          throw new ZipException("Wrong Central Directory signature");3002        }30033004        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();30153016        int diskStartNo = ReadLEUshort();  // Not currently used3017        int internalAttributes = ReadLEUshort();  // Not currently used30183019        uint externalAttributes = ReadLEUint();3020        long offset = ReadLEUint();30213022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];30233024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);3025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);30263027        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;30363037        if ((bitFlags & 8) == 0) {3038          entry.CryptoCheckValue = (byte)(crc >> 24);3039        } else {3040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3041        }30423043        if (extraLen > 0) {3044          byte[] extra = new byte[extraLen];3045          StreamUtils.ReadFully(baseStream_, extra);3046          entry.ExtraData = extra;3047        }30483049        entry.ProcessExtraData(false);30503051        if (commentLen > 0) {3052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);3053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3054        }30553056        entries_[i] = entry;3057      }3058    }30593060    /// <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 prematurely3068    /// </exception>3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3070    /// The local header signature is invalid, the entry and central header file name lengths are different3071    /// or the local and entry compression methods dont match3072    /// </exception>3073    long LocateEntry(ZipEntry entry)3074    {3075      return TestLocalHeader(entry, HeaderTest.Extract);3076    }30773078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3079    {3080      CryptoStream result = null;30813082      if ((entry.Version < ZipConstants.VersionStrongEncryption)3083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3084        var classicManaged = new PkzipClassicManaged();30853086        OnKeysRequired(entry.Name);3087        if (HaveKeys == false) {3088          throw new ZipException("No password available for encrypted stream");3089        }  30903091      if (baseStream_.CanSeek == false) {3092        throw new ZipException("ZipFile stream must be seekable");3093      }30943095      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,3096        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);30973098      if (locatedEndOfCentralDir < 0) {3099        throw new ZipException("Cannot find central directory");3100      }31013102      // Read end of central directory record3103      ushort thisDiskNumber           = ReadLEUshort();3104      ushort startCentralDirDisk      = ReadLEUshort();3105      ulong entriesForThisDisk        = ReadLEUshort();3106      ulong entriesForWholeCentralDir = ReadLEUshort();3107      ulong centralDirSize            = ReadLEUint();3108      long offsetOfCentralDir         = ReadLEUint();3109      uint commentSize                = ReadLEUshort();31103111      if ( commentSize > 0 ) {3112        byte[] comment = new byte[commentSize];31133114        StreamUtils.ReadFully(baseStream_, comment);3115        comment_ = ZipConstants.ConvertToString(comment);3116      }3117      else {3118        comment_ = string.Empty;3119      }31203121      bool isZip64 = false;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 bytes31093110          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      }31193120      return result;3121    }  31223123      // Check if zip64 header information is required.3124      if ( (thisDiskNumber == 0xffff) ||3125        (startCentralDirDisk == 0xffff) ||3126        (entriesForThisDisk == 0xffff) ||3127        (entriesForWholeCentralDir == 0xffff) ||3128        (centralDirSize == 0xffffffff) ||3129        (offsetOfCentralDir == 0xffffffff) ) {3130        isZip64 = true;31313132        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 3133        if ( offset < 0 ) {3134          throw new ZipException("Cannot find Zip64 locator");3135        }31363137        // number of the disk with the start of the zip64 end of central directory 4 bytes3138        // relative offset of the zip64 end of central directory record 8 bytes3139        // total number of disks 4 bytes3140        ReadLEUint(); // startDisk64 is not currently used3141        ulong offset64 = ReadLEUlong();3142        uint totalDisks = ReadLEUint();31433144        baseStream_.Position = (long)offset64;3145        long sig64 = ReadLEUint();31463147        if ( sig64 != ZipConstants.Zip64CentralFileHeaderSignature ) {3148          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));3149        }31503151        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.3152        ulong recordSize = ReadLEUlong();3153        int versionMadeBy = ReadLEUshort();3154        int versionToExtract = ReadLEUshort();3155        uint thisDisk = ReadLEUint();3156        uint centralDirDisk = ReadLEUint();3157        entriesForThisDisk = ReadLEUlong();3158        entriesForWholeCentralDir = ReadLEUlong();3159        centralDirSize = ReadLEUlong();3160        offsetOfCentralDir = (long)ReadLEUlong();31613162        // NOTE: zip64 extensible data sector (variable size) is ignored.3163      }31643165      entries_ = new ZipEntry[entriesForThisDisk];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();31293130        OnKeysRequired(entry.Name);3131        if (HaveKeys == false) {3132          throw new ZipException("No password available for encrypted stream");3133        }31343135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3136        // which doesnt do this.3137        result = new CryptoStream(new UncompressedStream(baseStream),3138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);31393140        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    }31483149    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    }31573158    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    }  31663167      // SFX/embedded support, find the offset of the first entry vis the start of the stream3168      // This applies to Zip files that are appended to the end of an SFX stub.3169      // Or are appended as a resource to an executable.3170      // Zip files created by some archivers have the offsets altered to reflect the true offsets3171      // and so dont require any adjustment here...3172      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?3173      if ( !isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize)) ) {3174        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);3175        if (offsetOfFirstEntry <= 0) {3176          throw new ZipException("Invalid embedded zip archive");3177        }3178      }31793180      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);31813182      for (ulong i = 0; i < entriesForThisDisk; i++) {3183        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {3184          throw new ZipException("Wrong Central Directory signature");3185        }3167    #endregion31683169    #region Instance Fields3170    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_;31803181    // Default is dynamic which is not backwards compatible and can cause problems3182    // 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;  31863187        int versionMadeBy      = ReadLEUshort();3188        int versionToExtract   = ReadLEUshort();3189        int bitFlags           = ReadLEUshort();3190        int method             = ReadLEUshort();3191        uint dostime           = ReadLEUint();3192        uint crc               = ReadLEUint();3193        var csize             = (long)ReadLEUint();3194        var size              = (long)ReadLEUint();3195        int nameLen            = ReadLEUshort();3196        int extraLen           = ReadLEUshort();3197        int commentLen         = ReadLEUshort();31983199        int diskStartNo        = ReadLEUshort();  // Not currently used3200        int internalAttributes = ReadLEUshort();  // Not currently used3187    #region Zip Update Instance Fields3188    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    #endregion3200    #endregion  32013202        uint externalAttributes = ReadLEUint();3203        long offset             = ReadLEUint();32043205        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];32063207        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);3208        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);32093210        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);3211        entry.Crc = crc & 0xffffffffL;3212        entry.Size = size & 0xffffffffL;3213        entry.CompressedSize = csize & 0xffffffffL;3214        entry.Flags = bitFlags;3215        entry.DosTime = (uint)dostime;3216        entry.ZipFileIndex = (long)i;3217        entry.Offset = offset;3218        entry.ExternalFileAttributes = (int)externalAttributes;32193220        if ((bitFlags & 8) == 0) {3221          entry.CryptoCheckValue = (byte)(crc >> 24);3222        }3223        else {3224          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3225        }32263227        if (extraLen > 0) {3228          byte[] extra = new byte[extraLen];3229          StreamUtils.ReadFully(baseStream_, extra);3230          entry.ExtraData = extra;3231        }32323233        entry.ProcessExtraData(false);32343235        if (commentLen > 0) {3236          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);3237          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3238        }32393240        entries_[i] = entry;3241      }3242    }32433244    /// <summary>3245    /// Locate the data for a given entry.3246    /// </summary>3247    /// <returns>3248    /// The start offset of the data.3249    /// </returns>3250    /// <exception cref="System.IO.EndOfStreamException">3251    /// The stream ends prematurely3252    /// </exception>3253    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3254    /// The local header signature is invalid, the entry and central header file name lengths are different3255    /// or the local and entry compression methods dont match3256    /// </exception>3257    long LocateEntry(ZipEntry entry)3258    {3259      return TestLocalHeader(entry, HeaderTest.Extract);3260    }32613262#if !NETCF_1_03263    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3264    {3265      CryptoStream result = null;32663267      if ( (entry.Version < ZipConstants.VersionStrongEncryption)3268        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3269        var classicManaged = new PkzipClassicManaged();32703271        OnKeysRequired(entry.Name);3272        if (HaveKeys == false) {3273          throw new ZipException("No password available for encrypted stream");3274        }3202    #region Support Classes3203    /// <summary>3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3205    /// </summary>3206    class ZipString3207    {3208      #region Constructors3209      /// <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      }32183219      /// <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      #endregion32283229      /// <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      }32363237      /// <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      }32463247      /// <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      }32563257      /// <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      }32683269      void MakeTextAvailable()3270      {3271        if (comment_ == null) {3272          comment_ = ZipConstants.ConvertToString(rawComment_);3273        }3274      }  32753276        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);3277        CheckClassicPassword(result, entry);3278      }3279      else {3280#if !NET_1_1 && !NETCF_2_03281        if (entry.Version == ZipConstants.VERSION_AES) {3282          //3283          OnKeysRequired(entry.Name);3284          if (HaveKeys == false) {3285            throw new ZipException("No password available for AES encrypted stream");3286          }3287          int saltLen = entry.AESSaltLen;3288          byte[] saltBytes = new byte[saltLen];3289          int saltIn = baseStream.Read(saltBytes, 0, saltLen);3290          if (saltIn != saltLen)3291            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);3292          //3293          byte[] pwdVerifyRead = new byte[2];3294          baseStream.Read(pwdVerifyRead, 0, 2);3295          int blockSize = entry.AESKeySize / 8;  // bits to bytes32963297          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);3298          byte[] pwdVerifyCalc = decryptor.PwdVerifier;3299          if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])3300            throw new Exception("Invalid password for AES");3301          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);3302        }3303        else3304#endif3305        {3306          throw new ZipException("Decryption method not supported");3307        }3308      }33093310      return result;3311    }33123313    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)3314    {3315      CryptoStream result = null;3316      if ( (entry.Version < ZipConstants.VersionStrongEncryption)3317        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3318        var classicManaged = new PkzipClassicManaged();3276      void MakeBytesAvailable()3277      {3278        if (rawComment_ == null) {3279          rawComment_ = ZipConstants.ConvertToArray(comment_);3280        }3281      }32823283      /// <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      }32933294      #region Instance Fields3295      string comment_;3296      byte[] rawComment_;3297      bool isSourceString_;3298      #endregion3299    }33003301    /// <summary>3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3303    /// </summary>3304    class ZipEntryEnumerator : IEnumerator3305    {3306      #region Constructors3307      public ZipEntryEnumerator(ZipEntry[] entries)3308      {3309        array = entries;3310      }33113312      #endregion3313      #region IEnumerator Members3314      public object Current {3315        get {3316          return array[index];3317        }3318      }  33193320        OnKeysRequired(entry.Name);3321        if (HaveKeys == false) {3322          throw new ZipException("No password available for encrypted stream");3323        }3320      public void Reset()3321      {3322        index = -1;3323      }  33243325        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3326        // which doesnt do this.3327        result = new CryptoStream(new UncompressedStream(baseStream),3328          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);33293330        if ( (entry.Crc < 0) || (entry.Flags & 8) != 0) {3331          WriteEncryptionHeader(result, entry.DosTime << 16);3332        }3333        else {3334          WriteEncryptionHeader(result, entry.Crc);3335        }3336      }3337      return result;3338    }33393340    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)3325      public bool MoveNext()3326      {3327        return (++index < array.Length);3328      }3329      #endregion3330      #region Instance Fields3331      ZipEntry[] array;3332      int index = -1;3333      #endregion3334    }33353336    /// <summary>3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3338    /// to and flush, but cannot read, seek or do anything else to.3339    /// </summary>3340    class UncompressedStream : Stream  3341    {3342      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];3343      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);3344      if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {3345        throw new ZipException("Invalid password");3342      #region Constructors3343      public UncompressedStream(Stream baseStream)3344      {3345        baseStream_ = baseStream;  3346      }3347    }3348#endif33473348      #endregion  33493350    static void WriteEncryptionHeader(Stream stream, long crcValue)3351    {3352      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];3353      var rnd = new Random();3354      rnd.NextBytes(cryptBuffer);3355      cryptBuffer[11] = (byte)(crcValue >> 24);3356      stream.Write(cryptBuffer, 0, cryptBuffer.Length);3357    }33583359    #endregion33603361    #region Instance Fields3362    bool       isDisposed_;3363    string     name_;3364    string     comment_;3365    string     rawPassword_;3366    Stream     baseStream_;3367    bool       isStreamOwner;3368    long       offsetOfFirstEntry;3369    ZipEntry[] entries_;3370    byte[] key;3371    bool isNewArchive_;33723373    // Default is dynamic which is not backwards compatible and can cause problems3374    // with XP's built in compression which cant read Zip64 archives.3375    // However it does avoid the situation were a large file is added and cannot be completed correctly.3376    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.3377    UseZip64 useZip64_ = UseZip64.Dynamic ;33783379    #region Zip Update Instance Fields3380    ArrayList updates_;3381    long updateCount_; // Count is managed manually as updates_ can contain nulls!3382    Hashtable updateIndex_;3383    IArchiveStorage archiveStorage_;3384    IDynamicDataSource updateDataSource_;3385    bool contentsEdited_;3386    int bufferSize_ = DefaultBufferSize;3387    byte[] copyBuffer_;3388    ZipString newComment_;3389    bool commentEdited_;3390    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();3391    #endregion3392    #endregion33933394    #region Support Classes3395    /// <summary>3396    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3397    /// </summary>3398    class ZipString3399    {3400      #region Constructors3401      /// <summary>3402      /// Initialise a <see cref="ZipString"/> with a string.3403      /// </summary>3404      /// <param name="comment">The textual string form.</param>3405      public ZipString(string comment)3406      {3407        comment_ = comment;3408        isSourceString_ = true;3409      }34103411      /// <summary>3412      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.3413      /// </summary>3414      /// <param name="rawString"></param>3415      public ZipString(byte[] rawString)3416      {3417        rawComment_ = rawString;3418      }3419      #endregion34203421      /// <summary>3422      /// Get a value indicating the original source of data for this instance.3423      /// True if the source was a string; false if the source was binary data.3424      /// </summary>3425      public bool IsSourceString3426      {3427        get { return isSourceString_; }3428      }34293430      /// <summary>3431      /// Get the length of the comment when represented as raw bytes.3432      /// </summary>3433      public int RawLength3434      {3435        get {3436          MakeBytesAvailable();3437          return rawComment_.Length;3438        }3439      }34403441      /// <summary>3442      /// Get the comment in its 'raw' form as plain bytes.3443      /// </summary>3444      public byte[] RawComment3445      {3446        get {3447          MakeBytesAvailable();3448          return (byte[])rawComment_.Clone();3449        }3450      }34513452      /// <summary>3453      /// Reset the comment to its initial state.3454      /// </summary>3455      public void Reset()3456      {3457        if ( isSourceString_ ) {3458          rawComment_ = null;3459        }3460        else {3461          comment_ = null;3462        }3463      }34643465      void MakeTextAvailable()3466      {3467        if ( comment_ == null ) {3468          comment_ = ZipConstants.ConvertToString(rawComment_);3469        }3470      }34713472      void MakeBytesAvailable()3473      {3474        if ( rawComment_ == null ) {3475          rawComment_ = ZipConstants.ConvertToArray(comment_);3476        }3477      }34783479      /// <summary>3480      /// Implicit conversion of comment to a string.3481      /// </summary>3482      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>3483      /// <returns>The textual equivalent for the input value.</returns>3484      static public implicit operator string(ZipString zipString)3485      {3486        zipString.MakeTextAvailable();3487        return zipString.comment_;3488      }34893490      #region Instance Fields3491      string comment_;3492      byte[] rawComment_;3493      bool isSourceString_;3494      #endregion3495    }34963497    /// <summary>3498    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3499    /// </summary>3500    class ZipEntryEnumerator : IEnumerator3501    {3502      #region Constructors3503      public ZipEntryEnumerator(ZipEntry[] entries)3504      {3505        array = entries;3506      }35073508      #endregion3509      #region IEnumerator Members3510      public object Current3511      {3512        get {3513          return array[index];3514        }3515      }35163517      public void Reset()3518      {3519        index = -1;3520      }35213522      public bool MoveNext()3523      {3524        return (++index < array.Length);3525      }3526      #endregion3527      #region Instance Fields3528      ZipEntry[] array;3529      int index = -1;3530      #endregion3531    }35323533    /// <summary>3534    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3535    /// to and flush, but cannot read, seek or do anything else to.3536    /// </summary>3537    class UncompressedStream : Stream3538    {3539      #region Constructors3540      public UncompressedStream(Stream baseStream)3541      {3542        baseStream_ = baseStream;3543      }35443545      #endregion35463547      /// <summary>3548      /// Close this stream instance.3549      /// </summary>3550      public override void Close()3551      {3552        // Do nothing3553      }35543555      /// <summary>3556      /// Gets a value indicating whether the current stream supports reading.3557      /// </summary>3558      public override bool CanRead3559      {3560        get {3561          return false;3562        }3563      }35643565      /// <summary>3566      /// Write any buffered data to underlying storage.3567      /// </summary>3568      public override void Flush()3569      {3570        baseStream_.Flush();3571      }35723573      /// <summary>3574      /// Gets a value indicating whether the current stream supports writing.3575      /// </summary>3576      public override bool CanWrite3577      {3578        get {3579          return baseStream_.CanWrite;3580        }3581      }35823583      /// <summary>3584      /// Gets a value indicating whether the current stream supports seeking.3585      /// </summary>3586      public override bool CanSeek3587      {3588        get {3589          return false;3590        }3591      }35923593      /// <summary>3594      /// Get the length in bytes of the stream.3595      /// </summary>3596      public override long Length3597      {3598        get {3599          return 0;3600        }3601      }36023603      /// <summary>3604      /// Gets or sets the position within the current stream.3605      /// </summary>3606      public override long Position3607      {3608        get  {3609          return baseStream_.Position;3610        }3611                set {3612                    throw new NotImplementedException();3613                }3614            }36153616            /// <summary>3617            /// Reads a sequence of bytes from the current stream and advances the position within the stream by the num3618            /// </summary>3619            /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte3620            /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from t3621            /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3622            /// <returns>3623            /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if t3624            /// </returns>3625            /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer lengt3626            /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </ex3627            /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3628            /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3629            /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3630            /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3631            public override int Read(byte[] buffer, int offset, int count)3632      {3633        return 0;3634      }36353636      /// <summary>3637      /// Sets the position within the current stream.3638      /// </summary>3639      /// <param name="offset">A byte offset relative to the origin parameter.</param>3640      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3641      /// <returns>3642      /// The new position within the current stream.3643      /// </returns>3644      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3645      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3646      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3647      public override long Seek(long offset, SeekOrigin origin)3648      {3649        return 0;3650      }36513652      /// <summary>3653      /// Sets the length of the current stream.3654      /// </summary>3655      /// <param name="value">The desired length of the current stream in bytes.</param>3656      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3350      /// <summary>3351      /// Close this stream instance.3352      /// </summary>3353      public override void Close()3354      {3355        // Do nothing3356      }33573358      /// <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      }33663367      /// <summary>3368      /// Write any buffered data to underlying storage.3369      /// </summary>3370      public override void Flush()3371      {3372        baseStream_.Flush();3373      }33743375      /// <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      }33833384      /// <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      }33923393      /// <summary>3394      /// Get the length in bytes of the stream.3395      /// </summary>3396      public override long Length {3397        get {3398          return 0;3399        }3400      }34013402      /// <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      }34133414      /// <summary>3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3416      /// </summary>3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3419      /// <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 ma3422      /// </returns>3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3425      /// <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      }34333434      /// <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 is3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3445      public override long Seek(long offset, SeekOrigin origin)3446      {3447        return 0;3448      }34493450      /// <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 as3455      /// <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. </exceptio3457      public override void SetLength(long value)3458      {3459      }34603461      /// <summary>3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3463      /// </summary>3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3466      /// <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. </exceptio3470      /// <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      }34773478      readonly34793480      #region Instance Fields3481      Stream baseStream_;3482      #endregion3483    }34843485    /// <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 : Stream3490    {3491      #region Constructors3492      /// <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;35023503        // Although this is the only time the zipfile is used3504        // keeping a reference here prevents premature closure of3505        // this zip file and thus the baseStream_.35063507        // Code like this will cause apparently random failures depending3508        // 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      #endregion35193520      /// <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        }35303531        lock (baseStream_) {3532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);3533          return baseStream_.ReadByte();3534        }3535      }35363537      /// <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      }35473548      /// <summary>3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3550      /// </summary>3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3553      /// <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 ma3556      /// </returns>3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3559      /// <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 Seek3573          // (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      }35843585      /// <summary>3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3587      /// </summary>3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3590      /// <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. </exceptio3594      /// <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      }36013602      /// <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 as3607      /// <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. </exceptio3609      public override void SetLength(long value)3610      {3611        throw new NotSupportedException();3612      }36133614      /// <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 is3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3625      public override long Seek(long offset, SeekOrigin origin)3626      {3627        long newPos = readPos_;36283629        switch (origin) {3630          case SeekOrigin.Begin:3631            newPos = start_ + offset;3632            break;36333634          case SeekOrigin.Current:3635            newPos = readPos_ + offset;3636            break;36373638          case SeekOrigin.End:3639            newPos = end_ + offset;3640            break;3641        }36423643        if (newPos < start_) {3644          throw new ArgumentException("Negative position is invalid");3645        }36463647        if (newPos >= end_) {3648          throw new IOException("Cannot seek past end");3649        }3650        readPos_ = newPos;3651        return readPos_;3652      }36533654      /// <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      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3659      public override void SetLength(long value)3660      {3658      public override void Flush()3659      {3660        // Nothing to do.  3661      }  3662  3663      /// <summary>3664      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3664      /// Gets or sets the position within the current stream.  3665      /// </summary>3666      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3667      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3668      /// <param name="count">The number of bytes to be written to the current stream.</param>3669      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3670      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3671      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3672      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3673      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3674      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3675      public override void Write(byte[] buffer, int offset, int count)3676      {3677        baseStream_.Write(buffer, offset, count);3678      }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. </exceptio3671      public override long Position {3672        get { return readPos_ - start_; }3673        set {3674          long newPos = start_ + value;36753676          if (newPos < start_) {3677            throw new ArgumentException("Negative position is invalid");3678          }  36793680      readonly36813682      #region Instance Fields3683      Stream baseStream_;3684      #endregion3685    }3680          if (newPos >= end_) {3681            throw new InvalidOperationException("Cannot seek past end");3682          }3683          readPos_ = newPos;3684        }3685      }  36863687    /// <summary>3688    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>3689    /// whose data is only a part or subsection of a file.3690    /// </summary>3691    class PartialInputStream : Stream3692    {3693      #region Constructors3694      /// <summary>3695      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.3696      /// </summary>3697      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>3698      /// <param name="start">The start of the partial data.</param>3699      /// <param name="length">The length of the partial data.</param>3700      public PartialInputStream(ZipFile zipFile, long start, long length)3701      {3702        start_ = start;3703        length_ = length;37043705        // Although this is the only time the zipfile is used3706        // keeping a reference here prevents premature closure of3707        // this zip file and thus the baseStream_.37083709        // Code like this will cause apparently random failures depending3710        // on the size of the files and when garbage is collected.3711        //3712        // ZipFile z = new ZipFile (stream);3713        // Stream reader = z.GetInputStream(0);3714        // uses reader here....3715        zipFile_ = zipFile;3716        baseStream_ = zipFile_.baseStream_;3717        readPos_ = start;3718        end_ = start + length;3719      }3720      #endregion37213722      /// <summary>3723      /// Read a byte from this stream.3724      /// </summary>3725      /// <returns>Returns the byte read or -1 on end of stream.</returns>3726      public override int ReadByte()3727      {3728        if (readPos_ >= end_) {3729           // -1 is the correct value at end of stream.3730          return -1;3731        }37323733        lock( baseStream_ ) {3734          baseStream_.Seek(readPos_++, SeekOrigin.Begin);3735          return baseStream_.ReadByte();3736        }3737      }37383739      /// <summary>3740      /// Close this <see cref="PartialInputStream">partial input stream</see>.3741      /// </summary>3742      /// <remarks>3743      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.3744      /// </remarks>3745      public override void Close()3746      {3747        // Do nothing at all!3748      }37493750      /// <summary>3751      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3752      /// </summary>3753      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3754      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3755      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3756      /// <returns>3757      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma3758      /// </returns>3759      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3760      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3761      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3762      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3763      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3764      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3765      public override int Read(byte[] buffer, int offset, int count)3766      {3767        lock(baseStream_) {3768          if (count > end_ - readPos_) {3769            count = (int) (end_ - readPos_);3770            if (count == 0) {3771              return 0;3772            }3773          }37743775          baseStream_.Seek(readPos_, SeekOrigin.Begin);3776          int readCount = baseStream_.Read(buffer, offset, count);3777          if (readCount > 0) {3778            readPos_ += readCount;3779          }3780          return readCount;3781        }3782      }37833784      /// <summary>3785      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3786      /// </summary>3787      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3788      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3789      /// <param name="count">The number of bytes to be written to the current stream.</param>3790      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3791      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3792      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3793      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3794      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3795      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3796      public override void Write(byte[] buffer, int offset, int count)3797      {3798        throw new NotSupportedException();3799      }38003801      /// <summary>3802      /// When overridden in a derived class, sets the length of the current stream.3803      /// </summary>3804      /// <param name="value">The desired length of the current stream in bytes.</param>3805      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3806      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3807      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3808      public override void SetLength(long value)3809      {3810        throw new NotSupportedException();3811      }38123813      /// <summary>3814      /// When overridden in a derived class, sets the position within the current stream.3815      /// </summary>3816      /// <param name="offset">A byte offset relative to the origin parameter.</param>3817      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3818      /// <returns>3819      /// The new position within the current stream.3820      /// </returns>3821      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3822      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3823      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3824      public override long Seek(long offset, SeekOrigin origin)3825      {3826        long newPos = readPos_;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. </excep3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3694      public override long Length {3695        get { return length_; }3696      }36973698      /// <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      }37063707      /// <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      }37153716      /// <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      }37243725      /// <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 Fields3734      ZipFile zipFile_;3735      Stream baseStream_;3736      long start_;3737      long length_;3738      long readPos_;3739      long end_;3740      #endregion3741    }3742    #endregion3743  }37443745  #endregion37463747  #region DataSources3748  /// <summary>3749  /// Provides a static way to obtain a source of data for an entry.3750  /// </summary>3751  public interface IStaticDataSource3752  {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  }37603761  /// <summary>3762  /// Represents a source of data that can dynamically provide3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3764  /// </summary>3765  public interface IDynamicDataSource3766  {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  }37763777  /// <summary>3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3779  /// </summary>3780  public class StaticDiskDataSource : IStaticDataSource3781  {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    }37903791    #region IDataSource Members37923793    /// <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    }38013802    readonly38033804    #endregion3805    #region Instance Fields3806    string fileName_;3807    #endregion3808  }380938103811  /// <summary>3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.3813  /// </summary>3814  public class DynamicDiskDataSource : IDynamicDataSource3815  {38163817    #region IDataSource Members3818    /// <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;  38273828        switch ( origin )3829        {3830          case SeekOrigin.Begin:3831            newPos = start_ + offset;3832            break;38333834          case SeekOrigin.Current:3835            newPos = readPos_ + offset;3836            break;3828      if (name != null) {3829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);3830      }38313832      return result;3833    }38343835    #endregion3836  }  38373838          case SeekOrigin.End:3839            newPos = end_ + offset;3840            break;3841        }38423843        if ( newPos < start_ ) {3844          throw new ArgumentException("Negative position is invalid");3845        }38463847        if ( newPos >= end_ ) {3848          throw new IOException("Cannot seek past end");3849        }3850        readPos_ = newPos;3851        return readPos_;3852      }38533854      /// <summary>3855      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.3856      /// </summary>3857      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3858      public override void Flush()3859      {3860        // Nothing to do.3861      }38623863      /// <summary>3864      /// Gets or sets the position within the current stream.3865      /// </summary>3866      /// <value></value>3867      /// <returns>The current position within the stream.</returns>3868      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3869      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>3870      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3871      public override long Position {3872        get { return readPos_ - start_; }3873        set {3874          long newPos = start_ + value;38753876          if ( newPos < start_ ) {3877            throw new ArgumentException("Negative position is invalid");3878          }3838  #endregion38393840  #region Archive Storage3841  /// <summary>3842  /// Defines facilities for data storage when updating Zip Archives.3843  /// </summary>3844  public interface IArchiveStorage3845  {3846    /// <summary>3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.3848    /// </summary>3849    FileUpdateMode UpdateMode { get; }38503851    /// <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();38573858    /// <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();38643865    /// <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);38713872    /// <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);  38793880          if ( newPos >= end_ ) {3881            throw new InvalidOperationException("Cannot seek past end");3882          }3883          readPos_ = newPos;3884        }3885      }38863887      /// <summary>3888      /// Gets the length in bytes of the stream.3889      /// </summary>3890      /// <value></value>3891      /// <returns>A long value representing the length of the stream in bytes.</returns>3892      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep3893      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3894      public override long Length {3895        get { return length_; }3896      }38973898      /// <summary>3899      /// Gets a value indicating whether the current stream supports writing.3900      /// </summary>3901      /// <value>false</value>3902      /// <returns>true if the stream supports writing; otherwise, false.</returns>3903      public override bool CanWrite {3904        get { return false; }3905      }39063907      /// <summary>3908      /// Gets a value indicating whether the current stream supports seeking.3909      /// </summary>3910      /// <value>true</value>3911      /// <returns>true if the stream supports seeking; otherwise, false.</returns>3912      public override bool CanSeek {3913        get { return true; }3914      }39153916      /// <summary>3917      /// Gets a value indicating whether the current stream supports reading.3918      /// </summary>3919      /// <value>true.</value>3920      /// <returns>true if the stream supports reading; otherwise, false.</returns>3921      public override bool CanRead {3922        get { return true; }3923      }39243925#if !NET_1_0 && !NET_1_1 && !NETCF_1_03926      /// <summary>3927      /// Gets a value that determines whether the current stream can time out.3928      /// </summary>3929      /// <value></value>3930      /// <returns>A value that determines whether the current stream can time out.</returns>3931      public override bool CanTimeout {3932        get { return baseStream_.CanTimeout; }3933      }3934#endif3935      #region Instance Fields3936      ZipFile zipFile_;3937      Stream baseStream_;3938      long start_;3939      long length_;3940      long readPos_;3941      long end_;3942      #endregion3943    }3944    #endregion3945  }39463947  #endregion39483949  #region DataSources3950  /// <summary>3951  /// Provides a static way to obtain a source of data for an entry.3952  /// </summary>3953  public interface IStaticDataSource3954  {3955    /// <summary>3956    /// Get a source of data by creating a new stream.3957    /// </summary>3958    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3959    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3960    Stream GetSource();3961  }39623963  /// <summary>3964  /// Represents a source of data that can dynamically provide3965  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3966  /// </summary>3967  public interface IDynamicDataSource3968  {3969    /// <summary>3970    /// Get a data source.3971    /// </summary>3972    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>3973    /// <param name="name">The name for data if known.</param>3974    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3975    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3976    Stream GetSource(ZipEntry entry, string name);3977  }39783979  /// <summary>3980  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3981  /// </summary>3982  public class StaticDiskDataSource : IStaticDataSource3983  {3984    /// <summary>3985    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>3986    /// </summary>3987    /// <param name="fileName">The name of the file to obtain data from.</param>3988    public StaticDiskDataSource(string fileName)3989    {3990      fileName_ = fileName;3991    }39923993    #region IDataSource Members39943995    /// <summary>3996    /// Get a <see cref="Stream"/> providing data.3997    /// </summary>3998    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>3999    public Stream GetSource()4000    {4001      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4002    }3880    /// <summary>3881    /// Dispose of this instance.3882    /// </summary>3883    void Dispose();3884  }38853886  /// <summary>3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.3888  /// </summary>3889  abstract public class BaseArchiveStorage : IArchiveStorage3890  {3891    #region Constructors3892    /// <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    #endregion39013902    #region IArchiveStorage Members39033904    /// <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();39103911    /// <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 read3915    /// the final storage for the archive.</returns>3916    /// <seealso cref="GetTemporaryOutput"/>3917    public abstract Stream ConvertTemporaryToFinal();39183919    /// <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);39253926    /// <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);39323933    /// <summary>3934    /// Disposes this instance.3935    /// </summary>3936    public abstract void Dispose();39373938    /// <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    }39473948    #endregion39493950    #region Instance Fields3951    FileUpdateMode updateMode_;3952    #endregion3953  }39543955  /// <summary>3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.3957  /// </summary>3958  public class DiskArchiveStorage : BaseArchiveStorage3959  {3960    #region Constructors3961    /// <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      }39723973      fileName_ = file.Name;3974    }39753976    /// <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    #endregion39853986    #region IArchiveStorage Members39873988    /// <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      }  40034004    readonly40054006    #endregion4007    #region Instance Fields4008    string fileName_;4009    #endregion4010  }401140124013  /// <summary>4014  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.4015  /// </summary>4016  public class DynamicDiskDataSource : IDynamicDataSource4017  {40184019    #region IDataSource Members4020    /// <summary>4021    /// Get a <see cref="Stream"/> providing data for an entry.4022    /// </summary>4023    /// <param name="entry">The entry to provide data for.</param>4024    /// <param name="name">The file name for data if known.</param>4025    /// <returns>Returns a stream providing data; or null if not available</returns>4026    public Stream GetSource(ZipEntry entry, string name)4027    {4028      Stream result = null;4004      return temporaryStream_;4005    }40064007    /// <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 read4011    /// 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      }40174018      Stream result = null;40194020      string moveTempName = GetTempFileName(fileName_, false);4021      bool newFileCreated = false;40224023      try {4024        temporaryStream_.Close();4025        File.Move(fileName_, moveTempName);4026        File.Move(temporaryName_, fileName_);4027        newFileCreated = true;4028        File.Delete(moveTempName);  40294030      if ( name != null ) {4031        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);4032      }4030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4031      } catch (Exception) {4032        result = null;  40334034      return result;4035    }40364037    #endregion4038  }4034        // Try to roll back changes...4035        if (!newFileCreated) {4036          File.Move(moveTempName, fileName_);4037          File.Delete(temporaryName_);4038        }  40394040  #endregion40414042  #region Archive Storage4043  /// <summary>4044  /// Defines facilities for data storage when updating Zip Archives.4045  /// </summary>4046  public interface IArchiveStorage4047  {4048    /// <summary>4049    /// Get the <see cref="FileUpdateMode"/> to apply during updates.4050    /// </summary>4051    FileUpdateMode UpdateMode { get; }40524053    /// <summary>4054    /// Get an empty <see cref="Stream"/> that can be used for temporary output.4055    /// </summary>4056    /// <returns>Returns a temporary output <see cref="Stream"/></returns>4057    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4058    Stream GetTemporaryOutput();40594060    /// <summary>4061    /// Convert a temporary output stream to a final stream.4062    /// </summary>4063    /// <returns>The resulting final <see cref="Stream"/></returns>4064    /// <seealso cref="GetTemporaryOutput"/>4065    Stream ConvertTemporaryToFinal();40664067    /// <summary>4068    /// Make a temporary copy of the original stream.4069    /// </summary>4070    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4071    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4072    Stream MakeTemporaryCopy(Stream stream);40734074    /// <summary>4075    /// Return a stream suitable for performing direct updates on the original source.4076    /// </summary>4077    /// <param name="stream">The current stream.</param>4078    /// <returns>Returns a stream suitable for direct updating.</returns>4079    /// <remarks>This may be the current stream passed.</remarks>4080    Stream OpenForDirectUpdate(Stream stream);40814082    /// <summary>4083    /// Dispose of this instance.4084    /// </summary>4085    void Dispose();4086  }4040        throw;4041      }40424043      return result;4044    }40454046    /// <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();40544055      temporaryName_ = GetTempFileName(fileName_, true);4056      File.Copy(fileName_, temporaryName_, true);40574058      temporaryStream_ = new FileStream(temporaryName_,4059        FileMode.Open,4060        FileAccess.ReadWrite);4061      return temporaryStream_;4062    }40634064    /// <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        }40774078        result = new FileStream(fileName_,4079            FileMode.Open,4080            FileAccess.ReadWrite);4081      } else {4082        result = stream;4083      }40844085      return result;4086    }  40874088  /// <summary>4089  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.4090  /// </summary>4091  abstract public class BaseArchiveStorage : IArchiveStorage4092  {4093    #region Constructors4094    /// <summary>4095    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.4096    /// </summary>4097    /// <param name="updateMode">The update mode.</param> - 484098    protected BaseArchiveStorage(FileUpdateMode updateMode)4099    { - 484100      updateMode_ = updateMode; - 484101    }4102    #endregion41034104    #region IArchiveStorage Members41054106    /// <summary>4107    /// Gets a temporary output <see cref="Stream"/>4108    /// </summary>4109    /// <returns>Returns the temporary output stream.</returns>4110    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4111    public abstract Stream GetTemporaryOutput();41124113    /// <summary>4114    /// Converts the temporary <see cref="Stream"/> to its final form.4115    /// </summary>4116    /// <returns>Returns a <see cref="Stream"/> that can be used to read4117    /// the final storage for the archive.</returns>4118    /// <seealso cref="GetTemporaryOutput"/>4119    public abstract Stream ConvertTemporaryToFinal();41204121    /// <summary>4122    /// Make a temporary copy of a <see cref="Stream"/>.4123    /// </summary>4124    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>4125    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4126    public abstract Stream MakeTemporaryCopy(Stream stream);41274128    /// <summary>4129    /// Return a stream suitable for performing direct updates on the original source.4130    /// </summary>4131    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>4132    /// <returns>Returns a stream suitable for direct updating.</returns>4133    public abstract Stream OpenForDirectUpdate(Stream stream);41344135    /// <summary>4136    /// Disposes this instance.4137    /// </summary>4138    public abstract void Dispose();41394140    /// <summary>4141    /// Gets the update mode applicable.4142    /// </summary>4143    /// <value>The update mode.</value>4144    public FileUpdateMode UpdateMode4145    {4146      get { - 364147        return updateMode_;4148      }4149    }41504151    #endregion41524153    #region Instance Fields4154    FileUpdateMode updateMode_;4155    #endregion4156  }41574158  /// <summary>4159  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.4160  /// </summary>4161  public class DiskArchiveStorage : BaseArchiveStorage4162  {4163    #region Constructors4164    /// <summary>4165    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4166    /// </summary>4167    /// <param name="file">The file.</param>4168    /// <param name="updateMode">The update mode.</param>4169    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)4170      : base(updateMode)4171    {4172      if ( file.Name == null ) {4173        throw new ZipException("Cant handle non file archives");4174      }41754176      fileName_ = file.Name;4177    }4088    /// <summary>4089    /// Disposes this instance.4090    /// </summary>4091    public override void Dispose()4092    {4093      if (temporaryStream_ != null) {4094        temporaryStream_.Close();4095      }4096    }40974098    #endregion40994100    #region Internal routines4101    static string GetTempFileName(string original, bool makeTempFile)4102    {4103      string result = null;41044105      if (original == null) {4106        result = Path.GetTempFileName();4107      } else {4108        int counter = 0;4109        int suffixSeed = DateTime.Now.Second;41104111        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    #endregion41334134    #region Instance Fields4135    Stream temporaryStream_;4136    string fileName_;4137    string temporaryName_;4138    #endregion4139  }41404141  /// <summary>4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4143  /// </summary>4144  public class MemoryArchiveStorage : BaseArchiveStorage4145  {4146    #region Constructors4147    /// <summary>4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4149    /// </summary>4150    public MemoryArchiveStorage()4151      : base(FileUpdateMode.Direct)4152    {4153    }41544155    /// <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    }41644165    #endregion41664167    #region Properties4168    /// <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    }41744175    #endregion41764177    #region IArchiveStorage Members  4178  4179    /// <summary>4180    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4180    /// Gets the temporary output <see cref="Stream"/>  4181    /// </summary>4182    /// <param name="file">The file.</param>4183    public DiskArchiveStorage(ZipFile file)4184      : this(file, FileUpdateMode.Safe)4185    {4186    }4187    #endregion4182    /// <returns>Returns the temporary output stream.</returns>4183    public override Stream GetTemporaryOutput()4184    {4185      temporaryStream_ = new MemoryStream();4186      return temporaryStream_;4187    }  41884189    #region IArchiveStorage Members41904191    /// <summary>4192    /// Gets a temporary output <see cref="Stream"/> for performing updates on.4193    /// </summary>4194    /// <returns>Returns the temporary output stream.</returns>4195    public override Stream GetTemporaryOutput()4196    {4197      if ( temporaryName_ != null ) {4198        temporaryName_ = GetTempFileName(temporaryName_, true);4199        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4200      }4201      else {4202        // Determine where to place files based on internal strategy.4203        // Currently this is always done in system temp directory.4204        temporaryName_ = Path.GetTempFileName();4205        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4206      }42074208      return temporaryStream_;4209    }42104211    /// <summary>4212    /// Converts a temporary <see cref="Stream"/> to its final form.4213    /// </summary>4214    /// <returns>Returns a <see cref="Stream"/> that can be used to read4215    /// the final storage for the archive.</returns>4216    public override Stream ConvertTemporaryToFinal()4217    {4218      if ( temporaryStream_ == null ) {4219        throw new ZipException("No temporary stream has been created");4220      }42214222      Stream result = null;42234224      string moveTempName = GetTempFileName(fileName_, false);4225      bool newFileCreated = false;42264227      try  {4228        temporaryStream_.Close();4229        File.Move(fileName_, moveTempName);4230        File.Move(temporaryName_, fileName_);4231        newFileCreated = true;4232        File.Delete(moveTempName);42334234        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4235      }4236      catch(Exception) {4237        result  = null;42384239        // Try to roll back changes...4240        if ( !newFileCreated ) {4241          File.Move(moveTempName, fileName_);4242          File.Delete(temporaryName_);4243        }42444245        throw;4246      }42474248      return result;4249    }42504251    /// <summary>4252    /// Make a temporary copy of a stream.4253    /// </summary>4254    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4255    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4256    public override Stream MakeTemporaryCopy(Stream stream)4257    {4258      stream.Close();42594260      temporaryName_ = GetTempFileName(fileName_, true);4261      File.Copy(fileName_, temporaryName_, true);42624263      temporaryStream_ = new FileStream(temporaryName_,4264        FileMode.Open,4265        FileAccess.ReadWrite);4266      return temporaryStream_;4267    }42684269    /// <summary>4270    /// Return a stream suitable for performing direct updates on the original source.4271    /// </summary>4272    /// <param name="stream">The current stream.</param>4273    /// <returns>Returns a stream suitable for direct updating.</returns>4274    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>4275    public override Stream OpenForDirectUpdate(Stream stream)4276    {4277      Stream result;4278      if ((stream == null) || !stream.CanWrite)4279      {4280        if (stream != null) {4281          stream.Close();4282        }42834284        result = new FileStream(fileName_,4285            FileMode.Open,4286            FileAccess.ReadWrite);4287      }4288      else4289      {4290        result = stream;4291      }42924293      return result;4294    }42954296    /// <summary>4297    /// Disposes this instance.4298    /// </summary>4299    public override void Dispose()4300    {4301      if ( temporaryStream_ != null ) {4302        temporaryStream_.Close();4303      }4304    }43054306    #endregion43074308    #region Internal routines4309    static string GetTempFileName(string original, bool makeTempFile)4310    {4311      string result = null;43124313      if ( original == null ) {4314        result = Path.GetTempFileName();4315      }4316      else {4317        int counter = 0;4318        int suffixSeed = DateTime.Now.Second;43194320        while ( result == null ) {4321          counter += 1;4322          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);4323          if ( !File.Exists(newName) ) {4324            if ( makeTempFile) {4325              try  {4326                // Try and create the file.4327                using ( FileStream stream = File.Create(newName) ) {4328                }4329                result = newName;4330              }4331              catch {4332                suffixSeed = DateTime.Now.Second;4333              }4334            }4335            else {4336              result = newName;4337            }4338          }4339        }4340      }4341      return result;4342    }4343    #endregion43444345    #region Instance Fields4346    Stream temporaryStream_;4347    string fileName_;4348    string temporaryName_;4349    #endregion4350  }43514352  /// <summary>4353  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4354  /// </summary>4355  public class MemoryArchiveStorage : BaseArchiveStorage4356  {4357    #region Constructors4358    /// <summary>4359    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4360    /// </summary>4361    public MemoryArchiveStorage()4362      : base(FileUpdateMode.Direct)4363    {4364    }43654366    /// <summary>4367    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4368    /// </summary>4369    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>4370    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>4371    public MemoryArchiveStorage(FileUpdateMode updateMode)4372      : base(updateMode)4373    {4374    }43754376    #endregion43774378    #region Properties4379    /// <summary>4380    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.4381    /// </summary>4382    public MemoryStream FinalStream4383    {4384      get { return finalStream_; }4385    }43864387    #endregion43884389    #region IArchiveStorage Members43904391    /// <summary>4392    /// Gets the temporary output <see cref="Stream"/>4393    /// </summary>4394    /// <returns>Returns the temporary output stream.</returns>4395    public override Stream GetTemporaryOutput()4396    {4397      temporaryStream_ = new MemoryStream();4398      return temporaryStream_;4399    }44004401    /// <summary>4402    /// Converts the temporary <see cref="Stream"/> to its final form.4403    /// </summary>4404    /// <returns>Returns a <see cref="Stream"/> that can be used to read4405    /// the final storage for the archive.</returns>4406    public override Stream ConvertTemporaryToFinal()4407    {4408      if ( temporaryStream_ == null ) {4409        throw new ZipException("No temporary stream has been created");4410      }44114412      finalStream_ = new MemoryStream(temporaryStream_.ToArray());4413      return finalStream_;4414    }44154416    /// <summary>4417    /// Make a temporary copy of the original stream.4418    /// </summary>4419    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4420    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4421    public override Stream MakeTemporaryCopy(Stream stream)4422    {4423      temporaryStream_ = new MemoryStream();4424      stream.Position = 0;4425      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);4426      return temporaryStream_;4427    }44284429    /// <summary>4430    /// Return a stream suitable for performing direct updates on the original source.4431    /// </summary>4432    /// <param name="stream">The original source stream</param>4433    /// <returns>Returns a stream suitable for direct updating.</returns>4434    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;4435    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>4436    public override Stream OpenForDirectUpdate(Stream stream)4437    {4438      Stream result;4439      if ((stream == null) || !stream.CanWrite) {44404441        result = new MemoryStream();44424443        if (stream != null) {4444          stream.Position = 0;4445          StreamUtils.Copy(stream, result, new byte[4096]);44464447          stream.Close();4448        }4449      }4450      else {4451        result = stream;4452      }44534454      return result;4455    }44564457    /// <summary>4458    /// Disposes this instance.4459    /// </summary>4460    public override void Dispose()4461    {4462      if ( temporaryStream_ != null ) {4463        temporaryStream_.Close();4464      }4465    }44664467    #endregion44684469    #region Instance Fields4470    MemoryStream temporaryStream_;4471    MemoryStream finalStream_;4472    #endregion4473  }44744475  #endregion4476}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 read4193    /// 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      }41994200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());4201      return finalStream_;4202    }42034204    /// <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    }42164217    /// <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) {42284229        result = new MemoryStream();42304231        if (stream != null) {4232          stream.Position = 0;4233          StreamUtils.Copy(stream, result, new byte[4096]);42344235          stream.Close();4236        }4237      } else {4238        result = stream;4239      }42404241      return result;4242    }42434244    /// <summary>4245    /// Disposes this instance.4246    /// </summary>4247    public override void Dispose()4248    {4249      if (temporaryStream_ != null) {4250        temporaryStream_.Close();4251      }4252    }42534254    #endregion42554256    #region Instance Fields4257    MemoryStream temporaryStream_;4258    MemoryStream finalStream_;4259    #endregion4260  }42614262  #endregion4263} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_CompletedFileHandler.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_CompletedFileHandler.htm index 592864962..2efd90445 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_CompletedFileHandler.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_CompletedFileHandler.htm @@ -24,6 +24,6 @@

Summary

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/Documentation/opencover/ICSharpCode.SharpZipLib_Crc32.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_Crc32.htm index fcb62a1eb..a34b59f50 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_Crc32.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_Crc32.htm @@ -2,7 +2,7 @@ -ICSharpCode.SharpZipLib.Checksums.Crc32 - Coverage Report +ICSharpCode.SharpZipLib.Checksum.Crc32 - Coverage Report

Summary

@@ -12,259 +12,226 @@

Summary

-Class:ICSharpCode.SharpZipLib.Checksums.Crc32 +Class:ICSharpCode.SharpZipLib.Checksum.Crc32 Assembly:ICSharpCode.SharpZipLib -File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Checksums\Crc32.cs -Covered lines:70 -Uncovered lines:9 -Coverable lines:79 -Total lines:223 -Line coverage:88.6% -Branch coverage:50% +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
Reset()1100100
Update(...)1100100
Update(...)200
Update(...)672.7363.64
.cctor()1100100
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\Checksums\Crc32.cs

+

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

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + +
#LineLine coverage
 1// CRC32.cs - Computes CRC32 data checksum of a data stream
 2// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team
 3//
 4// This file was translated from java, it was part of the GNU Classpath
 5// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
 6//
 7// This program is free software; you can redistribute it and/or
 8// modify it under the terms of the GNU General Public License
 9// as published by the Free Software Foundation; either version 2
 10// of the License, or (at your option) any later version.
 11//
 12// This program is distributed in the hope that it will be useful,
 13// but WITHOUT ANY WARRANTY; without even the implied warranty of
 14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15// GNU General Public License for more details.
 16//
 17// You should have received a copy of the GNU General Public License
 18// along with this program; if not, write to the Free Software
 19// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 20//
 21// Linking this library statically or dynamically with other modules is
 22// making a combined work based on this library.  Thus, the terms and
 23// conditions of the GNU General Public License cover the whole
 24// combination.
 25//
 26// As a special exception, the copyright holders of this library give you
 27// permission to link this library with independent modules to produce an
 28// executable, regardless of the license terms of these independent
 29// modules, and to copy and distribute the resulting executable under
 30// terms of your choice, provided that you also meet, for each linked
 31// independent module, the terms and conditions of the license of that
 32// module.  An independent module is a module which is not derived from
 33// or based on this library.  If you modify this library, you may extend
 34// this exception to your version of the library, but you are not
 35// obligated to do so.  If you do not wish to do so, delete this
 36// exception statement from your version.
 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
 38using System;
 39
 40namespace ICSharpCode.SharpZipLib.Checksums
 41{
 42
 43  /// <summary>
 44  /// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
 45  /// 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.
 46  ///
 47  /// Polynomials over GF(2) are represented in binary, one bit per coefficient,
 48  /// with the lowest powers in the most significant bit.  Then adding polynomials
 49  /// is just exclusive-or, and multiplying a polynomial by x is a right shift by
 50  /// one.  If we call the above polynomial p, and represent a byte as the
 51  /// polynomial q, also with the lowest power in the most significant bit (so the
 52  /// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
 53  /// where a mod b means the remainder after dividing a by b.
 54  ///
 55  /// This calculation is done using the shift-register method of multiplying and
 56  /// taking the remainder.  The register is initialized to zero, and for each
 57  /// incoming bit, x^32 is added mod p to the register if the bit is a one (where
 58  /// x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
 59  /// x (which is shifting right by one and adding x^32 mod p if the bit shifted
 60  /// out is a one).  We start with the highest power (least significant bit) of
 61  /// q and repeat for all eight bits of q.
 62  ///
 63  /// The table is simply the CRC of all possible eight bit values.  This is all
 64  /// the information needed to generate CRC's on data a byte at a time for all
 65  /// combinations of CRC register values and incoming bytes.
 66  /// </summary>
 67  public sealed class Crc32 : IChecksum
 68  {
 69    const uint CrcSeed = 0xFFFFFFFF;
 70
 171    readonly static uint[] CrcTable = {
 172      0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,
 173      0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
 174      0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
 175      0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
 176      0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,
 177      0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
 178      0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
 179      0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
 180      0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
 181      0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,
 182      0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
 183      0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
 184      0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,
 185      0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
 186      0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
 187      0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
 188      0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
 189      0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
 190      0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
 191      0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
 192      0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
 193      0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
 194      0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,
 195      0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
 196      0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,
 197      0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
 198      0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
 199      0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
 1100      0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
 1101      0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
 1102      0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,
 1103      0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
 1104      0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
 1105      0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
 1106      0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
 1107      0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
 1108      0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,
 1109      0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
 1110      0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
 1111      0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
 1112      0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
 1113      0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
 1114      0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,
 1115      0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
 1116      0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
 1117      0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
 1118      0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
 1119      0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
 1120      0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
 1121      0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
 1122      0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
 1123      0x2D02EF8D
 1124    };
 125
 126    internal static uint ComputeCrc32(uint oldCrc, byte value)
 127    {
 4521654128      return (uint)(Crc32.CrcTable[(oldCrc ^ value) & 0xFF] ^ (oldCrc >> 8));
 129    }
 130
 131    /// <summary>
 132    /// The crc data checksum so far.
 133    /// </summary>
 134    uint crc;
 135
 136    /// <summary>
 137    /// Returns the CRC32 data checksum computed so far.
 138    /// </summary>
 139    public long Value {
 140      get {
 66254141        return (long)crc;
 142      }
 143      set {
 0144        crc = (uint)value;
 0145      }
 146    }
 147
 148    /// <summary>
 149    /// Resets the CRC32 data checksum as if no update was ever called.
 150    /// </summary>
 151    public void Reset()
 152    {
 164153      crc = 0;
 164154    }
 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    /// Updates the checksum with the int bval.
 157    /// Update CRC data checksum based on a portion of a block of data
 158    /// </summary>
 159    /// <param name = "value">
 160    /// the byte is taken as the lower 8 bits of value
 161    /// </param>
 162    public void Update(int value)
 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    {
 10164      crc ^= CrcSeed;
 10165      crc  = CrcTable[(crc ^ value) & 0xFF] ^ (crc >> 8);
 10166      crc ^= CrcSeed;
 10167    }
 168
 169    /// <summary>
 170    /// Updates the checksum with the bytes taken from the array.
 171    /// </summary>
 172    /// <param name="buffer">
 173    /// buffer an array of bytes
 174    /// </param>
 175    public void Update(byte[] buffer)
 176    {
 0177       if (buffer == null) {
 0178        throw new ArgumentNullException(nameof(buffer));
 179      }
 180
 0181      Update(buffer, 0, buffer.Length);
 0182    }
 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
 184    /// <summary>
 185    /// Adds the byte array to the data checksum.
 186    /// </summary>
 187    /// <param name = "buffer">
 188    /// The buffer which contains the data
 189    /// </param>
 190    /// <param name = "offset">
 191    /// The offset in the buffer where the data starts
 192    /// </param>
 193    /// <param name = "count">
 194    /// The number of data bytes to update the CRC with.
 195    /// </param>
 196    public void Update(byte[] buffer, int offset, int count)
 197    {
 5162198       if (buffer == null) {
 0199        throw new ArgumentNullException(nameof(buffer));
 200      }
 201
 5162202       if ( count < 0 ) {
 203#if NETCF_1_0
 204        throw new ArgumentOutOfRangeException("count");
 205#else
 0206        throw new ArgumentOutOfRangeException(nameof(count), "Count cannot be less than zero");
 207#endif
 208      }
 209
 5162210       if (offset < 0 || offset + count > buffer.Length) {
 0211        throw new ArgumentOutOfRangeException(nameof(offset));
 212      }
 213
 5162214      crc ^= CrcSeed;
 215
 4734443216       while (--count >= 0) {
 4729281217        crc = CrcTable[(crc ^ buffer[offset++]) & 0xFF] ^ (crc >> 8);
 218      }
 219
 5162220      crc ^= CrcSeed;
 5162221    }
 222  }
 223}
 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/Documentation/opencover/ICSharpCode.SharpZipLib_Deflater.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_Deflater.htm index 59f2d8cf6..f926a7d9a 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_Deflater.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_Deflater.htm @@ -18,7 +18,7 @@

Summary

Covered lines:69 Uncovered lines:29 Coverable lines:98 -Total lines:563 +Total lines:521 Line coverage:70.4% Branch coverage:68% @@ -49,571 +49,529 @@

#LineLine coverage - 1// Deflater.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839using System;4041namespace ICSharpCode.SharpZipLib.Zip.Compression42{4344  /// <summary>45  /// This is the Deflater class.  The deflater class compresses input46  /// with the deflate algorithm described in RFC 1951.  It has several47  /// compression levels and three different strategies described below.48  ///49  /// This class is <i>not</i> thread safe.  This is inherent in the API, due50  /// to the split of deflate and setInput.51  ///52  /// author of the original java version : Jochen Hoenicke53  /// </summary>54  public class Deflater55  {56    #region Deflater Documentation57    /*58    * The Deflater can do the following state transitions:59    *60    * (1) -> INIT_STATE   ----> INIT_FINISHING_STATE ---.61    *        /  | (2)      (5)                          |62    *       /   v          (5)                          |63    *   (3)| SETDICT_STATE ---> SETDICT_FINISHING_STATE |(3)64    *       \   | (3)                 |        ,--------'65    *        |  |                     | (3)   /66    *        v  v          (5)        v      v67    * (1) -> BUSY_STATE   ----> FINISHING_STATE68    *                                | (6)69    *                                v70    *                           FINISHED_STATE71    *    \_____________________________________/72    *                    | (7)73    *                    v74    *               CLOSED_STATE75    *76    * (1) If we should produce a header we start in INIT_STATE, otherwise77    *     we start in BUSY_STATE.78    * (2) A dictionary may be set only when we are in INIT_STATE, then79    *     we change the state as indicated.80    * (3) Whether a dictionary is set or not, on the first call of deflate81    *     we change to BUSY_STATE.82    * (4) -- intentionally left blank -- :)83    * (5) FINISHING_STATE is entered, when flush() is called to indicate that84    *     there is no more INPUT.  There are also states indicating, that85    *     the header wasn't written yet.86    * (6) FINISHED_STATE is entered, when everything has been flushed to the87    *     internal pending output buffer.88    * (7) At any time (7)89    *90    */91    #endregion92    #region Public Constants93    /// <summary>94    /// The best and slowest compression level.  This tries to find very95    /// long and distant string repetitions.96    /// </summary>97    public const  int BEST_COMPRESSION = 9;9899    /// <summary>100    /// The worst but fastest compression level.101    /// </summary>102    public const  int BEST_SPEED = 1;103104    /// <summary>105    /// The default compression level.106    /// </summary>107    public const  int DEFAULT_COMPRESSION = -1;108109    /// <summary>110    /// This level won't compress at all but output uncompressed blocks.111    /// </summary>112    public const  int NO_COMPRESSION = 0;113114    /// <summary>115    /// The compression method.  This is the only method supported so far.116    /// There is no need to use this constant at all.117    /// </summary>118    public const  int DEFLATED = 8;119    #endregion120    #region Local Constants121    private const  int IS_SETDICT              = 0x01;122    private const  int IS_FLUSHING             = 0x04;123    private const  int IS_FINISHING            = 0x08;124125    private const  int INIT_STATE              = 0x00;126    private const  int SETDICT_STATE           = 0x01;127    //    private static  int INIT_FINISHING_STATE    = 0x08;128    //    private static  int SETDICT_FINISHING_STATE = 0x09;129    private const  int BUSY_STATE              = 0x10;130    private const  int FLUSHING_STATE          = 0x14;131    private const  int FINISHING_STATE         = 0x1c;132    private const  int FINISHED_STATE          = 0x1e;133    private const  int CLOSED_STATE            = 0x7f;134    #endregion135    #region Constructors136    /// <summary>137    /// Creates a new deflater with default compression level.138    /// </summary> - 4139    public Deflater() : this(DEFAULT_COMPRESSION, false)140    {141 - 4142    }143144    /// <summary>145    /// Creates a new deflater with given compression level.146    /// </summary>147    /// <param name="level">148    /// the compression level, a value between NO_COMPRESSION149    /// and BEST_COMPRESSION, or DEFAULT_COMPRESSION.150    /// </param>151    /// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception> - 0152    public Deflater(int level) : this(level, false)153    {154 - 0155    }156157    /// <summary>158    /// Creates a new deflater with given compression level.159    /// </summary>160    /// <param name="level">161    /// the compression level, a value between NO_COMPRESSION162    /// and BEST_COMPRESSION.163    /// </param>164    /// <param name="noZlibHeaderOrFooter">165    /// true, if we should suppress the Zlib/RFC1950 header at the166    /// beginning and the adler checksum at the end of the output.  This is167    /// useful for the GZIP/PKZIP formats.168    /// </param>169    /// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception> - 279170    public Deflater(int level, bool noZlibHeaderOrFooter)171    { - 279172       if (level == DEFAULT_COMPRESSION) { - 106173        level = 6; - 279174       } else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) { - 0175        throw new ArgumentOutOfRangeException(nameof(level));1using System;23namespace ICSharpCode.SharpZipLib.Zip.Compression4{5  /// <summary>6  /// This is the Deflater class.  The deflater class compresses input7  /// with the deflate algorithm described in RFC 1951.  It has several8  /// compression levels and three different strategies described below.9  ///10  /// This class is <i>not</i> thread safe.  This is inherent in the API, due11  /// to the split of deflate and setInput.12  ///13  /// author of the original java version : Jochen Hoenicke14  /// </summary>15  public class Deflater16  {17    #region Deflater Documentation18    /*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      v28    * (1) -> BUSY_STATE   ----> FINISHING_STATE29    *                                | (6)30    *                                v31    *                           FINISHED_STATE32    *    \_____________________________________/33    *                    | (7)34    *                    v35    *               CLOSED_STATE36    *37    * (1) If we should produce a header we start in INIT_STATE, otherwise38    *     we start in BUSY_STATE.39    * (2) A dictionary may be set only when we are in INIT_STATE, then40    *     we change the state as indicated.41    * (3) Whether a dictionary is set or not, on the first call of deflate42    *     we change to BUSY_STATE.43    * (4) -- intentionally left blank -- :)44    * (5) FINISHING_STATE is entered, when flush() is called to indicate that45    *     there is no more INPUT.  There are also states indicating, that46    *     the header wasn't written yet.47    * (6) FINISHED_STATE is entered, when everything has been flushed to the48    *     internal pending output buffer.49    * (7) At any time (7)50    *51    */52    #endregion53    #region Public Constants54    /// <summary>55    /// The best and slowest compression level.  This tries to find very56    /// long and distant string repetitions.57    /// </summary>58    public const int BEST_COMPRESSION = 9;5960    /// <summary>61    /// The worst but fastest compression level.62    /// </summary>63    public const int BEST_SPEED = 1;6465    /// <summary>66    /// The default compression level.67    /// </summary>68    public const int DEFAULT_COMPRESSION = -1;6970    /// <summary>71    /// This level won't compress at all but output uncompressed blocks.72    /// </summary>73    public const int NO_COMPRESSION = 0;7475    /// <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    #endregion81    #region Local Constants82    private const int IS_SETDICT = 0x01;83    private const int IS_FLUSHING = 0x04;84    private const int IS_FINISHING = 0x08;8586    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    #endregion96    #region Constructors97    /// <summary>98    /// Creates a new deflater with default compression level.99    /// </summary> + 4100    public Deflater() : this(DEFAULT_COMPRESSION, false)101    {102 + 4103    }104105    /// <summary>106    /// Creates a new deflater with given compression level.107    /// </summary>108    /// <param name="level">109    /// the compression level, a value between NO_COMPRESSION110    /// 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    }117118    /// <summary>119    /// Creates a new deflater with given compression level.120    /// </summary>121    /// <param name="level">122    /// the compression level, a value between NO_COMPRESSION123    /// and BEST_COMPRESSION.124    /// </param>125    /// <param name="noZlibHeaderOrFooter">126    /// true, if we should suppress the Zlib/RFC1950 header at the127    /// beginning and the adler checksum at the end of the output.  This is128    /// 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    #endregion147148    /// <summary>149    /// Resets the deflater.  The deflater acts afterwards as if it was150    /// just created with the same compression level and strategy as it151    /// 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    }160161    /// <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    }169170    /// <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 - 279178      pending = new DeflaterPending(); - 279179      engine = new DeflaterEngine(pending); - 279180      this.noZlibHeaderOrFooter = noZlibHeaderOrFooter; - 279181      SetStrategy(DeflateStrategy.Default); - 279182      SetLevel(level); - 279183      Reset(); - 279184    }185    #endregion186187    /// <summary>188    /// Resets the deflater.  The deflater acts afterwards as if it was189    /// just created with the same compression level and strategy as it190    /// had before.191    /// </summary>192    public void Reset()193    { - 401194       state = (noZlibHeaderOrFooter ? BUSY_STATE : INIT_STATE); - 401195      totalOut = 0; - 401196      pending.Reset(); - 401197      engine.Reset(); - 401198    }177    }178179    /// <summary>180    /// Gets the number of output bytes so far.181    /// </summary>182    public long TotalOut {183      get { + 119184        return totalOut;185      }186    }187188    /// <summary>189    /// Flushes the current input block.  Further calls to deflate() will190    /// produce enough output to inflate everything in the current input191    /// block.  This is not part of Sun's JDK so I have made it package192    /// private.  It is used by DeflaterOutputStream to implement193    /// flush().194    /// </summary>195    public void Flush()196    { + 30197      state |= IS_FLUSHING; + 30198    }  199  200    /// <summary>201    /// Gets the current adler checksum of the data that was processed so far.202    /// </summary>203    public int Adler {204      get { - 0205        return engine.Adler;206      }207    }208209    /// <summary>210    /// Gets the number of input bytes processed so far.211    /// </summary>212    public long TotalIn {213      get { - 10214        return engine.TotalIn;215      }216    }217218    /// <summary>219    /// Gets the number of output bytes so far.220    /// </summary>221    public long TotalOut {222      get { - 122223        return totalOut;224      }225    }226227    /// <summary>228    /// Flushes the current input block.  Further calls to deflate() will229    /// produce enough output to inflate everything in the current input230    /// block.  This is not part of Sun's JDK so I have made it package231    /// private.  It is used by DeflaterOutputStream to implement232    /// flush().233    /// </summary>234    public void Flush()235    { - 32236      state |= IS_FLUSHING; - 32237    }238239    /// <summary>240    /// Finishes the deflater with the current input block.  It is an error241    /// to give more input after this method was called.  This method must242    /// be called to force all bytes to be flushed.243    /// </summary>244    public void Finish()245    { - 329246      state |= (IS_FLUSHING | IS_FINISHING); - 329247    }248249    /// <summary>250    /// Returns true if the stream was finished and no more output bytes251    /// are available.252    /// </summary>253    public bool IsFinished {254      get { - 1913255        return (state == FINISHED_STATE) && pending.IsFlushed;256      }257    }258259    /// <summary>260    /// Returns true, if the input buffer is empty.261    /// You should then call setInput().262    /// NOTE: This method can also return true when the stream263    /// was finished.264    /// </summary>265    public bool IsNeedingInput {266      get { - 16295267        return engine.NeedsInput();268      }269    }270271    /// <summary>272    /// Sets the data which should be compressed next.  This should be only273    /// called when needsInput indicates that more input is needed.274    /// If you call setInput when needsInput() returns false, the275    /// previous input that is still pending will be thrown away.276    /// The given byte array should not be changed, before needsInput() returns277    /// true again.278    /// This call is equivalent to <code>setInput(input, 0, input.length)</code>.279    /// </summary>280    /// <param name="input">281    /// the buffer containing the input data.282    /// </param>283    /// <exception cref="System.InvalidOperationException">284    /// if the buffer was finished() or ended().285    /// </exception>286    public void SetInput(byte[] input)287    { - 0288      SetInput(input, 0, input.Length); - 0289    }290291    /// <summary>292    /// Sets the data which should be compressed next.  This should be293    /// only called when needsInput indicates that more input is needed.294    /// The given byte array should not be changed, before needsInput() returns295    /// true again.296    /// </summary>297    /// <param name="input">298    /// the buffer containing the input data.299    /// </param>300    /// <param name="offset">301    /// the start of the data.302    /// </param>303    /// <param name="count">304    /// the number of data bytes of input.305    /// </param>306    /// <exception cref="System.InvalidOperationException">307    /// if the buffer was Finish()ed or if previous input is still pending.308    /// </exception>309    public void SetInput(byte[] input, int offset, int count)310    { - 4485311       if ((state & IS_FINISHING) != 0) { - 0312        throw new InvalidOperationException("Finish() already called");313      } - 4485314      engine.SetInput(input, offset, count); - 4485315    }316317    /// <summary>318    /// Sets the compression level.  There is no guarantee of the exact319    /// position of the change, but if you call this when needsInput is320    /// true the change of compression level will occur somewhere near321    /// before the end of the so far given input.322    /// </summary>323    /// <param name="level">324    /// the new compression level.325    /// </param>326    public void SetLevel(int level)327    { - 458328       if (level == DEFAULT_COMPRESSION) { - 60329        level = 6; - 458330       } else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) { - 0331        throw new ArgumentOutOfRangeException(nameof(level));332      }333 - 458334       if (this.level != level) { - 335335        this.level = level; - 335336        engine.SetLevel(level);337      } - 458338    }339340    /// <summary>341    /// Get current compression level342    /// </summary>343    /// <returns>Returns the current compression level</returns>344    public int GetLevel() { - 3345      return level;346    }347348    /// <summary>349    /// Sets the compression strategy. Strategy is one of350    /// DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED.  For the exact351    /// position where the strategy is changed, the same as for352    /// SetLevel() applies.353    /// </summary>354    /// <param name="strategy">355    /// The new compression strategy.356    /// </param>357    public void SetStrategy(DeflateStrategy strategy)358    { - 279359      engine.Strategy = strategy; - 279360    }361362    /// <summary>363    /// Deflates the current input block with to the given array.364    /// </summary>365    /// <param name="output">366    /// The buffer where compressed data is stored367    /// </param>368    /// <returns>369    /// The number of compressed bytes added to the output, or 0 if either370    /// IsNeedingInput() or IsFinished returns true or length is zero.371    /// </returns>372    public int Deflate(byte[] output)373    { - 0374      return Deflate(output, 0, output.Length);375    }376377    /// <summary>378    /// Deflates the current input block to the given array.379    /// </summary>380    /// <param name="output">381    /// Buffer to store the compressed data.382    /// </param>383    /// <param name="offset">384    /// Offset into the output array.385    /// </param>386    /// <param name="length">387    /// The maximum number of bytes that may be stored.388    /// </param>389    /// <returns>390    /// The number of compressed bytes added to the output, or 0 if either391    /// needsInput() or finished() returns true or length is zero.392    /// </returns>393    /// <exception cref="System.InvalidOperationException">394    /// If Finish() was previously called.395    /// </exception>396    /// <exception cref="System.ArgumentOutOfRangeException">397    /// If offset or length don't match the array length.398    /// </exception>399    public int Deflate(byte[] output, int offset, int length)400    { - 12749401      int origLength = length;402 - 12749403       if (state == CLOSED_STATE) { - 0404        throw new InvalidOperationException("Deflater closed");405      }406 - 12749407       if (state < BUSY_STATE) {408        // output header - 14409        int header = (DEFLATED + - 14410          ((DeflaterConstants.MAX_WBITS - 8) << 4)) << 8; - 14411        int level_flags = (level - 1) >> 1; - 14412         if (level_flags < 0 || level_flags > 3) { - 2413          level_flags = 3;414        } - 14415        header |= level_flags << 6; - 14416         if ((state & IS_SETDICT) != 0) {417          // Dictionary was set - 0418          header |= DeflaterConstants.PRESET_DICT;419        } - 14420        header += 31 - (header % 31);421 - 14422        pending.WriteShortMSB(header); - 14423         if ((state & IS_SETDICT) != 0) { - 0424          int chksum = engine.Adler; - 0425          engine.ResetAdler(); - 0426          pending.WriteShortMSB(chksum >> 16); - 0427          pending.WriteShortMSB(chksum & 0xffff);428        }201    /// Finishes the deflater with the current input block.  It is an error202    /// to give more input after this method was called.  This method must203    /// be called to force all bytes to be flushed.204    /// </summary>205    public void Finish()206    { + 325207      state |= (IS_FLUSHING | IS_FINISHING); + 325208    }209210    /// <summary>211    /// Returns true if the stream was finished and no more output bytes212    /// are available.213    /// </summary>214    public bool IsFinished {215      get { + 1898216        return (state == FINISHED_STATE) && pending.IsFlushed;217      }218    }219220    /// <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 stream224    /// was finished.225    /// </summary>226    public bool IsNeedingInput {227      get { + 16258228        return engine.NeedsInput();229      }230    }231232    /// <summary>233    /// Sets the data which should be compressed next.  This should be only234    /// called when needsInput indicates that more input is needed.235    /// If you call setInput when needsInput() returns false, the236    /// previous input that is still pending will be thrown away.237    /// The given byte array should not be changed, before needsInput() returns238    /// 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    }251252    /// <summary>253    /// Sets the data which should be compressed next.  This should be254    /// only called when needsInput indicates that more input is needed.255    /// The given byte array should not be changed, before needsInput() returns256    /// 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    }277278    /// <summary>279    /// Sets the compression level.  There is no guarantee of the exact280    /// position of the change, but if you call this when needsInput is281    /// true the change of compression level will occur somewhere near282    /// 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    }300301    /// <summary>302    /// Get current compression level303    /// </summary>304    /// <returns>Returns the current compression level</returns>305    public int GetLevel()306    { + 3307      return level;308    }309310    /// <summary>311    /// Sets the compression strategy. Strategy is one of312    /// DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED.  For the exact313    /// position where the strategy is changed, the same as for314    /// 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    }323324    /// <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 stored329    /// </param>330    /// <returns>331    /// The number of compressed bytes added to the output, or 0 if either332    /// 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    }338339    /// <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 either353    /// 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      }394395      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 lookahead413                 * is needed by the zlib inflater, and we must fill414                 * 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 of419                   * 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 - 14430        state = BUSY_STATE | (state & (IS_FLUSHING | IS_FINISHING));431      }432433      for (;;) { - 13290434        int count = pending.Flush(output, offset, length); - 13290435        offset   += count; - 13290436        totalOut += count; - 13290437        length   -= count;438 - 13290439         if (length == 0 || state == FINISHED_STATE) {440          break;441        }442 - 4892443         if (!engine.Deflate((state & IS_FLUSHING) != 0, (state & IS_FINISHING) != 0)) { - 4660444                     switch (state)445                    {446                        case BUSY_STATE:447                            // We need more input now - 4351448                            return origLength - length;449                        case FLUSHING_STATE: - 0450                             if (level != NO_COMPRESSION)451                            {452                                /* We have to supply some lookahead.  8 bit lookahead453                                 * is needed by the zlib inflater, and we must fill454                                 * the next byte, so that all bits are flushed.455                                 */ - 0456                                int neededbits = 8 + ((-pending.BitCount) & 7); - 0457                                 while (neededbits > 0)458                                {459                                    /* write a static tree block consisting solely of460                                     * an EOF:461                                     */ - 0462                                    pending.WriteBits(2, 10); - 0463                                    neededbits -= 10;464                                }465                            } - 0466                            state = BUSY_STATE; - 0467                            break;468                        case FINISHING_STATE: - 309469                            pending.AlignToByte();470471                            // Compressed data is complete.  Write footer information if required. - 309472                             if (!noZlibHeaderOrFooter)473                            { - 14474                                int adler = engine.Adler; - 14475                                pending.WriteShortMSB(adler >> 16); - 14476                                pending.WriteShortMSB(adler & 0xffff);477                            } - 309478                            state = FINISHED_STATE; - 309479                            break;480                    }481                }482      } - 8398483      return origLength - length;484    }485486    /// <summary>487    /// Sets the dictionary which should be used in the deflate process.488    /// This call is equivalent to <code>setDictionary(dict, 0, dict.Length)</code>.489    /// </summary>490    /// <param name="dictionary">491    /// the dictionary.492    /// </param>493    /// <exception cref="System.InvalidOperationException">494    /// if SetInput () or Deflate () were already called or another dictionary was already set.495    /// </exception>496    public void SetDictionary(byte[] dictionary)497    { - 0498      SetDictionary(dictionary, 0, dictionary.Length); - 0499    }500501    /// <summary>502    /// Sets the dictionary which should be used in the deflate process.503    /// The dictionary is a byte array containing strings that are504    /// likely to occur in the data which should be compressed.  The505    /// dictionary is not stored in the compressed output, only a506    /// checksum.  To decompress the output you need to supply the same507    /// dictionary again.508    /// </summary>509    /// <param name="dictionary">510    /// The dictionary data511    /// </param>512    /// <param name="index">513    /// The index where dictionary information commences.514    /// </param>515    /// <param name="count">516    /// The number of bytes in the dictionary.517    /// </param>518    /// <exception cref="System.InvalidOperationException">519    /// If SetInput () or Deflate() were already called or another dictionary was already set.520    /// </exception>521    public void SetDictionary(byte[] dictionary, int index, int count)522    { - 0523       if (state != INIT_STATE) { - 0524        throw new InvalidOperationException();525      }526 - 0527      state = SETDICT_STATE; - 0528      engine.SetDictionary(dictionary, index, count); - 0529    }530531    #region Instance Fields532    /// <summary>533    /// Compression level.534    /// </summary>535    int level;536537    /// <summary>538    /// If true no Zlib/RFC1950 headers or footers are generated539    /// </summary>540    bool noZlibHeaderOrFooter;541542    /// <summary>543    /// The current state.544    /// </summary>545    int state;546547    /// <summary>548    /// The total bytes of output written.549    /// </summary>550    long totalOut;551552    /// <summary>553    /// The pending output.554    /// </summary>555    DeflaterPending pending;556557    /// <summary>558    /// The deflater engine.559    /// </summary>560    DeflaterEngine engine;561    #endregion562  }563}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    }443444    /// <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    }458459    /// <summary>460    /// Sets the dictionary which should be used in the deflate process.461    /// The dictionary is a byte array containing strings that are462    /// likely to occur in the data which should be compressed.  The463    /// dictionary is not stored in the compressed output, only a464    /// checksum.  To decompress the output you need to supply the same465    /// dictionary again.466    /// </summary>467    /// <param name="dictionary">468    /// The dictionary data469    /// </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    }488489    #region Instance Fields490    /// <summary>491    /// Compression level.492    /// </summary>493    int level;494495    /// <summary>496    /// If true no Zlib/RFC1950 headers or footers are generated497    /// </summary>498    bool noZlibHeaderOrFooter;499500    /// <summary>501    /// The current state.502    /// </summary>503    int state;504505    /// <summary>506    /// The total bytes of output written.507    /// </summary>508    long totalOut;509510    /// <summary>511    /// The pending output.512    /// </summary>513    DeflaterPending pending;514515    /// <summary>516    /// The deflater engine.517    /// </summary>518    DeflaterEngine engine;519    #endregion520  }521} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterConstants.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterConstants.htm index 6c7236921..5ff6a3b35 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterConstants.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterConstants.htm @@ -18,7 +18,7 @@

Summary

Covered lines:6 Uncovered lines:0 Coverable lines:6 -Total lines:185 +Total lines:146 Line coverage:100% @@ -34,193 +34,154 @@

#LineLine coverage - 1// DeflaterConstants.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839using System;4041namespace ICSharpCode.SharpZipLib.Zip.Compression42{4344  /// <summary>45  /// This class contains constants used for deflation.46  /// </summary>47  public static class DeflaterConstants48  {49    /// <summary>50    /// Set to true to enable debugging51    /// </summary>52    public const bool DEBUGGING = false;5354    /// <summary>55    /// Written to Zip file to identify a stored block56    /// </summary>57    public const int STORED_BLOCK = 0;5859    /// <summary>60    /// Identifies static tree in Zip file61    /// </summary>62    public const int STATIC_TREES = 1;6364    /// <summary>65    /// Identifies dynamic tree in Zip file66    /// </summary>67    public const int DYN_TREES    = 2;6869    /// <summary>70    /// Header flag indicating a preset dictionary for deflation71    /// </summary>72    public const int PRESET_DICT  = 0x20;7374    /// <summary>75    /// Sets internal buffer sizes for Huffman encoding76    /// </summary>77    public const int DEFAULT_MEM_LEVEL = 8;7879    /// <summary>80    /// Internal compression engine constant81    /// </summary>82    public const int MAX_MATCH = 258;8384    /// <summary>85    /// Internal compression engine constant86    /// </summary>87    public const int MIN_MATCH = 3;8889    /// <summary>90    /// Internal compression engine constant91    /// </summary>92    public const int MAX_WBITS = 15;9394    /// <summary>95    /// Internal compression engine constant96    /// </summary>97    public const int WSIZE = 1 << MAX_WBITS;9899    /// <summary>100    /// Internal compression engine constant101    /// </summary>102    public const int WMASK = WSIZE - 1;103104    /// <summary>105    /// Internal compression engine constant106    /// </summary>107    public const int HASH_BITS = DEFAULT_MEM_LEVEL + 7;108109    /// <summary>110    /// Internal compression engine constant111    /// </summary>112    public const int HASH_SIZE = 1 << HASH_BITS;113114    /// <summary>115    /// Internal compression engine constant116    /// </summary>117    public const int HASH_MASK = HASH_SIZE - 1;118119    /// <summary>120    /// Internal compression engine constant121    /// </summary>122    public const int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH;123124    /// <summary>125    /// Internal compression engine constant126    /// </summary>127    public const int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;128129    /// <summary>130    /// Internal compression engine constant131    /// </summary>132    public const int MAX_DIST = WSIZE - MIN_LOOKAHEAD;133134    /// <summary>135    /// Internal compression engine constant136    /// </summary>137    public const int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8);138139    /// <summary>140    /// Internal compression engine constant141    /// </summary> - 1142    public static int MAX_BLOCK_SIZE = Math.Min(65535, PENDING_BUF_SIZE - 5);143144    /// <summary>145    /// Internal compression engine constant146    /// </summary>147    public const int DEFLATE_STORED = 0;148149    /// <summary>150    /// Internal compression engine constant151    /// </summary>152    public const int DEFLATE_FAST   = 1;153154    /// <summary>155    /// Internal compression engine constant156    /// </summary>157    public const int DEFLATE_SLOW   = 2;158159    /// <summary>160    /// Internal compression engine constant161    /// </summary> - 1162    public static int[] GOOD_LENGTH = { 0, 4,  4,  4,  4,  8,   8,   8,   32,   32 };163164    /// <summary>165    /// Internal compression engine constant166    /// </summary> - 1167    public static int[] MAX_LAZY    = { 0, 4,  5,  6,  4, 16,  16,  32,  128,  258 };168169    /// <summary>170    /// Internal compression engine constant171    /// </summary> - 1172    public static int[] NICE_LENGTH = { 0, 8, 16, 32, 16, 32, 128, 128,  258,  258 };173174    /// <summary>175    /// Internal compression engine constant176    /// </summary> - 1177    public static int[] MAX_CHAIN   = { 0, 4,  8, 32, 16, 32, 128, 256, 1024, 4096 };178179    /// <summary>180    /// Internal compression engine constant181    /// </summary> - 1182    public static int[] COMPR_FUNC  = { 0, 1,  1,  1,  1,  2,   2,   2,    2,    2 };183184  }185}1using System;23namespace ICSharpCode.SharpZipLib.Zip.Compression4{5  /// <summary>6  /// This class contains constants used for deflation.7  /// </summary>8  public static class DeflaterConstants9  {10    /// <summary>11    /// Set to true to enable debugging12    /// </summary>13    public const bool DEBUGGING = false;1415    /// <summary>16    /// Written to Zip file to identify a stored block17    /// </summary>18    public const int STORED_BLOCK = 0;1920    /// <summary>21    /// Identifies static tree in Zip file22    /// </summary>23    public const int STATIC_TREES = 1;2425    /// <summary>26    /// Identifies dynamic tree in Zip file27    /// </summary>28    public const int DYN_TREES = 2;2930    /// <summary>31    /// Header flag indicating a preset dictionary for deflation32    /// </summary>33    public const int PRESET_DICT = 0x20;3435    /// <summary>36    /// Sets internal buffer sizes for Huffman encoding37    /// </summary>38    public const int DEFAULT_MEM_LEVEL = 8;3940    /// <summary>41    /// Internal compression engine constant42    /// </summary>43    public const int MAX_MATCH = 258;4445    /// <summary>46    /// Internal compression engine constant47    /// </summary>48    public const int MIN_MATCH = 3;4950    /// <summary>51    /// Internal compression engine constant52    /// </summary>53    public const int MAX_WBITS = 15;5455    /// <summary>56    /// Internal compression engine constant57    /// </summary>58    public const int WSIZE = 1 << MAX_WBITS;5960    /// <summary>61    /// Internal compression engine constant62    /// </summary>63    public const int WMASK = WSIZE - 1;6465    /// <summary>66    /// Internal compression engine constant67    /// </summary>68    public const int HASH_BITS = DEFAULT_MEM_LEVEL + 7;6970    /// <summary>71    /// Internal compression engine constant72    /// </summary>73    public const int HASH_SIZE = 1 << HASH_BITS;7475    /// <summary>76    /// Internal compression engine constant77    /// </summary>78    public const int HASH_MASK = HASH_SIZE - 1;7980    /// <summary>81    /// Internal compression engine constant82    /// </summary>83    public const int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH;8485    /// <summary>86    /// Internal compression engine constant87    /// </summary>88    public const int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;8990    /// <summary>91    /// Internal compression engine constant92    /// </summary>93    public const int MAX_DIST = WSIZE - MIN_LOOKAHEAD;9495    /// <summary>96    /// Internal compression engine constant97    /// </summary>98    public const int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8);99100    /// <summary>101    /// Internal compression engine constant102    /// </summary> + 1103    public static int MAX_BLOCK_SIZE = Math.Min(65535, PENDING_BUF_SIZE - 5);104105    /// <summary>106    /// Internal compression engine constant107    /// </summary>108    public const int DEFLATE_STORED = 0;109110    /// <summary>111    /// Internal compression engine constant112    /// </summary>113    public const int DEFLATE_FAST = 1;114115    /// <summary>116    /// Internal compression engine constant117    /// </summary>118    public const int DEFLATE_SLOW = 2;119120    /// <summary>121    /// Internal compression engine constant122    /// </summary> + 1123    public static int[] GOOD_LENGTH = { 0, 4, 4, 4, 4, 8, 8, 8, 32, 32 };124125    /// <summary>126    /// Internal compression engine constant127    /// </summary> + 1128    public static int[] MAX_LAZY = { 0, 4, 5, 6, 4, 16, 16, 32, 128, 258 };129130    /// <summary>131    /// Internal compression engine constant132    /// </summary> + 1133    public static int[] NICE_LENGTH = { 0, 8, 16, 32, 16, 32, 128, 128, 258, 258 };134135    /// <summary>136    /// Internal compression engine constant137    /// </summary> + 1138    public static int[] MAX_CHAIN = { 0, 4, 8, 32, 16, 32, 128, 256, 1024, 4096 };139140    /// <summary>141    /// Internal compression engine constant142    /// </summary> + 1143    public static int[] COMPR_FUNC = { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2 };144145  }146} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterEngine.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterEngine.htm index 4a83b9c9d..078abf45e 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterEngine.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterEngine.htm @@ -18,7 +18,7 @@

Summary

Covered lines:238 Uncovered lines:37 Coverable lines:275 -Total lines:868 +Total lines:812 Line coverage:86.5% Branch coverage:84.4% @@ -50,876 +50,820 @@

#LineLine coverage - 1// DeflaterEngine.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839using System;4041using ICSharpCode.SharpZipLib.Checksums;4243namespace ICSharpCode.SharpZipLib.Zip.Compression44{4546  /// <summary>47  /// Strategies for deflater1using System;2using ICSharpCode.SharpZipLib.Checksum;34namespace ICSharpCode.SharpZipLib.Zip.Compression5{6  /// <summary>7  /// Strategies for deflater8  /// </summary>9  public enum DeflateStrategy10  {11    /// <summary>12    /// The default strategy13    /// </summary>14    Default = 0,1516    /// <summary>17    /// This strategy will only allow longer string repetitions.  It is18    /// useful for random data with a small character set.19    /// </summary>20    Filtered = 1,212223    /// <summary>24    /// This strategy will not look for string repetitions at all.  It25    /// only encodes with Huffman trees (which means, that more common26    /// characters get a smaller encoding.27    /// </summary>28    HuffmanOnly = 229  }3031  // DEFLATE ALGORITHM:32  //33  // The uncompressed stream is inserted into the window array.  When34  // the window array is full the first half is thrown away and the35  // second half is copied to the beginning.36  //37  // The head array is a hash table.  Three characters build a hash value38  // and they the value points to the corresponding index in window of39  // the last string with this hash.  The prev array implements a40  // linked list of matches with the same hash: prev[index & WMASK] points41  // to the previous index with the same hash.42  //434445  /// <summary>46  /// Low level compression engine for deflate algorithm which uses a 32K sliding window47  /// with secondary compression from Huffman/Shannon-Fano codes.  48  /// </summary>49  public enum DeflateStrategy49  public class DeflaterEngine  50  {51    /// <summary>52    /// The default strategy53    /// </summary>54    Default  = 0,5551    #region Constants52    const int TooFar = 4096;53    #endregion5455    #region Constructors  56    /// <summary>57    /// This strategy will only allow longer string repetitions.  It is58    /// useful for random data with a small character set.59    /// </summary>60    Filtered = 1,616263    /// <summary>64    /// This strategy will not look for string repetitions at all.  It65    /// only encodes with Huffman trees (which means, that more common66    /// characters get a smaller encoding.67    /// </summary>68    HuffmanOnly = 269  }7071  // DEFLATE ALGORITHM:72  //73  // The uncompressed stream is inserted into the window array.  When74  // the window array is full the first half is thrown away and the75  // second half is copied to the beginning.76  //77  // The head array is a hash table.  Three characters build a hash value78  // and they the value points to the corresponding index in window of79  // the last string with this hash.  The prev array implements a80  // linked list of matches with the same hash: prev[index & WMASK] points81  // to the previous index with the same hash.82  //838485  /// <summary>86  /// Low level compression engine for deflate algorithm which uses a 32K sliding window87  /// with secondary compression from Huffman/Shannon-Fano codes.88  /// </summary>89  public class DeflaterEngine90  {91    #region Constants92    const int TooFar = 4096;93    #endregion9495    #region Constructors96    /// <summary>97    /// Construct instance with pending buffer98    /// </summary>99    /// <param name="pending">100    /// Pending buffer to use101    /// </param>> - 279102    public DeflaterEngine(DeflaterPending pending)103    { - 279104      this.pending = pending; - 279105      huffman = new DeflaterHuffman(pending); - 279106      adler = new Adler32();107 - 279108      window = new byte[2 * DeflaterConstants.WSIZE]; - 279109      head   = new short[DeflaterConstants.HASH_SIZE]; - 279110      prev   = new short[DeflaterConstants.WSIZE];111112      // We start at index 1, to avoid an implementation deficiency, that113      // we cannot build a repeat pattern at index 0. - 279114      blockStart = strstart = 1; - 279115    }116117    #endregion118119    /// <summary>120    /// Deflate drives actual compression of data121    /// </summary>122    /// <param name="flush">True to flush input buffers</param>123    /// <param name="finish">Finish deflation with the current input.</param>124    /// <returns>Returns true if progress has been made.</returns>125    public bool Deflate(bool flush, bool finish)126    {127      bool progress;128      do129      { - 9158130        FillWindow(); - 9158131        bool canFlush = flush && (inputOff == inputEnd);132133#if DebugDeflation134        if (DeflaterConstants.DEBUGGING) {135          Console.WriteLine("window: [" + blockStart + "," + strstart + ","136                + lookahead + "], " + compressionFunction + "," + canFlush);137        }138#endif - 9158139         switch (compressionFunction)140        {141          case DeflaterConstants.DEFLATE_STORED: - 1373142            progress = DeflateStored(canFlush, finish); - 1373143            break;144          case DeflaterConstants.DEFLATE_FAST: - 3242145            progress = DeflateFast(canFlush, finish); - 3242146            break;147          case DeflaterConstants.DEFLATE_SLOW: - 4543148            progress = DeflateSlow(canFlush, finish); - 4543149            break;150          default: - 0151            throw new InvalidOperationException("unknown compressionFunction");152        } - 9158153       } while (pending.IsFlushed && progress); // repeat while we have no pending output and progress was made - 4892154      return progress;155    }156157    /// <summary>158    /// Sets input data to be deflated.  Should only be called when <code>NeedsInput()</code>159    /// returns true160    /// </summary>161    /// <param name="buffer">The buffer containing input data.</param>162    /// <param name="offset">The offset of the first byte of data.</param>163    /// <param name="count">The number of bytes of data to use as input.</param>164    public void SetInput(byte[] buffer, int offset, int count)165    { - 4485166       if ( buffer == null )167      { - 0168        throw new ArgumentNullException(nameof(buffer));169      }170 - 4485171       if ( offset < 0 )172      { - 0173        throw new ArgumentOutOfRangeException(nameof(offset));174      }175 - 4485176       if ( count < 0 )177      { - 0178        throw new ArgumentOutOfRangeException(nameof(count));179      }180 - 4485181       if (inputOff < inputEnd)182      { - 0183        throw new InvalidOperationException("Old input was not completely processed");184      }185 - 4485186      int end = offset + count;187188      /* We want to throw an ArrayIndexOutOfBoundsException early.  The189      * check is very tricky: it also handles integer wrap around.190      */ - 4485191       if ((offset > end) || (end > buffer.Length) )192      { - 0193        throw new ArgumentOutOfRangeException(nameof(count));57    /// Construct instance with pending buffer58    /// </summary>59    /// <param name="pending">60    /// Pending buffer to use61    /// </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];7172      // We start at index 1, to avoid an implementation deficiency, that73      // we cannot build a repeat pattern at index 0. + 27374      blockStart = strstart = 1; + 27375    }7677    #endregion7879    /// <summary>80    /// Deflate drives actual compression of data81    /// </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);9192#if DebugDeflation93        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    }114115    /// <summary>116    /// Sets input data to be deflated.  Should only be called when <code>NeedsInput()</code>117    /// returns true118    /// </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;141142      /* We want to throw an ArrayIndexOutOfBoundsException early.  The143      * 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    }153154    /// <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    }162163    /// <summary>164    /// Set compression dictionary165    /// </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 DebugDeflation172      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      }195 - 4485196      inputBuf = buffer; - 4485197      inputOff = offset; - 4485198      inputEnd = end; - 4485199    }200201    /// <summary>202    /// Determines if more <see cref="SetInput">input</see> is needed.203    /// </summary>204    /// <returns>Return true if input is needed via <see cref="SetInput">SetInput</see></returns>205    public bool NeedsInput()206    { - 16295207      return (inputEnd == inputOff);208    }209210    /// <summary>211    /// Set compression dictionary212    /// </summary>213    /// <param name="buffer">The buffer containing the dictionary data</param>214    /// <param name="offset">The offset in the buffer for the first byte of data</param>215    /// <param name="length">The length of the dictionary data.</param>216    public void SetDictionary(byte[] buffer, int offset, int length)217    {218#if DebugDeflation219      if (DeflaterConstants.DEBUGGING && (strstart != 1) )220      {221        throw new InvalidOperationException("strstart not 1");222      }223#endif - 0224      adler.Update(buffer, offset, length); - 0225       if (length < DeflaterConstants.MIN_MATCH)226      { - 0227        return;228      }229 - 0230       if (length > DeflaterConstants.MAX_DIST)231      { - 0232        offset += length - DeflaterConstants.MAX_DIST; - 0233        length = DeflaterConstants.MAX_DIST;234      }235 - 0236      System.Array.Copy(buffer, offset, window, strstart, length); + 0195      strstart += 2; + 0196      blockStart = strstart; + 0197    }198199    /// <summary>200    /// Reset internal state201    /// </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    }220221    /// <summary>222    /// Reset Adler checksum223    /// </summary>224    public void ResetAdler()225    { + 0226      adler.Reset(); + 0227    }228229    /// <summary>230    /// Get current value of Adler checksum231    /// </summary>232    public int Adler {233      get { + 14234        return unchecked((int)adler.Value);235      }236    }  237 - 0238      UpdateHash(); - 0239      --length; - 0240       while (--length > 0)241      { - 0242        InsertString(); - 0243        strstart++;238    /// <summary>239    /// Total data processed240    /// </summary>241    public long TotalIn {242      get { + 9243        return totalIn;  244      } - 0245      strstart += 2; - 0246      blockStart = strstart; - 0247    }248249    /// <summary>250    /// Reset internal state251    /// </summary>252    public void Reset()253    { - 401254      huffman.Reset(); - 401255      adler.Reset(); - 401256      blockStart = strstart = 1; - 401257      lookahead = 0; - 401258      totalIn   = 0; - 401259      prevAvailable = false; - 401260      matchLen = DeflaterConstants.MIN_MATCH - 1;261 - 26280738262       for (int i = 0; i < DeflaterConstants.HASH_SIZE; i++) { - 13139968263        head[i] = 0;264      }265 - 26280738266       for (int i = 0; i < DeflaterConstants.WSIZE; i++) { - 13139968267        prev[i] = 0;268      } - 401269    }270271    /// <summary>272    /// Reset Adler checksum273    /// </summary>274    public void ResetAdler()275    { - 0276      adler.Reset(); - 0277    }278279    /// <summary>280    /// Get current value of Adler checksum281    /// </summary>282    public int Adler {283      get { - 14284        return unchecked((int)adler.Value);285      }286    }287288    /// <summary>289    /// Total data processed290    /// </summary>291    public long TotalIn {292      get { - 10293        return totalIn;294      }295    }296297    /// <summary>298    /// Get/set the <see cref="DeflateStrategy">deflate strategy</see>299    /// </summary>300    public DeflateStrategy Strategy {301      get { - 0302        return strategy;303      }304      set { - 279305        strategy = value; - 279306      }307    }308309    /// <summary>310    /// Set the deflate level (0-9)311    /// </summary>312    /// <param name="level">The value to set the level to.</param>313    public void SetLevel(int level)314    { - 335315       if ( (level < 0) || (level > 9) )316      { - 0317        throw new ArgumentOutOfRangeException(nameof(level));318      }319 - 335320      goodLength = DeflaterConstants.GOOD_LENGTH[level]; - 335321      max_lazy   = DeflaterConstants.MAX_LAZY[level]; - 335322      niceLength = DeflaterConstants.NICE_LENGTH[level]; - 335323      max_chain  = DeflaterConstants.MAX_CHAIN[level];324 - 335325       if (DeflaterConstants.COMPR_FUNC[level] != compressionFunction) {326327#if DebugDeflation328        if (DeflaterConstants.DEBUGGING) {329           Console.WriteLine("Change from " + compressionFunction + " to "330                      + DeflaterConstants.COMPR_FUNC[level]);331        }332#endif - 317333         switch (compressionFunction) {334          case DeflaterConstants.DEFLATE_STORED: - 278335             if (strstart > blockStart) { - 0336              huffman.FlushStoredBlock(window, blockStart, - 0337                strstart - blockStart, false); - 0338              blockStart = strstart;339            } - 278340            UpdateHash(); - 278341            break;342343          case DeflaterConstants.DEFLATE_FAST: - 6344             if (strstart > blockStart) { - 0345              huffman.FlushBlock(window, blockStart, strstart - blockStart, - 0346                false); - 0347              blockStart = strstart;348            } - 0349            break;245    }246247    /// <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    }258259    /// <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) {275276#if DebugDeflation277        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;291292          case DeflaterConstants.DEFLATE_FAST: + 6293             if (strstart > blockStart) { + 0294              huffman.FlushBlock(window, blockStart, strstart - blockStart, + 0295                false); + 0296              blockStart = strstart;297            } + 0298            break;299300          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    }315316    /// <summary>317    /// Fill the window318    /// </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      }327328      /* If there is not enough lookahead, but still some input left,329       * read in the input330       */ + 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    }  350351          case DeflaterConstants.DEFLATE_SLOW: - 33352             if (prevAvailable) { - 0353              huffman.TallyLit(window[strstart-1] & 0xff);354            } - 33355             if (strstart > blockStart) { - 0356              huffman.FlushBlock(window, blockStart, strstart - blockStart, false); - 0357              blockStart = strstart;358            } - 33359            prevAvailable = false; - 33360            matchLen = DeflaterConstants.MIN_MATCH - 1;361            break;362        } - 317363        compressionFunction = DeflaterConstants.COMPR_FUNC[level];364      } - 335365    }366367    /// <summary>368    /// Fill the window369    /// </summary>370    public void FillWindow()371    {372      /* If the window is almost full and there is insufficient lookahead,373       * move the upper half to the lower one to make room in the upper half.374       */ - 9158375       if (strstart >= DeflaterConstants.WSIZE + DeflaterConstants.MAX_DIST)376      { - 20377        SlideWindow();378      }379380      /* If there is not enough lookahead, but still some input left,381       * read in the input382       */ - 13684383       while (lookahead < DeflaterConstants.MIN_LOOKAHEAD && inputOff < inputEnd)384      { - 4526385        int more = 2 * DeflaterConstants.WSIZE - lookahead - strstart;386 - 4526387         if (more > inputEnd - inputOff)388        { - 4484389          more = inputEnd - inputOff;390        }391 - 4526392        System.Array.Copy(inputBuf, inputOff, window, strstart + lookahead, more); - 4526393        adler.Update(inputBuf, inputOff, more);394 - 4526395        inputOff += more; - 4526396        totalIn  += more; - 4526397        lookahead += more;398      }399 - 9158400       if (lookahead >= DeflaterConstants.MIN_MATCH)401      { - 8397402        UpdateHash();403      } - 9158404    }405406    void UpdateHash()407    {408/*409      if (DEBUGGING) {410        Console.WriteLine("updateHash: "+strstart);411      }412*/ - 8675413      ins_h = (window[strstart] << DeflaterConstants.HASH_SHIFT) ^ window[strstart + 1]; - 8675414    }415416    /// <summary>417    /// Inserts the current string in the head hash and returns the previous418    /// value for this hash.419    /// </summary>420    /// <returns>The previous hash value</returns>421    int InsertString()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    }360361    /// <summary>362    /// Inserts the current string in the head hash and returns the previous363    /// 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)]) & Defl370371#if DebugDeflation372      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    }389390    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;396397      // Slide the hash table (could be avoided with 32 bit values398      // 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      }403404      // 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    }410411    /// <summary>412    /// Find the best (longest) string in the window matching the413    /// 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    {423      short match; - 3726688424      int hash = ((ins_h << DeflaterConstants.HASH_SHIFT) ^ window[strstart + (DeflaterConstants.MIN_MATCH -1)]) & Defla425426#if DebugDeflation427      if (DeflaterConstants.DEBUGGING)428      {429        if (hash != (((window[strstart] << (2*HASH_SHIFT)) ^430                  (window[strstart + 1] << HASH_SHIFT) ^431                  (window[strstart + 2])) & HASH_MASK)) {432            throw new SharpZipBaseException("hash inconsistent: " + hash + "/"433                        +window[strstart] + ","434                        +window[strstart + 1] + ","435                        +window[strstart + 2] + "," + HASH_SHIFT);436          }437      }438#endif - 3726688439      prev[strstart & DeflaterConstants.WMASK] = match = head[hash]; - 3726688440      head[hash] = unchecked((short)strstart); - 3726688441      ins_h = hash; - 3726688442      return match & 0xffff;443    }444445    void SlideWindow()446    { - 42447      Array.Copy(window, DeflaterConstants.WSIZE, window, 0, DeflaterConstants.WSIZE); - 42448      matchStart -= DeflaterConstants.WSIZE; - 42449      strstart   -= DeflaterConstants.WSIZE; - 42450      blockStart -= DeflaterConstants.WSIZE;451452      // Slide the hash table (could be avoided with 32 bit values453      // at the expense of memory usage). - 2752596454       for (int i = 0; i < DeflaterConstants.HASH_SIZE; ++i) { - 1376256455        int m = head[i] & 0xffff; - 1376256456         head[i] = (short)(m >= DeflaterConstants.WSIZE ? (m - DeflaterConstants.WSIZE) : 0);457      } + 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];436437      // Do not waste too much time if we already have a good match: + 1801927438       if (best_len >= this.goodLength) { + 66439        chainLength >>= 2;440      }441442      /* Do not look for matches beyond the end of the input. This is necessary443      * to make deflate deterministic.444      */ + 1801927445       if (niceLength > lookahead) { + 3257446        niceLength = lookahead;447      }448449#if DebugDeflation450451      if (DeflaterConstants.DEBUGGING && (strstart > 2 * DeflaterConstants.WSIZE - DeflaterConstants.MIN_LOOKAHEAD))452      {453        throw new InvalidOperationException("need lookahead");454      }455#endif456457      do {  458459      // Slide the prev table. - 2752596460       for (int i = 0; i < DeflaterConstants.WSIZE; i++) { - 1376256461        int m = prev[i] & 0xffff; - 1376256462         prev[i] = (short)(m >= DeflaterConstants.WSIZE ? (m - DeflaterConstants.WSIZE) : 0);463      } - 42464    }465466    /// <summary>467    /// Find the best (longest) string in the window matching the468    /// string starting at strstart.469    ///470    /// Preconditions:471    /// <code>472    /// strstart + DeflaterConstants.MAX_MATCH &lt;= window.length.</code>473    /// </summary>474    /// <param name="curMatch"></param>475    /// <returns>True if a match greater than the minimum length is found</returns>476    bool FindLongestMatch(int curMatch)477    { - 1855075478      int chainLength = this.max_chain; - 1855075479      int niceLength  = this.niceLength; - 1855075480      short[] prev    = this.prev; - 1855075481      int scan        = this.strstart;482      int match; - 1855075483      int best_end = this.strstart + matchLen; - 1855075484      int best_len = Math.Max(matchLen, DeflaterConstants.MIN_MATCH - 1);485 - 1855075486      int limit = Math.Max(strstart - DeflaterConstants.MAX_DIST, 0);487 - 1855075488      int strend = strstart + DeflaterConstants.MAX_MATCH - 1; - 1855075489      byte scan_end1 = window[best_end - 1]; - 1855075490      byte scan_end  = window[best_end];459#if DebugDeflation460461        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;475476        /* 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 nothing490        }  491492      // Do not waste too much time if we already have a good match: - 1855075493       if (best_len >= this.goodLength) { - 66494        chainLength >>= 2;495      }496497      /* Do not look for matches beyond the end of the input. This is necessary498      * to make deflate deterministic.499      */ - 1855075500       if (niceLength > lookahead) { - 3375501        niceLength = lookahead;502      }503504#if DebugDeflation505506      if (DeflaterConstants.DEBUGGING && (strstart > 2 * DeflaterConstants.WSIZE - DeflaterConstants.MIN_LOOKAHEAD))507      {508        throw new InvalidOperationException("need lookahead");509      }510#endif511512      do {513514#if DebugDeflation515516        if (DeflaterConstants.DEBUGGING && (curMatch >= strstart) )517        {518          throw new InvalidOperationException("no future");519        }520#endif - 2780567521         if (window[curMatch + best_len] != scan_end      || - 2780567522          window[curMatch + best_len - 1] != scan_end1 || - 2780567523          window[curMatch] != window[scan]             || - 2780567524          window[curMatch + 1] != window[scan + 1]) {525          continue;526        }527 - 5573528        match = curMatch + 2; - 5573529        scan += 2;530531        /* We check for insufficient lookahead only every 8th comparison;532        * the 256th check will be made at strstart + 258.533        */ - 9473534         while ( - 9473535          window[++scan] == window[++match] && - 9473536          window[++scan] == window[++match] && - 9473537          window[++scan] == window[++match] && - 9473538          window[++scan] == window[++match] && - 9473539          window[++scan] == window[++match] && - 9473540          window[++scan] == window[++match] && - 9473541          window[++scan] == window[++match] && - 9473542          window[++scan] == window[++match] && - 9473543          (scan < strend))544        {545          // Do nothing546        }547 - 5573548         if (scan > best_end) {549#if DebugDeflation550          if (DeflaterConstants.DEBUGGING && (ins_h == 0) )551            Console.Error.WriteLine("Found match: " + curMatch + "-" + (scan - strstart));552#endif - 5511553          matchStart = curMatch; - 5511554          best_end = scan; - 5511555          best_len = scan - strstart;556 - 5511557           if (best_len >= niceLength) {558            break;559          }560 - 5435561          scan_end1  = window[best_end - 1]; - 5435562          scan_end   = window[best_end];563        } - 5497564        scan = strstart; - 2780491565       } while ((curMatch = (prev[curMatch & DeflaterConstants.WMASK] & 0xffff)) > limit && --chainLength != 0);566 - 1855075567      matchLen = Math.Min(best_len, lookahead); - 1855075568      return matchLen >= DeflaterConstants.MIN_MATCH;569    } + 5274492         if (scan > best_end) {493#if DebugDeflation494          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    }514515    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        }534535#if DebugDeflation536        if (DeflaterConstants.DEBUGGING)537        {538           Console.WriteLine("storedBlock[" + storedLength + "," + lastBlock + "]");539        }540#endif541 + 21542        huffman.FlushStoredBlock(window, blockStart, storedLength, lastBlock); + 21543        blockStart += storedLength; + 21544        return !lastBlock;545      } + 676546      return true;547    }548549    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 window566           * is almost full.567           */ + 0568          SlideWindow();569        }  570571    bool DeflateStored(bool flush, bool finish)572    { - 1373573       if (!flush && (lookahead == 0)) { - 676574        return false;575      }576 - 697577      strstart += lookahead; - 697578      lookahead = 0;579 - 697580      int storedLength = strstart - blockStart;581 - 697582       if ((storedLength >= DeflaterConstants.MAX_BLOCK_SIZE) || // Block is full - 697583        (blockStart < DeflaterConstants.WSIZE && storedLength >= DeflaterConstants.MAX_DIST) ||   // Block may move out  - 697584        flush) { - 21585        bool lastBlock = finish; - 21586         if (storedLength > DeflaterConstants.MAX_BLOCK_SIZE) { - 2587          storedLength = DeflaterConstants.MAX_BLOCK_SIZE; - 2588          lastBlock = false;589        }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 matchLen578#if DebugDeflation579          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#endif588 + 2203589          bool full = huffman.TallyDist(strstart - matchStart, matchLen);  590591#if DebugDeflation592        if (DeflaterConstants.DEBUGGING)593        {594           Console.WriteLine("storedBlock[" + storedLength + "," + lastBlock + "]");595        }596#endif597 - 21598        huffman.FlushStoredBlock(window, blockStart, storedLength, lastBlock); - 21599        blockStart += storedLength; - 21600        return !lastBlock;601      } - 676602      return true;603    }604605    bool DeflateFast(bool flush, bool finish)606    { - 3242607       if (lookahead < DeflaterConstants.MIN_LOOKAHEAD && !flush) { - 1528608        return false;609      }610 - 1598486611       while (lookahead >= DeflaterConstants.MIN_LOOKAHEAD || flush) { - 1596900612         if (lookahead == 0) {613          // We are flushing everything - 32614          huffman.FlushBlock(window, blockStart, strstart - blockStart, finish); - 32615          blockStart = strstart; - 32616          return false;617        }618 - 1596868619         if (strstart > 2 * DeflaterConstants.WSIZE - DeflaterConstants.MIN_LOOKAHEAD) {620          /* slide window, as FindLongestMatch needs this.621           * This should only happen when flushing and the window622           * is almost full.623           */ - 0624          SlideWindow();625        }626627        int hashHead; - 1596868628         if (lookahead >= DeflaterConstants.MIN_MATCH && - 1596868629          (hashHead = InsertString()) != 0 && - 1596868630          strategy != DeflateStrategy.HuffmanOnly && - 1596868631          strstart - hashHead <= DeflaterConstants.MAX_DIST && - 1596868632          FindLongestMatch(hashHead)) {633          // longestMatch sets matchStart and matchLen634#if DebugDeflation635          if (DeflaterConstants.DEBUGGING)636          {637            for (int i = 0 ; i < matchLen; i++) {638              if (window[strstart + i] != window[matchStart + i]) {639                throw new SharpZipBaseException("Match failure");640              }641            }642          }643#endif644 - 2381645          bool full = huffman.TallyDist(strstart - matchStart, matchLen);646 - 2381647          lookahead -= matchLen; - 2381648           if (matchLen <= max_lazy && lookahead >= DeflaterConstants.MIN_MATCH) { - 7147649             while (--matchLen > 0) { - 4769650              ++strstart; - 4769651              InsertString();652            } - 2378653            ++strstart; - 2378654          } else { - 3655            strstart += matchLen; - 3656             if (lookahead >= DeflaterConstants.MIN_MATCH - 1) { - 0657              UpdateHash();658            }659          } - 2381660          matchLen = DeflaterConstants.MIN_MATCH - 1; - 2381661           if (!full) { - 2381662            continue;663          }664        } else {665          // No match found - 1594487666          huffman.TallyLit(window[strstart] & 0xff); - 1594487667          ++strstart; - 1594487668          --lookahead;669        }670 - 1594487671         if (huffman.IsFull()) { - 96672          bool lastBlock = finish && (lookahead == 0); - 96673          huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock); - 96674          blockStart = strstart; - 96675          return !lastBlock;676        }677      } - 1586678      return true;679    }680681    bool DeflateSlow(bool flush, bool finish)682    { - 4543683       if (lookahead < DeflaterConstants.MIN_LOOKAHEAD && !flush) { - 2147684        return false;685      }686 - 2111644687       while (lookahead >= DeflaterConstants.MIN_LOOKAHEAD || flush) { - 2109640688         if (lookahead == 0) { - 266689           if (prevAvailable) { - 207690            huffman.TallyLit(window[strstart-1] & 0xff);691          } - 266692          prevAvailable = false;693694          // We are flushing everything695#if DebugDeflation696          if (DeflaterConstants.DEBUGGING && !flush)697          {698            throw new SharpZipBaseException("Not flushing, but no lookahead");699          }700#endif - 266701          huffman.FlushBlock(window, blockStart, strstart - blockStart, - 266702            finish); - 266703          blockStart = strstart; - 266704          return false;705        }706 - 2109374707         if (strstart >= 2 * DeflaterConstants.WSIZE - DeflaterConstants.MIN_LOOKAHEAD) {708          /* slide window, as FindLongestMatch needs this.709           * This should only happen when flushing and the window710           * is almost full.711           */ - 22712          SlideWindow();713        }714 - 2109374715        int prevMatch = matchStart; - 2109374716        int prevLen = matchLen; - 2109374717         if (lookahead >= DeflaterConstants.MIN_MATCH) {718 - 2108976719          int hashHead = InsertString();720 - 2108976721           if (strategy != DeflateStrategy.HuffmanOnly && - 2108976722            hashHead != 0 && - 2108976723            strstart - hashHead <= DeflaterConstants.MAX_DIST && - 2108976724            FindLongestMatch(hashHead)) {725726            // longestMatch sets matchStart and matchLen727728            // Discard match if too small and too far away - 3497729             if (matchLen <= 5 && (strategy == DeflateStrategy.Filtered || (matchLen == DeflaterConstants.MIN_MATCH && st - 2509730              matchLen = DeflaterConstants.MIN_MATCH - 1;731            }732          }733        }734735        // previous match was better - 2109374736         if ((prevLen >= DeflaterConstants.MIN_MATCH) && (matchLen <= prevLen) ) {737#if DebugDeflation738          if (DeflaterConstants.DEBUGGING)739          {740             for (int i = 0 ; i < matchLen; i++) {741              if (window[strstart-1+i] != window[prevMatch + i])742               throw new SharpZipBaseException();743            }744          }745#endif - 621746          huffman.TallyDist(strstart - 1 - prevMatch, prevLen); - 621747          prevLen -= 2;748          do { - 16191749            strstart++; - 16191750            lookahead--; - 16191751             if (lookahead >= DeflaterConstants.MIN_MATCH) { - 16130752              InsertString();753            } - 16191754           } while (--prevLen > 0); + 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    }624625    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;637638          // We are flushing everything639#if DebugDeflation640          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 window654           * 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)) {669670            // longestMatch sets matchStart and matchLen671672            // 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        }678679        // previous match was better + 2009366680         if ((prevLen >= DeflaterConstants.MIN_MATCH) && (matchLen <= prevLen)) {681#if DebugDeflation682          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    }726727    #region Instance Fields728729    // Hash index of string to be inserted730    int ins_h;731732    /// <summary>733    /// Hashtable, hashing three characters to an index for window, so734    /// that window[index]..window[index+2] have this hash code.735    /// Note that the array should really be unsigned short, so you need736    /// to and the values with 0xffff.737    /// </summary>738    short[] head;739740    /// <summary>741    /// <code>prev[index &amp; WMASK]</code> points to the previous index that has the742    /// same hash code as the string starting at index.  This way743    /// entries with the same hash code are in a linked list.744    /// Note that the array should really be unsigned short, so you need745    /// to and the values with 0xffff.746    /// </summary>747    short[] prev;748749    int matchStart;750    // Length of best match751    int matchLen;752    // Set if previous match exists753    bool prevAvailable;754    int blockStart;  755 - 621756          strstart ++; - 621757          lookahead--; - 621758          prevAvailable = false; - 621759          matchLen = DeflaterConstants.MIN_MATCH - 1; - 621760        } else { - 2108753761           if (prevAvailable) { - 2107925762            huffman.TallyLit(window[strstart-1] & 0xff);763          } - 2108753764          prevAvailable = true; - 2108753765          strstart++; - 2108753766          lookahead--;767        }756    /// <summary>757    /// Points to the current character in the window.758    /// </summary>759    int strstart;760761    /// <summary>762    /// lookahead is the number of characters starting at strstart in763    /// window that are valid.764    /// So window[strstart] until window[strstart+lookahead-1] are valid765    /// characters.766    /// </summary>767    int lookahead;  768 - 2109374769         if (huffman.IsFull()) { - 126770          int len = strstart - blockStart; - 126771           if (prevAvailable) { - 126772            len--;773          } - 126774          bool lastBlock = (finish && (lookahead == 0) && !prevAvailable); - 126775          huffman.FlushBlock(window, blockStart, len, lastBlock); - 126776          blockStart += len; - 126777          return !lastBlock;778        }779      } - 2004780      return true;781    }769    /// <summary>770    /// This array contains the part of the uncompressed stream that771    /// is of relevance.  The current character is indexed by strstart.772    /// </summary>773    byte[] window;774775    DeflateStrategy strategy;776    int max_chain, max_lazy, niceLength, goodLength;777778    /// <summary>779    /// The current compression function.780    /// </summary>781    int compressionFunction;  782783    #region Instance Fields784785    // Hash index of string to be inserted786    int ins_h;783    /// <summary>784    /// The input data for compression.785    /// </summary>786    byte[] inputBuf;  787  788    /// <summary>789    /// Hashtable, hashing three characters to an index for window, so790    /// that window[index]..window[index+2] have this hash code.791    /// Note that the array should really be unsigned short, so you need792    /// to and the values with 0xffff.793    /// </summary>794    short[] head;795796    /// <summary>797    /// <code>prev[index &amp; WMASK]</code> points to the previous index that has the798    /// same hash code as the string starting at index.  This way799    /// entries with the same hash code are in a linked list.800    /// Note that the array should really be unsigned short, so you need801    /// to and the values with 0xffff.802    /// </summary>803    short[] prev;804805    int    matchStart;806    // Length of best match807    int    matchLen;808    // Set if previous match exists809    bool   prevAvailable;810    int    blockStart;811812    /// <summary>813    /// Points to the current character in the window.814    /// </summary>815    int    strstart;816817    /// <summary>818    /// lookahead is the number of characters starting at strstart in819    /// window that are valid.820    /// So window[strstart] until window[strstart+lookahead-1] are valid821    /// characters.822    /// </summary>823    int    lookahead;824825    /// <summary>826    /// This array contains the part of the uncompressed stream that827    /// is of relevance.  The current character is indexed by strstart.828    /// </summary>829    byte[] window;830831    DeflateStrategy strategy;832    int max_chain, max_lazy, niceLength, goodLength;833834    /// <summary>835    /// The current compression function.836    /// </summary>837    int compressionFunction;838839    /// <summary>840    /// The input data for compression.841    /// </summary>842    byte[] inputBuf;843844    /// <summary>845    /// The total bytes of input read.846    /// </summary>847    long totalIn;848849    /// <summary>850    /// The offset into inputBuf, where input data starts.851    /// </summary>852    int inputOff;853854    /// <summary>855    /// The end offset of the input data.856    /// </summary>857    int inputEnd;858859    DeflaterPending pending;860    DeflaterHuffman huffman;861862    /// <summary>863    /// The adler checksum864    /// </summary>865    Adler32 adler;866    #endregion867  }868}789    /// The total bytes of input read.790    /// </summary>791    long totalIn;792793    /// <summary>794    /// The offset into inputBuf, where input data starts.795    /// </summary>796    int inputOff;797798    /// <summary>799    /// The end offset of the input data.800    /// </summary>801    int inputEnd;802803    DeflaterPending pending;804    DeflaterHuffman huffman;805806    /// <summary>807    /// The adler checksum808    /// </summary>809    Adler32 adler;810    #endregion811  }812} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterHuffman.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterHuffman.htm index e7fdd11bf..7251b9384 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterHuffman.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterHuffman.htm @@ -18,9 +18,9 @@

Summary

Covered lines:349 Uncovered lines:9 Coverable lines:358 -Total lines:905 +Total lines:865 Line coverage:97.4% -Branch coverage:91.7% +Branch coverage:91.1%

Metrics

@@ -50,7 +50,7 @@

Metrics

GetEncodedLength()2100100 CalcBLFreq(...)10100100 WriteTree(...)1191.1885.71 -BuildLength(...)1310088 +BuildLength(...)1310084

File(s)

@@ -58,913 +58,873 @@

#LineLine coverage - 1// DeflaterHuffman.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839using System;4041namespace ICSharpCode.SharpZipLib.Zip.Compression42{4344  /// <summary>45  /// This is the DeflaterHuffman class.46  ///47  /// This class is <i>not</i> thread safe.  This is inherent in the API, due48  /// to the split of Deflate and SetInput.49  ///50  /// author of the original java version : Jochen Hoenicke51  /// </summary>52  public class DeflaterHuffman53  {54    const  int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6);55    const  int LITERAL_NUM = 286;5657    // Number of distance codes58    const  int DIST_NUM = 30;59    // Number of codes used to transfer bit lengths60    const  int BITLEN_NUM = 19;6162    // repeat previous bit length 3-6 times (2 bits of repeat count)63    const  int REP_3_6    = 16;64    // repeat a zero length 3-10 times  (3 bits of repeat count)65    const  int REP_3_10   = 17;66    // repeat a zero length 11-138 times  (7 bits of repeat count)67    const  int REP_11_138 = 18;1using System;23namespace ICSharpCode.SharpZipLib.Zip.Compression4{5  /// <summary>6  /// This is the DeflaterHuffman class.7  ///8  /// This class is <i>not</i> thread safe.  This is inherent in the API, due9  /// to the split of Deflate and SetInput.10  ///11  /// author of the original java version : Jochen Hoenicke12  /// </summary>13  public class DeflaterHuffman14  {15    const int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6);16    const int LITERAL_NUM = 286;1718    // Number of distance codes19    const int DIST_NUM = 30;20    // Number of codes used to transfer bit lengths21    const int BITLEN_NUM = 19;2223    // 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;2930    const int EOF_SYMBOL = 256;3132    // The lengths of the bit length codes are sent in order of decreasing33    // 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    };5455    static short[] staticLCodes;56    static byte[] staticLLength;57    static short[] staticDCodes;58    static byte[] staticDLength;5960    class Tree61    {62      #region Instance Fields63      public short[] freqs;6465      public byte[] length;6667      public int minNumCodes;  6869    const  int EOF_SYMBOL = 256;69      public int numCodes;  7071    // The lengths of the bit length codes are sent in order of decreasing72     // probability, to avoid transmitting the lengths for unused bit length codes. - 173    static readonly int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };74 - 175    static readonly byte[] bit4Reverse = { - 176      0, - 177      8, - 178      4, - 179      12, - 180      2, - 181      10, - 182      6, - 183      14, - 184      1, - 185      9, - 186      5, - 187      13, - 188      3, - 189      11, - 190      7, - 191      15 - 192    };9394    static short[] staticLCodes;95    static byte[]  staticLLength;96    static short[] staticDCodes;97    static byte[]  staticDLength;9899    class Tree100    {101      #region Instance Fields102      public short[] freqs;103104      public byte[]  length;105106      public int     minNumCodes;107108      public int     numCodes;71      short[] codes;72      readonly int[] bl_counts;73      readonly int maxLength;74      DeflaterHuffman dh;75      #endregion7677      #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      }8687      #endregion8889      /// <summary>90      /// Resets the internal state of the tree91      /// </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      }100101      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      }  109110      short[] codes;111      readonly int[] bl_counts;112      readonly int maxLength;113      DeflaterHuffman dh;114      #endregion115116      #region Constructors - 837117      public Tree(DeflaterHuffman dh, int elems, int minCodes, int maxLength)118      { - 837119        this.dh =  dh; - 837120        this.minNumCodes = minCodes; - 837121        this.maxLength  = maxLength; - 837122        freqs  = new short[elems]; - 837123        bl_counts = new int[maxLength]; - 837124      }125126      #endregion110      /// <summary>111      /// Check that all frequencies are zero112      /// </summary>113      /// <exception cref="SharpZipBaseException">114      /// At least one frequency is non-zero115      /// </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      /// Resets the internal state of the tree129      /// Set static codes and length  130      /// </summary>131      public void Reset()132      { - 636792133         for (int i = 0; i < freqs.Length; i++) { - 315570134          freqs[i] = 0;135        } - 2826136        codes = null; - 2826137        length = null; - 2826138      }139140      public void WriteSymbol(int code)141      {142        //        if (DeflaterConstants.DEBUGGING) {143        //          freqs[code]--;144        //          //      Console.Write("writeSymbol("+freqs.length+","+code+"): ");145        //        } - 8301146        dh.pending.WriteBits(codes[code] & 0xffff, length[code]); - 8301147      }148149      /// <summary>150      /// Check that all frequencies are zero151      /// </summary>152      /// <exception cref="SharpZipBaseException">153      /// At least one frequency is non-zero154      /// </exception>155      public void CheckEmpty()156      { - 0157        bool empty = true; - 0158         for (int i = 0; i < freqs.Length; i++) { - 0159          empty &= freqs[i] == 0;160        }161 - 0162         if (!empty) { - 0163          throw new SharpZipBaseException("!Empty");164        } - 0165      }166167      /// <summary>168      /// Set static codes and length169      /// </summary>170      /// <param name="staticCodes">new codes</param>171      /// <param name="staticLengths">length for new codes</param>172      public void SetStaticCodes(short[] staticCodes, byte[] staticLengths)173      { - 476174        codes = staticCodes; - 476175        length = staticLengths; - 476176      }177178      /// <summary>179      /// Build dynamic codes and lengths180      /// </summary>181      public void BuildCodes()182      { - 3183        int numSymbols = freqs.Length; - 3184        int[] nextCode = new int[maxLength]; - 3185        int code = 0;186 - 3187        codes = new short[freqs.Length];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      }138139      /// <summary>140      /// Build dynamic codes and lengths141      /// </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];149150        //        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);157158          //          if (DeflaterConstants.DEBUGGING) {159          //            //Console.WriteLine("bits: " + ( bits + 1) + " count: " + bl_counts[bits]160          //                              +" nextCode: "+code);161          //          }162        }163164#if DebugDeflation165        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) {173174            //            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      }184185      public void BuildTree()186      { + 1530187        int numSymbols = freqs.Length;  188189        //        if (DeflaterConstants.DEBUGGING) {190        //          //Console.WriteLine("buildCodes: "+freqs.Length);191        //        }192 - 80193         for (int bits = 0; bits < maxLength; bits++) { - 37194          nextCode[bits] = code; - 37195          code += bl_counts[bits] << (15 - bits);196197          //          if (DeflaterConstants.DEBUGGING) {198          //            //Console.WriteLine("bits: " + ( bits + 1) + " count: " + bl_counts[bits]199          //                              +" nextCode: "+code);200          //          }201        }202203#if DebugDeflation204        if ( DeflaterConstants.DEBUGGING && (code != 65536) )205        {206          throw new SharpZipBaseException("Inconsistent bl_counts!");207        }208#endif - 576209         for (int i=0; i < numCodes; i++) { - 285210          int bits = length[i]; - 285211           if (bits > 0) {212213            //            if (DeflaterConstants.DEBUGGING) {214            //                //Console.WriteLine("codes["+i+"] = rev(" + nextCode[bits-1]+"),215            //                                  +bits);216            //            }217 - 38218            codes[i] = BitReverse(nextCode[bits-1]); - 38219            nextCode[bits-1] += 1 << (16 - bits);220          }221        } - 3222      }223224      public void BuildTree()225      { - 1560226        int numSymbols = freqs.Length;189        /* heap is a priority queue, sorted by frequency, least frequent190        * nodes first.  The heap is a binary tree, with the property, that191        * the parent node is smaller than both child nodes.  This assures192        * that the smallest node is the first parent.193        *194        * The binary tree is encoded in an array:  0 is root node and195        * 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        }215216        /* We could encode a single literal with 0 bits but then we217        * don't see the literals.  Therefore we force at least two218        * literals to avoid this case.  We don't care about order in219        * 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);  227228        /* heap is a priority queue, sorted by frequency, least frequent229        * nodes first.  The heap is a binary tree, with the property, that230        * the parent node is smaller than both child nodes.  This assures231        * that the smallest node is the first parent.232        *233        * The binary tree is encoded in an array:  0 is root node and234        * the nodes 2*n+1, 2*n+2 are the child nodes of node n.235        */ - 1560236        int[] heap = new int[numSymbols]; - 1560237        int heapLen = 0; - 1560238        int maxCode = 0; - 351520239         for (int n = 0; n < numSymbols; n++) { - 174200240          int freq = freqs[n]; - 174200241           if (freq != 0) {242            // Insert n into heap - 84176243            int pos = heapLen++;244            int ppos; - 166131245             while (pos > 0 && freqs[heap[ppos = (pos - 1) / 2]] > freq) { - 81955246              heap[pos] = heap[ppos]; - 81955247              pos = ppos;248            } - 84176249            heap[pos] = n; + 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        }239240        /* Construct the Huffman tree by repeatedly combining the least two241        * frequent nodes.242        */243        do { + 80814244          int first = heap[0]; + 80814245          int last = heap[--heapLen];246247          // Propagate the hole to the leafs of the heap + 80814248          int ppos = 0; + 80814249          int path = 1;  250 - 84176251            maxCode = n;252          }253        }254255        /* We could encode a single literal with 0 bits but then we256        * don't see the literals.  Therefore we force at least two257        * literals to avoid this case.  We don't care about order in258        * this case, both literals get a 1 bit code.259        */ - 2116260         while (heapLen < 2) { - 556261           int node = maxCode < 2 ? ++maxCode : 0; - 556262          heap[heapLen++] = node;263        }264 - 1560265        numCodes = Math.Max(maxCode + 1, minNumCodes);266 - 1560267        int numLeafs = heapLen; - 1560268        int[] childs = new int[4 * heapLen - 2]; - 1560269        int[] values = new int[2 * heapLen - 1]; - 1560270        int numNodes = numLeafs; - 172584271         for (int i = 0; i < heapLen; i++) { - 84732272          int node = heap[i]; - 84732273          childs[2 * i]   = node; - 84732274          childs[2 * i + 1] = -1; - 84732275          values[i] = freqs[node] << 8; - 84732276          heap[i] = i;277        }278279        /* Construct the Huffman tree by repeatedly combining the least two280        * frequent nodes.281        */282        do { - 83172283          int first = heap[0]; - 83172284          int last  = heap[--heapLen];285286          // Propagate the hole to the leafs of the heap - 83172287          int ppos = 0; - 83172288          int path = 1;289 - 522164290           while (path < heapLen) { - 438992291             if (path + 1 < heapLen && values[heap[path]] > values[heap[path+1]]) { - 197234292              path++;293            }294 - 438992295            heap[ppos] = heap[path]; - 438992296            ppos = path; - 438992297            path = path * 2 + 1;298          }299300          /* Now propagate the last element down along path.  Normally301          * it shouldn't go too deep.302          */ - 83172303          int lastVal = values[last]; - 106831304           while ((path = ppos) > 0 && values[heap[ppos = (path - 1)/2]] > lastVal) { - 23659305            heap[path] = heap[ppos];306          } - 83172307          heap[path] = last;308309 - 83172310          int second = heap[0];311312          // Create a new node father of first and second - 83172313          last = numNodes++; - 83172314          childs[2 * last] = first; - 83172315          childs[2 * last + 1] = second; - 83172316          int mindepth = Math.Min(values[first] & 0xff, values[second] & 0xff); - 83172317          values[last] = lastVal = values[first] + values[second] - mindepth + 1;318319          // Again, propagate the hole to the leafs - 83172320          ppos = 0; - 83172321          path = 1;322 - 522887323           while (path < heapLen) { - 439715324             if (path + 1 < heapLen && values[heap[path]] > values[heap[path+1]]) { - 198811325              path++;326            }327 - 439715328            heap[ppos] = heap[path]; - 439715329            ppos = path; - 439715330            path = ppos * 2 + 1;331          }332333          // Now propagate the new element down along path - 88613334           while ((path = ppos) > 0 && values[heap[ppos = (path - 1)/2]] > lastVal) { - 5441335            heap[path] = heap[ppos];336          } - 83172337          heap[path] = last; - 83172338         } while (heapLen > 1);339 - 1560340         if (heap[0] != childs.Length / 2 - 1) { - 0341          throw new SharpZipBaseException("Heap invariant violated");342        }343 - 1560344        BuildLength(childs); - 1560345      }346347      /// <summary>348      /// Get encoded length349      /// </summary>350      /// <returns>Encoded length, the sum of frequencies * lengths</returns>351      public int GetEncodedLength()352      { - 1560353        int len = 0; - 351520354         for (int i = 0; i < freqs.Length; i++) { - 174200355          len += freqs[i] * length[i];356        } - 1560357        return len;358      }359360      /// <summary>361      /// Scan a literal or distance tree to determine the frequencies of the codes362      /// in the bit length tree.363      /// </summary>364      public void CalcBLFreq(Tree blTree)365      {366        int max_count;               /* max repeat count */367        int min_count;               /* min repeat count */368        int count;                   /* repeat count of the current code */ - 1040369        int curlen = -1;             /* length of current code */370 - 1040371        int i = 0; - 27219372         while (i < numCodes) { - 26179373          count = 1; - 26179374          int nextlen = length[i]; - 26179375           if (nextlen == 0) { - 3048376            max_count = 138; - 3048377            min_count = 3; - 3048378          } else { - 23131379            max_count = 6; - 23131380            min_count = 3; - 23131381             if (curlen != nextlen) { - 13307382              blTree.freqs[nextlen]++; - 13307383              count = 0;384            }385          } - 26179386          curlen = nextlen; - 26179387          i++;388 - 132059389           while (i < numCodes && curlen == length[i]) { - 116053390            i++; - 116053391             if (++count >= max_count) {392              break; + 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          }260261          /* Now propagate the last element down along path.  Normally262          * 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;269270 + 80814271          int second = heap[0];272273          // 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;279280          // 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          }293294          // 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      }307308      /// <summary>309      /// Get encoded length310      /// </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      }320321      /// <summary>322      /// Scan a literal or distance tree to determine the frequencies of the codes323      /// 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      }368369      /// <summary>370      /// Write tree values371      /// </summary>372      /// <param name="blTree">Tree to write</param>373      public void WriteTree(Tree blTree)374      {375        int max_count;               // max repeat count376        int min_count;               // min repeat count377        int count;                   // repeat count of the current code + 2378        int curlen = -1;             // length of current code379 + 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          }395 - 26179396           if (count < min_count) { - 13826397            blTree.freqs[curlen] += (short)count; - 26179398           } else if (curlen != 0) { - 10965399            blTree.freqs[REP_3_6]++; - 12353400           } else if (count <= 10) { - 317401            blTree.freqs[REP_3_10]++; - 317402          } else { - 1071403            blTree.freqs[REP_11_138]++;404          }405        } - 1040406      }407408      /// <summary>409      /// Write tree values410      /// </summary>411      /// <param name="blTree">Tree to write</param>412      public void WriteTree(Tree blTree)413      {414        int max_count;               // max repeat count415        int min_count;               // min repeat count416        int count;                   // repeat count of the current code - 2417        int curlen = -1;             // length of current code418 - 2419        int i = 0; - 42420         while (i < numCodes) { - 40421          count = 1; - 40422          int nextlen = length[i]; - 40423           if (nextlen == 0) { - 14424            max_count = 138; - 14425            min_count = 3; - 14426          } else { - 26427            max_count = 6; - 26428            min_count = 3; - 26429             if (curlen != nextlen) { - 26430              blTree.WriteSymbol(nextlen); - 26431              count = 0;432            }433          } - 40434          curlen = nextlen; - 40435          i++; + 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      }421422      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        }432433        // First calculate optimal bit lengths + 1530434        int[] lengths = new int[numNodes]; + 1530435        lengths[numNodes - 1] = 0;  436 - 266437           while (i < numCodes && curlen == length[i]) { - 226438            i++; - 226439             if (++count >= max_count) {440              break;441            }442          }443 - 40444           if (count < min_count) { - 41445             while (count-- > 0) { - 10446              blTree.WriteSymbol(curlen);447            } - 40448           } else if (curlen != 0) { - 0449            blTree.WriteSymbol(REP_3_6); - 0450            dh.pending.WriteBits(count - 3, 2); - 9451           } else if (count <= 10) { - 4452            blTree.WriteSymbol(REP_3_10); - 4453            dh.pending.WriteBits(count - 3, 3); - 4454          } else { - 5455            blTree.WriteSymbol(REP_11_138); - 5456            dh.pending.WriteBits(count - 11, 7);457          }458        } - 2459      } + 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        }452453        //        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        //        }  460461      void BuildLength(int[] childs)462      { - 1560463        this.length = new byte [freqs.Length]; - 1560464        int numNodes = childs.Length / 2; - 1560465        int numLeafs = (numNodes + 1) / 2; - 1560466        int overflow = 0;467 - 41600468         for (int i = 0; i < maxLength; i++) { - 19240469          bl_counts[i] = 0;470        }471472        // First calculate optimal bit lengths - 1560473        int[] lengths = new int[numNodes]; - 1560474        lengths[numNodes-1] = 0;475 - 338928476         for (int i = numNodes - 1; i >= 0; i--) { - 167904477           if (childs[2 * i + 1] != -1) { - 83172478            int bitLength = lengths[i] + 1; - 83172479             if (bitLength > maxLength) { - 5480              bitLength = maxLength; - 5481              overflow++;482            } - 83172483            lengths[childs[2 * i]] = lengths[childs[2 * i + 1]] = bitLength; - 83172484          } else {485            // A leaf node - 84732486            int bitLength = lengths[i]; - 84732487            bl_counts[bitLength - 1]++; - 84732488            this.length[childs[2*i]] = (byte) lengths[i];489          }490        }491492        //        if (DeflaterConstants.DEBUGGING) {493        //          //Console.WriteLine("Tree "+freqs.Length+" lengths:");494        //          for (int i=0; i < numLeafs; i++) {495        //            //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]496        //                              + " len: "+length[childs[2*i]]);497        //          }498        //        }499 - 1560500         if (overflow == 0) { - 1555501          return;502        }503 - 5504        int incrBitLen = maxLength - 1;505        do {506          // Find the first bit length which could increase: - 7507           while (bl_counts[--incrBitLen] == 0)508          {509          }510511          // Move this node one down and remove a corresponding512          // number of overflow nodes.513          do { - 5514            bl_counts[incrBitLen]--; - 5515            bl_counts[++incrBitLen]++; - 5516            overflow -= 1 << (maxLength - 1 - incrBitLen); - 5517           } while (overflow > 0 && incrBitLen < maxLength - 1); - 5518         } while (overflow > 0);519520        /* We may have overshot above.  Move some nodes from maxLength to521        * maxLength-1 in that case.522        */ - 5523        bl_counts[maxLength-1] += overflow; - 5524        bl_counts[maxLength-2] -= overflow;525526        /* Now recompute all bit lengths, scanning in increasing527        * frequency.  It is simpler to reconstruct all lengths instead of528        * fixing only the wrong ones. This idea is taken from 'ar'529        * written by Haruhiko Okumura.530        *531        * The nodes were inserted with decreasing frequency into the childs532        * array.533        */ - 5534        int nodePtr = 2 * numLeafs; - 80535         for (int bits = maxLength; bits != 0; bits--) { - 35536          int n = bl_counts[bits-1]; - 114537           while (n > 0) { - 79538            int childPtr = 2*childs[nodePtr++]; - 79539             if (childs[childPtr + 1] == -1) {540              // We found another leaf - 47541              length[childs[childPtr]] = (byte) bits; - 47542              n--;543            }544          }545        }546        //        if (DeflaterConstants.DEBUGGING) {547        //          //Console.WriteLine("*** After overflow elimination. ***");548        //          for (int i=0; i < numLeafs; i++) {549        //            //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]550        //                              + " len: "+length[childs[2*i]]);551        //          }552        //        } - 5553      }554555    } + 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          }470471          // Move this node one down and remove a corresponding472          // 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);479480        /* We may have overshot above.  Move some nodes from maxLength to481        * maxLength-1 in that case.482        */ + 2483        bl_counts[maxLength - 1] += overflow; + 2484        bl_counts[maxLength - 2] -= overflow;485486        /* Now recompute all bit lengths, scanning in increasing487        * frequency.  It is simpler to reconstruct all lengths instead of488        * 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 childs492        * 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      }514515    }516517    #region Instance Fields518    /// <summary>519    /// Pending buffer to use520    /// </summary>521    public DeflaterPending pending;522523    Tree literalTree;524    Tree distTree;525    Tree blTree;526527    // Buffer for distances528    short[] d_buf;529    byte[] l_buf;530    int last_lit;531    int extra_bits;532    #endregion533534    static DeflaterHuffman()535    {536      // See RFC 1951 3.2.6537      // 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      }  556557    #region Instance Fields558    /// <summary>559    /// Pending buffer to use560    /// </summary>561    public DeflaterPending pending;562563    Tree literalTree;564    Tree distTree;565    Tree blTree;566567    // Buffer for distances568    short[] d_buf;569    byte[]  l_buf;570    int last_lit;571    int extra_bits;572    #endregion573574    static DeflaterHuffman()575    {576      // See RFC 1951 3.2.6577      // Literal codes - 1578      staticLCodes = new short[LITERAL_NUM]; - 1579      staticLLength = new byte[LITERAL_NUM];580 - 1581      int i = 0; - 145582       while (i < 144) { - 144583        staticLCodes[i] = BitReverse((0x030 + i) << 8); - 144584        staticLLength[i++] = 8;585      } + 7557       while (i < LITERAL_NUM) { + 6558        staticLCodes[i] = BitReverse((0x0c0 - 280 + i) << 8); + 6559        staticLLength[i++] = 8;560      }561562      // 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    }570571    /// <summary>572    /// Construct instance with pending buffer573    /// </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 - 113587       while (i < 256) { - 112588        staticLCodes[i] = BitReverse((0x190 - 144 + i) << 7); - 112589        staticLLength[i++] = 9;590      }591 - 25592       while (i < 280) { - 24593        staticLCodes[i] = BitReverse((0x000 - 256 + i) << 9); - 24594        staticLLength[i++] = 7;595      }596 - 7597       while (i < LITERAL_NUM) { - 6598        staticLCodes[i] = BitReverse((0x0c0 - 280 + i)  << 8); - 6599        staticLLength[i++] = 8;600      }601602      // Distance codes - 1603      staticDCodes = new short[DIST_NUM]; - 1604      staticDLength = new byte[DIST_NUM]; - 62605       for (i = 0; i < DIST_NUM; i++) { - 30606        staticDCodes[i] = BitReverse(i << 11); - 30607        staticDLength[i] = 5;608      } - 1609    }610611    /// <summary>612    /// Construct instance with pending buffer613    /// </summary>614    /// <param name="pending">Pending buffer to use</param> - 279615    public DeflaterHuffman(DeflaterPending pending)616    { - 279617      this.pending = pending;618 - 279619      literalTree = new Tree(this, LITERAL_NUM, 257, 15); - 279620      distTree    = new Tree(this, DIST_NUM, 1, 15); - 279621      blTree      = new Tree(this, BITLEN_NUM, 4, 7);622 - 279623      d_buf = new short[BUFSIZE]; - 279624      l_buf = new byte [BUFSIZE]; - 279625    }626627    /// <summary>628    /// Reset internal state629    /// </summary>630    public void Reset()631    { - 942632      last_lit = 0; - 942633      extra_bits = 0; - 942634      literalTree.Reset(); - 942635      distTree.Reset(); - 942636      blTree.Reset(); - 942637    }638639    /// <summary>640    /// Write all trees to pending buffer641    /// </summary>642    /// <param name="blTreeCodes">The number/rank of treecodes to send.</param>643    public void SendAllTrees(int blTreeCodes)644    { - 1645      blTree.BuildCodes(); - 1646      literalTree.BuildCodes(); - 1647      distTree.BuildCodes(); - 1648      pending.WriteBits(literalTree.numCodes - 257, 5); - 1649      pending.WriteBits(distTree.numCodes - 1, 5); - 1650      pending.WriteBits(blTreeCodes - 4, 4); - 38651       for (int rank = 0; rank < blTreeCodes; rank++) { - 18652        pending.WriteBits(blTree.length[BL_ORDER[rank]], 3);653      } - 1654      literalTree.WriteTree(blTree); - 1655      distTree.WriteTree(blTree);656657#if DebugDeflation658      if (DeflaterConstants.DEBUGGING) {659        blTree.CheckEmpty();660      }661#endif - 1662    }587    /// <summary>588    /// Reset internal state589    /// </summary>590    public void Reset()591    { + 923592      last_lit = 0; + 923593      extra_bits = 0; + 923594      literalTree.Reset(); + 923595      distTree.Reset(); + 923596      blTree.Reset(); + 923597    }598599    /// <summary>600    /// Write all trees to pending buffer601    /// </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);616617#if DebugDeflation618      if (DeflaterConstants.DEBUGGING) {619        blTree.CheckEmpty();620      }621#endif + 1622    }623624    /// <summary>625    /// Compress current buffer writing data to pending buffer626    /// </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      }  663664    /// <summary>665    /// Compress current buffer writing data to pending buffer666    /// </summary>667    public void CompressBlock()668    { - 16330669       for (int i = 0; i < last_lit; i++) { - 7926670        int litlen = l_buf[i] & 0xff; - 7926671        int dist = d_buf[i]; - 7926672         if (dist-- != 0) {673          //          if (DeflaterConstants.DEBUGGING) {674          //            Console.Write("["+(dist+1)+","+(litlen+3)+"]: ");675          //          }676 - 91677          int lc = Lcode(litlen); - 91678          literalTree.WriteSymbol(lc);679 - 91680          int bits = (lc - 261) / 4; - 91681           if (bits > 0 && bits <= 5) { - 25682            pending.WriteBits(litlen & ((1 << bits) - 1), bits);683          }684 - 91685          int dc = Dcode(dist); - 91686          distTree.WriteSymbol(dc);687 - 91688          bits = dc / 2 - 1; - 91689           if (bits > 0) { - 70690            pending.WriteBits(dist & ((1 << bits) - 1), bits);691          } - 70692        } else {693          //          if (DeflaterConstants.DEBUGGING) {694          //            if (litlen > 32 && litlen < 127) {695          //              Console.Write("("+(char)litlen+"): ");696          //            } else {697          //              Console.Write("{"+litlen+"}: ");698          //            }699          //          } - 7835700          literalTree.WriteSymbol(litlen);701        }702      }703704#if DebugDeflation705      if (DeflaterConstants.DEBUGGING) {706        Console.Write("EOF: ");707      }708#endif - 239709      literalTree.WriteSymbol(EOF_SYMBOL);710711#if DebugDeflation712      if (DeflaterConstants.DEBUGGING) {713        literalTree.CheckEmpty();714        distTree.CheckEmpty();715      }716#endif - 239717    }718719    /// <summary>720    /// Flush block to output with no compression721    /// </summary>722    /// <param name="stored">Data to write</param>723    /// <param name="storedOffset">Index of first byte to write</param>724    /// <param name="storedLength">Count of bytes to write</param>725    /// <param name="lastBlock">True if this is the last block</param>726    public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)727    {728#if DebugDeflation729      //      if (DeflaterConstants.DEBUGGING) {730      //        //Console.WriteLine("Flushing stored block "+ storedLength);731      //      }732#endif - 302733       pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3); - 302734      pending.AlignToByte(); - 302735      pending.WriteShort(storedLength); - 302736      pending.WriteShort(~storedLength); - 302737      pending.WriteBlock(stored, storedOffset, storedLength); - 302738      Reset(); - 302739    }740741    /// <summary>742    /// Flush block to output with compression743    /// </summary>744    /// <param name="stored">Data to flush</param>745    /// <param name="storedOffset">Index of first byte to flush</param>746    /// <param name="storedLength">Count of bytes to flush</param>747    /// <param name="lastBlock">True if this is the last block</param>748    public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)749    { - 520750      literalTree.freqs[EOF_SYMBOL]++;751752      // Build trees - 520753      literalTree.BuildTree(); - 520754      distTree.BuildTree();755756      // Calculate bitlen frequency - 520757      literalTree.CalcBLFreq(blTree); - 520758      distTree.CalcBLFreq(blTree);759760      // Build bitlen tree - 520761      blTree.BuildTree();762 - 520763      int blTreeCodes = 4; - 3632764       for (int i = 18; i > blTreeCodes; i--) { - 1296765         if (blTree.length[BL_ORDER[i]] > 0) { - 520766          blTreeCodes = i+1;767        }768      } - 520769      int opt_len = 14 + blTreeCodes * 3 + blTree.GetEncodedLength() + - 520770        literalTree.GetEncodedLength() + distTree.GetEncodedLength() + - 520771        extra_bits;772 - 520773      int static_len = extra_bits; - 298480774       for (int i = 0; i < LITERAL_NUM; i++) { - 148720775        static_len += literalTree.freqs[i] * staticLLength[i];776      } - 32240777       for (int i = 0; i < DIST_NUM; i++) { - 15600778        static_len += distTree.freqs[i] * staticDLength[i];779      } - 520780       if (opt_len >= static_len) {781        // Force static trees - 274782        opt_len = static_len;783      }784 - 520785       if (storedOffset >= 0 && storedLength + 4 < opt_len >> 3) {786        // Store Block787788        //        if (DeflaterConstants.DEBUGGING) {789        //          //Console.WriteLine("Storing, since " + storedLength + " < " + opt_len790        //                            + " <= " + static_len);791        //        } - 281792        FlushStoredBlock(stored, storedOffset, storedLength, lastBlock); - 520793       } else if (opt_len == static_len) {794        // Encode with static tree - 238795         pending.WriteBits((DeflaterConstants.STATIC_TREES << 1) + (lastBlock ? 1 : 0), 3); - 238796        literalTree.SetStaticCodes(staticLCodes, staticLLength); - 238797        distTree.SetStaticCodes(staticDCodes, staticDLength); - 238798        CompressBlock(); - 238799        Reset(); - 238800      } else {801        // Encode with dynamic tree - 1802         pending.WriteBits((DeflaterConstants.DYN_TREES << 1) + (lastBlock ? 1 : 0), 3); - 1803        SendAllTrees(blTreeCodes); - 1804        CompressBlock(); - 1805        Reset();806      } - 1807    }808809    /// <summary>810    /// Get value indicating if internal buffer is full811    /// </summary>812    /// <returns>true if buffer is full</returns>813    public bool IsFull()814    { - 7409482815      return last_lit >= BUFSIZE;816    }817818    /// <summary>819    /// Add literal to buffer820    /// </summary>821    /// <param name="literal">Literal value to add to buffer.</param>822    /// <returns>Value indicating internal buffer is full</returns>823    public bool TallyLit(int literal)824    {825      //      if (DeflaterConstants.DEBUGGING) {826      //        if (lit > 32 && lit < 127) {827      //          //Console.WriteLine("("+(char)lit+")");828      //        } else {829      //          //Console.WriteLine("{"+lit+"}");830      //        }831      //      } - 3702619832      d_buf[last_lit] = 0; - 3702619833      l_buf[last_lit++] = (byte)literal; - 3702619834      literalTree.freqs[literal]++; - 3702619835      return IsFull();836    }837838    /// <summary>839    /// Add distance code and length to literal and distance trees840    /// </summary>841    /// <param name="distance">Distance code</param>842    /// <param name="length">Length</param>843    /// <returns>Value indicating if internal buffer is full</returns>844    public bool TallyDist(int distance, int length)845    {846      //      if (DeflaterConstants.DEBUGGING) {847      //        //Console.WriteLine("[" + distance + "," + length + "]");848      //      }849 - 3002850      d_buf[last_lit]   = (short)distance; - 3002851      l_buf[last_lit++] = (byte)(length - 3);852 - 3002853      int lc = Lcode(length - 3); - 3002854      literalTree.freqs[lc]++; - 3002855       if (lc >= 265 && lc < 285) { - 25856        extra_bits += (lc - 261) / 4;857      }858 - 3002859      int dc = Dcode(distance - 1); - 3002860      distTree.freqs[dc]++; - 3002861       if (dc >= 4) { - 2980862        extra_bits += dc / 2 - 1;863      } - 3002864      return IsFull();865    }866867868    /// <summary>869    /// Reverse the bits of a 16 bit value.870    /// </summary>871    /// <param name="toReverse">Value to reverse bits</param>872    /// <returns>Value with bits reversed</returns>873    public static short BitReverse(int toReverse)874    { - 712875      return (short) (bit4Reverse[toReverse & 0xF] << 12 | - 712876                      bit4Reverse[(toReverse >> 4) & 0xF] << 8 | - 712877                      bit4Reverse[(toReverse >> 8) & 0xF] << 4 | - 712878                      bit4Reverse[toReverse >> 12]);879    }880881    static int Lcode(int length)882    { - 3093883       if (length == 255) { - 82884        return 285;885      }886 - 3011887      int code = 257; - 3241888       while (length >= 8) { - 230889        code += 4; - 230890        length >>= 1;891      } - 3011892      return code + length;893    }894895    static int Dcode(int distance)896    { - 3093897      int code = 0; - 36621898       while (distance >= 4) { - 33528899        code += 2; - 33528900        distance >>= 1;901      } - 3093902      return code + distance;903    }904  }905}664#if DebugDeflation665      if (DeflaterConstants.DEBUGGING) {666        Console.Write("EOF: ");667      }668#endif + 238669      literalTree.WriteSymbol(EOF_SYMBOL);670671#if DebugDeflation672      if (DeflaterConstants.DEBUGGING) {673        literalTree.CheckEmpty();674        distTree.CheckEmpty();675      }676#endif + 238677    }678679    /// <summary>680    /// Flush block to output with no compression681    /// </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 DebugDeflation689      //      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    }700701    /// <summary>702    /// Flush block to output with compression703    /// </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]++;711712      // Build trees + 510713      literalTree.BuildTree(); + 510714      distTree.BuildTree();715716      // Calculate bitlen frequency + 510717      literalTree.CalcBLFreq(blTree); + 510718      distTree.CalcBLFreq(blTree);719720      // 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 Block747748        //        if (DeflaterConstants.DEBUGGING) {749        //          //Console.WriteLine("Storing, since " + storedLength + " < " + opt_len750        //                            + " <= " + 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    }768769    /// <summary>770    /// Get value indicating if internal buffer is full771    /// </summary>772    /// <returns>true if buffer is full</returns>773    public bool IsFull()774    { + 7208362775      return last_lit >= BUFSIZE;776    }777778    /// <summary>779    /// Add literal to buffer780    /// </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    }797798    /// <summary>799    /// Add distance code and length to literal and distance trees800    /// </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    }826827828    /// <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    }840841    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    }854855    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/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterOutputStream.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterOutputStream.htm index 69128d45a..51246dacc 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterOutputStream.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterOutputStream.htm @@ -18,7 +18,7 @@

Summary

Covered lines:76 Uncovered lines:28 Coverable lines:104 -Total lines:602 +Total lines:476 Line coverage:73% Branch coverage:71.4% @@ -53,610 +53,484 @@

#LineLine coverage - 1// DeflaterOutputStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  22-12-2009  DavidPierson  Added AES support1using System;2using System.IO;3using System.Security.Cryptography;4using ICSharpCode.SharpZipLib.Encryption;56namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams7{8  /// <summary>9  /// A special stream deflating or compressing the bytes that are10  /// written to it.  It uses a Deflater to perform actual deflating.<br/>11  /// Authors of the original java version : Tom Tromey, Jochen Hoenicke12  /// </summary>13  public class DeflaterOutputStream : Stream14  {15    #region Constructors16    /// <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    }2627    /// <summary>28    /// Creates a new DeflaterOutputStream with the given Deflater and29    /// 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    }  4142using System;43using System.IO;4445#if !NETCF_1_046using System.Security.Cryptography;47using ICSharpCode.SharpZipLib.Encryption;48#endif4950namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams51{52  /// <summary>53  /// A special stream deflating or compressing the bytes that are54  /// written to it.  It uses a Deflater to perform actual deflating.<br/>55  /// Authors of the original java version : Tom Tromey, Jochen Hoenicke56  /// </summary>57  public class DeflaterOutputStream : Stream58  {59    #region Constructors60    /// <summary>61    /// Creates a new DeflaterOutputStream with a default Deflater and default buffer size.62    /// </summary>63    /// <param name="baseOutputStream">64    /// the output stream where deflated output should be written.65    /// </param>66    public DeflaterOutputStream(Stream baseOutputStream) - 467      : this(baseOutputStream, new Deflater(), 512)68    { - 469    }7071    /// <summary>72    /// Creates a new DeflaterOutputStream with the given Deflater and73    /// default buffer size.74    /// </summary>75    /// <param name="baseOutputStream">76    /// the output stream where deflated output should be written.77    /// </param>78    /// <param name="deflater">79    /// the underlying deflater.80    /// </param>81    public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater) - 26582      : this(baseOutputStream, deflater, 512)83    { - 26584    }8586    /// <summary>87    /// Creates a new DeflaterOutputStream with the given Deflater and88    /// buffer size.89    /// </summary>90    /// <param name="baseOutputStream">91    /// The output stream where deflated output is written.92    /// </param>93    /// <param name="deflater">94    /// The underlying deflater to use95    /// </param>96    /// <param name="bufferSize">97    /// The buffer size in bytes to use when deflating (minimum value 512)98    /// </param>99    /// <exception cref="ArgumentOutOfRangeException">100    /// bufsize is less than or equal to zero.101    /// </exception>102    /// <exception cref="ArgumentException">103    /// baseOutputStream does not support writing104    /// </exception>105    /// <exception cref="ArgumentNullException">106    /// deflater instance is null107    /// </exception> - 279108    public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater, int bufferSize)109    { - 279110       if ( baseOutputStream == null ) { - 0111        throw new ArgumentNullException(nameof(baseOutputStream));112      }113 - 279114       if (baseOutputStream.CanWrite == false) { - 0115        throw new ArgumentException("Must support writing", nameof(baseOutputStream));116      }117 - 279118       if (deflater == null) { - 0119        throw new ArgumentNullException(nameof(deflater));120      }121 - 279122       if (bufferSize < 512) { - 0123        throw new ArgumentOutOfRangeException(nameof(bufferSize));124      }42    /// <summary>43    /// Creates a new DeflaterOutputStream with the given Deflater and44    /// 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 use51    /// </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 writing60    /// </exception>61    /// <exception cref="ArgumentNullException">62    /// deflater instance is null63    /// </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    #endregion8788    #region Public API89    /// <summary>90    /// Finishes the stream by calling finish() on the deflater.91    /// </summary>92    /// <exception cref="SharpZipBaseException">93    /// Not all input is deflated94    /// </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 - 279126      baseOutputStream_ = baseOutputStream; - 279127      buffer_ = new byte[bufferSize]; - 279128      deflater_ = deflater; - 279129    }130    #endregion131132    #region Public API133    /// <summary>134    /// Finishes the stream by calling finish() on the deflater.135    /// </summary>136    /// <exception cref="SharpZipBaseException">137    /// Not all input is deflated138    /// </exception>139    public virtual void Finish()140    { - 329141      deflater_.Finish(); - 1584142       while (!deflater_.IsFinished)  { - 1255143        int len = deflater_.Deflate(buffer_, 0, buffer_.Length); - 1255144         if (len <= 0) {145          break;146        }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    }134135    ///  <summary>136    /// Allows client to determine if an entry can be patched after its added137    /// </summary>138    public bool CanPatchEntries {139      get { + 141140        return baseOutputStream_.CanSeek;141      }142    }143144    #endregion145146    #region Encryption  147148#if NETCF_1_0149        if ( keys != null ) {150#else - 1255151         if (cryptoTransform_ != null) {152#endif - 199153          EncryptBlock(buffer_, 0, len);154        }155 - 1255156        baseOutputStream_.Write(buffer_, 0, len);157      }158 - 329159       if (!deflater_.IsFinished) { - 0160        throw new SharpZipBaseException("Can't deflate all input?");161      }162 - 329163      baseOutputStream_.Flush();164165#if NETCF_1_0166      if ( keys != null ) {167        keys = null;168      }169#else - 329170       if (cryptoTransform_ != null) {171#if !NET_1_1 && !NETCF_2_0 - 34172         if (cryptoTransform_ is ZipAESTransform) { - 0173          AESAuthCode = ((ZipAESTransform)cryptoTransform_).GetAuthCode();174        }175#endif - 34176        cryptoTransform_.Dispose(); - 34177        cryptoTransform_ = null;178      }179#endif - 329180    }181182    /// <summary>183    /// Get/set flag indicating ownership of the underlying stream.184    /// When the flag is true <see cref="Close"></see> will close the underlying stream also.185    /// </summary>186    public bool IsStreamOwner148    string password;149150    ICryptoTransform cryptoTransform_;151152    /// <summary>153    /// Returns the 10 byte AUTH CODE to be appended immediately following the AES data stream.154    /// </summary>155    protected byte[] AESAuthCode;156157    /// <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    }173174    /// <summary>175    /// Encrypt a block of data176    /// </summary>177    /// <param name="buffer">178    /// Data to encrypt.  NOTE the original contents of the buffer are lost179    /// </param>180    /// <param name="offset">181    /// Offset of first byte in buffer to encrypt182    /// </param>183    /// <param name="length">184    /// Number of bytes in buffer to encrypt185    /// </param>186    protected void EncryptBlock(byte[] buffer, int offset, int length)  187    { - 11188      get { return isStreamOwner_; } - 388189      set { isStreamOwner_ = value; }190    }191192    ///  <summary>193    /// Allows client to determine if an entry can be patched after its added194    /// </summary>195    public bool CanPatchEntries {196      get { - 144197        return baseOutputStream_.CanSeek;198      }199    }200201    #endregion202203    #region Encryption204205    string password;206207#if NETCF_1_0208    uint[] keys;209#else210    ICryptoTransform cryptoTransform_;211212    /// <summary>213    /// Returns the 10 byte AUTH CODE to be appended immediately following the AES data stream.214    /// </summary>215    protected byte[] AESAuthCode;216#endif217218    /// <summary>219    /// Get/set the password used for encryption.220    /// </summary>221    /// <remarks>When set to null or if the password is empty no encryption is performed</remarks>222    public string Password {223      get { - 367224        return password;225      }226      set { - 72227         if ( (value != null) && (value.Length == 0) ) { - 0228          password = null; - 0229        } else { - 72230          password = value;231        } - 72232      }233    }234235    /// <summary>236    /// Encrypt a block of data237    /// </summary>238    /// <param name="buffer">239    /// Data to encrypt.  NOTE the original contents of the buffer are lost240    /// </param>241    /// <param name="offset">242    /// Offset of first byte in buffer to encrypt243    /// </param>244    /// <param name="length">245    /// Number of bytes in buffer to encrypt246    /// </param>247    protected void EncryptBlock(byte[] buffer, int offset, int length)248    {249#if NETCF_1_0250      for (int i = offset; i < offset + length; ++i) {251        byte oldbyte = buffer[i];252        buffer[i] ^= EncryptByte();253        UpdateKeys(oldbyte);254      }255#else - 2311256      cryptoTransform_.TransformBlock(buffer, 0, length, buffer, 0);257#endif - 2311258    }259260    /// <summary>261    /// Initializes encryption keys based on given <paramref name="password"/>.262    /// </summary>263    /// <param name="password">The password.</param>264    protected void InitializePassword(string password)265    {266#if NETCF_1_0267      keys = new uint[] {268        0x12345678,269        0x23456789,270        0x34567890271      };272273      byte[] rawPassword = ZipConstants.ConvertToArray(password);274275      for (int i = 0; i < rawPassword.Length; ++i) {276        UpdateKeys((byte)rawPassword[i]);277      }278279#else - 36280      var pkManaged = new PkzipClassicManaged(); - 36281      byte[] key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(password)); - 36282      cryptoTransform_ = pkManaged.CreateEncryptor(key, null);283#endif - 36284    } + 2305188      cryptoTransform_.TransformBlock(buffer, 0, length, buffer, 0); + 2305189    }190191    /// <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    }201202    /// <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 bytes214 + 0215      cryptoTransform_ = new ZipAESTransform(rawPassword, salt, blockSize, true); + 0216      pwdVerifier = ((ZipAESTransform)cryptoTransform_).PwdVerifier; + 0217    }218219    #endregion220221    #region Deflation Support222    /// <summary>223    /// Deflates everything in the input buffers.  This will call224    /// <code>def.deflate()</code> until all bytes from the input buffers225    /// 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    #endregion247248    #region Stream Overrides249    /// <summary>250    /// Gets value indicating stream can be read from251    /// </summary>252    public override bool CanRead {253      get { + 0254        return false;255      }256    }257258    /// <summary>259    /// Gets a value indicating if seeking is supported for this stream260    /// This property always returns false261    /// </summary>262    public override bool CanSeek {263      get { + 2264        return false;265      }266    }267268    /// <summary>269    /// Get value indicating if this stream supports writing270    /// </summary>271    public override bool CanWrite {272      get { + 5273        return baseOutputStream_.CanWrite;274      }275    }276277    /// <summary>278    /// Get current length of stream279    /// </summary>280    public override long Length {281      get { + 0282        return baseOutputStream_.Length;283      }284    }  285286#if !NET_1_1 && !NETCF_2_0287    /// <summary>288    /// Initializes encryption keys based on given password.289    /// </summary>290    protected void InitializeAESPassword(ZipEntry entry, string rawPassword,291                      out byte[] salt, out byte[] pwdVerifier) { - 0292      salt = new byte[entry.AESSaltLen];293      // Salt needs to be cryptographically random, and unique per file - 0294       if (_aesRnd == null) - 0295        _aesRnd = new RNGCryptoServiceProvider(); - 0296      _aesRnd.GetBytes(salt); - 0297      int blockSize = entry.AESKeySize / 8;  // bits to bytes286    /// <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 - 0299      cryptoTransform_ = new ZipAESTransform(rawPassword, salt, blockSize, true); - 0300      pwdVerifier = ((ZipAESTransform)cryptoTransform_).PwdVerifier; - 0301    }302#endif303304#if NETCF_1_0305306    /// <summary>307    /// Encrypt a single byte308    /// </summary>309    /// <returns>310    /// The encrypted value311    /// </returns>312    protected byte EncryptByte()313    {314      uint temp = ((keys[2] & 0xFFFF) | 2);315      return (byte)((temp * (temp ^ 1)) >> 8);316    }317318    /// <summary>319    /// Update encryption keys320    /// </summary>321    protected void UpdateKeys(byte ch)322    {323      keys[0] = Crc32.ComputeCrc32(keys[0], ch);324      keys[1] = keys[1] + (byte)keys[0];325      keys[1] = keys[1] * 134775813 + 1;326      keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));327    }328#endif329330    #endregion331332    #region Deflation Support333    /// <summary>334    /// Deflates everything in the input buffers.  This will call335    /// <code>def.deflate()</code> until all bytes from the input buffers336    /// are processed.337    /// </summary>338    protected void Deflate()339    { - 11778340       while (!deflater_.IsNeedingInput)341      { - 11494342        int deflateCount = deflater_.Deflate(buffer_, 0, buffer_.Length);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    }310311    /// <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    }320321    /// <summary>322    /// Read a byte from stream advancing position by one323    /// </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    }330331    /// <summary>332    /// Read a block of bytes from stream333    /// </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 - 11494344         if (deflateCount <= 0) {345          break;346        }347#if NETCF_1_0348        if (keys != null)349#else - 7261350         if (cryptoTransform_ != null)351#endif352        { - 1977353          EncryptBlock(buffer_, 0, deflateCount);354        }355 - 7261356        baseOutputStream_.Write(buffer_, 0, deflateCount);357      }344    /// <summary>345    /// Asynchronous reads are not supported a NotSupportedException is always thrown346    /// </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 - 4517359       if (!deflater_.IsNeedingInput) { - 0360        throw new SharpZipBaseException("DeflaterOutputStream can't deflate all input?");361      } - 4517362    }363    #endregion364365    #region Stream Overrides366    /// <summary>367    /// Gets value indicating stream can be read from368    /// </summary>369    public override bool CanRead359    /// <summary>360    /// Asynchronous writes arent supported, a NotSupportedException is always thrown361    /// </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    {371      get { - 0372        return false;373      }374    }375376    /// <summary>377    /// Gets a value indicating if seeking is supported for this stream378    /// This property always returns false379    /// </summary>380    public override bool CanSeek {381      get { - 2382        return false;383      }384    }385386    /// <summary>387    /// Get value indicating if this stream supports writing + 0371      throw new NotSupportedException("BeginWrite is not supported");372    }373374    /// <summary>375    /// Flushes the stream by calling <see cref="DeflaterOutputStream.Flush">Flush</see> on the deflater and then376    /// 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    }384385    /// <summary>386    /// Calls <see cref="Finish"/> and closes the underlying387    /// stream when <see cref="IsStreamOwner"></see> is true.  388    /// </summary>389    public override bool CanWrite {390      get { - 5391        return baseOutputStream_.CanWrite;392      }393    }394395    /// <summary>396    /// Get current length of stream397    /// </summary>398    public override long Length {399      get { - 0400        return baseOutputStream_.Length;401      }402    }403404    /// <summary>405    /// Gets the current position within the stream.406    /// </summary>407    /// <exception cref="NotSupportedException">Any attempt to set position</exception>408    public override long Position {409      get { - 0410        return baseOutputStream_.Position;411      }412      set { - 0413        throw new NotSupportedException("Position property not supported");414      }415    }416417    /// <summary>418    /// Sets the current position of this stream to the given value. Not supported by this class!419    /// </summary>420    /// <param name="offset">The offset relative to the <paramref name="origin"/> to seek.</param>421    /// <param name="origin">The <see cref="SeekOrigin"/> to seek from.</param>422    /// <returns>The new position in the stream.</returns>423    /// <exception cref="NotSupportedException">Any access</exception>424    public override long Seek(long offset, SeekOrigin origin)425    { - 0426      throw new NotSupportedException("DeflaterOutputStream Seek not supported");427    }389    public override void Close()390    { + 267391       if (!isClosed_) { + 259392        isClosed_ = true;393394        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    }408409    private void GetAuthCodeIfAES()410    { + 1411       if (cryptoTransform_ is ZipAESTransform) { + 0412        AESAuthCode = ((ZipAESTransform)cryptoTransform_).GetAuthCode();413      } + 1414    }415416    /// <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    /// Sets the length of this stream to the given value. Not supported by this class!430    /// Writes bytes from an array to the compressed stream.  431    /// </summary>432    /// <param name="value">The new stream length.</param>433    /// <exception cref="NotSupportedException">Any access</exception>434    public override void SetLength(long value)435    { - 0436      throw new NotSupportedException("DeflaterOutputStream SetLength not supported");437    }438439    /// <summary>440    /// Read a byte from stream advancing position by one441    /// </summary>442    /// <returns>The byte read cast to an int.  THe value is -1 if at the end of the stream.</returns>443    /// <exception cref="NotSupportedException">Any access</exception>444    public override int ReadByte()445    { - 0446      throw new NotSupportedException("DeflaterOutputStream ReadByte not supported");447    }448432    /// <param name="buffer">433    /// The byte array434    /// </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    #endregion447448    #region Instance Fields  449    /// <summary>450    /// Read a block of bytes from stream451    /// </summary>452    /// <param name="buffer">The buffer to store read data in.</param>453    /// <param name="offset">The offset to start storing at.</param>454    /// <param name="count">The maximum number of bytes to read.</param>455    /// <returns>The actual number of bytes read.  Zero if end of stream is detected.</returns>456    /// <exception cref="NotSupportedException">Any access</exception>457    public override int Read(byte[] buffer, int offset, int count)458    { - 0459      throw new NotSupportedException("DeflaterOutputStream Read not supported");460    }461462    /// <summary>463    /// Asynchronous reads are not supported a NotSupportedException is always thrown464    /// </summary>465    /// <param name="buffer">The buffer to read into.</param>466    /// <param name="offset">The offset to start storing data at.</param>467    /// <param name="count">The number of bytes to read</param>468    /// <param name="callback">The async callback to use.</param>469    /// <param name="state">The state to use.</param>470    /// <returns>Returns an <see cref="IAsyncResult"/></returns>471    /// <exception cref="NotSupportedException">Any access</exception>472    public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)473    { - 0474      throw new NotSupportedException("DeflaterOutputStream BeginRead not currently supported");475    }476477    /// <summary>478    /// Asynchronous writes arent supported, a NotSupportedException is always thrown479    /// </summary>480    /// <param name="buffer">The buffer to write.</param>481    /// <param name="offset">The offset to begin writing at.</param>482    /// <param name="count">The number of bytes to write.</param>483    /// <param name="callback">The <see cref="AsyncCallback"/> to use.</param>484    /// <param name="state">The state object.</param>485    /// <returns>Returns an IAsyncResult.</returns>486    /// <exception cref="NotSupportedException">Any access</exception>487    public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)488    { - 0489      throw new NotSupportedException("BeginWrite is not supported");490    }491492    /// <summary>493    /// Flushes the stream by calling <see cref="DeflaterOutputStream.Flush">Flush</see> on the deflater and then494    /// on the underlying stream.  This ensures that all bytes are flushed.495    /// </summary>496    public override void Flush()497    { - 32498      deflater_.Flush(); - 32499      Deflate(); - 32500      baseOutputStream_.Flush(); - 32501    }502503    /// <summary>504    /// Calls <see cref="Finish"/> and closes the underlying505    /// stream when <see cref="IsStreamOwner"></see> is true.506    /// </summary>507    public override void Close()508    { - 273509       if ( !isClosed_ ) { - 264510        isClosed_ = true;511512        try { - 264513          Finish();514#if NETCF_1_0515          keys=null;516#else - 263517           if ( cryptoTransform_ != null ) { - 1518            GetAuthCodeIfAES(); - 1519            cryptoTransform_.Dispose(); - 1520            cryptoTransform_ = null;521          }522#endif - 263523        }524        finally { - 264525           if( isStreamOwner_ ) { - 72526            baseOutputStream_.Close();527          } - 264528        }529      } - 272530    }531532    private void GetAuthCodeIfAES() {533#if !NET_1_1 && !NETCF_2_0 - 1534       if (cryptoTransform_ is ZipAESTransform) { - 0535        AESAuthCode = ((ZipAESTransform)cryptoTransform_).GetAuthCode();536      }537#endif - 1538    }539540    /// <summary>541    /// Writes a single byte to the compressed output stream.542    /// </summary>543    /// <param name="value">544    /// The byte value.545    /// </param>546    public override void WriteByte(byte value)547    { - 26548      byte[] b = new byte[1]; - 26549      b[0] = value; - 26550      Write(b, 0, 1); - 24551    }552553    /// <summary>554    /// Writes bytes from an array to the compressed stream.555    /// </summary>556    /// <param name="buffer">557    /// The byte array558    /// </param>559    /// <param name="offset">560    /// The offset into the byte array where to start.561    /// </param>562    /// <param name="count">563    /// The number of bytes to write.564    /// </param>565    public override void Write(byte[] buffer, int offset, int count)566    { - 4485567      deflater_.SetInput(buffer, offset, count); - 4485568      Deflate(); - 4485569    }570    #endregion571572    #region Instance Fields573    /// <summary>574    /// This buffer is used temporarily to retrieve the bytes from the575    /// deflater and write them to the underlying output stream.576    /// </summary>577    byte[] buffer_;578579    /// <summary>580    /// The deflater which is used to deflate the stream.581    /// </summary>582    protected Deflater deflater_;583584    /// <summary>585    /// Base stream the deflater depends on.586    /// </summary>587    protected Stream baseOutputStream_;588589    bool isClosed_;590 - 279591    bool isStreamOwner_ = true;592    #endregion593594    #region Static Fields595596#if !NET_1_1 && !NETCF_2_0597    // Static to help ensure that multiple files within a zip will get different random salt598    private static RNGCryptoServiceProvider _aesRnd;599#endif600    #endregion601  }602}450    /// This buffer is used temporarily to retrieve the bytes from the451    /// deflater and write them to the underlying output stream.452    /// </summary>453    byte[] buffer_;454455    /// <summary>456    /// The deflater which is used to deflate the stream.457    /// </summary>458    protected Deflater deflater_;459460    /// <summary>461    /// Base stream the deflater depends on.462    /// </summary>463    protected Stream baseOutputStream_;464465    bool isClosed_;466 + 273467    bool isStreamOwner_ = true;468    #endregion469470    #region Static Fields471472    // Static to help ensure that multiple files within a zip will get different random salt473    private static RNGCryptoServiceProvider _aesRnd;474    #endregion475  }476} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterPending.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterPending.htm index 3be11609d..2c5833543 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterPending.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_DeflaterPending.htm @@ -18,7 +18,7 @@

Summary

Covered lines:2 Uncovered lines:0 Coverable lines:2 -Total lines:56 +Total lines:17 Line coverage:100% @@ -34,64 +34,25 @@

#LineLine coverage - 1// DeflaterPending.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839namespace ICSharpCode.SharpZipLib.Zip.Compression40{4142  /// <summary>43  /// This class stores the pending output of the Deflater.44  ///45  /// author of the original java version : Jochen Hoenicke46  /// </summary>47  public class DeflaterPending : PendingBuffer48  {49    /// <summary>50    /// Construct instance with default buffer size51    /// </summary> - 27952    public DeflaterPending() : base(DeflaterConstants.PENDING_BUF_SIZE)53    { - 27954    }55  }56}1namespace ICSharpCode.SharpZipLib.Zip.Compression2{3  /// <summary>4  /// This class stores the pending output of the Deflater.5  ///6  /// author of the original java version : Jochen Hoenicke7  /// </summary>8  public class DeflaterPending : PendingBuffer9  {10    /// <summary>11    /// Construct instance with default buffer size12    /// </summary> + 27313    public DeflaterPending() : base(DeflaterConstants.PENDING_BUF_SIZE)14    { + 27315    }16  }17} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_DescriptorData.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_DescriptorData.htm index ad48481d9..46ecdf5be 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_DescriptorData.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_DescriptorData.htm @@ -18,7 +18,7 @@

Summary

Covered lines:6 Uncovered lines:0 Coverable lines:6 -Total lines:623 +Total lines:560 Line coverage:100% @@ -27,631 +27,568 @@

#LineLine coverage - 1// ZipHelperStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.1using System;2using System.IO;3using System.Text;45namespace ICSharpCode.SharpZipLib.Zip6{7  /// <summary>8  /// Holds data pertinent to a data descriptor.9  /// </summary>10  public class DescriptorData11  {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    }1920    /// <summary>21    /// Get / set the uncompressed size of data22    /// </summary>23    public long Size { + 1324      get { return size; } + 2625      set { size = value; }26    }2728    /// <summary>29    /// Get /set the crc value.30    /// </summary>31    public long Crc { + 1332      get { return crc; } + 2633      set { crc = (value & 0xffffffff); }34    }  3536using System;37using System.IO;38using System.Text;3940namespace ICSharpCode.SharpZipLib.Zip41{36    #region Instance Fields37    long size;38    long compressedSize;39    long crc;40    #endregion41  }  4243  /// <summary>44  /// Holds data pertinent to a data descriptor.45  /// </summary>46  public class DescriptorData47  {48    /// <summary>49    /// Get /set the compressed size of data.50    /// </summary>51    public long CompressedSize52    { - 1353      get { return compressedSize; } - 2654      set { compressedSize = value; }55    }5657    /// <summary>58    /// Get / set the uncompressed size of data59    /// </summary>60    public long Size61    { - 1362      get { return size; } - 2663      set { size = value; }64    }6566    /// <summary>67    /// Get /set the crc value.68    /// </summary>69    public long Crc70    { - 1371      get { return crc; } - 2672      set { crc = (value & 0xffffffff); }73    }7475    #region Instance Fields76    long size;77    long compressedSize;78    long crc;79    #endregion80  }8182  class EntryPatchData83  {84    public long SizePatchOffset85    {86      get { return sizePatchOffset_; }87      set { sizePatchOffset_ = value; }88    }8990    public long CrcPatchOffset91    {92      get { return crcPatchOffset_; }93      set { crcPatchOffset_ = value; }43  class EntryPatchData44  {45    public long SizePatchOffset {46      get { return sizePatchOffset_; }47      set { sizePatchOffset_ = value; }48    }4950    public long CrcPatchOffset {51      get { return crcPatchOffset_; }52      set { crcPatchOffset_ = value; }53    }5455    #region Instance Fields56    long sizePatchOffset_;57    long crcPatchOffset_;58    #endregion59  }6061  /// <summary>62  /// This class assists with writing/reading from Zip files.63  /// </summary>64  internal class ZipHelperStream : Stream65  {66    #region Constructors67    /// <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    }7677    /// <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    #endregion8687    /// <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    }  9596    #region Instance Fields97    long sizePatchOffset_;98    long crcPatchOffset_;99    #endregion100  }101102  /// <summary>103  /// This class assists with writing/reading from Zip files.104  /// </summary>105  internal class ZipHelperStream : Stream106  {107    #region Constructors108    /// <summary>109    /// Initialise an instance of this class.110    /// </summary>111    /// <param name="name">The name of the file to open.</param>112    public ZipHelperStream(string name)113    {114      stream_ = new FileStream(name, FileMode.Open, FileAccess.ReadWrite);115      isOwner_ = true;96    #region Base Stream Methods97    public override bool CanRead {98      get { return stream_.CanRead; }99    }100101    public override bool CanSeek {102      get { return stream_.CanSeek; }103    }104105    public override bool CanTimeout {106      get { return stream_.CanTimeout; }107    }108109    public override long Length {110      get { return stream_.Length; }111    }112113    public override long Position {114      get { return stream_.Position; }115      set { stream_.Position = value; }  116    }  117118    /// <summary>119    /// Initialise a new instance of <see cref="ZipHelperStream"/>.120    /// </summary>121    /// <param name="stream">The stream to use.</param>122    public ZipHelperStream(Stream stream)118    public override bool CanWrite {119      get { return stream_.CanWrite; }120    }121122    public override void Flush()  123    {124      stream_ = stream;124      stream_.Flush();  125    }126    #endregion127128    /// <summary>129    /// Get / set a value indicating wether the the underlying stream is owned or not.130    /// </summary>131    /// <remarks>If the stream is owned it is closed when this instance is closed.</remarks>132    public bool IsStreamOwner126127    public override long Seek(long offset, SeekOrigin origin)128    {129      return stream_.Seek(offset, origin);130    }131132    public override void SetLength(long value)  133    {134      get { return isOwner_; }135      set { isOwner_ = value; }136    }137138    #region Base Stream Methods139    public override bool CanRead140    {141      get { return stream_.CanRead; }142    }143144    public override bool CanSeek145    {146      get { return stream_.CanSeek; }147    }148149#if !NET_1_0 && !NET_1_1 && !NETCF_1_0150    public override bool CanTimeout151    {152      get { return stream_.CanTimeout; }153    }154#endif155156    public override long Length157    {158      get { return stream_.Length; }159    }160161    public override long Position162    {163      get { return stream_.Position; }164      set { stream_.Position = value;  }165    }166167    public override bool CanWrite168    {169      get { return stream_.CanWrite; }170    }134      stream_.SetLength(value);135    }136137    public override int Read(byte[] buffer, int offset, int count)138    {139      return stream_.Read(buffer, offset, count);140    }141142    public override void Write(byte[] buffer, int offset, int count)143    {144      stream_.Write(buffer, offset, count);145    }146147    /// <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    #endregion163164    // Write the local file header165    // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage166    void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)167    {168      CompressionMethod method = entry.CompressionMethod;169      bool headerInfoAvailable = true; // How to get this?170      bool patchEntryHeader = false;  171172    public override void Flush()173    {174      stream_.Flush();175    }176177    public override long Seek(long offset, SeekOrigin origin)178    {179      return stream_.Seek(offset, origin);180    }181182    public override void SetLength(long value)183    {184      stream_.SetLength(value);185    }186187    public override int Read(byte[] buffer, int offset, int count)188    {189      return stream_.Read(buffer, offset, count);190    }191192    public override void Write(byte[] buffer, int offset, int count)193    {194      stream_.Write(buffer, offset, count);195    }196197    /// <summary>198    /// Close the stream.199    /// </summary>200    /// <remarks>201    /// The underlying stream is closed only if <see cref="IsStreamOwner"/> is true.202    /// </remarks>203    override public void Close()204    {205      Stream toClose = stream_;206      stream_ = null;207      if (isOwner_ && (toClose != null))208      {209        isOwner_ = false;210        toClose.Close();211      }212    }213    #endregion214215    // Write the local file header216    // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage217    void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)218    {219      CompressionMethod method = entry.CompressionMethod;220      bool headerInfoAvailable = true; // How to get this?221      bool patchEntryHeader = false;222223      WriteLEInt(ZipConstants.LocalHeaderSignature);224225      WriteLEShort(entry.Version);226      WriteLEShort(entry.Flags);227      WriteLEShort((byte)method);228      WriteLEInt((int)entry.DosTime);229230      if (headerInfoAvailable == true) {231        WriteLEInt((int)entry.Crc);232        if ( entry.LocalHeaderRequiresZip64 ) {233          WriteLEInt(-1);234          WriteLEInt(-1);235        }236        else {237          WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.Compressed238          WriteLEInt((int)entry.Size);239        }240      } else {241        if (patchData != null) {242          patchData.CrcPatchOffset = stream_.Position;243        }244        WriteLEInt(0);  // Crc245246        if ( patchData != null ) {247          patchData.SizePatchOffset = stream_.Position;248        }249250        // For local header both sizes appear in Zip64 Extended Information251        if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) {252          WriteLEInt(-1);253          WriteLEInt(-1);254        }255        else {256          WriteLEInt(0);  // Compressed size257          WriteLEInt(0);  // Uncompressed size258        }259      }260261      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);262263      if (name.Length > 0xFFFF) {264        throw new ZipException("Entry name too long.");265      }266267      var ed = new ZipExtraData(entry.ExtraData);268269      if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader)) {270        ed.StartNewEntry();271        if (headerInfoAvailable) {272          ed.AddLeLong(entry.Size);273          ed.AddLeLong(entry.CompressedSize);274        }275        else {276          ed.AddLeLong(-1);277          ed.AddLeLong(-1);278        }279        ed.AddNewEntry(1);172      WriteLEInt(ZipConstants.LocalHeaderSignature);173174      WriteLEShort(entry.Version);175      WriteLEShort(entry.Flags);176      WriteLEShort((byte)method);177      WriteLEInt((int)entry.DosTime);178179      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.Compressed186          WriteLEInt((int)entry.Size);187        }188      } else {189        if (patchData != null) {190          patchData.CrcPatchOffset = stream_.Position;191        }192        WriteLEInt(0);  // Crc193194        if (patchData != null) {195          patchData.SizePatchOffset = stream_.Position;196        }197198        // For local header both sizes appear in Zip64 Extended Information199        if (entry.LocalHeaderRequiresZip64 && patchEntryHeader) {200          WriteLEInt(-1);201          WriteLEInt(-1);202        } else {203          WriteLEInt(0);  // Compressed size204          WriteLEInt(0);  // Uncompressed size205        }206      }207208      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);209210      if (name.Length > 0xFFFF) {211        throw new ZipException("Entry name too long.");212      }213214      var ed = new ZipExtraData(entry.ExtraData);215216      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);226227        if (!ed.Find(1)) {228          throw new ZipException("Internal error cant find extra data");229        }230231        if (patchData != null) {232          patchData.SizePatchOffset = ed.CurrentReadIndex;233        }234      } else {235        ed.Delete(1);236      }237238      byte[] extra = ed.GetEntryData();239240      WriteLEShort(name.Length);241      WriteLEShort(extra.Length);242243      if (name.Length > 0) {244        stream_.Write(name, 0, name.Length);245      }246247      if (entry.LocalHeaderRequiresZip64 && patchEntryHeader) {248        patchData.SizePatchOffset += stream_.Position;249      }250251      if (extra.Length > 0) {252        stream_.Write(extra, 0, extra.Length);253      }254    }255256    /// <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      }270271      long giveUpMarker = Math.Max(pos - maximumVariableData, 0);272273      // 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);  280281        if ( !ed.Find(1) ) {282          throw new ZipException("Internal error cant find extra data");283        }284285        if ( patchData != null ) {286          patchData.SizePatchOffset = ed.CurrentReadIndex;287        }288      }289      else {290        ed.Delete(1);291      }292293      byte[] extra = ed.GetEntryData();294295      WriteLEShort(name.Length);296      WriteLEShort(extra.Length);297298      if ( name.Length > 0 ) {299        stream_.Write(name, 0, name.Length);300      }301302      if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) {303        patchData.SizePatchOffset += stream_.Position;304      }305306      if ( extra.Length > 0 ) {307        stream_.Write(extra, 0, extra.Length);308      }309    }281      return Position;282    }283284    /// <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 by296      WriteLEShort(ZipConstants.VersionZip64);   // Version to extract297      WriteLEInt(0);      // Number of this disk298      WriteLEInt(0);      // number of the disk with the start of the central directory299      WriteLELong(noOfEntries);       // No of entries on this disk300      WriteLELong(noOfEntries);       // Total No of entries in central directory301      WriteLELong(sizeEntries);       // Size of the central directory302      WriteLELong(centralDirOffset);  // offset of start of central directory303                      // zip64 extensible data sector not catered for here (variable size)304305      // Write the Zip64 end of central directory locator306      WriteLEInt(ZipConstants.Zip64CentralDirLocatorSignature);307308      // no of the disk with the start of the zip64 end of central directory309      WriteLEInt(0);  310311    /// <summary>312    /// Locates a block with the desired <paramref name="signature"/>.313    /// </summary>314    /// <param name="signature">The signature to find.</param>315    /// <param name="endLocation">Location, marking the end of block.</param>316    /// <param name="minimumBlockSize">Minimum size of the block.</param>317    /// <param name="maximumVariableData">The maximum variable data.</param>318    /// <returns>Eeturns the offset of the first byte after the signature; -1 if not found</returns>319    public long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)320    {321      long pos = endLocation - minimumBlockSize;322      if ( pos < 0 ) {323        return -1;324      }325326      long giveUpMarker = Math.Max(pos - maximumVariableData, 0);327328      // TODO: This loop could be optimised for speed.329      do {330        if ( pos < giveUpMarker ) {331          return -1;332        }333        Seek(pos--, SeekOrigin.Begin);334      } while ( ReadLEInt() != signature );335336      return Position;337    }338339    /// <summary>340    /// Write Zip64 end of central directory records (File header and locator).341    /// </summary>342    /// <param name="noOfEntries">The number of entries in the central directory.</param>343    /// <param name="sizeEntries">The size of entries in the central directory.</param>344    /// <param name="centralDirOffset">The offset of the dentral directory.</param>345    public void WriteZip64EndOfCentralDirectory(long noOfEntries, long sizeEntries, long centralDirOffset)346    {347      long centralSignatureOffset = stream_.Position;348      WriteLEInt(ZipConstants.Zip64CentralFileHeaderSignature);349      WriteLELong(44);    // Size of this record (total size of remaining fields in header or full size - 12)350      WriteLEShort(ZipConstants.VersionMadeBy);   // Version made by351      WriteLEShort(ZipConstants.VersionZip64);   // Version to extract352      WriteLEInt(0);      // Number of this disk353      WriteLEInt(0);      // number of the disk with the start of the central directory354      WriteLELong(noOfEntries);       // No of entries on this disk355      WriteLELong(noOfEntries);       // Total No of entries in central directory356      WriteLELong(sizeEntries);       // Size of the central directory357      WriteLELong(centralDirOffset);  // offset of start of central directory358      // zip64 extensible data sector not catered for here (variable size)359360      // Write the Zip64 end of central directory locator361      WriteLEInt(ZipConstants.Zip64CentralDirLocatorSignature);362363      // no of the disk with the start of the zip64 end of central directory364      WriteLEInt(0);311      // relative offset of the zip64 end of central directory record312      WriteLELong(centralSignatureOffset);313314      // total number of disks315      WriteLEInt(1);316    }317318    /// <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    {328329      if ((noOfEntries >= 0xffff) ||330        (startOfCentralDirectory >= 0xffffffff) ||331        (sizeEntries >= 0xffffffff)) {332        WriteZip64EndOfCentralDirectory(noOfEntries, sizeEntries, startOfCentralDirectory);333      }334335      WriteLEInt(ZipConstants.EndOfCentralDirectorySignature);336337      // TODO: ZipFile Multi disk handling not done338      WriteLEShort(0);                    // number of this disk339      WriteLEShort(0);                    // no of disk with start of central dir340341342      // Number of entries343      if (noOfEntries >= 0xffff) {344        WriteLEUshort(0xffff);  // Zip64 marker345        WriteLEUshort(0xffff);346      } else {347        WriteLEShort((short)noOfEntries);          // entries in central dir for this disk348        WriteLEShort((short)noOfEntries);          // total entries in central directory349      }350351      // Size of the central directory352      if (sizeEntries >= 0xffffffff) {353        WriteLEUint(0xffffffff);    // Zip64 marker354      } else {355        WriteLEInt((int)sizeEntries);356      }357358359      // offset of start of central directory360      if (startOfCentralDirectory >= 0xffffffff) {361        WriteLEUint(0xffffffff);    // Zip64 marker362      } else {363        WriteLEInt((int)startOfCentralDirectory);364      }  365366      // relative offset of the zip64 end of central directory record367      WriteLELong(centralSignatureOffset);368369      // total number of disks370      WriteLEInt(1);371    }372373    /// <summary>374    /// Write the required records to end the central directory.375    /// </summary>376    /// <param name="noOfEntries">The number of entries in the directory.</param>377    /// <param name="sizeEntries">The size of the entries in the directory.</param>378    /// <param name="startOfCentralDirectory">The start of the central directory.</param>379    /// <param name="comment">The archive comment.  (This can be null).</param>380    public void WriteEndOfCentralDirectory(long noOfEntries, long sizeEntries,381      long startOfCentralDirectory, byte[] comment)382    {383384      if ( (noOfEntries >= 0xffff) ||385        (startOfCentralDirectory >= 0xffffffff) ||386        (sizeEntries >= 0xffffffff) ) {387        WriteZip64EndOfCentralDirectory(noOfEntries, sizeEntries, startOfCentralDirectory);388      }389390      WriteLEInt(ZipConstants.EndOfCentralDirectorySignature);391392      // TODO: ZipFile Multi disk handling not done393      WriteLEShort(0);                    // number of this disk394      WriteLEShort(0);                    // no of disk with start of central dir395396397      // Number of entries398      if ( noOfEntries >= 0xffff ) {399        WriteLEUshort(0xffff);  // Zip64 marker400        WriteLEUshort(0xffff);366      int commentLength = (comment != null) ? comment.Length : 0;367368      if (commentLength > 0xffff) {369        throw new ZipException(string.Format("Comment length({0}) is too long can only be 64K", commentLength));370      }371372      WriteLEShort(commentLength);373374      if (commentLength > 0) {375        Write(comment, 0, comment.Length);376      }377    }378379    #region LE value reading/writing380    /// <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 prematurely389    /// </exception>390    public int ReadLEShort()391    {392      int byteValue1 = stream_.ReadByte();393394      if (byteValue1 < 0) {395        throw new EndOfStreamException();396      }397398      int byteValue2 = stream_.ReadByte();399      if (byteValue2 < 0) {400        throw new EndOfStreamException();  401      }402      else {403        WriteLEShort(( short )noOfEntries);          // entries in central dir for this disk404        WriteLEShort(( short )noOfEntries);          // total entries in central directory405      }406407      // Size of the central directory408      if ( sizeEntries >= 0xffffffff ) {409        WriteLEUint(0xffffffff);    // Zip64 marker410      }411      else {412        WriteLEInt(( int )sizeEntries);413      }414415416      // offset of start of central directory417      if ( startOfCentralDirectory >= 0xffffffff ) {418        WriteLEUint(0xffffffff);    // Zip64 marker419      }420      else {421        WriteLEInt(( int )startOfCentralDirectory);422      }423424      int commentLength = (comment != null) ? comment.Length : 0;425426      if ( commentLength > 0xffff ) {427        throw new ZipException(string.Format("Comment length({0}) is too long can only be 64K", commentLength));428      }402403      return byteValue1 | (byteValue2 << 8);404    }405406    /// <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 prematurely415    /// </exception>416    public int ReadLEInt()417    {418      return ReadLEShort() | (ReadLEShort() << 16);419    }420421    /// <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    }  429430      WriteLEShort(commentLength);431432      if ( commentLength > 0 ) {433        Write(comment, 0, comment.Length);434      }435    }436437    #region LE value reading/writing438    /// <summary>439    /// Read an unsigned short in little endian byte order.440    /// </summary>441    /// <returns>Returns the value read.</returns>442    /// <exception cref="IOException">443    /// An i/o error occurs.444    /// </exception>445    /// <exception cref="EndOfStreamException">446    /// The file ends prematurely447    /// </exception>448    public int ReadLEShort()449    {450      int byteValue1 = stream_.ReadByte();451452      if (byteValue1 < 0) {453        throw new EndOfStreamException();454      }455456      int byteValue2 = stream_.ReadByte();457      if (byteValue2 < 0) {458        throw new EndOfStreamException();459      }460461      return byteValue1 | (byteValue2 << 8);462    }463464    /// <summary>465    /// Read an int in little endian byte order.466    /// </summary>467    /// <returns>Returns the value read.</returns>468    /// <exception cref="IOException">469    /// An i/o error occurs.470    /// </exception>471    /// <exception cref="System.IO.EndOfStreamException">472    /// The file ends prematurely473    /// </exception>474    public int ReadLEInt()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    }439440    /// <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    }449450    /// <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    }459460    /// <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    }469470    /// <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      return ReadLEShort() | (ReadLEShort() << 16);477    }478479    /// <summary>480    /// Read a long in little endian byte order.481    /// </summary>482    /// <returns>The value read.</returns>483    public long ReadLELong()484    {485      return (uint)ReadLEInt() | ((long)ReadLEInt() << 32);486    }487488    /// <summary>489    /// Write an unsigned short in little endian byte order.490    /// </summary>491    /// <param name="value">The value to write.</param>492    public void WriteLEShort(int value)493    {494      stream_.WriteByte(( byte )(value & 0xff));495      stream_.WriteByte(( byte )((value >> 8) & 0xff));496    }497498    /// <summary>499    /// Write a ushort in little endian byte order.500    /// </summary>501    /// <param name="value">The value to write.</param>502    public void WriteLEUshort(ushort value)503    {504      stream_.WriteByte(( byte )(value & 0xff));505      stream_.WriteByte(( byte )(value >> 8));506    }507508    /// <summary>509    /// Write an int in little endian byte order.510    /// </summary>511    /// <param name="value">The value to write.</param>512    public void WriteLEInt(int value)513    {514      WriteLEShort(value);515      WriteLEShort(value >> 16);516    }517518    /// <summary>519    /// Write a uint in little endian byte order.520    /// </summary>521    /// <param name="value">The value to write.</param>522    public void WriteLEUint(uint value)523    {524      WriteLEUshort(( ushort )(value & 0xffff));525      WriteLEUshort(( ushort )(value >> 16));476      WriteLEInt((int)value);477      WriteLEInt((int)(value >> 32));478    }479480    /// <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    }489490    #endregion491492    /// <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      }502503      int result = 0;504505      // Add data descriptor if flagged as required506      if ((entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {507        // The signature is not PKZIP originally but is now described as optional508        // in the PKZIP Appnote documenting trhe format.509        WriteLEInt(ZipConstants.DataDescriptorSignature);510        WriteLEInt(unchecked((int)(entry.Crc)));511512        result += 8;513514        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      }524525      return result;  526    }  527  528    /// <summary>529    /// Write a long in little endian byte order.529    /// Read data descriptor at the end of compressed data.  530    /// </summary>531    /// <param name="value">The value to write.</param>532    public void WriteLELong(long value)533    {534      WriteLEInt(( int )value);535      WriteLEInt(( int )(value >> 32));536    }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();  537538    /// <summary>539    /// Write a ulong in little endian byte order.540    /// </summary>541    /// <param name="value">The value to write.</param>542    public void WriteLEUlong(ulong value)543    {544      WriteLEUint(( uint )(value & 0xffffffff));545      WriteLEUint(( uint )(value >> 32));546    }547548    #endregion549550    /// <summary>551    /// Write a data descriptor.552    /// </summary>553    /// <param name="entry">The entry to write a descriptor for.</param>554    /// <returns>Returns the number of descriptor bytes written.</returns>555    public int WriteDataDescriptor(ZipEntry entry)556    {557      if (entry == null) {558        throw new ArgumentNullException(nameof(entry));559      }560561      int result=0;562563      // Add data descriptor if flagged as required564      if ((entry.Flags & (int)GeneralBitFlags.Descriptor) != 0)565      {566        // The signature is not PKZIP originally but is now described as optional567        // in the PKZIP Appnote documenting trhe format.568        WriteLEInt(ZipConstants.DataDescriptorSignature);569        WriteLEInt(unchecked((int)(entry.Crc)));570571        result+=8;572573        if (entry.LocalHeaderRequiresZip64)574        {575          WriteLELong(entry.CompressedSize);576          WriteLELong(entry.Size);577          result+=16;578        }579        else580        {581          WriteLEInt((int)entry.CompressedSize);582          WriteLEInt((int)entry.Size);583          result+=8;584        }585      }586587      return result;588    }589590    /// <summary>591    /// Read data descriptor at the end of compressed data.592    /// </summary>593    /// <param name="zip64">if set to <c>true</c> [zip64].</param>594    /// <param name="data">The data to fill in.</param>595    /// <returns>Returns the number of bytes read in the descriptor.</returns>596    public void ReadDataDescriptor(bool zip64, DescriptorData data)597    {598      int intValue = ReadLEInt();599600      // In theory this may not be a descriptor according to PKZIP appnote.601      // In practise its always there.602      if (intValue != ZipConstants.DataDescriptorSignature) {603        throw new ZipException("Data descriptor signature not found");604      }605606      data.Crc = ReadLEInt();607608      if (zip64) {609        data.CompressedSize = ReadLELong();610        data.Size = ReadLELong();611      }612      else {613        data.CompressedSize = ReadLEInt();614        data.Size = ReadLEInt();615      }616    }617618    #region Instance Fields619    bool isOwner_;620    Stream stream_;621    #endregion622  }623}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      }543544      data.Crc = ReadLEInt();545546      if (zip64) {547        data.CompressedSize = ReadLELong();548        data.Size = ReadLELong();549      } else {550        data.CompressedSize = ReadLEInt();551        data.Size = ReadLEInt();552      }553    }554555    #region Instance Fields556    bool isOwner_;557    Stream stream_;558    #endregion559  }560} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_DirectoryEventArgs.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_DirectoryEventArgs.htm index 39c433925..e90b09ae2 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_DirectoryEventArgs.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_DirectoryEventArgs.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:4 Coverable lines:4 -Total lines:530 +Total lines:475 Line coverage:0% @@ -34,538 +34,483 @@

#LineLine coverage - 1// FileSystemScanner.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.351using System;23namespace ICSharpCode.SharpZipLib.Core4{5  #region EventArgs6  /// <summary>7  /// Event arguments for scanning.8  /// </summary>9  public class ScanEventArgs : EventArgs10  {11    #region Constructors12    /// <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    #endregion2122    /// <summary>23    /// The file or directory name for this event.24    /// </summary>25    public string Name {26      get { return name_; }27    }2829    /// <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    }  3637using System;3839namespace ICSharpCode.SharpZipLib.Core40{41  #region EventArgs42  /// <summary>43  /// Event arguments for scanning.44  /// </summary>45  public class ScanEventArgs : EventArgs46  {47    #region Constructors48    /// <summary>49    /// Initialise a new instance of <see cref="ScanEventArgs"/>50    /// </summary>51    /// <param name="name">The file or directory name.</param>52    public ScanEventArgs(string name)53    {54      name_ = name;55    }56    #endregion5758    /// <summary>59    /// The file or directory name for this event.60    /// </summary>61    public string Name62    {63      get { return name_; }64    }6566    /// <summary>67    /// Get set a value indicating if scanning should continue or not.68    /// </summary>69    public bool ContinueRunning70    {71      get { return continueRunning_; }72      set { continueRunning_ = value; }73    }7475    #region Instance Fields76    string name_;77    bool continueRunning_ = true;78    #endregion79  }8081  /// <summary>82  /// Event arguments during processing of a single file or directory.83  /// </summary>84  public class ProgressEventArgs : EventArgs85  {86    #region Constructors87    /// <summary>88    /// Initialise a new instance of <see cref="ScanEventArgs"/>89    /// </summary>90    /// <param name="name">The file or directory name if known.</param>91    /// <param name="processed">The number of bytes processed so far</param>92    /// <param name="target">The total number of bytes to process, 0 if not known</param>93    public ProgressEventArgs(string name, long processed, long target)94    {95      name_ = name;96      processed_ = processed;97      target_ = target;98    }99    #endregion37    #region Instance Fields38    string name_;39    bool continueRunning_ = true;40    #endregion41  }4243  /// <summary>44  /// Event arguments during processing of a single file or directory.45  /// </summary>46  public class ProgressEventArgs : EventArgs47  {48    #region Constructors49    /// <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    #endregion6263    /// <summary>64    /// The name for this event if known.65    /// </summary>66    public string Name {67      get { return name_; }68    }6970    /// <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    }7778    /// <summary>79    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed80    /// </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    }9394    /// <summary>95    /// The number of bytes processed so far96    /// </summary>97    public long Processed {98      get { return processed_; }99    }  100  101    /// <summary>102    /// The name for this event if known.102    /// The number of bytes to process.  103    /// </summary>104    public string Name105    {106      get { return name_; }104    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>105    public long Target {106      get { return target_; }  107    }  108109    /// <summary>110    /// Get set a value indicating wether scanning should continue or not.111    /// </summary>112    public bool ContinueRunning113    {114      get { return continueRunning_; }115      set { continueRunning_ = value; }116    }117118    /// <summary>119    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed120    /// </summary>121    /// <value>0.0 to 100.0 percent; 0 if target is not known.</value>122    public float PercentComplete123    {124      get125      {126          float result;127        if (target_ <= 0)128        {129          result = 0;130        }131        else132        {133          result = ((float)processed_ / (float)target_) * 100.0f;134        }135          return result;136      }137    }138139    /// <summary>140    /// The number of bytes processed so far141    /// </summary>142    public long Processed143    {144      get { return processed_; }145    }146147    /// <summary>148    /// The number of bytes to process.149    /// </summary>150    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>151    public long Target152    {153      get { return target_; }154    }155156    #region Instance Fields157    string name_;158    long processed_;159    long target_;160    bool continueRunning_ = true;161    #endregion162  }163164  /// <summary>165  /// Event arguments for directories.166  /// </summary>167  public class DirectoryEventArgs : ScanEventArgs168  {169    #region Constructors170    /// <summary>171    /// Initialize an instance of <see cref="DirectoryEventArgs"></see>.172    /// </summary>173    /// <param name="name">The name for this directory.</param>174    /// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</par175    public DirectoryEventArgs(string name, bool hasMatchingFiles) - 0176      : base (name)177    { - 0178      hasMatchingFiles_ = hasMatchingFiles; - 0179    }180    #endregion109    #region Instance Fields110    string name_;111    long processed_;112    long target_;113    bool continueRunning_ = true;114    #endregion115  }116117  /// <summary>118  /// Event arguments for directories.119  /// </summary>120  public class DirectoryEventArgs : ScanEventArgs121  {122    #region Constructors123    /// <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.</par128    public DirectoryEventArgs(string name, bool hasMatchingFiles) + 0129      : base(name)130    { + 0131      hasMatchingFiles_ = hasMatchingFiles; + 0132    }133    #endregion134135    /// <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    }141142    readonly143144    #region Instance Fields145    bool hasMatchingFiles_;146    #endregion147  }148149  /// <summary>150  /// Arguments passed when scan failures are detected.151  /// </summary>152  public class ScanFailureEventArgs : EventArgs153  {154    #region Constructors155    /// <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    #endregion167168    /// <summary>169    /// The applicable name.170    /// </summary>171    public string Name {172      get { return name_; }173    }174175    /// <summary>176    /// The applicable exception.177    /// </summary>178    public Exception Exception {179      get { return exception_; }180    }  181  182    /// <summary>183    /// Get a value indicating if the directory contains any matching files or not.183    /// Get / set a value indicating wether scanning should continue.  184    /// </summary>185    public bool HasMatchingFiles186    { - 0187      get { return hasMatchingFiles_; }185    public bool ContinueRunning {186      get { return continueRunning_; }187      set { continueRunning_ = value; }  188    }  189190    readonly191192    #region Instance Fields193    bool hasMatchingFiles_;190    #region Instance Fields191    string name_;192    Exception exception_;193    bool continueRunning_;  194    #endregion  195  }  196197  /// <summary>198  /// Arguments passed when scan failures are detected.199  /// </summary>200  public class ScanFailureEventArgs : EventArgs201  {202    #region Constructors203    /// <summary>204    /// Initialise a new instance of <see cref="ScanFailureEventArgs"></see>205    /// </summary>206    /// <param name="name">The name to apply.</param>207    /// <param name="e">The exception to use.</param>208    public ScanFailureEventArgs(string name, Exception e)209    {210      name_ = name;211      exception_ = e;212      continueRunning_ = true;213    }214    #endregion215216    /// <summary>217    /// The applicable name.218    /// </summary>219    public string Name220    {221      get { return name_; }222    }223224    /// <summary>225    /// The applicable exception.226    /// </summary>227    public Exception Exception228    {229      get { return exception_; }230    }231232    /// <summary>233    /// Get / set a value indicating wether scanning should continue.234    /// </summary>235    public bool ContinueRunning236    {237      get { return continueRunning_; }238      set { continueRunning_ = value; }239    }240241    #region Instance Fields242    string name_;243    Exception exception_;244    bool continueRunning_;245    #endregion246  }247248  #endregion249250  #region Delegates251  /// <summary>252  /// Delegate invoked before starting to process a file.253  /// </summary>254  /// <param name="sender">The source of the event</param>255  /// <param name="e">The event arguments.</param>256  public delegate void ProcessFileHandler(object sender, ScanEventArgs e);257258  /// <summary>259  /// Delegate invoked during processing of a file or directory260  /// </summary>261  /// <param name="sender">The source of the event</param>262  /// <param name="e">The event arguments.</param>263  public delegate void ProgressHandler(object sender, ProgressEventArgs e);264265  /// <summary>266  /// Delegate invoked when a file has been completely processed.267  /// </summary>268  /// <param name="sender">The source of the event</param>269  /// <param name="e">The event arguments.</param>270  public delegate void CompletedFileHandler(object sender, ScanEventArgs e);271272  /// <summary>273  /// Delegate invoked when a directory failure is detected.274  /// </summary>275  /// <param name="sender">The source of the event</param>276  /// <param name="e">The event arguments.</param>277  public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e);278279  /// <summary>280  /// Delegate invoked when a file failure is detected.281  /// </summary>282  /// <param name="sender">The source of the event</param>283  /// <param name="e">The event arguments.</param>284  public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e);285  #endregion286287  /// <summary>288  /// FileSystemScanner provides facilities scanning of files and directories.289  /// </summary>290  public class FileSystemScanner291  {292    #region Constructors293    /// <summary>294    /// Initialise a new instance of <see cref="FileSystemScanner"></see>295    /// </summary>296    /// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param>297    public FileSystemScanner(string filter)298    {299      fileFilter_ = new PathFilter(filter);300    }301302    /// <summary>303    /// Initialise a new instance of <see cref="FileSystemScanner"></see>304    /// </summary>305    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>306    /// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param>307    public FileSystemScanner(string fileFilter, string directoryFilter)308    {309      fileFilter_ = new PathFilter(fileFilter);310      directoryFilter_ = new PathFilter(directoryFilter);311    }312313    /// <summary>314    /// Initialise a new instance of <see cref="FileSystemScanner"></see>315    /// </summary>316    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param>317    public FileSystemScanner(IScanFilter fileFilter)318    {319      fileFilter_ = fileFilter;320    }321322    /// <summary>323    /// Initialise a new instance of <see cref="FileSystemScanner"></see>324    /// </summary>325    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see>  to apply.</param>326    /// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see>  to apply.</param>327    public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter)328    {329      fileFilter_ = fileFilter;330      directoryFilter_ = directoryFilter;331    }332    #endregion333334    #region Delegates335    /// <summary>336    /// Delegate to invoke when a directory is processed.337    /// </summary>338    public event EventHandler<DirectoryEventArgs> ProcessDirectory;339340    /// <summary>341    /// Delegate to invoke when a file is processed.342    /// </summary>343    public ProcessFileHandler ProcessFile;344345    /// <summary>346    /// Delegate to invoke when processing for a file has finished.347    /// </summary>348    public CompletedFileHandler CompletedFile;349350    /// <summary>351    /// Delegate to invoke when a directory failure is detected.352    /// </summary>353    public DirectoryFailureHandler DirectoryFailure;354355    /// <summary>356    /// Delegate to invoke when a file failure is detected.357    /// </summary>358    public FileFailureHandler FileFailure;359    #endregion197  #endregion198199  #region Delegates200  /// <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);206207  /// <summary>208  /// Delegate invoked during processing of a file or directory209  /// </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);213214  /// <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);220221  /// <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);227228  /// <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  #endregion235236  /// <summary>237  /// FileSystemScanner provides facilities scanning of files and directories.238  /// </summary>239  public class FileSystemScanner240  {241    #region Constructors242    /// <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    }250251    /// <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    }261262    /// <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    }270271    /// <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    #endregion282283    #region Delegates284    /// <summary>285    /// Delegate to invoke when a directory is processed.286    /// </summary>287    public event EventHandler<DirectoryEventArgs> ProcessDirectory;288289    /// <summary>290    /// Delegate to invoke when a file is processed.291    /// </summary>292    public ProcessFileHandler ProcessFile;293294    /// <summary>295    /// Delegate to invoke when processing for a file has finished.296    /// </summary>297    public CompletedFileHandler CompletedFile;298299    /// <summary>300    /// Delegate to invoke when a directory failure is detected.301    /// </summary>302    public DirectoryFailureHandler DirectoryFailure;303304    /// <summary>305    /// Delegate to invoke when a file failure is detected.306    /// </summary>307    public FileFailureHandler FileFailure;308    #endregion309310    /// <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    }326327    /// <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;335336      bool result = (handler != null);337338      if (result) {339        var args = new ScanFailureEventArgs(file, e);340        FileFailure(this, args);341        alive_ = args.ContinueRunning;342      }343      return result;344    }345346    /// <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;353354      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 DirectoryFailure event.362    /// Raise the complete file event  363    /// </summary>364    /// <param name="directory">The directory name.</param>365    /// <param name="e">The exception detected.</param>366    bool OnDirectoryFailure(string directory, Exception e)367    {368            DirectoryFailureHandler handler = DirectoryFailure;369            bool result = (handler != null);370            if ( result ) {371        var args = new ScanFailureEventArgs(directory, e);372        handler(this, args);373        alive_ = args.ContinueRunning;374      }375            return result;376    }377378    /// <summary>379    /// Raise the FileFailure event.380    /// </summary>381    /// <param name="file">The file name.</param>382    /// <param name="e">The exception detected.</param>383    bool OnFileFailure(string file, Exception e)384    {385            FileFailureHandler handler = FileFailure;386387            bool result = (handler != null);388389      if ( result ){390        var args = new ScanFailureEventArgs(file, e);391        FileFailure(this, args);392        alive_ = args.ContinueRunning;393      }394            return result;395    }396397    /// <summary>398    /// Raise the ProcessFile event.399    /// </summary>400    /// <param name="file">The file name.</param>401    void OnProcessFile(string file)402    {403      ProcessFileHandler handler = ProcessFile;404405      if ( handler!= null ) {406        var args = new ScanEventArgs(file);407        handler(this, args);408        alive_ = args.ContinueRunning;409      }410    }411412    /// <summary>413    /// Raise the complete file event414    /// </summary>415    /// <param name="file">The file name</param>416    void OnCompleteFile(string file)417    {418      CompletedFileHandler handler = CompletedFile;419420      if (handler != null)421      {422        var args = new ScanEventArgs(file);423        handler(this, args);424        alive_ = args.ContinueRunning;425      }426    }427428    /// <summary>429    /// Raise the ProcessDirectory event.430    /// </summary>431    /// <param name="directory">The directory name.</param>432    /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param>433    void OnProcessDirectory(string directory, bool hasMatchingFiles)434    {435      EventHandler<DirectoryEventArgs> handler = ProcessDirectory;436437      if ( handler != null ) {438        var args = new DirectoryEventArgs(directory, hasMatchingFiles);439        handler(this, args);440        alive_ = args.ContinueRunning;441      }442    }443444    /// <summary>445    /// Scan a directory.446    /// </summary>447    /// <param name="directory">The base directory to scan.</param>448    /// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param>449    public void Scan(string directory, bool recurse)450    {451      alive_ = true;452      ScanDir(directory, recurse);453    }454455    void ScanDir(string directory, bool recurse)456    {457458      try {459        string[] names = System.IO.Directory.GetFiles(directory);460        bool hasMatch = false;461        for (int fileIndex = 0; fileIndex < names.Length; ++fileIndex) {462          if ( !fileFilter_.IsMatch(names[fileIndex]) ) {463            names[fileIndex] = null;464          } else {465            hasMatch = true;466          }467        }468469        OnProcessDirectory(directory, hasMatch);470471        if ( alive_ && hasMatch ) {472          foreach (string fileName in names) {473            try {474              if ( fileName != null ) {475                OnProcessFile(fileName);476                if ( !alive_ ) {477                  break;478                }479              }480            }481            catch (Exception e) {482                            if (!OnFileFailure(fileName, e)) {483                                throw;484                            }485            }486          }487        }488      }489      catch (Exception e) {490                if (!OnDirectoryFailure(directory, e)) {491                    throw;492                }493      }494495      if ( alive_ && recurse ) {496        try {497          string[] names = System.IO.Directory.GetDirectories(directory);498          foreach (string fulldir in names) {499            if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir))) {500              ScanDir(fulldir, true);501              if ( !alive_ ) {502                break;503              }504            }505          }506        }507        catch (Exception e) {508                    if (!OnDirectoryFailure(directory, e)) {509                        throw;510                    }511        }512      }513    }514515    #region Instance Fields516    /// <summary>517    /// The file filter currently in use.518    /// </summary>519    IScanFilter fileFilter_;520    /// <summary>521    /// The directory filter currently in use.522    /// </summary>523    IScanFilter directoryFilter_;524    /// <summary>525    /// Flag indicating if scanning should continue running.526    /// </summary>527    bool alive_;528    #endregion529  }530}364    /// <param name="file">The file name</param>365    void OnCompleteFile(string file)366    {367      CompletedFileHandler handler = CompletedFile;368369      if (handler != null) {370        var args = new ScanEventArgs(file);371        handler(this, args);372        alive_ = args.ContinueRunning;373      }374    }375376    /// <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;384385      if (handler != null) {386        var args = new DirectoryEventArgs(directory, hasMatchingFiles);387        handler(this, args);388        alive_ = args.ContinueRunning;389      }390    }391392    /// <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    }402403    void ScanDir(string directory, bool recurse)404    {405406      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        }416417        OnProcessDirectory(directory, hasMatch);418419        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      }440441      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    }459460    #region Instance Fields461    /// <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    #endregion474  }475} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_DirectoryFailureHandler.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_DirectoryFailureHandler.htm index 70add9e30..1e6026acd 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_DirectoryFailureHandler.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_DirectoryFailureHandler.htm @@ -24,6 +24,6 @@

Summary

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/Documentation/opencover/ICSharpCode.SharpZipLib_DiskArchiveStorage.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_DiskArchiveStorage.htm index 41bb2f47b..85960e1f1 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_DiskArchiveStorage.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_DiskArchiveStorage.htm @@ -16,10 +16,10 @@

Summary

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:17 -Coverable lines:72 -Total lines:4476 -Line coverage:76.3% +Uncovered lines:15 +Coverable lines:70 +Total lines:4263 +Line coverage:78.5% Branch coverage:62.5% @@ -42,4484 +42,4271 @@

#LineLine coverage - 1// ZipFile.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  2009-12-22  Z-1649  Added AES support41//  2010-03-02  Z-1650  Fixed updating ODT archives in memory. Exposed exceptions in updating.42//  2010-05-25  Z-1663  Fixed exception when testing local header compressed size of -143//  2012-11-29  Z-1684  Fixed ZipFile.Add(string fileName, string entryName) losing the file TimeStamp4445using System;46using System.Collections;47using System.IO;48using System.Text;49using System.Globalization;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;1213namespace ICSharpCode.SharpZipLib.Zip14{15  #region Keys Required Event Args16  /// <summary>17  /// Arguments used with KeysRequiredEvent18  /// </summary>19  public class KeysRequiredEventArgs : EventArgs20  {21    #region Constructors22    /// <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    }3031    /// <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    }4142    #endregion43    #region Properties44    /// <summary>45    /// Gets the name of the file for which keys are required.46    /// </summary>47    public string FileName {48      get { return fileName; }49    }  5051#if !NETCF_1_052using System.Security.Cryptography;53using ICSharpCode.SharpZipLib.Encryption;54#endif5556using ICSharpCode.SharpZipLib.Core;57using ICSharpCode.SharpZipLib.Checksums;58using ICSharpCode.SharpZipLib.Zip.Compression.Streams;59using ICSharpCode.SharpZipLib.Zip.Compression;6061namespace ICSharpCode.SharpZipLib.Zip62{63  #region Keys Required Event Args64  /// <summary>65  /// Arguments used with KeysRequiredEvent66  /// </summary>67  public class KeysRequiredEventArgs : EventArgs68  {69    #region Constructors70    /// <summary>71    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>72    /// </summary>73    /// <param name="name">The name of the file for which keys are required.</param>74    public KeysRequiredEventArgs(string name)75    {76      fileName = name;77    }7879    /// <summary>80    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>81    /// </summary>82    /// <param name="name">The name of the file for which keys are required.</param>83    /// <param name="keyValue">The current key value.</param>84    public KeysRequiredEventArgs(string name, byte[] keyValue)85    {86      fileName = name;87      key = keyValue;88    }8990    #endregion91    #region Properties92    /// <summary>93    /// Gets the name of the file for which keys are required.94    /// </summary>95    public string FileName96    {97      get { return fileName; }98    }99100    /// <summary>101    /// Gets or sets the key value102    /// </summary>103    public byte[] Key104    {105      get { return key; }106      set { key = value; }107    }108    #endregion109110    #region Instance Fields111    string fileName;112    byte[] key;113    #endregion114  }115  #endregion116117  #region Test Definitions118  /// <summary>119  /// The strategy to apply to testing.120  /// </summary>121  public enum TestStrategy122  {123    /// <summary>124    /// Find the first error only.125    /// </summary>126    FindFirstError,51    /// <summary>52    /// Gets or sets the key value53    /// </summary>54    public byte[] Key {55      get { return key; }56      set { key = value; }57    }58    #endregion5960    #region Instance Fields61    string fileName;62    byte[] key;63    #endregion64  }65  #endregion6667  #region Test Definitions68  /// <summary>69  /// The strategy to apply to testing.70  /// </summary>71  public enum TestStrategy72  {73    /// <summary>74    /// Find the first error only.75    /// </summary>76    FindFirstError,77    /// <summary>78    /// Find all possible errors.79    /// </summary>80    FindAllErrors,81  }8283  /// <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 TestOperation88  {89    /// <summary>90    /// Setting up testing.91    /// </summary>92    Initialising,9394    /// <summary>95    /// Testing an individual entries header96    /// </summary>97    EntryHeader,9899    /// <summary>100    /// Testing an individual entries data101    /// </summary>102    EntryData,103104    /// <summary>105    /// Testing an individual entry has completed.106    /// </summary>107    EntryComplete,108109    /// <summary>110    /// Running miscellaneous tests111    /// </summary>112    MiscellaneousTests,113114    /// <summary>115    /// Testing is complete116    /// </summary>117    Complete,118  }119120  /// <summary>121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.122  /// </summary>123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>124  public class TestStatus125  {126    #region Constructors  127    /// <summary>128    /// Find all possible errors.128    /// Initialise a new instance of <see cref="TestStatus"/>  129    /// </summary>130    FindAllErrors,131  }132133  /// <summary>134  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.135  /// </summary>136  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>137  public enum TestOperation138  {130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>131    public TestStatus(ZipFile file)132    {133      file_ = file;134    }135    #endregion136137    #region Properties138  139    /// <summary>140    /// Setting up testing.140    /// Get the current <see cref="TestOperation"/> in progress.  141    /// </summary>142    Initialising,143144    /// <summary>145    /// Testing an individual entries header146    /// </summary>147    EntryHeader,148149    /// <summary>150    /// Testing an individual entries data151    /// </summary>152    EntryData,153154    /// <summary>155    /// Testing an individual entry has completed.156    /// </summary>157    EntryComplete,158159    /// <summary>160    /// Running miscellaneous tests161    /// </summary>162    MiscellaneousTests,163164    /// <summary>165    /// Testing is complete166    /// </summary>167    Complete,168  }169170  /// <summary>171  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.172  /// </summary>173  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>174  public class TestStatus175  {176    #region Constructors177    /// <summary>178    /// Initialise a new instance of <see cref="TestStatus"/>179    /// </summary>180    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>181    public TestStatus(ZipFile file)182    {183      file_ = file;184    }185    #endregion186187    #region Properties142    public TestOperation Operation {143      get { return operation_; }144    }145146    /// <summary>147    /// Get the <see cref="ZipFile"/> this status is applicable to.148    /// </summary>149    public ZipFile File {150      get { return file_; }151    }152153    /// <summary>154    /// Get the current/last entry tested.155    /// </summary>156    public ZipEntry Entry {157      get { return entry_; }158    }159160    /// <summary>161    /// Get the number of errors detected so far.162    /// </summary>163    public int ErrorCount {164      get { return errorCount_; }165    }166167    /// <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    }173174    /// <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    #endregion181182    #region Internal API183    internal void AddError()184    {185      errorCount_++;186      entryValid_ = false;187    }  188189    /// <summary>190    /// Get the current <see cref="TestOperation"/> in progress.191    /// </summary>192    public TestOperation Operation193    {194      get { return operation_; }195    }196197    /// <summary>198    /// Get the <see cref="ZipFile"/> this status is applicable to.199    /// </summary>200    public ZipFile File201    {202      get { return file_; }203    }204205    /// <summary>206    /// Get the current/last entry tested.207    /// </summary>208    public ZipEntry Entry209    {210      get { return entry_; }211    }212213    /// <summary>214    /// Get the number of errors detected so far.215    /// </summary>216    public int ErrorCount217    {218      get { return errorCount_; }219    }220221    /// <summary>222    /// Get the number of bytes tested so far for the current entry.223    /// </summary>224    public long BytesTested225    {226      get { return bytesTested_; }227    }228229    /// <summary>230    /// Get a value indicating wether the last entry test was valid.231    /// </summary>232    public bool EntryValid233    {234      get { return entryValid_; }235    }236    #endregion237238    #region Internal API239    internal void AddError()240    {241      errorCount_++;242      entryValid_ = false;243    }244245    internal void SetOperation(TestOperation operation)246    {247      operation_ = operation;248    }249250    internal void SetEntry(ZipEntry entry)251    {252      entry_ = entry;253      entryValid_ = true;254      bytesTested_ = 0;255    }256257    internal void SetBytesTested(long value)258    {259      bytesTested_ = value;260    }261    #endregion262263    #region Instance Fields264    ZipFile file_;265    ZipEntry entry_;266    bool entryValid_;267    int errorCount_;268    long bytesTested_;269    TestOperation operation_;270    #endregion271  }272273  /// <summary>274  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if275  /// </summary>276  /// <remarks>If the message is non-null an error has occured.  If the message is null277  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>278  public delegate void ZipTestResultHandler(TestStatus status, string message);279  #endregion280281  #region Update Definitions282  /// <summary>283  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.284  /// </summary>285  public enum FileUpdateMode286  {287    /// <summary>288    /// Perform all updates on temporary files ensuring that the original file is saved.289    /// </summary>290    Safe,291    /// <summary>292    /// Update the archive directly, which is faster but less safe.293    /// </summary>294    Direct,295  }296  #endregion189    internal void SetOperation(TestOperation operation)190    {191      operation_ = operation;192    }193194    internal void SetEntry(ZipEntry entry)195    {196      entry_ = entry;197      entryValid_ = true;198      bytesTested_ = 0;199    }200201    internal void SetBytesTested(long value)202    {203      bytesTested_ = value;204    }205    #endregion206207    #region Instance Fields208    ZipFile file_;209    ZipEntry entry_;210    bool entryValid_;211    int errorCount_;212    long bytesTested_;213    TestOperation operation_;214    #endregion215  }216217  /// <summary>218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if219  /// </summary>220  /// <remarks>If the message is non-null an error has occured.  If the message is null221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>222  public delegate void ZipTestResultHandler(TestStatus status, string message);223  #endregion224225  #region Update Definitions226  /// <summary>227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.228  /// </summary>229  public enum FileUpdateMode230  {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  #endregion241242  #region ZipFile Class243  /// <summary>244  /// This class represents a Zip archive.  You can ask for the contained245  /// entries, or get an input stream for a file entry.  The entry is246  /// 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 arbitrary251  /// entries in different threads.252  /// <br/>253  /// <br/>Author of the original java version : Jochen Hoenicke254  /// </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 MainClass265  /// {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, IDisposable287  {288    #region KeyHandling289290    /// <summary>291    /// Delegate for handling keys/password setting during compresion/decompression.292    /// </summary>293    public delegate void KeysRequiredEventHandler(294      object sender,295      KeysRequiredEventArgs e296    );  297298  #region ZipFile Class299  /// <summary>300  /// This class represents a Zip archive.  You can ask for the contained301  /// entries, or get an input stream for a file entry.  The entry is302  /// automatically decompressed.303  ///304  /// You can also update the archive adding or deleting entries.305  ///306  /// This class is thread safe for input:  You can open input streams for arbitrary307  /// entries in different threads.308  /// <br/>309  /// <br/>Author of the original java version : Jochen Hoenicke310  /// </summary>311  /// <example>312  /// <code>313  /// using System;314  /// using System.Text;315  /// using System.Collections;316  /// using System.IO;317  ///318  /// using ICSharpCode.SharpZipLib.Zip;319  ///320  /// class MainClass321  /// {322  ///   static public void Main(string[] args)323  ///   {324  ///     using (ZipFile zFile = new ZipFile(args[0])) {325  ///       Console.WriteLine("Listing of : " + zFile.Name);326  ///       Console.WriteLine("");327  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");328  ///       Console.WriteLine("--------  --------  --------  ------  ---------");329  ///       foreach (ZipEntry e in zFile) {330  ///         if ( e.IsFile ) {331  ///           DateTime d = e.DateTime;332  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,333  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),334  ///             e.Name);335  ///         }336  ///       }337  ///     }338  ///   }339  /// }340  /// </code>341  /// </example>342  public class ZipFile : IEnumerable, IDisposable343  {344    #region KeyHandling345346    /// <summary>347    /// Delegate for handling keys/password setting during compresion/decompression.348    /// </summary>349    public delegate void KeysRequiredEventHandler(350      object sender,351      KeysRequiredEventArgs e352    );353354    /// <summary>355    /// Event handler for handling encryption keys.356    /// </summary>357    public KeysRequiredEventHandler KeysRequired;358359    /// <summary>360    /// Handles getting of encryption keys when required.361    /// </summary>362    /// <param name="fileName">The file for which encryption keys are required.</param>363    void OnKeysRequired(string fileName)364    {365      if (KeysRequired != null) {366        var krea = new KeysRequiredEventArgs(fileName, key);367        KeysRequired(this, krea);368        key = krea.Key;369      }370    }371372    /// <summary>373    /// Get/set the encryption key value.374    /// </summary>375    byte[] Key376    {377      get { return key; }378      set { key = value; }379    }380381#if !NETCF_1_0382    /// <summary>383    /// Password to be used for encrypting/decrypting files.384    /// </summary>385    /// <remarks>Set to null if no password is required.</remarks>386    public string Password387    {388      set389      {390        if ( string.IsNullOrEmpty(value)) {391          key = null;392        }393        else {394          rawPassword_ = value;395          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));396        }298    /// <summary>299    /// Event handler for handling encryption keys.300    /// </summary>301    public KeysRequiredEventHandler KeysRequired;302303    /// <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    }315316    /// <summary>317    /// Get/set the encryption key value.318    /// </summary>319    byte[] Key {320      get { return key; }321      set { key = value; }322    }323324    /// <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    }338339    /// <summary>340    /// Get a value indicating wether encryption keys are currently available.341    /// </summary>342    bool HaveKeys {343      get { return key != null; }344    }345    #endregion346347    #region Constructors348    /// <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 occurs355    /// </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      }364365      name_ = name;366367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);368      isStreamOwner = true;369370      try {371        ReadEntries();372      } catch {373        DisposeInternal(true);374        throw;375      }376    }377378    /// <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      }394395      if (!file.CanSeek) {396        throw new ArgumentException("Stream is not seekable", nameof(file));  397      }398    }399#endif400401    /// <summary>402    /// Get a value indicating wether encryption keys are currently available.403    /// </summary>404    bool HaveKeys405    {406      get { return key != null; }407    }408    #endregion409410    #region Constructors398399      baseStream_ = file;400      name_ = file.Name;401      isStreamOwner = true;402403      try {404        ReadEntries();405      } catch {406        DisposeInternal(true);407        throw;408      }409    }410  411    /// <summary>412    /// Opens a Zip file with the given name for reading.412    /// Opens a Zip file reading the given <see cref="Stream"/>.  413    /// </summary>414    /// <param name="name">The name of the file to open.</param>415    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>416    /// <exception cref="IOException">417    /// An i/o error occurs418    /// </exception>419    /// <exception cref="ZipException">420    /// The file doesn't contain a valid zip archive.421    /// </exception>422    public ZipFile(string name)423    {424      if ( name == null ) {425        throw new ArgumentNullException(nameof(name));426      }427428      name_ = name;429430      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);431      isStreamOwner = true;414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>415    /// <exception cref="IOException">416    /// An i/o error occurs417    /// </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      }  432433      try {434        ReadEntries();433      if (!stream.CanSeek) {434        throw new ArgumentException("Stream is not seekable", nameof(stream));  435      }436      catch {437        DisposeInternal(true);438        throw;439      }440    }441442    /// <summary>443    /// Opens a Zip file reading the given <see cref="FileStream"/>.444    /// </summary>445    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>446    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>447    /// <exception cref="IOException">448    /// An i/o error occurs.449    /// </exception>450    /// <exception cref="ZipException">451    /// The file doesn't contain a valid zip archive.452    /// </exception>453    public ZipFile(FileStream file)454    {455      if ( file == null ) {456        throw new ArgumentNullException(nameof(file));457      }458459      if ( !file.CanSeek ) {460        throw new ArgumentException("Stream is not seekable", nameof(file));461      }462463      baseStream_  = file;464      name_ = file.Name;465      isStreamOwner = true;466467      try {468        ReadEntries();469      }470      catch {471        DisposeInternal(true);472        throw;473      }474    }475476    /// <summary>477    /// Opens a Zip file reading the given <see cref="Stream"/>.478    /// </summary>479    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>480    /// <exception cref="IOException">481    /// An i/o error occurs482    /// </exception>483    /// <exception cref="ZipException">484    /// The stream doesn't contain a valid zip archive.<br/>485    /// </exception>486    /// <exception cref="ArgumentException">487    /// The <see cref="Stream">stream</see> doesnt support seeking.488    /// </exception>489    /// <exception cref="ArgumentNullException">490    /// The <see cref="Stream">stream</see> argument is null.491    /// </exception>492    public ZipFile(Stream stream)493    {494      if ( stream == null ) {495        throw new ArgumentNullException(nameof(stream));496      }497498      if ( !stream.CanSeek ) {499        throw new ArgumentException("Stream is not seekable", nameof(stream));500      }501502      baseStream_  = stream;503      isStreamOwner = true;504505      if ( baseStream_.Length > 0 ) {506        try {507          ReadEntries();508        }509        catch {510          DisposeInternal(true);511          throw;512        }513      } else {514        entries_ = new ZipEntry[0];515        isNewArchive_ = true;516      }517    }518519    /// <summary>520    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.521    /// </summary>522    internal ZipFile()523    {524      entries_ = new ZipEntry[0];525      isNewArchive_ = true;526    }527528    #endregion529530    #region Destructors and Closing531    /// <summary>532    /// Finalize this instance.533    /// </summary>534    ~ZipFile()535    {536      Dispose(false);537    }538436437      baseStream_ = stream;438      isStreamOwner = true;439440      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    }452453    /// <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    }461462    #endregion463464    #region Destructors and Closing465    /// <summary>466    /// Finalize this instance.467    /// </summary>468    ~ZipFile()469    {470      Dispose(false);471    }472473    /// <summary>474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying475    /// 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    }485486    #endregion487488    #region Creators489    /// <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      }500501      FileStream fs = File.Create(fileName);502503      var result = new ZipFile();504      result.name_ = fileName;505      result.baseStream_ = fs;506      result.isStreamOwner = true;507      return result;508    }509510    /// <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      }522523      if (!outStream.CanWrite) {524        throw new ArgumentException("Stream is not writeable", nameof(outStream));525      }526527      if (!outStream.CanSeek) {528        throw new ArgumentException("Stream is not seekable", nameof(outStream));529      }530531      var result = new ZipFile();532      result.baseStream_ = outStream;533      return result;534    }535536    #endregion537538    #region Properties  539    /// <summary>540    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying541    /// Once closed, no further instance methods should be called.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    /// <exception cref="System.IO.IOException">544    /// An i/o error occurs.545    /// </exception>546    public void Close()547    {548      DisposeInternal(true);549      GC.SuppressFinalize(this);550    }551552    #endregion553554    #region Creators555    /// <summary>556    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.557    /// </summary>558    /// <param name="fileName">The name of the archive to create.</param>559    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>560    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>561    public static ZipFile Create(string fileName)562    {563      if ( fileName == null ) {564        throw new ArgumentNullException(nameof(fileName));565      }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    }550551    /// <summary>552    /// Get a value indicating wether553    /// this archive is embedded in another file or not.554    /// </summary>555    public bool IsEmbeddedArchive {556      // Not strictly correct in all circumstances currently557      get { return offsetOfFirstEntry > 0; }558    }559560    /// <summary>561    /// Get a value indicating that this archive is a new one.562    /// </summary>563    public bool IsNewArchive {564      get { return isNewArchive_; }565    }  566567      FileStream fs = File.Create(fileName);568569      var result = new ZipFile();570      result.name_ = fileName;571      result.baseStream_ = fs;572      result.isStreamOwner = true;573      return result;574    }575576    /// <summary>577    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.578    /// </summary>579    /// <param name="outStream">The stream providing data storage.</param>580    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>581    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>582    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>583    public static ZipFile Create(Stream outStream)584    {585      if ( outStream == null ) {586        throw new ArgumentNullException(nameof(outStream));587      }588589      if ( !outStream.CanWrite ) {590        throw new ArgumentException("Stream is not writeable", nameof(outStream));567    /// <summary>568    /// Gets the comment for the zip file.569    /// </summary>570    public string ZipFileComment {571      get { return comment_; }572    }573574    /// <summary>575    /// Gets the name of this zip file.576    /// </summary>577    public string Name {578      get { return name_; }579    }580581    /// <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      }592593      if ( !outStream.CanSeek ) {594        throw new ArgumentException("Stream is not seekable", nameof(outStream));595      }596597      var result = new ZipFile();598      result.baseStream_ = outStream;599      return result;600    }601602    #endregion603604    #region Properties605    /// <summary>606    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.607    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.608    /// </summary>609    /// <remarks>610    /// The default value is true in all cases.611    /// </remarks>612    public bool IsStreamOwner613    {614      get { return isStreamOwner; }615      set { isStreamOwner = value; }616    }617618    /// <summary>619    /// Get a value indicating wether620    /// this archive is embedded in another file or not.621    /// </summary>622    public bool IsEmbeddedArchive623    {624      // Not strictly correct in all circumstances currently625      get { return offsetOfFirstEntry > 0; }626    }627628    /// <summary>629    /// Get a value indicating that this archive is a new one.630    /// </summary>631    public bool IsNewArchive632    {633      get { return isNewArchive_; }634    }635636    /// <summary>637    /// Gets the comment for the zip file.638    /// </summary>639    public string ZipFileComment640    {641      get { return comment_; }642    }643644    /// <summary>645    /// Gets the name of this zip file.646    /// </summary>647    public string Name648    {649      get { return name_; }650    }651652    /// <summary>653    /// Gets the number of entries in this zip file.654    /// </summary>655    /// <exception cref="InvalidOperationException">656    /// The Zip file has been closed.657    /// </exception>658    [Obsolete("Use the Count property instead")]659    public int Size660    {661      get662      {663        return entries_.Length;664      }665    }666667    /// <summary>668    /// Get the number of entries contained in this <see cref="ZipFile"/>.669    /// </summary>670    public long Count671    {672      get673      {674        return entries_.Length;675      }676    }677678    /// <summary>679    /// Indexer property for ZipEntries680    /// </summary>681    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]682    public ZipEntry this[int index]683    {684      get {685        return (ZipEntry) entries_[index].Clone();686      }687    }688689    #endregion690691    #region Input Handling692    /// <summary>693    /// Gets an enumerator for the Zip entries in this Zip file.694    /// </summary>695    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>696    /// <exception cref="ObjectDisposedException">697    /// The Zip file has been closed.698    /// </exception>699    public IEnumerator GetEnumerator()700    {701      if (isDisposed_) {702        throw new ObjectDisposedException("ZipFile");703      }704705      return new ZipEntryEnumerator(entries_);706    }707708    /// <summary>709    /// Return the index of the entry with a matching name710    /// </summary>711    /// <param name="name">Entry name to find</param>712    /// <param name="ignoreCase">If true the comparison is case insensitive</param>713    /// <returns>The index position of the matching entry or -1 if not found</returns>714    /// <exception cref="ObjectDisposedException">715    /// The Zip file has been closed.716    /// </exception>717    public int FindEntry(string name, bool ignoreCase)718    {719      if (isDisposed_) {720        throw new ObjectDisposedException("ZipFile");721      }722723      // TODO: This will be slow as the next ice age for huge archives!724      for (int i = 0; i < entries_.Length; i++) {725        if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {726          return i;727        }728      }729      return -1;730    }731732    /// <summary>733    /// Searches for a zip entry in this archive with the given name.734    /// String comparisons are case insensitive735    /// </summary>736    /// <param name="name">737    /// The name to find. May contain directory components separated by slashes ('/').738    /// </param>739    /// <returns>740    /// A clone of the zip entry, or null if no entry with that name exists.741    /// </returns>742    /// <exception cref="ObjectDisposedException">743    /// The Zip file has been closed.744    /// </exception>745    public ZipEntry GetEntry(string name)746    {747      if (isDisposed_) {748        throw new ObjectDisposedException("ZipFile");749      }750751      int index = FindEntry(name, true);752      return (index >= 0) ? (ZipEntry) entries_[index].Clone() : null;753    }754755    /// <summary>756    /// Gets an input stream for reading the given zip entry data in an uncompressed form.757    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().758    /// </summary>759    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>760    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>761    /// <exception cref="ObjectDisposedException">762    /// The ZipFile has already been closed763    /// </exception>764    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">765    /// The compression method for the entry is unknown766    /// </exception>767    /// <exception cref="IndexOutOfRangeException">768    /// The entry is not found in the ZipFile769    /// </exception>770    public Stream GetInputStream(ZipEntry entry)771    {772      if ( entry == null ) {773        throw new ArgumentNullException(nameof(entry));774      }775776      if ( isDisposed_ ) {777        throw new ObjectDisposedException("ZipFile");778      }779780      long index = entry.ZipFileIndex;781      if ( (index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name) ) {782        index = FindEntry(entry.Name, true);783        if (index < 0) {784          throw new ZipException("Entry cannot be found");785        }786      }787      return GetInputStream(index);788    }789790    /// <summary>791    /// Creates an input stream reading a zip entry792    /// </summary>793    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>794    /// <returns>795    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>796    /// </returns>797    /// <exception cref="ObjectDisposedException">798    /// The ZipFile has already been closed799    /// </exception>800    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">801    /// The compression method for the entry is unknown802    /// </exception>803    /// <exception cref="IndexOutOfRangeException">804    /// The entry is not found in the ZipFile805    /// </exception>806    public Stream GetInputStream(long entryIndex)807    {808      if ( isDisposed_ ) {809        throw new ObjectDisposedException("ZipFile");810      }592    }593594    /// <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    }602603    /// <summary>604    /// Indexer property for ZipEntries605    /// </summary>606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]607    public ZipEntry this[int index] {608      get {609        return (ZipEntry)entries_[index].Clone();610      }611    }612613    #endregion614615    #region Input Handling616    /// <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      }628629      return new ZipEntryEnumerator(entries_);630    }631632    /// <summary>633    /// Return the index of the entry with a matching name634    /// </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      }646647      // 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    }655656    /// <summary>657    /// Searches for a zip entry in this archive with the given name.658    /// String comparisons are case insensitive659    /// </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      }674675      int index = FindEntry(name, true);676      return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;677    }678679    /// <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 closed687    /// </exception>688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">689    /// The compression method for the entry is unknown690    /// </exception>691    /// <exception cref="IndexOutOfRangeException">692    /// The entry is not found in the ZipFile693    /// </exception>694    public Stream GetInputStream(ZipEntry entry)695    {696      if (entry == null) {697        throw new ArgumentNullException(nameof(entry));698      }699700      if (isDisposed_) {701        throw new ObjectDisposedException("ZipFile");702      }703704      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    }713714    /// <summary>715    /// Creates an input stream reading a zip entry716    /// </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 closed723    /// </exception>724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">725    /// The compression method for the entry is unknown726    /// </exception>727    /// <exception cref="IndexOutOfRangeException">728    /// The entry is not found in the ZipFile729    /// </exception>730    public Stream GetInputStream(long entryIndex)731    {732      if (isDisposed_) {733        throw new ObjectDisposedException("ZipFile");734      }735736      long start = LocateEntry(entries_[entryIndex]);737      CompressionMethod method = entries_[entryIndex].CompressionMethod;738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);739740      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      }746747      switch (method) {748        case CompressionMethod.Stored:749          // read as is.750          break;751752        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;756757        default:758          throw new ZipException("Unsupported compression method " + method);759      }760761      return result;762    }763764    #endregion765766    #region Archive Testing767    /// <summary>768    /// Test an archive for integrity/validity769    /// </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    }777778    /// <summary>779    /// Test an archive for integrity/validity780    /// </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      }791792      var status = new TestStatus(this);793794      if (resultHandler != null) {795        resultHandler(status, null);796      }797798      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;799800      bool testing = true;801802      try {803        int entryIndex = 0;804805        while (testing && (entryIndex < Count)) {806          if (resultHandler != null) {807            status.SetEntry(this[entryIndex]);808            status.SetOperation(TestOperation.EntryHeader);809            resultHandler(status, null);810          }  811812      long start = LocateEntry(entries_[entryIndex]);813      CompressionMethod method = entries_[entryIndex].CompressionMethod;814      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);815816      if (entries_[entryIndex].IsCrypted == true) {817#if NETCF_1_0818        throw new ZipException("decryption not supported for Compact Framework 1.0");819#else820        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);821        if (result == null) {822          throw new ZipException("Unable to decrypt this entry");823        }824#endif825      }826827      switch (method) {828        case CompressionMethod.Stored:829          // read as is.830          break;831832        case CompressionMethod.Deflated:833          // No need to worry about ownership and closing as underlying stream close does nothing.834          result = new InflaterInputStream(result, new Inflater(true));835          break;836837        default:838          throw new ZipException("Unsupported compression method " + method);839      }812          try {813            TestLocalHeader(this[entryIndex], test);814          } catch (ZipException ex) {815            status.AddError();816817            if (resultHandler != null) {818              resultHandler(status,819                string.Format("Exception during test - '{0}'", ex.Message));820            }821822            testing &= strategy != TestStrategy.FindFirstError;823          }824825          if (testing && testData && this[entryIndex].IsFile) {826            if (resultHandler != null) {827              status.SetOperation(TestOperation.EntryData);828              resultHandler(status, null);829            }830831            var crc = new Crc32();832833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {834835              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);  840841      return result;842    }843844    #endregion845846    #region Archive Testing847    /// <summary>848    /// Test an archive for integrity/validity849    /// </summary>850    /// <param name="testData">Perform low level data Crc check</param>851    /// <returns>true if all tests pass, false otherwise</returns>852    /// <remarks>Testing will terminate on the first error found.</remarks>853    public bool TestArchive(bool testData)854    {855      return TestArchive(testData, TestStrategy.FindFirstError, null);856    }857858    /// <summary>859    /// Test an archive for integrity/validity860    /// </summary>861    /// <param name="testData">Perform low level data Crc check</param>862    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>863    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>864    /// <returns>true if all tests pass, false otherwise</returns>865    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>866    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)867    {868      if (isDisposed_) {869        throw new ObjectDisposedException("ZipFile");870      }871872      var status = new TestStatus(this);873874      if ( resultHandler != null ) {875        resultHandler(status, null);876      }877878      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;879880      bool testing = true;841                if (resultHandler != null) {842                  totalBytes += bytesRead;843                  status.SetBytesTested(totalBytes);844                  resultHandler(status, null);845                }846              }847            }848849            if (this[entryIndex].Crc != crc.Value) {850              status.AddError();851852              if (resultHandler != null) {853                resultHandler(status, "CRC mismatch");854              }855856              testing &= strategy != TestStrategy.FindFirstError;857            }858859            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              }866867              if (this[entryIndex].CompressedSize != data.CompressedSize) {868                status.AddError();869              }870871              if (this[entryIndex].Size != data.Size) {872                status.AddError();873              }874            }875          }876877          if (resultHandler != null) {878            status.SetOperation(TestOperation.EntryComplete);879            resultHandler(status, null);880          }  881882      try {883        int entryIndex = 0;882          entryIndex += 1;883        }  884885        while ( testing && (entryIndex < Count) ) {886          if ( resultHandler != null ) {887            status.SetEntry(this[entryIndex]);888            status.SetOperation(TestOperation.EntryHeader);889            resultHandler(status, null);890          }891892          try  {893            TestLocalHeader(this[entryIndex], test);894          }895          catch(ZipException ex) {896            status.AddError();897898            if ( resultHandler != null ) {899              resultHandler(status,900                string.Format("Exception during test - '{0}'", ex.Message));901            }902903            testing &= strategy != TestStrategy.FindFirstError;904          }885        if (resultHandler != null) {886          status.SetOperation(TestOperation.MiscellaneousTests);887          resultHandler(status, null);888        }889890        // TODO: the 'Corrina Johns' test where local headers are missing from891        // the central directory.  They are therefore invisible to many archivers.892      } catch (Exception ex) {893        status.AddError();894895        if (resultHandler != null) {896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));897        }898      }899900      if (resultHandler != null) {901        status.SetOperation(TestOperation.Complete);902        status.SetEntry(null);903        resultHandler(status, null);904      }  905906          if ( testing && testData && this[entryIndex].IsFile ) {907            if ( resultHandler != null ) {908              status.SetOperation(TestOperation.EntryData);909              resultHandler(status, null);910            }911912                        var crc = new Crc32();913914                        using (Stream entryStream = this.GetInputStream(this[entryIndex]))915                        {916917                            byte[] buffer = new byte[4096];918                            long totalBytes = 0;919                            int bytesRead;920                            while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0)921                            {922                                crc.Update(buffer, 0, bytesRead);923924                                if (resultHandler != null)925                                {926                                    totalBytes += bytesRead;927                                    status.SetBytesTested(totalBytes);928                                    resultHandler(status, null);929                                }930                            }931                        }932933            if (this[entryIndex].Crc != crc.Value) {934              status.AddError();935936              if ( resultHandler != null ) {937                resultHandler(status, "CRC mismatch");938              }939940              testing &= strategy != TestStrategy.FindFirstError;941            }942943            if (( this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0 ) {944              var helper = new ZipHelperStream(baseStream_);945              var data = new DescriptorData();946              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);947              if (this[entryIndex].Crc != data.Crc) {948                status.AddError();949              }950951              if (this[entryIndex].CompressedSize != data.CompressedSize) {952                status.AddError();953              }954955              if (this[entryIndex].Size != data.Size) {956                status.AddError();957              }958            }959          }960961          if ( resultHandler != null ) {962            status.SetOperation(TestOperation.EntryComplete);963            resultHandler(status, null);964          }965966          entryIndex += 1;967        }968969        if ( resultHandler != null ) {970          status.SetOperation(TestOperation.MiscellaneousTests);971          resultHandler(status, null);972        }973974        // TODO: the 'Corrina Johns' test where local headers are missing from975        // the central directory.  They are therefore invisible to many archivers.976      }977      catch (Exception ex) {978        status.AddError();906      return (status.ErrorCount == 0);907    }908909    [Flags]910    enum HeaderTest911    {912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted913      Header = 0x02,     // Check that this header contents are valid914    }915916    /// <summary>917    /// Test a local header against that provided from the central directory918    /// </summary>919    /// <param name="entry">920    /// The entry to test against921    /// </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;929930        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        }934935        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();945946        byte[] nameData = new byte[storedNameLength];947        StreamUtils.ReadFully(baseStream_, nameData);948949        byte[] extraData = new byte[extraDataLength];950        StreamUtils.ReadFully(baseStream_, extraData);951952        var localExtraData = new ZipExtraData(extraData);953954        // Extra data / zip64 checks955        if (localExtraData.Find(1)) {956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64957          // and size or compressedSize = MaxValue, due to rogue creators.958959          size = localExtraData.ReadLong();960          compressedSize = localExtraData.ReadLong();961962          if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {963            // These may be valid if patched later964            if ((size != -1) && (size != entry.Size)) {965              throw new ZipException("Size invalid for descriptor");966            }967968            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        }  979980        if ( resultHandler != null ) {981          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));982        }983      }984985      if ( resultHandler != null ) {986        status.SetOperation(TestOperation.Complete);987        status.SetEntry(null);988        resultHandler(status, null);989      }980        if (testData) {981          if (entry.IsFile) {982            if (!entry.IsCompressionMethodSupported()) {983              throw new ZipException("Compression method not supported");984            }985986            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})", extract989            }  990991      return (status.ErrorCount == 0);992    }993994    [Flags]995    enum HeaderTest996    {997      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted998      Header  = 0x02,     // Check that this header contents are valid999    }10001001    /// <summary>1002    /// Test a local header against that provided from the central directory1003    /// </summary>1004    /// <param name="entry">1005    /// The entry to test against1006    /// </param>1007    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>1008    /// <returns>The offset of the entries data in the file</returns>1009    long TestLocalHeader(ZipEntry entry, HeaderTest tests)1010    {1011      lock(baseStream_)1012      {1013        bool testHeader = (tests & HeaderTest.Header) != 0;1014        bool testData = (tests & HeaderTest.Extract) != 0;10151016        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);1017        if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {1018          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)1019        }10201021        var extractVersion = ( short ) (ReadLEUshort() & 0x00ff);1022        var localFlags = ( short )ReadLEUshort();1023        var compressionMethod = ( short )ReadLEUshort();1024        var fileTime = ( short )ReadLEUshort();1025        var fileDate = ( short )ReadLEUshort();1026        uint crcValue = ReadLEUint();1027        long compressedSize = ReadLEUint();1028        long size = ReadLEUint();1029        int storedNameLength = ReadLEUshort();1030        int extraDataLength = ReadLEUshort();10311032        byte[] nameData = new byte[storedNameLength];1033        StreamUtils.ReadFully(baseStream_, nameData);10341035        byte[] extraData = new byte[extraDataLength];1036        StreamUtils.ReadFully(baseStream_, extraData);991            if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance992              throw new ZipException("The library does not support the zip version required to extract this entry");993            }994          }995        }996997        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})", extractVersi1015          }10161017          // Local entry flags dont have reserved bit set on.1018          if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R1019            throw new ZipException("Reserved bit flags cannot be set.");1020          }10211022          // Encryption requires extract version >= 201023          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          }10261027          // 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            }10321033            if (extractVersion < 50) {1034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({01035            }1036          }  10371038        var localExtraData = new ZipExtraData(extraData);10391040        // Extra data / zip64 checks1041        if (localExtraData.Find(1))1042        {1043          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip641044          // and size or compressedSize = MaxValue, due to rogue creators.10451046          size = localExtraData.ReadLong();1047          compressedSize = localExtraData.ReadLong();10481049                    if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0)1050                    {1051                        // These may be valid if patched later1052                        if ( (size != -1) && (size != entry.Size)) {1053                            throw new ZipException("Size invalid for descriptor");1054                        }10551056                        if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {1057                            throw new ZipException("Compressed size invalid for descriptor");1058                        }1059                    }1060                }1061        else1062        {1063          // No zip64 extra data but entry requires it.1064          if ((extractVersion >= ZipConstants.VersionZip64) &&1065            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue)))1066          {1067            throw new ZipException("Required Zip64 extended information missing");1038          // Patched entries require extract version >= 271039          if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {1040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));1041          }10421043          // Central header flags match local entry flags.1044          if (localFlags != entry.Flags) {1045            throw new ZipException("Central header/local header flags mismatch");1046          }10471048          // Central header compression method matches local entry1049          if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {1050            throw new ZipException("Central header/local header compression method mismatch");1051          }10521053          if (entry.Version != extractVersion) {1054            throw new ZipException("Extract version mismatch");1055          }10561057          // Strong encryption and extract version match1058          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          }10631064          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        }10701071        if ( testData ) {1072          if ( entry.IsFile ) {1073            if ( !entry.IsCompressionMethodSupported() ) {1074              throw new ZipException("Compression method not supported");1075            }10761077            if ( (extractVersion > ZipConstants.VersionMadeBy)1078              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)) ) {1079              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract1080            }10811082            if ( (localFlags & ( int )(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enha1083              throw new ZipException("The library does not support the zip version required to extract this entry");1084            }1085          }1086        }10871088                if (testHeader)1089                {1090                    if ((extractVersion <= 63) &&  // Ignore later versions as we dont know about them..1091                        (extractVersion != 10) &&1092                        (extractVersion != 11) &&1093                        (extractVersion != 20) &&1094                        (extractVersion != 21) &&1095                        (extractVersion != 25) &&1096                        (extractVersion != 27) &&1097                        (extractVersion != 45) &&1098                        (extractVersion != 46) &&1099                        (extractVersion != 50) &&1100                        (extractVersion != 51) &&1101                        (extractVersion != 52) &&1102                        (extractVersion != 61) &&1103                        (extractVersion != 62) &&1104                        (extractVersion != 63)1105                        )1106                    {1107                        throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", 1108                    }11091110                    // Local entry flags dont have reserved bit set on.1111                    if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | General1112                    {1113                        throw new ZipException("Reserved bit flags cannot be set.");1114                    }11151116                    // Encryption requires extract version >= 201117                    if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20))1118                    {1119                        throw new ZipException(string.Format("Version required to extract this entry is too low for encr1120                    }11211122                    // Strong encryption requires encryption flag to be set and extract version >= 50.1123                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1124                    {1125                        if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0)1126                        {1127                            throw new ZipException("Strong encryption flag set but encryption flag is not set");1128                        }10691070          if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {1071            if (crcValue != (uint)entry.Crc) {1072              throw new ZipException("Central header/local header crc mismatch");1073            }1074          }10751076          // Crc valid for empty entry.1077          // This will also apply to streamed entries where size isnt known and the header cant be patched1078          if ((size == 0) && (compressedSize == 0)) {1079            if (crcValue != 0) {1080              throw new ZipException("Invalid CRC for empty entry");1081            }1082          }10831084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably1086          if (entry.Name.Length > storedNameLength) {1087            throw new ZipException("File name length mismatch");1088          }10891090          // Name data has already been read convert it and compare.1091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);10921093          // Central directory and local entry name match1094          if (localName != entry.Name) {1095            throw new ZipException("Central header and local header file name mismatch");1096          }10971098          // Directories have zero actual size but can have compressed size1099          if (entry.IsDirectory) {1100            if (size > 0) {1101              throw new ZipException("Directory cannot have size");1102            }11031104            // 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 bytes1112              // 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 bytes1114              throw new ZipException("Directory compressed size invalid");1115            }1116          }11171118          if (!ZipNameTransform.IsValidName(localName, true)) {1119            throw new ZipException("Name is invalid");1120          }1121        }11221123        // Tests that apply to both data and header.11241125        // 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)) {  11291130                        if (extractVersion < 50)1131                        {1132                            throw new ZipException(string.Format("Version required to extract this entry is too low for 1133                        }1134                    }11351136                    // Patched entries require extract version >= 271137                    if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27))1138                    {1139                        throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractV1140                    }11411142                    // Central header flags match local entry flags.1143                    if (localFlags != entry.Flags)1144                    {1145                        throw new ZipException("Central header/local header flags mismatch");1146                    }11471148                    // Central header compression method matches local entry1149                    if (entry.CompressionMethod != (CompressionMethod)compressionMethod)1150                    {1151                        throw new ZipException("Central header/local header compression method mismatch");1152                    }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          }11361137          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        }11441145        int extraLength = storedNameLength + extraDataLength;1146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;1147      }1148    }11491150    #endregion11511152    #region Updating  11531154                    if (entry.Version != extractVersion)1155                    {1156                        throw new ZipException("Extract version mismatch");1157                    }11581159                    // Strong encryption and extract version match1160                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1161                    {1162                        if (extractVersion < 62)1163                        {1164                            throw new ZipException("Strong encryption flag set but version not high enough");1165                        }1166                    }11671168                    if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0)1169                    {1170                        if ((fileTime != 0) || (fileDate != 0))1171                        {1172                            throw new ZipException("Header masked set but date/time values non-zero");1173                        }1174                    }11751176                    if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0)1177                    {1178                        if (crcValue != (uint)entry.Crc)1179                        {1180                            throw new ZipException("Central header/local header crc mismatch");1181                        }1182                    }11831184                    // Crc valid for empty entry.1185                    // This will also apply to streamed entries where size isnt known and the header cant be patched1186                    if ((size == 0) && (compressedSize == 0))1187                    {1188                        if (crcValue != 0)1189                        {1190                            throw new ZipException("Invalid CRC for empty entry");1191                        }1192                    }11931194                    // TODO: make test more correct...  can't compare lengths as was done originally as this can fail fo1195                    // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntr1196                    if (entry.Name.Length > storedNameLength)1197                    {1198                        throw new ZipException("File name length mismatch");1199                    }12001201                    // Name data has already been read convert it and compare.1202                    string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);12031204                    // Central directory and local entry name match1205                    if (localName != entry.Name)1206                    {1207                        throw new ZipException("Central header and local header file name mismatch");1208                    }12091210                    // Directories have zero actual size but can have compressed size1211                    if (entry.IsDirectory)1212                    {1213                        if (size > 0)1214                        {1215                            throw new ZipException("Directory cannot have size");1216                        }12171218                        // There may be other cases where the compressed size can be greater than this?1219                        // If so until details are known we will be strict.1220                        if (entry.IsCrypted)1221                        {1222                            if (compressedSize > ZipConstants.CryptoHeaderSize + 2)1223                            {1224                                throw new ZipException("Directory compressed size invalid");1225                            }1226                        }1227                        else if (compressedSize > 2)1228                        {1229                            // When not compressed the directory size can validly be 2 bytes1230                            // if the true size wasnt known when data was originally being written.1231                            // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes1232                            throw new ZipException("Directory compressed size invalid");1233                        }1234                    }12351236                    if (!ZipNameTransform.IsValidName(localName, true))1237                    {1238                        throw new ZipException("Name is invalid");1239                    }1240                }12411242        // Tests that apply to both data and header.1154    const int DefaultBufferSize = 4096;11551156    /// <summary>1157    /// The kind of update to apply.1158    /// </summary>1159    enum UpdateCommand1160    {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    }11651166    #region Properties1167    /// <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      }11741175      set {1176        updateEntryFactory_.NameTransform = value;1177      }1178    }11791180    /// <summary>1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1182    /// during updates.1183    /// </summary>1184    public IEntryFactory EntryFactory {1185      get {1186        return updateEntryFactory_;1187      }11881189      set {1190        if (value == null) {1191          updateEntryFactory_ = new ZipEntryFactory();1192        } else {1193          updateEntryFactory_ = value;1194        }1195      }1196    }11971198    /// <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        }12071208        if (bufferSize_ != value) {1209          bufferSize_ = value;1210          copyBuffer_ = null;1211        }1212      }1213    }12141215    /// <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    }12211222    /// <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    }12291230    #endregion12311232    #region Immediate updating1233    //    TBD: Direct form of updating1234    //1235    //    public void Update(IEntryMatcher deleteMatcher)1236    //    {1237    //    }1238    //1239    //    public void Update(IScanner addScanner)1240    //    {1241    //    }1242    #endregion  12431244        // Size can be verified only if it is known in the local header.1245        // it will always be known in the central header.1246        if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||1247          ((size > 0) || (compressedSize > 0))) {12481249          if (size != entry.Size) {1250            throw new ZipException(1251              string.Format("Size mismatch between central header({0}) and local header({1})",1252                entry.Size, size));1253          }12541255          if (compressedSize != entry.CompressedSize &&1256            compressedSize != 0xFFFFFFFF && compressedSize != -1) {1257            throw new ZipException(1258              string.Format("Compressed size mismatch between central header({0}) and local header({1})",1259              entry.CompressedSize, compressedSize));1260          }1261        }1244    #region Deferred Updating1245    /// <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.</p1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1250    /// <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      }12581259      if (dataSource == null) {1260        throw new ArgumentNullException(nameof(dataSource));1261      }  12621263        int extraLength = storedNameLength + extraDataLength;1264        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;1263      if (isDisposed_) {1264        throw new ObjectDisposedException("ZipFile");  1265      }1266    }12671268    #endregion12691270    #region Updating12711272    const int DefaultBufferSize = 4096;12661267      if (IsEmbeddedArchive) {1268        throw new ZipException("Cannot update embedded/SFX archives");1269      }12701271      archiveStorage_ = archiveStorage;1272      updateDataSource_ = dataSource;  12731274    /// <summary>1275    /// The kind of update to apply.1276    /// </summary>1277    enum UpdateCommand1278    {1279      Copy,       // Copy original file contents.1280      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.1281      Add,        // Add a new file to the archive.1282    }1274      // NOTE: the baseStream_ may not currently support writing or seeking.12751276      updateIndex_ = new Hashtable();12771278      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      }  12831284    #region Properties1285    /// <summary>1286    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.1287    /// </summary>1288    public INameTransform NameTransform1289    {1290      get {1291        return updateEntryFactory_.NameTransform;1292      }12931294      set {1295        updateEntryFactory_.NameTransform = value;1296      }1297    }12981299    /// <summary>1300    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1301    /// during updates.1302    /// </summary>1303    public IEntryFactory EntryFactory1304    {1305      get {1306        return updateEntryFactory_;1307      }13081309      set {1310        if (value == null) {1311          updateEntryFactory_ = new ZipEntryFactory();1312        }1313        else {1314          updateEntryFactory_ = value;1315        }1316      }1317    }13181319    /// <summary>1320    /// Get /set the buffer size to be used when updating this zip file.1321    /// </summary>1322    public int BufferSize1323    {1324      get { return bufferSize_; }1325      set {1326        if ( value < 1024 ) {1327#if NETCF_1_01328          throw new ArgumentOutOfRangeException("value");1329#else1330          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");1331#endif1332        }13331334        if ( bufferSize_ != value ) {1335          bufferSize_ = value;1336          copyBuffer_ = null;1337        }1338      }1339    }1284      // We must sort by offset before using offset's calculated sizes1285      updates_.Sort(new UpdateComparer());12861287      int idx = 0;1288      foreach (ZipUpdate update in updates_) {1289        //If last entry, there is no next entry offset to use1290        if (idx == updates_.Count - 1)1291          break;12921293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;1294        idx++;1295      }1296      updateCount_ = updates_.Count;12971298      contentsEdited_ = false;1299      commentEdited_ = false;1300      newComment_ = null;1301    }13021303    /// <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    }13111312    /// <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    }13261327    /// <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      }13381339      CheckUpdating();  13401341    /// <summary>1342    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.1343    /// </summary>1344    public bool IsUpdating1345    {1346      get { return updates_ != null; }1347    }13481349    /// <summary>1350    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.1351    /// </summary>1352    public UseZip64 UseZip641353    {1354      get { return useZip64_; }1355      set { useZip64_ = value; }1356    }13571358    #endregion13591360    #region Immediate updating1361//    TBD: Direct form of updating1362//1363//    public void Update(IEntryMatcher deleteMatcher)1364//    {1365//    }1366//1367//    public void Update(IScanner addScanner)1368//    {1369//    }1370    #endregion13711372    #region Deferred Updating1373    /// <summary>1374    /// Begin updating this <see cref="ZipFile"/> archive.1375    /// </summary>1376    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p1377    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1341      try {1342        updateIndex_.Clear();1343        updateIndex_ = null;13441345        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        }13581359      } finally {1360        PostUpdateCleanup();1361      }1362    }13631364    /// <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    }13731374    /// <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    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>1380    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1381    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)1382    {1383      if ( archiveStorage == null ) {1384        throw new ArgumentNullException(nameof(archiveStorage));1385      }1379    public void SetComment(string comment)1380    {1381      if (isDisposed_) {1382        throw new ObjectDisposedException("ZipFile");1383      }13841385      CheckUpdating();  13861387      if ( dataSource == null ) {1388        throw new ArgumentNullException(nameof(dataSource));1389      }13901391      if ( isDisposed_ ) {1392        throw new ObjectDisposedException("ZipFile");1393      }13941395      if ( IsEmbeddedArchive ) {1396        throw new ZipException ("Cannot update embedded/SFX archives");1397      }1387      newComment_ = new ZipString(comment);13881389      if (newComment_.RawLength > 0xffff) {1390        newComment_ = null;1391        throw new ZipException("Comment length exceeds maximum - 65535");1392      }13931394      // We dont take account of the original and current comment appearing to be the same1395      // as encoding may be different.1396      commentEdited_ = true;1397    }  13981399      archiveStorage_ = archiveStorage;1400      updateDataSource_ = dataSource;14011402      // NOTE: the baseStream_ may not currently support writing or seeking.14031404      updateIndex_ = new Hashtable();14051406      updates_ = new ArrayList(entries_.Length);1407      foreach(ZipEntry entry in entries_) {1408        int index = updates_.Add(new ZipUpdate(entry));1409        updateIndex_.Add(entry.Name, index);1410      }14111412      // We must sort by offset before using offset's calculated sizes1413      updates_.Sort(new UpdateComparer());14141415      int idx = 0;1416      foreach (ZipUpdate update in updates_) {1417        //If last entry, there is no next entry offset to use1418        if (idx == updates_.Count - 1)1419          break;14201421        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;1422        idx++;1423      }1424      updateCount_ = updates_.Count;14251426      contentsEdited_ = false;1427      commentEdited_ = false;1428      newComment_ = null;1429    }14301431    /// <summary>1432    /// Begin updating to this <see cref="ZipFile"/> archive.1433    /// </summary>1434    /// <param name="archiveStorage">The storage to use during the update.</param>1435    public void BeginUpdate(IArchiveStorage archiveStorage)1436    {1437      BeginUpdate(archiveStorage, new DynamicDiskDataSource());1438    }14391440    /// <summary>1441    /// Begin updating this <see cref="ZipFile"/> archive.1442    /// </summary>1443    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>1444    /// <seealso cref="CommitUpdate"></seealso>1445    /// <seealso cref="AbortUpdate"></seealso>1446    public void BeginUpdate()1447    {1448      if ( Name == null ) {1449        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());1450      }1451      else {1452        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());1453      }1399    #endregion14001401    #region Adding Entries14021403    void AddUpdate(ZipUpdate update)1404    {1405      contentsEdited_ = true;14061407      int index = FindExistingUpdate(update.Entry.Name);14081409      if (index >= 0) {1410        if (updates_[index] == null) {1411          updateCount_ += 1;1412        }14131414        // 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    }14221423    /// <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      }14371438      if (isDisposed_) {1439        throw new ObjectDisposedException("ZipFile");1440      }14411442      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1444      }14451446      CheckUpdating();1447      contentsEdited_ = true;14481449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1450      entry.IsUnicodeText = useUnicodeText;1451      entry.CompressionMethod = compressionMethod;14521453      AddUpdate(new ZipUpdate(fileName, entry));  1454    }  1455  1456    /// <summary>1457    /// Commit current updates, updating this archive.1457    /// Add a new entry to the archive.  1458    /// </summary>1459    /// <seealso cref="BeginUpdate()"></seealso>1460    /// <seealso cref="AbortUpdate"></seealso>1461    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1462    public void CommitUpdate()1463    {1464      if ( isDisposed_ ) {1465        throw new ObjectDisposedException("ZipFile");1466      }14671468      CheckUpdating();14691470      try {1471        updateIndex_.Clear();1472        updateIndex_=null;14731474        if( contentsEdited_ ) {1475          RunUpdates();1476        }1477        else if( commentEdited_ ) {1478          UpdateCommentOnly();1479        }1480        else {1481          // Create an empty archive if none existed originally.1482          if( entries_.Length==0 ) {1483            byte[] theComment=(newComment_!=null)?newComment_.RawComment:ZipConstants.ConvertToArray(comment_);1484            using( ZipHelperStream zhs=new ZipHelperStream(baseStream_) ) {1485              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);1486            }1487          }1488        }14891459    /// <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      }14681469      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1471      }14721473      CheckUpdating();1474      contentsEdited_ = true;14751476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1477      entry.CompressionMethod = compressionMethod;1478      AddUpdate(new ZipUpdate(fileName, entry));1479    }14801481    /// <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      finally {1492        PostUpdateCleanup();1493      }14911492      CheckUpdating();1493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));  1494    }  1495  1496    /// <summary>1497    /// Abort updating leaving the archive unchanged.1497    /// Add a file to the archive.  1498    /// </summary>1499    /// <seealso cref="BeginUpdate()"></seealso>1500    /// <seealso cref="CommitUpdate"></seealso>1501    public void AbortUpdate()1502    {1503      PostUpdateCleanup();1504    }15051506    /// <summary>1507    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.1508    /// </summary>1509    /// <param name="comment">The comment to record.</param>1510    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1511    public void SetComment(string comment)1512    {1513      if ( isDisposed_ ) {1514        throw new ObjectDisposedException("ZipFile");1515      }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      }15071508      if (entryName == null) {1509        throw new ArgumentNullException(nameof(entryName));1510      }15111512      CheckUpdating();1513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));1514    }1515  15161517      CheckUpdating();15181519      newComment_ = new ZipString(comment);15201521      if ( newComment_.RawLength  > 0xffff ) {1522        newComment_ = null;1523        throw new ZipException("Comment length exceeds maximum - 65535");1524      }15251526      // We dont take account of the original and current comment appearing to be the same1527      // as encoding may be different.1528      commentEdited_ = true;1529    }15301531    #endregion15321533    #region Adding Entries15341535    void AddUpdate(ZipUpdate update)1536    {1537      contentsEdited_ = true;15381539      int index = FindExistingUpdate(update.Entry.Name);15401541      if (index >= 0) {1542        if ( updates_[index] == null ) {1543          updateCount_ += 1;1544        }15451546        // Direct replacement is faster than delete and add.1547        updates_[index] = update;1548      }1549      else {1550        index = updates_.Add(update);1551        updateCount_ += 1;1552        updateIndex_.Add(update.Entry.Name, index);1553      }1554    }15551556    /// <summary>1557    /// Add a new entry to the archive.1558    /// </summary>1559    /// <param name="fileName">The name of the file to add.</param>1560    /// <param name="compressionMethod">The compression method to use.</param>1561    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>1562    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1563    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1564    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>1565    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText )1566    {1567      if (fileName == null) {1568        throw new ArgumentNullException(nameof(fileName));1569      }15701571      if ( isDisposed_ ) {1572        throw new ObjectDisposedException("ZipFile");1573      }15741575      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1576        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1577      }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      }15271528      if (entryName == null) {1529        throw new ArgumentNullException(nameof(entryName));1530      }15311532      CheckUpdating();1533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));1534    }15351536    /// <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      }15471548      if (entryName == null) {1549        throw new ArgumentNullException(nameof(entryName));1550      }15511552      CheckUpdating();15531554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1555      entry.CompressionMethod = compressionMethod;15561557      AddUpdate(new ZipUpdate(dataSource, entry));1558    }15591560    /// <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 useUnicode1568    {1569      if (dataSource == null) {1570        throw new ArgumentNullException(nameof(dataSource));1571      }15721573      if (entryName == null) {1574        throw new ArgumentNullException(nameof(entryName));1575      }15761577      CheckUpdating();  15781579      CheckUpdating();1580      contentsEdited_ = true;15811582      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1583      entry.IsUnicodeText = useUnicodeText;1584      entry.CompressionMethod = compressionMethod;1579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1580      entry.IsUnicodeText = useUnicodeText;1581      entry.CompressionMethod = compressionMethod;15821583      AddUpdate(new ZipUpdate(dataSource, entry));1584    }  15851586      AddUpdate(new ZipUpdate(fileName, entry));1587    }15881589    /// <summary>1590    /// Add a new entry to the archive.1591    /// </summary>1592    /// <param name="fileName">The name of the file to add.</param>1593    /// <param name="compressionMethod">The compression method to use.</param>1594    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>1595    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>1596    public void Add(string fileName, CompressionMethod compressionMethod)1597    {1598      if ( fileName == null ) {1599        throw new ArgumentNullException(nameof(fileName));1600      }16011602      if ( !ZipEntry.IsCompressionMethodSupported(compressionMethod) ) {1603        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1604      }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      }15961597      CheckUpdating();15981599      if ((entry.Size != 0) || (entry.CompressedSize != 0)) {1600        throw new ZipException("Entry cannot have any data");1601      }16021603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));1604    }  16051606      CheckUpdating();1607      contentsEdited_ = true;16081609      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1610      entry.CompressionMethod = compressionMethod;1611      AddUpdate(new ZipUpdate(fileName, entry));1612    }16131614    /// <summary>1615    /// Add a file to the archive.1616    /// </summary>1617    /// <param name="fileName">The name of the file to add.</param>1618    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1619    public void Add(string fileName)1620    {1621      if ( fileName == null ) {1622        throw new ArgumentNullException(nameof(fileName));1623      }16241625      CheckUpdating();1626      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));1627    }16281629    /// <summary>1630    /// Add a file to the archive.1631    /// </summary>1632    /// <param name="fileName">The name of the file to add.</param>1633    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>1634    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1635    public void Add(string fileName, string entryName)1636    {1637      if (fileName == null) {1638        throw new ArgumentNullException(nameof(fileName));1639      }16401641      if ( entryName == null ) {1642        throw new ArgumentNullException(nameof(entryName));1643      }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      }16151616      CheckUpdating();16171618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);1619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));1620    }16211622    #endregion16231624    #region Modifying Entries1625    /* 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          }16331634          if ( updated == null ) {1635            throw new ArgumentNullException("updated");1636          }16371638          CheckUpdating();1639          contentsEdited_ = true;1640          updates_.Add(new ZipUpdate(original, updated));1641        }1642    */1643    #endregion  16441645      CheckUpdating();1646      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));1647    }164816491650    /// <summary>1651    /// Add a file entry with data.1652    /// </summary>1653    /// <param name="dataSource">The source of the data for this entry.</param>1654    /// <param name="entryName">The name to give to the entry.</param>1655    public void Add(IStaticDataSource dataSource, string entryName)1656    {1657      if ( dataSource == null ) {1658        throw new ArgumentNullException(nameof(dataSource));1659      }16601661      if ( entryName == null ) {1662        throw new ArgumentNullException(nameof(entryName));1663      }16641665      CheckUpdating();1666      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));1667    }16681669    /// <summary>1670    /// Add a file entry with data.1671    /// </summary>1672    /// <param name="dataSource">The source of the data for this entry.</param>1673    /// <param name="entryName">The name to give to the entry.</param>1674    /// <param name="compressionMethod">The compression method to use.</param>1675    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)1676    {1677      if ( dataSource == null ) {1678        throw new ArgumentNullException(nameof(dataSource));1679      }16801681      if ( entryName == null ) {1682        throw new ArgumentNullException(nameof(entryName));1683      }16841685      CheckUpdating();16861687      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1688      entry.CompressionMethod = compressionMethod;16891690      AddUpdate(new ZipUpdate(dataSource, entry));1691    }16921693    /// <summary>1694    /// Add a file entry with data.1695    /// </summary>1696    /// <param name="dataSource">The source of the data for this entry.</param>1697    /// <param name="entryName">The name to give to the entry.</param>1698    /// <param name="compressionMethod">The compression method to use.</param>1699    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>1700    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode1701    {1702      if (dataSource == null) {1703        throw new ArgumentNullException(nameof(dataSource));1704      }17051706      if ( entryName == null ) {1707        throw new ArgumentNullException(nameof(entryName));1708      }17091710      CheckUpdating();17111712      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1713      entry.IsUnicodeText = useUnicodeText;1714      entry.CompressionMethod = compressionMethod;17151716      AddUpdate(new ZipUpdate(dataSource, entry));1717    }17181719    /// <summary>1720    /// Add a <see cref="ZipEntry"/> that contains no data.1721    /// </summary>1722    /// <param name="entry">The entry to add.</param>1723    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>1724    public void Add(ZipEntry entry)1725    {1726      if ( entry == null ) {1727        throw new ArgumentNullException(nameof(entry));1728      }17291730      CheckUpdating();1645    #region Deleting Entries1646    /// <summary>1647    /// Delete an entry by name1648    /// </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      }16561657      CheckUpdating();16581659      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    }16711672    /// <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      }16811682      CheckUpdating();16831684      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    }16931694    #endregion16951696    #region Update Support16971698    #region Writing Values/Headers1699    void WriteLEShort(int value)1700    {1701      baseStream_.WriteByte((byte)(value & 0xff));1702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));1703    }17041705    /// <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    }17131714    /// <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    }17221723    /// <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    }  17311732      if ( (entry.Size != 0) || (entry.CompressedSize != 0) ) {1733        throw new ZipException("Entry cannot have any data");1734      }17351736      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));1737    }17381739    /// <summary>1740    /// Add a directory entry to the archive.1741    /// </summary>1742    /// <param name="directoryName">The directory to add.</param>1743    public void AddDirectory(string directoryName)1744    {1745      if ( directoryName == null ) {1746        throw new ArgumentNullException(nameof(directoryName));1747      }17481749      CheckUpdating();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    }17401741    void WriteLEUlong(ulong value)1742    {1743      WriteLEUint((uint)(value & 0xffffffff));1744      WriteLEUint((uint)(value >> 32));1745    }17461747    void WriteLocalEntryHeader(ZipUpdate update)1748    {1749      ZipEntry entry = update.OutEntry;  17501751      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);1752      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));1753    }17541755    #endregion17561757    #region Modifying Entries1758/* Modify not yet ready for public consumption.1759   Direct modification of an entry should not overwrite original data before its read.1760   Safe mode is trivial in this sense.1761    public void Modify(ZipEntry original, ZipEntry updated)1762    {1763      if ( original == null ) {1764        throw new ArgumentNullException("original");1765      }1751      // TODO: Local offset will require adjusting for multi-disk zip files.1752      entry.Offset = baseStream_.Position;17531754      // 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        }  17661767      if ( updated == null ) {1768        throw new ArgumentNullException("updated");1769      }17701771      CheckUpdating();1772      contentsEdited_ = true;1773      updates_.Add(new ZipUpdate(original, updated));1774    }1775*/1776    #endregion17771778    #region Deleting Entries1779    /// <summary>1780    /// Delete an entry by name1781    /// </summary>1782    /// <param name="fileName">The filename to delete</param>1783    /// <returns>True if the entry was found and deleted; false otherwise.</returns>1784    public bool Delete(string fileName)1785    {1786      if ( fileName == null ) {1787        throw new ArgumentNullException(nameof(fileName));1788      }17891790      CheckUpdating();17911792      bool result = false;1793      int index = FindExistingUpdate(fileName);1794      if ( (index >= 0) && (updates_[index] != null) ) {1795        result = true;1796        contentsEdited_ = true;1797        updates_[index] = null;1798        updateCount_ -= 1;1799      }1800      else {1801        throw new ZipException("Cannot find entry to delete");1802      }1803      return result;1804    }18051806    /// <summary>1807    /// Delete a <see cref="ZipEntry"/> from the archive.1808    /// </summary>1809    /// <param name="entry">The entry to delete.</param>1810    public void Delete(ZipEntry entry)1811    {1812      if ( entry == null ) {1813        throw new ArgumentNullException(nameof(entry));1814      }18151816      CheckUpdating();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        }17751776        switch (useZip64_) {1777          case UseZip64.Dynamic:1778            if (entry.Size < 0) {1779              entry.ForceZip64();1780            }1781            break;17821783          case UseZip64.On:1784            entry.ForceZip64();1785            break;17861787          case UseZip64.Off:1788            // Do nothing.  The entry itself may be using Zip64 independantly.1789            break;1790        }1791      }17921793      // Write the local file header1794      WriteLEInt(ZipConstants.LocalHeaderSignature);17951796      WriteLEShort(entry.Version);1797      WriteLEShort(entry.Flags);17981799      WriteLEShort((byte)entry.CompressionMethod);1800      WriteLEInt((int)entry.DosTime);18011802      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      }18091810      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        }  18171818      int index = FindExistingUpdate(entry);1819      if ( index >= 0 ) {1820        contentsEdited_ = true;1821        updates_[index] = null;1822        updateCount_ -= 1;1823      }1824      else {1825        throw new ZipException("Cannot find entry to delete");1818        WriteLEInt((int)entry.CompressedSize);1819        WriteLEInt((int)entry.Size);1820      }18211822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);18231824      if (name.Length > 0xFFFF) {1825        throw new ZipException("Entry name too long.");  1826      }1827    }18281829    #endregion18301831    #region Update Support18271828      var ed = new ZipExtraData(entry.ExtraData);18291830      if (entry.LocalHeaderRequiresZip64) {1831        ed.StartNewEntry();  18321833    #region Writing Values/Headers1834    void WriteLEShort(int value)1835    {1836      baseStream_.WriteByte(( byte )(value & 0xff));1837      baseStream_.WriteByte(( byte )((value >> 8) & 0xff));1838    }18391840    /// <summary>1841    /// Write an unsigned short in little endian byte order.1842    /// </summary>1843    void WriteLEUshort(ushort value)1844    {1845      baseStream_.WriteByte(( byte )(value & 0xff));1846      baseStream_.WriteByte(( byte )(value >> 8));1847    }18481849    /// <summary>1850    /// Write an int in little endian byte order.1851    /// </summary>1852    void WriteLEInt(int value)1853    {1854      WriteLEShort(value & 0xffff);1855      WriteLEShort(value >> 16);1856    }18571858    /// <summary>1859    /// Write an unsigned int in little endian byte order.1860    /// </summary>1861    void WriteLEUint(uint value)1862    {1863      WriteLEUshort((ushort)(value & 0xffff));1864      WriteLEUshort((ushort)(value >> 16));1865    }18661867    /// <summary>1868    /// Write a long in little endian byte order.1869    /// </summary>1870    void WriteLeLong(long value)1871    {1872      WriteLEInt(( int )(value & 0xffffffff));1873      WriteLEInt(( int )(value >> 32));1874    }18751876    void WriteLEUlong(ulong value)1877    {1878      WriteLEUint(( uint )(value & 0xffffffff));1879      WriteLEUint(( uint )(value >> 32));1880    }18811882    void WriteLocalEntryHeader(ZipUpdate update)1883    {1884      ZipEntry entry = update.OutEntry;18851886      // TODO: Local offset will require adjusting for multi-disk zip files.1887      entry.Offset = baseStream_.Position;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      }18411842      entry.ExtraData = ed.GetEntryData();18431844      WriteLEShort(name.Length);1845      WriteLEShort(entry.ExtraData.Length);18461847      if (name.Length > 0) {1848        baseStream_.Write(name, 0, name.Length);1849      }18501851      if (entry.LocalHeaderRequiresZip64) {1852        if (!ed.Find(1)) {1853          throw new ZipException("Internal error cannot find extra data");1854        }18551856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1857      }18581859      if (entry.ExtraData.Length > 0) {1860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);1861      }1862    }18631864    int WriteCentralDirectoryHeader(ZipEntry entry)1865    {1866      if (entry.CompressedSize < 0) {1867        throw new ZipException("Attempt to write central directory entry with unknown csize");1868      }18691870      if (entry.Size < 0) {1871        throw new ZipException("Attempt to write central directory entry with unknown size");1872      }18731874      if (entry.Crc < 0) {1875        throw new ZipException("Attempt to write central directory entry with unknown crc");1876      }18771878      // Write the central file header1879      WriteLEInt(ZipConstants.CentralHeaderSignature);18801881      // Version made by1882      WriteLEShort(ZipConstants.VersionMadeBy);18831884      // Version required to extract1885      WriteLEShort(entry.Version);18861887      WriteLEShort(entry.Flags);  18881889      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.1890      if (update.Command != UpdateCommand.Copy) {1891        if (entry.CompressionMethod == CompressionMethod.Deflated) {1892          if (entry.Size == 0) {1893            // No need to compress - no data.1894            entry.CompressedSize = entry.Size;1895            entry.Crc = 0;1896            entry.CompressionMethod = CompressionMethod.Stored;1897          }1898        }1899        else if (entry.CompressionMethod == CompressionMethod.Stored) {1900          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;1901        }19021903        if (HaveKeys) {1904          entry.IsCrypted = true;1905          if (entry.Crc < 0) {1906            entry.Flags |= (int)GeneralBitFlags.Descriptor;1907          }1908        }1909        else {1910          entry.IsCrypted = false;1911        }1889      unchecked {1890        WriteLEShort((byte)entry.CompressionMethod);1891        WriteLEInt((int)entry.DosTime);1892        WriteLEInt((int)entry.Crc);1893      }18941895      if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {1896        WriteLEInt(-1);1897      } else {1898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));1899      }19001901      if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {1902        WriteLEInt(-1);1903      } else {1904        WriteLEInt((int)entry.Size);1905      }19061907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);19081909      if (name.Length > 0xFFFF) {1910        throw new ZipException("Entry name is too long.");1911      }  19121913        switch (useZip64_) {1914          case UseZip64.Dynamic:1915            if (entry.Size < 0) {1916              entry.ForceZip64();1917            }1918            break;19191920          case UseZip64.On:1921            entry.ForceZip64();1922            break;19231924          case UseZip64.Off:1925            // Do nothing.  The entry itself may be using Zip64 independantly.1926            break;1913      WriteLEShort(name.Length);19141915      // Central header extra data is different to local header version so regenerate.1916      var ed = new ZipExtraData(entry.ExtraData);19171918      if (entry.CentralHeaderRequiresZip64) {1919        ed.StartNewEntry();19201921        if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {1922          ed.AddLeLong(entry.Size);1923        }19241925        if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {1926          ed.AddLeLong(entry.CompressedSize);  1927        }1928      }19291930      // Write the local file header1931      WriteLEInt(ZipConstants.LocalHeaderSignature);19281929        if (entry.Offset >= 0xffffffff) {1930          ed.AddLeLong(entry.Offset);1931        }  19321933      WriteLEShort(entry.Version);1934      WriteLEShort(entry.Flags);19351936      WriteLEShort((byte)entry.CompressionMethod);1937      WriteLEInt(( int )entry.DosTime);19381939      if ( !entry.HasCrc ) {1940        // Note patch address for updating CRC later.1941        update.CrcPatchOffset = baseStream_.Position;1942        WriteLEInt(( int )0);1943      }1944      else {1945        WriteLEInt(unchecked(( int )entry.Crc));1946      }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      }19391940      byte[] centralExtraData = ed.GetEntryData();19411942      WriteLEShort(centralExtraData.Length);1943      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);19441945      WriteLEShort(0);    // disk number1946      WriteLEShort(0);    // internal file attributes  19471948      if (entry.LocalHeaderRequiresZip64) {1949        WriteLEInt(-1);1950        WriteLEInt(-1);1951      }1952      else {1953        if ( (entry.CompressedSize < 0) || (entry.Size < 0) ) {1954          update.SizePatchOffset = baseStream_.Position;1955        }19561957        WriteLEInt(( int )entry.CompressedSize);1958        WriteLEInt(( int )entry.Size);1959      }19601961      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);19621963      if ( name.Length > 0xFFFF ) {1964        throw new ZipException("Entry name too long.");1965      }19661967      var ed = new ZipExtraData(entry.ExtraData);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      }19581959      if (entry.Offset >= 0xffffffff) {1960        WriteLEUint(0xffffffff);1961      } else {1962        WriteLEUint((uint)(int)entry.Offset);1963      }19641965      if (name.Length > 0) {1966        baseStream_.Write(name, 0, name.Length);1967      }  19681969      if ( entry.LocalHeaderRequiresZip64 ) {1970        ed.StartNewEntry();19711972        // Local entry header always includes size and compressed size.1973        // NOTE the order of these fields is reversed when compared to the normal headers!1974        ed.AddLeLong(entry.Size);1975        ed.AddLeLong(entry.CompressedSize);1976        ed.AddNewEntry(1);1969      if (centralExtraData.Length > 0) {1970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);1971      }19721973      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];19741975      if (rawComment.Length > 0) {1976        baseStream_.Write(rawComment, 0, rawComment.Length);  1977      }1978      else {1979        ed.Delete(1);1980      }19811982      entry.ExtraData = ed.GetEntryData();19831984      WriteLEShort(name.Length);1985      WriteLEShort(entry.ExtraData.Length);19861987      if ( name.Length > 0 ) {1988        baseStream_.Write(name, 0, name.Length);1989      }19901991      if ( entry.LocalHeaderRequiresZip64 ) {1992        if ( !ed.Find(1) ) {1993          throw new ZipException("Internal error cannot find extra data");1994        }19951996        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1997      }19981999      if ( entry.ExtraData.Length > 0 ) {2000        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);2001      }2002    }20032004    int WriteCentralDirectoryHeader(ZipEntry entry)2005    {2006      if ( entry.CompressedSize < 0 ) {2007        throw new ZipException("Attempt to write central directory entry with unknown csize");2008      }20092010      if ( entry.Size < 0 ) {2011        throw new ZipException("Attempt to write central directory entry with unknown size");2012      }20132014      if ( entry.Crc < 0 ) {2015        throw new ZipException("Attempt to write central directory entry with unknown crc");2016      }20172018      // Write the central file header2019      WriteLEInt(ZipConstants.CentralHeaderSignature);20202021      // Version made by2022      WriteLEShort(ZipConstants.VersionMadeBy);20232024      // Version required to extract2025      WriteLEShort(entry.Version);19781979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;1980    }1981    #endregion19821983    void PostUpdateCleanup()1984    {1985      updateDataSource_ = null;1986      updates_ = null;1987      updateIndex_ = null;19881989      if (archiveStorage_ != null) {1990        archiveStorage_.Dispose();1991        archiveStorage_ = null;1992      }1993    }19941995    string GetTransformedFileName(string name)1996    {1997      INameTransform transform = NameTransform;1998      return (transform != null) ?1999        transform.TransformFile(name) :2000        name;2001    }20022003    string GetTransformedDirectoryName(string name)2004    {2005      INameTransform transform = NameTransform;2006      return (transform != null) ?2007        transform.TransformDirectory(name) :2008        name;2009    }20102011    /// <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    }20222023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2024    {2025      int bytesToCopy = GetDescriptorSize(update);  20262027      WriteLEShort(entry.Flags);20282029      unchecked {2030        WriteLEShort((byte)entry.CompressionMethod);2031        WriteLEInt((int)entry.DosTime);2032        WriteLEInt((int)entry.Crc);2033      }20342035      if ( (entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff) ) {2036        WriteLEInt(-1);2037      }2038      else {2039        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));2040      }20412042      if ( (entry.IsZip64Forced()) || (entry.Size >= 0xffffffff) ) {2043        WriteLEInt(-1);2044      }2045      else {2046        WriteLEInt((int)entry.Size);2047      }20482049      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);2027      if (bytesToCopy > 0) {2028        byte[] buffer = GetBuffer();20292030        while (bytesToCopy > 0) {2031          int readSize = Math.Min(buffer.Length, bytesToCopy);20322033          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    }20432044    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      }  20502051      if ( name.Length > 0xFFFF ) {2052        throw new ZipException("Entry name is too long.");2053      }2051      // NOTE: Compressed size is updated elsewhere.2052      var crc = new Crc32();2053      byte[] buffer = GetBuffer();  20542055      WriteLEShort(name.Length);20562057      // Central header extra data is different to local header version so regenerate.2058      var ed = new ZipExtraData(entry.ExtraData);20592060      if ( entry.CentralHeaderRequiresZip64 ) {2061        ed.StartNewEntry();20622063        if ( (entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On) )2064        {2065          ed.AddLeLong(entry.Size);2066        }20672068        if ( (entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On) )2069        {2070          ed.AddLeLong(entry.CompressedSize);2071        }20722073        if ( entry.Offset >= 0xffffffff ) {2074          ed.AddLeLong(entry.Offset);2075        }20762077        // Number of disk on which this file starts isnt supported and is never written here.2078        ed.AddNewEntry(1);2079      }2080      else {2081        // Should have already be done when local header was added.2082        ed.Delete(1);2083      }20842085      byte[] centralExtraData = ed.GetEntryData();2055      long targetBytes = bytesToCopy;2056      long totalBytesRead = 0;20572058      int bytesRead;2059      do {2060        int readSize = buffer.Length;20612062        if (bytesToCopy < readSize) {2063          readSize = (int)bytesToCopy;2064        }20652066        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));20772078      if (totalBytesRead != targetBytes) {2079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2080      }20812082      if (updateCrc) {2083        update.OutEntry.Crc = crc.Value;2084      }2085    }  20862087      WriteLEShort(centralExtraData.Length);2088      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);20892090      WriteLEShort(0);  // disk number2091      WriteLEShort(0);  // internal file attributes20922093      // External file attributes...2094      if ( entry.ExternalFileAttributes != -1 ) {2095        WriteLEInt(entry.ExternalFileAttributes);2096      }2097      else {2098        if ( entry.IsDirectory ) {2099          WriteLEUint(16);2100        }2101        else {2102          WriteLEUint(0);2103        }2104      }21052106      if ( entry.Offset >= 0xffffffff ) {2107        WriteLEUint(0xffffffff);2108      }2109      else {2110        WriteLEUint((uint)(int)entry.Offset);2111      }21122113      if ( name.Length > 0 ) {2114        baseStream_.Write(name, 0, name.Length);2115      }21162117      if ( centralExtraData.Length > 0 ) {2118        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);2119      }21202121      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];21222123      if ( rawComment.Length > 0 ) {2124        baseStream_.Write(rawComment, 0, rawComment.Length);2125      }21262127      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;2128    }2129    #endregion21302131    void PostUpdateCleanup()2132    {2133            updateDataSource_ = null;2134            updates_ = null;2135            updateIndex_ = null;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    }21032104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2105    {2106      int bytesToCopy = GetDescriptorSize(update);21072108      while (bytesToCopy > 0) {2109        var readSize = (int)bytesToCopy;2110        byte[] buffer = GetBuffer();21112112        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    }21252126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2127    {2128      long bytesToCopy = update.Entry.CompressedSize;21292130      // NOTE: Compressed size is updated elsewhere.2131      var crc = new Crc32();2132      byte[] buffer = GetBuffer();21332134      long targetBytes = bytesToCopy;2135      long totalBytesRead = 0;  21362137            if (archiveStorage_ != null)2138            {2139        archiveStorage_.Dispose();2140        archiveStorage_=null;2141      }2142    }21432144    string GetTransformedFileName(string name)2145    {2146            INameTransform transform = NameTransform;2147      return (transform != null) ?2148        transform.TransformFile(name) :2149        name;2150    }21512152    string GetTransformedDirectoryName(string name)2153    {2154            INameTransform transform = NameTransform;2155            return (transform != null) ?2156        transform.TransformDirectory(name) :2157        name;2158    }21592160    /// <summary>2161    /// Get a raw memory buffer.2162    /// </summary>2163    /// <returns>Returns a raw memory buffer.</returns>2164    byte[] GetBuffer()2165    {2166      if ( copyBuffer_ == null ) {2167        copyBuffer_ = new byte[bufferSize_];2137      int bytesRead;2138      do {2139        int readSize = buffer.Length;21402141        if (bytesToCopy < readSize) {2142          readSize = (int)bytesToCopy;2143        }21442145        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);21532154          destinationPosition += bytesRead;2155          sourcePosition += bytesRead;2156          bytesToCopy -= bytesRead;2157          totalBytesRead += bytesRead;2158        }2159      }2160      while ((bytesRead > 0) && (bytesToCopy > 0));21612162      if (totalBytesRead != targetBytes) {2163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2164      }21652166      if (updateCrc) {2167        update.OutEntry.Crc = crc.Value;  2168      }2169      return copyBuffer_;2170    }21712172    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2173    {2174      int bytesToCopy = GetDescriptorSize(update);2169    }21702171    int FindExistingUpdate(ZipEntry entry)2172    {2173      int result = -1;2174      string convertedName = GetTransformedFileName(entry.Name);  21752176      if ( bytesToCopy > 0 ) {2177        byte[] buffer = GetBuffer();21782179        while ( bytesToCopy > 0 ) {2180          int readSize = Math.Min(buffer.Length, bytesToCopy);21812182          int bytesRead = source.Read(buffer, 0, readSize);2183          if ( bytesRead > 0 ) {2184            dest.Write(buffer, 0, bytesRead);2185            bytesToCopy -= bytesRead;2186          }2187          else {2188            throw new ZipException("Unxpected end of stream");2189          }2190        }2191      }2192    }21932194    void CopyBytes(ZipUpdate update, Stream destination, Stream source,2195      long bytesToCopy, bool updateCrc)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 useful2181            // 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    }21942195    int FindExistingUpdate(string fileName)  2196    {2197      if ( destination == source ) {2198        throw new InvalidOperationException("Destination and source are the same");2199      }2197      int result = -1;21982199      string convertedName = GetTransformedFileName(fileName);  22002201      // NOTE: Compressed size is updated elsewhere.2202      var crc = new Crc32();2203      byte[] buffer = GetBuffer();2201      if (updateIndex_.ContainsKey(convertedName)) {2202        result = (int)updateIndex_[convertedName];2203      }  22042205      long targetBytes = bytesToCopy;2206      long totalBytesRead = 0;22072208      int bytesRead;2209      do {2210        int readSize = buffer.Length;22112212        if ( bytesToCopy < readSize ) {2213          readSize = (int)bytesToCopy;2214        }22152216        bytesRead = source.Read(buffer, 0, readSize);2217        if ( bytesRead > 0 ) {2218          if ( updateCrc ) {2219            crc.Update(buffer, 0, bytesRead);2220          }2221          destination.Write(buffer, 0, bytesRead);2222          bytesToCopy -= bytesRead;2223          totalBytesRead += bytesRead;2224        }2225      }2226      while ( (bytesRead > 0) && (bytesToCopy > 0) );22272228      if ( totalBytesRead != targetBytes ) {2229        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2230      }22312232      if ( updateCrc ) {2233        update.OutEntry.Crc = crc.Value;2234      }2235    }22362237    /// <summary>2238    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.2239    /// </summary>2240    /// <param name="update">The update to get the size for.</param>2241    /// <returns>The descriptor size, zero if there isnt one.</returns>2242    int GetDescriptorSize(ZipUpdate update)2243    {2244      int result = 0;2245      if ( (update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {2246        result = ZipConstants.DataDescriptorSize - 4;2247        if ( update.Entry.LocalHeaderRequiresZip64 ) {2248          result = ZipConstants.Zip64DataDescriptorSize - 4;2249        }2250      }2251      return result;2252    }2205      /*2206            // This is slow like the coming of the next ice age but takes less storage and may be useful2207            // 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       */22162217      return result;2218    }22192220    /// <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_;22282229      if (entry.IsCrypted == true) {2230        result = CreateAndInitEncryptionStream(result, entry);2231      }22322233      switch (entry.CompressionMethod) {2234        case CompressionMethod.Stored:2235          result = new UncompressedStream(result);2236          break;22372238        case CompressionMethod.Deflated:2239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));2240          dos.IsStreamOwner = false;2241          result = dos;2242          break;22432244        default:2245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2246      }2247      return result;2248    }22492250    void AddEntry(ZipFile workFile, ZipUpdate update)2251    {2252      Stream source = null;  22532254    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2255    {2256      int bytesToCopy = GetDescriptorSize(update);22572258      while ( bytesToCopy > 0 ) {2259        var readSize = (int)bytesToCopy;2260        byte[] buffer = GetBuffer();2254      if (update.Entry.IsFile) {2255        source = update.GetSource();22562257        if (source == null) {2258          source = updateDataSource_.GetSource(update.Entry, update.Filename);2259        }2260      }  22612262        stream.Position = sourcePosition;2263        int bytesRead = stream.Read(buffer, 0, readSize);2264        if ( bytesRead > 0 ) {2265          stream.Position = destinationPosition;2266          stream.Write(buffer, 0, bytesRead);2267          bytesToCopy -= bytesRead;2268          destinationPosition += bytesRead;2269          sourcePosition += bytesRead;2270        }2271        else {2272          throw new ZipException("Unxpected end of stream");2273        }2274      }2275    }22762277    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2278    {2279      long bytesToCopy = update.Entry.CompressedSize;22802281      // NOTE: Compressed size is updated elsewhere.2282      var crc = new Crc32();2283      byte[] buffer = GetBuffer();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          }22732274          workFile.WriteLocalEntryHeader(update);22752276          long dataStart = workFile.baseStream_.Position;22772278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {2279            CopyBytes(update, output, source, sourceStreamLength, true);2280          }22812282          long dataEnd = workFile.baseStream_.Position;2283          update.OutEntry.CompressedSize = dataEnd - dataStart;  22842285      long targetBytes = bytesToCopy;2286      long totalBytesRead = 0;22872288      int bytesRead;2289      do2290      {2291        int readSize = buffer.Length;22922293        if ( bytesToCopy < readSize ) {2294          readSize = (int)bytesToCopy;2295        }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      }22942295    }  22962297        stream.Position = sourcePosition;2298        bytesRead = stream.Read(buffer, 0, readSize);2299        if ( bytesRead > 0 ) {2300          if ( updateCrc ) {2301            crc.Update(buffer, 0, bytesRead);2302          }2303          stream.Position = destinationPosition;2304          stream.Write(buffer, 0, bytesRead);23052306          destinationPosition += bytesRead;2307          sourcePosition += bytesRead;2308          bytesToCopy -= bytesRead;2309          totalBytesRead += bytesRead;2310        }2311      }2312      while ( (bytesRead > 0) && (bytesToCopy > 0) );23132314      if ( totalBytesRead != targetBytes ) {2315        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2316      }23172318      if ( updateCrc ) {2319        update.OutEntry.Crc = crc.Value;2320      }2321    }23222323    int FindExistingUpdate(ZipEntry entry)2324    {2325      int result = -1;2326      string convertedName = GetTransformedFileName(entry.Name);23272328      if (updateIndex_.ContainsKey(convertedName)) {2329        result = (int)updateIndex_[convertedName];2330      }2331/*2332      // This is slow like the coming of the next ice age but takes less storage and may be useful2333      // for CF?2334      for (int index = 0; index < updates_.Count; ++index)2335      {2336        ZipUpdate zu = ( ZipUpdate )updates_[index];2337        if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&2338          (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {2339          result = index;2340          break;2341        }2342      }2343 */2344      return result;2345    }23462347    int FindExistingUpdate(string fileName)2348    {2349      int result = -1;23502351      string convertedName = GetTransformedFileName(fileName);23522353      if (updateIndex_.ContainsKey(convertedName)) {2354        result = (int)updateIndex_[convertedName];2355      }23562357/*2358      // This is slow like the coming of the next ice age but takes less storage and may be useful2359      // for CF?2360      for ( int index = 0; index < updates_.Count; ++index ) {2361        if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,2362          true, CultureInfo.InvariantCulture) == 0 ) {2363          result = index;2364          break;2365        }2366      }2367 */23682369      return result;2370    }23712372    /// <summary>2373    /// Get an output stream for the specified <see cref="ZipEntry"/>2374    /// </summary>2375    /// <param name="entry">The entry to get an output stream for.</param>2376    /// <returns>The output stream obtained for the entry.</returns>2377    Stream GetOutputStream(ZipEntry entry)2378    {2379      Stream result = baseStream_;2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)2298    {2299      workFile.WriteLocalEntryHeader(update);2300      long dataStart = workFile.baseStream_.Position;23012302      // 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      }23102311      long dataEnd = workFile.baseStream_.Position;2312      update.Entry.CompressedSize = dataEnd - dataStart;2313    }23142315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2316    {2317      bool skipOver = false || update.Entry.Offset == destinationPosition;23182319      if (!skipOver) {2320        baseStream_.Position = destinationPosition;2321        workFile.WriteLocalEntryHeader(update);2322        destinationPosition = baseStream_.Position;2323      }23242325      long sourcePosition = 0;23262327      const int NameLengthOffset = 26;23282329      // TODO: Add base for SFX friendly handling2330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;23312332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23332334      // 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();23382339      sourcePosition = baseStream_.Position + nameLength + extraLength;23402341      if (skipOver) {2342        if (update.OffsetBasedSize != -1)2343          destinationPosition += update.OffsetBasedSize;2344        else2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2346          // WinZip produces a warning on these entries:2347          // "caution: value of lrec.csize (compressed size) changed from ..."2348          destinationPosition +=2349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size2350            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    }23582359    void CopyEntry(ZipFile workFile, ZipUpdate update)2360    {2361      workFile.WriteLocalEntryHeader(update);23622363      if (update.Entry.CompressedSize > 0) {2364        const int NameLengthOffset = 26;23652366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;23672368        // TODO: This wont work for SFX files!2369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23702371        uint nameLength = ReadLEUshort();2372        uint extraLength = ReadLEUshort();23732374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);23752376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2377      }2378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);2379    }  23802381      if ( entry.IsCrypted == true ) {2382#if NETCF_1_02383        throw new ZipException("Encryption not supported for Compact Framework 1.0");2384#else2385        result = CreateAndInitEncryptionStream(result, entry);2386#endif2387      }23882389      switch ( entry.CompressionMethod ) {2390        case CompressionMethod.Stored:2391          result = new UncompressedStream(result);2392          break;23932394        case CompressionMethod.Deflated:2395          var dos = new DeflaterOutputStream(result, new Deflater(9, true));2396          dos.IsStreamOwner = false;2397          result = dos;2398          break;23992400        default:2401          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2402      }2403      return result;2404    }24052406    void AddEntry(ZipFile workFile, ZipUpdate update)2407    {2408      Stream source = null;24092410      if ( update.Entry.IsFile ) {2411        source = update.GetSource();24122413        if ( source == null ) {2414          source = updateDataSource_.GetSource(update.Entry, update.Filename);2415        }2416      }24172418      if ( source != null ) {2419        using ( source ) {2420          long sourceStreamLength = source.Length;2421          if ( update.OutEntry.Size < 0 ) {2422            update.OutEntry.Size = sourceStreamLength;2423          }2424          else {2425            // Check for errant entries.2426            if ( update.OutEntry.Size != sourceStreamLength ) {2427              throw new ZipException("Entry size/stream size mismatch");2428            }2429          }24302431          workFile.WriteLocalEntryHeader(update);24322433          long dataStart = workFile.baseStream_.Position;24342435          using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {2436            CopyBytes(update, output, source, sourceStreamLength, true);2437          }24382439          long dataEnd = workFile.baseStream_.Position;2440          update.OutEntry.CompressedSize = dataEnd - dataStart;24412442          if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor)2443          {2444            var helper = new ZipHelperStream(workFile.baseStream_);2445            helper.WriteDataDescriptor(update.OutEntry);2446          }2447        }2381    void Reopen(Stream source)2382    {2383      if (source == null) {2384        throw new ZipException("Failed to reopen archive - no source");2385      }23862387      isNewArchive_ = false;2388      baseStream_ = source;2389      ReadEntries();2390    }23912392    void Reopen()2393    {2394      if (Name == null) {2395        throw new InvalidOperationException("Name is not known cannot Reopen");2396      }23972398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));2399    }24002401    void UpdateCommentOnly()2402    {2403      long baseLength = baseStream_.Length;24042405      ZipHelperStream updateFile = null;24062407      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {2408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);2409        updateFile = new ZipHelperStream(copyStream);2410        updateFile.IsStreamOwner = true;24112412        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 doesnt2418          // 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.24212422          // 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      }24312432      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        }24392440        const int CentralHeaderCommentSizeOffset = 16;2441        updateFile.Position += CentralHeaderCommentSizeOffset;24422443        byte[] rawComment = newComment_.RawComment;24442445        updateFile.WriteLEShort(rawComment.Length);2446        updateFile.Write(rawComment, 0, rawComment.Length);2447        updateFile.SetLength(updateFile.Position);  2448      }2449      else {2450        workFile.WriteLocalEntryHeader(update);2451        update.OutEntry.CompressedSize = 0;2452      }24532454    }24552456    void ModifyEntry(ZipFile workFile, ZipUpdate update)2457    {2458      workFile.WriteLocalEntryHeader(update);2459      long dataStart = workFile.baseStream_.Position;24602461      // TODO: This is slow if the changes don't effect the data!!2462      if ( update.Entry.IsFile && (update.Filename != null) ) {2463        using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {2464          using ( Stream source = this.GetInputStream(update.Entry) ) {2465            CopyBytes(update, output, source, source.Length, true);2466          }2467        }2468      }24692470      long dataEnd = workFile.baseStream_.Position;2471      update.Entry.CompressedSize = dataEnd - dataStart;2472    }24732474    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2475    {2476      bool skipOver = false || update.Entry.Offset == destinationPosition;24492450      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {2451        Reopen(archiveStorage_.ConvertTemporaryToFinal());2452      } else {2453        ReadEntries();2454      }2455    }24562457    /// <summary>2458    /// Class used to sort updates.2459    /// </summary>2460    class UpdateComparer : IComparer2461    {2462      /// <summary>2463      /// Compares two objects and returns a value indicating whether one is2464      /// 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;24752476        int result;  24772478      if ( !skipOver ) {2479        baseStream_.Position = destinationPosition;2480        workFile.WriteLocalEntryHeader(update);2481        destinationPosition = baseStream_.Position;2482      }24832484      long sourcePosition = 0;24852486      const int NameLengthOffset = 26;24872488      // TODO: Add base for SFX friendly handling2489      long entryDataOffset = update.Entry.Offset + NameLengthOffset;24902491      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);24922493      // Clumsy way of handling retrieving the original name and extra data length for now.2494      // TODO: Stop re-reading name and data length in CopyEntryDirect.2495      uint nameLength = ReadLEUshort();2496      uint extraLength = ReadLEUshort();24972498      sourcePosition = baseStream_.Position + nameLength + extraLength;24992500      if (skipOver) {2501        if (update.OffsetBasedSize != -1)2502          destinationPosition += update.OffsetBasedSize;2503        else2504          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2505          // WinZip produces a warning on these entries:2506          // "caution: value of lrec.csize (compressed size) changed from ..."2507          destinationPosition +=2508            (sourcePosition - entryDataOffset) + NameLengthOffset +  // Header size2509            update.Entry.CompressedSize + GetDescriptorSize(update);2510      }2511      else {2512        if ( update.Entry.CompressedSize > 0 ) {2513          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition );2514        }2515        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);2516      }2517    }25182519    void CopyEntry(ZipFile workFile, ZipUpdate update)2520    {2521      workFile.WriteLocalEntryHeader(update);25222523      if ( update.Entry.CompressedSize > 0 ) {2524        const int NameLengthOffset = 26;25252526        long entryDataOffset = update.Entry.Offset + NameLengthOffset;25272528        // TODO: This wont work for SFX files!2529        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);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;24892490          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    }25052506    void RunUpdates()2507    {2508      long sizeEntries = 0;2509      long endOfStream = 0;2510      bool directUpdate = false;2511      long destinationPosition = 0; // NOT SFX friendly25122513      ZipFile workFile;25142515      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;25232524        // 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;  25302531        uint nameLength = ReadLEUshort();2532        uint extraLength = ReadLEUshort();25332534        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);2531        if (key != null) {2532          workFile.key = (byte[])key.Clone();2533        }2534      }  25352536        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2537      }2538      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);2539    }25402541    void Reopen(Stream source)2542    {2543      if ( source == null ) {2544        throw new ZipException("Failed to reopen archive - no source");2545      }25462547      isNewArchive_ = false;2548      baseStream_ = source;2549      ReadEntries();2550    }25512552    void Reopen()2553    {2554      if (Name == null) {2555        throw new InvalidOperationException("Name is not known cannot Reopen");2556      }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;25472548              case UpdateCommand.Modify:2549                // TODO: Direct modifying of an entry will take some legwork.2550                ModifyEntry(workFile, update);2551                break;25522553              case UpdateCommand.Add:2554                if (!IsNewArchive && directUpdate) {2555                  workFile.baseStream_.Position = destinationPosition;2556                }  25572558      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));2559    }25602561    void UpdateCommentOnly()2562    {2563      long baseLength = baseStream_.Length;25642565      ZipHelperStream updateFile = null;25662567      if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {2568        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);2569        updateFile = new ZipHelperStream(copyStream);2570        updateFile.IsStreamOwner = true;2558                AddEntry(workFile, update);25592560                if (directUpdate) {2561                  destinationPosition = workFile.baseStream_.Position;2562                }2563                break;2564            }2565          }2566        }25672568        if (!IsNewArchive && directUpdate) {2569          workFile.baseStream_.Position = destinationPosition;2570        }  25712572        baseStream_.Close();2573        baseStream_ = null;2574      }2575      else {2576        if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {2577          // TODO: archiveStorage wasnt originally intended for this use.2578          // Need to revisit this to tidy up handling as archive storage currently doesnt2579          // handle the original stream well.2580          // The problem is when using an existing zip archive with an in memory archive storage.2581          // The open stream wont support writing but the memory storage should open the same file not an in memory one.25822583          // Need to tidy up the archive storage interface and contract basically.2584          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);2585          updateFile = new ZipHelperStream(baseStream_);2586        }2587        else {2588          baseStream_.Close();2589          baseStream_ = null;2590          updateFile = new ZipHelperStream(Name);2591        }2592      }25932594      using ( updateFile ) {2595        long locatedCentralDirOffset =2596          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,2597                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);2598        if ( locatedCentralDirOffset < 0 ) {2599          throw new ZipException("Cannot find central directory");2600        }26012602        const int CentralHeaderCommentSizeOffset = 16;2603        updateFile.Position += CentralHeaderCommentSizeOffset;26042605        byte[] rawComment = newComment_.RawComment;26062607        updateFile.WriteLEShort(rawComment.Length);2608        updateFile.Write(rawComment, 0, rawComment.Length);2609        updateFile.SetLength(updateFile.Position);2610      }26112612      if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {2613        Reopen(archiveStorage_.ConvertTemporaryToFinal());2614      }2615      else {2616        ReadEntries();2617      }2618    }26192620    /// <summary>2621    /// Class used to sort updates.2622    /// </summary>2623    class UpdateComparer : IComparer2624    {2625      /// <summary>2626      /// Compares two objects and returns a value indicating whether one is2627      /// less than, equal to or greater than the other.2628      /// </summary>2629      /// <param name="x">First object to compare</param>2630      /// <param name="y">Second object to compare.</param>2631      /// <returns>Compare result.</returns>2632      public int Compare(2633        object x,2634        object y)2635      {2636        var zx = x as ZipUpdate;2637        var zy = y as ZipUpdate;26382639        int result;26402641        if (zx == null) {2642          if (zy == null) {2643            result = 0;2644          }2645          else {2646            result = -1;2647          }2648        }2649        else if (zy == null) {2650          result = 1;2651        }2652        else {2653          int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;2654          int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;26552656          result = xCmdValue - yCmdValue;2657          if (result == 0) {2658            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;2659            if (offsetDiff < 0) {2660              result = -1;2661            }2662            else if (offsetDiff == 0) {2663              result = 0;2664            }2665            else {2666              result = 1;2667            }2668          }2669        }2670        return result;2671      }2672    }26732674    void RunUpdates()2675    {2676      long sizeEntries = 0;2677      long endOfStream = 0;2678      bool directUpdate = false;2679      long destinationPosition = 0; // NOT SFX friendly26802681      ZipFile workFile;2572        long centralDirOffset = workFile.baseStream_.Position;25732574        foreach (ZipUpdate update in updates_) {2575          if (update != null) {2576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2577          }2578        }25792580        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        }25842585        endOfStream = workFile.baseStream_.Position;25862587        // 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            }25962597            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      }26162617      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    }26272628    void CheckUpdating()2629    {2630      if (updates_ == null) {2631        throw new InvalidOperationException("BeginUpdate has not been called");2632      }2633    }26342635    #endregion26362637    #region ZipUpdate class2638    /// <summary>2639    /// Represents a pending update to a Zip file.2640    /// </summary>2641    class ZipUpdate2642    {2643      #region Constructors2644      public ZipUpdate(string fileName, ZipEntry entry)2645      {2646        command_ = UpdateCommand.Add;2647        entry_ = entry;2648        filename_ = fileName;2649      }26502651      [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      }26592660      [Obsolete]2661      public ZipUpdate(string fileName, string entryName)2662        : this(fileName, entryName, CompressionMethod.Deflated)2663      {2664        // Do nothing.2665      }26662667      [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      }26752676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2677      {2678        command_ = UpdateCommand.Add;2679        entry_ = entry;2680        dataSource_ = dataSource;2681      }  26822683      if ( IsNewArchive ) {2684        workFile = this;2685        workFile.baseStream_.Position = 0;2686        directUpdate = true;2687      }2688      else if ( archiveStorage_.UpdateMode == FileUpdateMode.Direct ) {2689        workFile = this;2690        workFile.baseStream_.Position = 0;2691        directUpdate = true;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      }  26922693        // Sort the updates by offset within copies/modifies, then adds.2694        // This ensures that data required by copies will not be overwritten.2695        updates_.Sort(new UpdateComparer());2696      }2697      else {2698        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());2699        workFile.UseZip64 = UseZip64;27002701        if (key != null) {2702          workFile.key = (byte[])key.Clone();2703        }2704      }27052706      try {2707        foreach ( ZipUpdate update in updates_ ) {2708          if (update != null) {2709            switch (update.Command) {2710              case UpdateCommand.Copy:2711                if (directUpdate) {2712                  CopyEntryDirect(workFile, update, ref destinationPosition);2713                }2714                else {2715                  CopyEntry(workFile, update);2716                }2717                break;2693      public ZipUpdate(UpdateCommand command, ZipEntry entry)2694      {2695        command_ = command;2696        entry_ = (ZipEntry)entry.Clone();2697      }269826992700      /// <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      #endregion27102711      /// <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      }  27182719              case UpdateCommand.Modify:2720                // TODO: Direct modifying of an entry will take some legwork.2721                ModifyEntry(workFile, update);2722                break;27232724              case UpdateCommand.Add:2725                if (!IsNewArchive && directUpdate) {2726                  workFile.baseStream_.Position = destinationPosition;2727                }27282729                AddEntry(workFile, update);27302731                if (directUpdate) {2732                  destinationPosition = workFile.baseStream_.Position;2733                }2734                break;2735            }2736          }2737        }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          }27272728          return outEntry_;2729        }2730      }27312732      /// <summary>2733      /// Get the command for this update.2734      /// </summary>2735      public UpdateCommand Command {2736        get { return command_; }2737      }  27382739        if ( !IsNewArchive && directUpdate ) {2740          workFile.baseStream_.Position = destinationPosition;2741        }27422743        long centralDirOffset = workFile.baseStream_.Position;27442745        foreach ( ZipUpdate update in updates_ ) {2746          if (update != null) {2747            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2748          }2749        }27502751        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);2752        using ( ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_) ) {2753          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);2754        }27552756        endOfStream = workFile.baseStream_.Position;27572758        // And now patch entries...2759        foreach ( ZipUpdate update in updates_ ) {2760          if (update != null)2761          {2762            // If the size of the entry is zero leave the crc as 0 as well.2763            // The calculated crc will be all bits on...2764            if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {2765              workFile.baseStream_.Position = update.CrcPatchOffset;2766              workFile.WriteLEInt((int)update.OutEntry.Crc);2767            }27682769            if (update.SizePatchOffset > 0) {2770              workFile.baseStream_.Position = update.SizePatchOffset;2771              if (update.OutEntry.LocalHeaderRequiresZip64) {2772                workFile.WriteLeLong(update.OutEntry.Size);2773                workFile.WriteLeLong(update.OutEntry.CompressedSize);2774              }2775              else {2776                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);2777                workFile.WriteLEInt((int)update.OutEntry.Size);2778              }2779            }2780          }2781        }2782      }2783      catch {2784        workFile.Close();2785        if (!directUpdate && (workFile.Name != null)) {2786          File.Delete(workFile.Name);2787        }2788        throw;2789      }27902791      if (directUpdate) {2792        workFile.baseStream_.SetLength(endOfStream);2793        workFile.baseStream_.Flush();2794        isNewArchive_ = false;2795        ReadEntries();2796      }2797      else {2798        baseStream_.Close();2799        Reopen(archiveStorage_.ConvertTemporaryToFinal());2800      }2801    }28022803    void CheckUpdating()2804    {2805      if ( updates_ == null ) {2806        throw new InvalidOperationException("BeginUpdate has not been called");2807      }2808    }28092810    #endregion28112812    #region ZipUpdate class2813    /// <summary>2814    /// Represents a pending update to a Zip file.2815    /// </summary>2816    class ZipUpdate2817    {2818      #region Constructors2819      public ZipUpdate(string fileName, ZipEntry entry)2820      {2821        command_ = UpdateCommand.Add;2822        entry_ = entry;2823        filename_ = fileName;2824      }28252826      [Obsolete]2827      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)2828      {2829        command_ = UpdateCommand.Add;2830        entry_ = new ZipEntry(entryName);2831        entry_.CompressionMethod = compressionMethod;2832        filename_ = fileName;2833      }28342835      [Obsolete]2836      public ZipUpdate(string fileName, string entryName)2837        : this(fileName, entryName, CompressionMethod.Deflated)2838      {2839        // Do nothing.2840      }28412842      [Obsolete]2843      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)2844      {2845        command_ = UpdateCommand.Add;2846        entry_ = new ZipEntry(entryName);2847        entry_.CompressionMethod = compressionMethod;2848        dataSource_ = dataSource;2849      }28502851      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2852      {2853        command_ = UpdateCommand.Add;2854        entry_ = entry;2855        dataSource_ = dataSource;2856      }28572858      public ZipUpdate(ZipEntry original, ZipEntry updated)2859      {2860        throw new ZipException("Modify not currently supported");2861      /*2862        command_ = UpdateCommand.Modify;2863        entry_ = ( ZipEntry )original.Clone();2864        outEntry_ = ( ZipEntry )updated.Clone();2865      */2866      }28672868      public ZipUpdate(UpdateCommand command, ZipEntry entry)2869      {2870        command_ = command;2871        entry_ = ( ZipEntry )entry.Clone();2872      }28732739      /// <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      }27452746      /// <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      }27532754      /// <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      }27612762      /// <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      }27702771      public Stream GetSource()2772      {2773        Stream result = null;2774        if (dataSource_ != null) {2775          result = dataSource_.GetSource();2776        }27772778        return result;2779      }27802781      #region Instance Fields2782      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      #endregion2791    }27922793    #endregion2794    #endregion27952796    #region Disposing27972798    #region IDisposable Members2799    void IDisposable.Dispose()2800    {2801      Close();2802    }2803    #endregion28042805    void DisposeInternal(bool disposing)2806    {2807      if (!isDisposed_) {2808        isDisposed_ = true;2809        entries_ = new ZipEntry[0];28102811        if (IsStreamOwner && (baseStream_ != null)) {2812          lock (baseStream_) {2813            baseStream_.Close();2814          }2815        }28162817        PostUpdateCleanup();2818      }2819    }28202821    /// <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    }28302831    #endregion28322833    #region Internal routines2834    #region Reading2835    /// <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 prematurely2841    /// </exception>2842    ushort ReadLEUshort()2843    {2844      int data1 = baseStream_.ReadByte();28452846      if (data1 < 0) {2847        throw new EndOfStreamException("End of stream");2848      }28492850      int data2 = baseStream_.ReadByte();28512852      if (data2 < 0) {2853        throw new EndOfStreamException("End of stream");2854      }285528562857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));2858    }28592860    /// <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 prematurely2869    /// </exception>2870    uint ReadLEUint()2871    {2872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));2873    }  28742875      /// <summary>2876      /// Copy an existing entry.2877      /// </summary>2878      /// <param name="entry">The existing entry to copy.</param>2879      public ZipUpdate(ZipEntry entry)2880        : this(UpdateCommand.Copy, entry)2881      {2882        // Do nothing.2883      }2884      #endregion28852886      /// <summary>2887      /// Get the <see cref="ZipEntry"/> for this update.2888      /// </summary>2889      /// <remarks>This is the source or original entry.</remarks>2890      public ZipEntry Entry2891      {2892        get { return entry_; }2893      }28942895      /// <summary>2896      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.2897      /// </summary>2898      public ZipEntry OutEntry2899      {2900        get {2901          if ( outEntry_ == null ) {2902            outEntry_ = (ZipEntry)entry_.Clone();2903          }29042905          return outEntry_;2906        }2907      }2875    ulong ReadLEUlong()2876    {2877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);2878    }28792880    #endregion2881    // 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    }28882889    /// <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 found2897    /// </exception>2898    void ReadEntries()2899    {2900      // Search for the End Of Central Directory.  When a zip comment is2901      // present the directory will start earlier2902      //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 files2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then2906      // this could be invalid.2907      // Could also speed this up by reading memory in larger blocks.  29082909      /// <summary>2910      /// Get the command for this update.2911      /// </summary>2912      public UpdateCommand Command2913      {2914        get { return command_; }2915      }29162917      /// <summary>2918      /// Get the filename if any for this update.  Null if none exists.2919      /// </summary>2920      public string Filename2921      {2922        get { return filename_; }2923      }29242925      /// <summary>2926      /// Get/set the location of the size patch for this update.2927      /// </summary>2928      public long SizePatchOffset2929      {2930        get { return sizePatchOffset_; }2931        set { sizePatchOffset_ = value; }2932      }29332934      /// <summary>2935      /// Get /set the location of the crc patch for this update.2936      /// </summary>2937      public long CrcPatchOffset2938      {2939        get { return crcPatchOffset_; }2940        set { crcPatchOffset_ = value; }2941      }29422943      /// <summary>2944      /// Get/set the size calculated by offset.2945      /// Specifically, the difference between this and next entry's starting offset.2946      /// </summary>2947      public long OffsetBasedSize2948      {2949        get { return _offsetBasedSize; }2950        set { _offsetBasedSize = value; }2951      }29522953      public Stream GetSource()2954      {2955        Stream result = null;2956        if ( dataSource_ != null ) {2957          result = dataSource_.GetSource();2958        }29592960        return result;2961      }29622963      #region Instance Fields2964      ZipEntry entry_;2965      ZipEntry outEntry_;2966      UpdateCommand command_;2967      IStaticDataSource dataSource_;2968      string filename_;2969      long sizePatchOffset_ = -1;2970      long crcPatchOffset_ = -1;2971      long _offsetBasedSize = -1;2972      #endregion2973    }29742975    #endregion2976    #endregion29772978    #region Disposing29792980    #region IDisposable Members2981    void IDisposable.Dispose()2982    {2983      Close();2984    }2985    #endregion29862987    void DisposeInternal(bool disposing)2988    {2989      if ( !isDisposed_ ) {2990        isDisposed_ = true;2991        entries_ = new ZipEntry[0];29922993        if ( IsStreamOwner && (baseStream_ != null) ) {2994          lock(baseStream_) {2995            baseStream_.Close();2996          }2997        }2909      if (baseStream_.CanSeek == false) {2910        throw new ZipException("ZipFile stream must be seekable");2911      }29122913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,2914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);29152916      if (locatedEndOfCentralDir < 0) {2917        throw new ZipException("Cannot find central directory");2918      }29192920      // Read end of central directory record2921      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();29282929      if (commentSize > 0) {2930        byte[] comment = new byte[commentSize];29312932        StreamUtils.ReadFully(baseStream_, comment);2933        comment_ = ZipConstants.ConvertToString(comment);2934      } else {2935        comment_ = string.Empty;2936      }29372938      bool isZip64 = false;29392940      // 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;29482949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 2950        if (offset < 0) {2951          throw new ZipException("Cannot find Zip64 locator");2952        }29532954        // number of the disk with the start of the zip64 end of central directory 4 bytes2955        // relative offset of the zip64 end of central directory record 8 bytes2956        // total number of disks 4 bytes2957        ReadLEUint(); // startDisk64 is not currently used2958        ulong offset64 = ReadLEUlong();2959        uint totalDisks = ReadLEUint();29602961        baseStream_.Position = (long)offset64;2962        long sig64 = ReadLEUint();29632964        if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {2965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));2966        }29672968        // 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();29782979        // NOTE: zip64 extensible data sector (variable size) is ignored.2980      }29812982      entries_ = new ZipEntry[entriesForThisDisk];29832984      // SFX/embedded support, find the offset of the first entry vis the start of the stream2985      // 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 offsets2988      // 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      }29962997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);  29982999        PostUpdateCleanup();3000      }3001    }30023003    /// <summary>3004    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.3005    /// </summary>3006    /// <param name="disposing">true to release both managed and unmanaged resources;3007    /// false to release only unmanaged resources.</param>3008    protected virtual void Dispose(bool disposing)3009    {3010      DisposeInternal(disposing);3011    }30123013    #endregion30143015    #region Internal routines3016    #region Reading3017    /// <summary>3018    /// Read an unsigned short in little endian byte order.3019    /// </summary>3020    /// <returns>Returns the value read.</returns>3021    /// <exception cref="EndOfStreamException">3022    /// The stream ends prematurely3023    /// </exception>3024    ushort ReadLEUshort()3025    {3026      int data1 = baseStream_.ReadByte();30273028      if ( data1 < 0 ) {3029        throw new EndOfStreamException("End of stream");3030      }30313032      int data2 = baseStream_.ReadByte();30333034      if ( data2 < 0 ) {3035        throw new EndOfStreamException("End of stream");3036      }303730383039      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));3040    }30413042    /// <summary>3043    /// Read a uint in little endian byte order.3044    /// </summary>3045    /// <returns>Returns the value read.</returns>3046    /// <exception cref="IOException">3047    /// An i/o error occurs.3048    /// </exception>3049    /// <exception cref="System.IO.EndOfStreamException">3050    /// The file ends prematurely3051    /// </exception>3052    uint ReadLEUint()3053    {3054      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));3055    }30563057    ulong ReadLEUlong()3058    {3059      return ReadLEUint() | ((ulong)ReadLEUint() << 32);3060    }30613062    #endregion3063    // NOTE this returns the offset of the first byte after the signature.3064    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)3065    {3066      using ( ZipHelperStream les = new ZipHelperStream(baseStream_) ) {3067        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);3068      }3069    }30703071    /// <summary>3072    /// Search for and read the central directory of a zip file filling the entries array.3073    /// </summary>3074    /// <exception cref="System.IO.IOException">3075    /// An i/o error occurs.3076    /// </exception>3077    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3078    /// The central directory is malformed or cannot be found3079    /// </exception>3080    void ReadEntries()3081    {3082      // Search for the End Of Central Directory.  When a zip comment is3083      // present the directory will start earlier3084      //3085      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.3086      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files3087      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then3088      // this could be invalid.3089      // Could also speed this up by reading memory in larger blocks.2999      for (ulong i = 0; i < entriesForThisDisk; i++) {3000        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {3001          throw new ZipException("Wrong Central Directory signature");3002        }30033004        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();30153016        int diskStartNo = ReadLEUshort();  // Not currently used3017        int internalAttributes = ReadLEUshort();  // Not currently used30183019        uint externalAttributes = ReadLEUint();3020        long offset = ReadLEUint();30213022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];30233024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);3025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);30263027        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;30363037        if ((bitFlags & 8) == 0) {3038          entry.CryptoCheckValue = (byte)(crc >> 24);3039        } else {3040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3041        }30423043        if (extraLen > 0) {3044          byte[] extra = new byte[extraLen];3045          StreamUtils.ReadFully(baseStream_, extra);3046          entry.ExtraData = extra;3047        }30483049        entry.ProcessExtraData(false);30503051        if (commentLen > 0) {3052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);3053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3054        }30553056        entries_[i] = entry;3057      }3058    }30593060    /// <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 prematurely3068    /// </exception>3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3070    /// The local header signature is invalid, the entry and central header file name lengths are different3071    /// or the local and entry compression methods dont match3072    /// </exception>3073    long LocateEntry(ZipEntry entry)3074    {3075      return TestLocalHeader(entry, HeaderTest.Extract);3076    }30773078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3079    {3080      CryptoStream result = null;30813082      if ((entry.Version < ZipConstants.VersionStrongEncryption)3083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3084        var classicManaged = new PkzipClassicManaged();30853086        OnKeysRequired(entry.Name);3087        if (HaveKeys == false) {3088          throw new ZipException("No password available for encrypted stream");3089        }  30903091      if (baseStream_.CanSeek == false) {3092        throw new ZipException("ZipFile stream must be seekable");3093      }30943095      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,3096        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);30973098      if (locatedEndOfCentralDir < 0) {3099        throw new ZipException("Cannot find central directory");3100      }31013102      // Read end of central directory record3103      ushort thisDiskNumber           = ReadLEUshort();3104      ushort startCentralDirDisk      = ReadLEUshort();3105      ulong entriesForThisDisk        = ReadLEUshort();3106      ulong entriesForWholeCentralDir = ReadLEUshort();3107      ulong centralDirSize            = ReadLEUint();3108      long offsetOfCentralDir         = ReadLEUint();3109      uint commentSize                = ReadLEUshort();31103111      if ( commentSize > 0 ) {3112        byte[] comment = new byte[commentSize];31133114        StreamUtils.ReadFully(baseStream_, comment);3115        comment_ = ZipConstants.ConvertToString(comment);3116      }3117      else {3118        comment_ = string.Empty;3119      }31203121      bool isZip64 = false;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 bytes31093110          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      }31193120      return result;3121    }  31223123      // Check if zip64 header information is required.3124      if ( (thisDiskNumber == 0xffff) ||3125        (startCentralDirDisk == 0xffff) ||3126        (entriesForThisDisk == 0xffff) ||3127        (entriesForWholeCentralDir == 0xffff) ||3128        (centralDirSize == 0xffffffff) ||3129        (offsetOfCentralDir == 0xffffffff) ) {3130        isZip64 = true;31313132        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 3133        if ( offset < 0 ) {3134          throw new ZipException("Cannot find Zip64 locator");3135        }31363137        // number of the disk with the start of the zip64 end of central directory 4 bytes3138        // relative offset of the zip64 end of central directory record 8 bytes3139        // total number of disks 4 bytes3140        ReadLEUint(); // startDisk64 is not currently used3141        ulong offset64 = ReadLEUlong();3142        uint totalDisks = ReadLEUint();31433144        baseStream_.Position = (long)offset64;3145        long sig64 = ReadLEUint();31463147        if ( sig64 != ZipConstants.Zip64CentralFileHeaderSignature ) {3148          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));3149        }31503151        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.3152        ulong recordSize = ReadLEUlong();3153        int versionMadeBy = ReadLEUshort();3154        int versionToExtract = ReadLEUshort();3155        uint thisDisk = ReadLEUint();3156        uint centralDirDisk = ReadLEUint();3157        entriesForThisDisk = ReadLEUlong();3158        entriesForWholeCentralDir = ReadLEUlong();3159        centralDirSize = ReadLEUlong();3160        offsetOfCentralDir = (long)ReadLEUlong();31613162        // NOTE: zip64 extensible data sector (variable size) is ignored.3163      }31643165      entries_ = new ZipEntry[entriesForThisDisk];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();31293130        OnKeysRequired(entry.Name);3131        if (HaveKeys == false) {3132          throw new ZipException("No password available for encrypted stream");3133        }31343135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3136        // which doesnt do this.3137        result = new CryptoStream(new UncompressedStream(baseStream),3138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);31393140        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    }31483149    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    }31573158    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    }  31663167      // SFX/embedded support, find the offset of the first entry vis the start of the stream3168      // This applies to Zip files that are appended to the end of an SFX stub.3169      // Or are appended as a resource to an executable.3170      // Zip files created by some archivers have the offsets altered to reflect the true offsets3171      // and so dont require any adjustment here...3172      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?3173      if ( !isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize)) ) {3174        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);3175        if (offsetOfFirstEntry <= 0) {3176          throw new ZipException("Invalid embedded zip archive");3177        }3178      }31793180      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);31813182      for (ulong i = 0; i < entriesForThisDisk; i++) {3183        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {3184          throw new ZipException("Wrong Central Directory signature");3185        }3167    #endregion31683169    #region Instance Fields3170    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_;31803181    // Default is dynamic which is not backwards compatible and can cause problems3182    // 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;  31863187        int versionMadeBy      = ReadLEUshort();3188        int versionToExtract   = ReadLEUshort();3189        int bitFlags           = ReadLEUshort();3190        int method             = ReadLEUshort();3191        uint dostime           = ReadLEUint();3192        uint crc               = ReadLEUint();3193        var csize             = (long)ReadLEUint();3194        var size              = (long)ReadLEUint();3195        int nameLen            = ReadLEUshort();3196        int extraLen           = ReadLEUshort();3197        int commentLen         = ReadLEUshort();31983199        int diskStartNo        = ReadLEUshort();  // Not currently used3200        int internalAttributes = ReadLEUshort();  // Not currently used3187    #region Zip Update Instance Fields3188    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    #endregion3200    #endregion  32013202        uint externalAttributes = ReadLEUint();3203        long offset             = ReadLEUint();32043205        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];32063207        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);3208        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);32093210        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);3211        entry.Crc = crc & 0xffffffffL;3212        entry.Size = size & 0xffffffffL;3213        entry.CompressedSize = csize & 0xffffffffL;3214        entry.Flags = bitFlags;3215        entry.DosTime = (uint)dostime;3216        entry.ZipFileIndex = (long)i;3217        entry.Offset = offset;3218        entry.ExternalFileAttributes = (int)externalAttributes;32193220        if ((bitFlags & 8) == 0) {3221          entry.CryptoCheckValue = (byte)(crc >> 24);3222        }3223        else {3224          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3225        }32263227        if (extraLen > 0) {3228          byte[] extra = new byte[extraLen];3229          StreamUtils.ReadFully(baseStream_, extra);3230          entry.ExtraData = extra;3231        }32323233        entry.ProcessExtraData(false);32343235        if (commentLen > 0) {3236          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);3237          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3238        }32393240        entries_[i] = entry;3241      }3242    }32433244    /// <summary>3245    /// Locate the data for a given entry.3246    /// </summary>3247    /// <returns>3248    /// The start offset of the data.3249    /// </returns>3250    /// <exception cref="System.IO.EndOfStreamException">3251    /// The stream ends prematurely3252    /// </exception>3253    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3254    /// The local header signature is invalid, the entry and central header file name lengths are different3255    /// or the local and entry compression methods dont match3256    /// </exception>3257    long LocateEntry(ZipEntry entry)3258    {3259      return TestLocalHeader(entry, HeaderTest.Extract);3260    }32613262#if !NETCF_1_03263    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3264    {3265      CryptoStream result = null;32663267      if ( (entry.Version < ZipConstants.VersionStrongEncryption)3268        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3269        var classicManaged = new PkzipClassicManaged();32703271        OnKeysRequired(entry.Name);3272        if (HaveKeys == false) {3273          throw new ZipException("No password available for encrypted stream");3274        }3202    #region Support Classes3203    /// <summary>3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3205    /// </summary>3206    class ZipString3207    {3208      #region Constructors3209      /// <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      }32183219      /// <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      #endregion32283229      /// <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      }32363237      /// <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      }32463247      /// <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      }32563257      /// <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      }32683269      void MakeTextAvailable()3270      {3271        if (comment_ == null) {3272          comment_ = ZipConstants.ConvertToString(rawComment_);3273        }3274      }  32753276        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);3277        CheckClassicPassword(result, entry);3278      }3279      else {3280#if !NET_1_1 && !NETCF_2_03281        if (entry.Version == ZipConstants.VERSION_AES) {3282          //3283          OnKeysRequired(entry.Name);3284          if (HaveKeys == false) {3285            throw new ZipException("No password available for AES encrypted stream");3286          }3287          int saltLen = entry.AESSaltLen;3288          byte[] saltBytes = new byte[saltLen];3289          int saltIn = baseStream.Read(saltBytes, 0, saltLen);3290          if (saltIn != saltLen)3291            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);3292          //3293          byte[] pwdVerifyRead = new byte[2];3294          baseStream.Read(pwdVerifyRead, 0, 2);3295          int blockSize = entry.AESKeySize / 8;  // bits to bytes32963297          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);3298          byte[] pwdVerifyCalc = decryptor.PwdVerifier;3299          if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])3300            throw new Exception("Invalid password for AES");3301          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);3302        }3303        else3304#endif3305        {3306          throw new ZipException("Decryption method not supported");3307        }3308      }33093310      return result;3311    }33123313    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)3314    {3315      CryptoStream result = null;3316      if ( (entry.Version < ZipConstants.VersionStrongEncryption)3317        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3318        var classicManaged = new PkzipClassicManaged();3276      void MakeBytesAvailable()3277      {3278        if (rawComment_ == null) {3279          rawComment_ = ZipConstants.ConvertToArray(comment_);3280        }3281      }32823283      /// <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      }32933294      #region Instance Fields3295      string comment_;3296      byte[] rawComment_;3297      bool isSourceString_;3298      #endregion3299    }33003301    /// <summary>3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3303    /// </summary>3304    class ZipEntryEnumerator : IEnumerator3305    {3306      #region Constructors3307      public ZipEntryEnumerator(ZipEntry[] entries)3308      {3309        array = entries;3310      }33113312      #endregion3313      #region IEnumerator Members3314      public object Current {3315        get {3316          return array[index];3317        }3318      }  33193320        OnKeysRequired(entry.Name);3321        if (HaveKeys == false) {3322          throw new ZipException("No password available for encrypted stream");3323        }3320      public void Reset()3321      {3322        index = -1;3323      }  33243325        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3326        // which doesnt do this.3327        result = new CryptoStream(new UncompressedStream(baseStream),3328          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);33293330        if ( (entry.Crc < 0) || (entry.Flags & 8) != 0) {3331          WriteEncryptionHeader(result, entry.DosTime << 16);3332        }3333        else {3334          WriteEncryptionHeader(result, entry.Crc);3335        }3336      }3337      return result;3338    }33393340    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)3325      public bool MoveNext()3326      {3327        return (++index < array.Length);3328      }3329      #endregion3330      #region Instance Fields3331      ZipEntry[] array;3332      int index = -1;3333      #endregion3334    }33353336    /// <summary>3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3338    /// to and flush, but cannot read, seek or do anything else to.3339    /// </summary>3340    class UncompressedStream : Stream  3341    {3342      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];3343      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);3344      if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {3345        throw new ZipException("Invalid password");3342      #region Constructors3343      public UncompressedStream(Stream baseStream)3344      {3345        baseStream_ = baseStream;  3346      }3347    }3348#endif33473348      #endregion  33493350    static void WriteEncryptionHeader(Stream stream, long crcValue)3351    {3352      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];3353      var rnd = new Random();3354      rnd.NextBytes(cryptBuffer);3355      cryptBuffer[11] = (byte)(crcValue >> 24);3356      stream.Write(cryptBuffer, 0, cryptBuffer.Length);3357    }33583359    #endregion33603361    #region Instance Fields3362    bool       isDisposed_;3363    string     name_;3364    string     comment_;3365    string     rawPassword_;3366    Stream     baseStream_;3367    bool       isStreamOwner;3368    long       offsetOfFirstEntry;3369    ZipEntry[] entries_;3370    byte[] key;3371    bool isNewArchive_;33723373    // Default is dynamic which is not backwards compatible and can cause problems3374    // with XP's built in compression which cant read Zip64 archives.3375    // However it does avoid the situation were a large file is added and cannot be completed correctly.3376    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.3377    UseZip64 useZip64_ = UseZip64.Dynamic ;33783379    #region Zip Update Instance Fields3380    ArrayList updates_;3381    long updateCount_; // Count is managed manually as updates_ can contain nulls!3382    Hashtable updateIndex_;3383    IArchiveStorage archiveStorage_;3384    IDynamicDataSource updateDataSource_;3385    bool contentsEdited_;3386    int bufferSize_ = DefaultBufferSize;3387    byte[] copyBuffer_;3388    ZipString newComment_;3389    bool commentEdited_;3390    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();3391    #endregion3392    #endregion33933394    #region Support Classes3395    /// <summary>3396    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3397    /// </summary>3398    class ZipString3399    {3400      #region Constructors3401      /// <summary>3402      /// Initialise a <see cref="ZipString"/> with a string.3403      /// </summary>3404      /// <param name="comment">The textual string form.</param>3405      public ZipString(string comment)3406      {3407        comment_ = comment;3408        isSourceString_ = true;3409      }34103411      /// <summary>3412      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.3413      /// </summary>3414      /// <param name="rawString"></param>3415      public ZipString(byte[] rawString)3416      {3417        rawComment_ = rawString;3418      }3419      #endregion34203421      /// <summary>3422      /// Get a value indicating the original source of data for this instance.3423      /// True if the source was a string; false if the source was binary data.3424      /// </summary>3425      public bool IsSourceString3426      {3427        get { return isSourceString_; }3428      }34293430      /// <summary>3431      /// Get the length of the comment when represented as raw bytes.3432      /// </summary>3433      public int RawLength3434      {3435        get {3436          MakeBytesAvailable();3437          return rawComment_.Length;3438        }3439      }34403441      /// <summary>3442      /// Get the comment in its 'raw' form as plain bytes.3443      /// </summary>3444      public byte[] RawComment3445      {3446        get {3447          MakeBytesAvailable();3448          return (byte[])rawComment_.Clone();3449        }3450      }34513452      /// <summary>3453      /// Reset the comment to its initial state.3454      /// </summary>3455      public void Reset()3456      {3457        if ( isSourceString_ ) {3458          rawComment_ = null;3459        }3460        else {3461          comment_ = null;3462        }3463      }34643465      void MakeTextAvailable()3466      {3467        if ( comment_ == null ) {3468          comment_ = ZipConstants.ConvertToString(rawComment_);3469        }3470      }34713472      void MakeBytesAvailable()3473      {3474        if ( rawComment_ == null ) {3475          rawComment_ = ZipConstants.ConvertToArray(comment_);3476        }3477      }34783479      /// <summary>3480      /// Implicit conversion of comment to a string.3481      /// </summary>3482      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>3483      /// <returns>The textual equivalent for the input value.</returns>3484      static public implicit operator string(ZipString zipString)3485      {3486        zipString.MakeTextAvailable();3487        return zipString.comment_;3488      }34893490      #region Instance Fields3491      string comment_;3492      byte[] rawComment_;3493      bool isSourceString_;3494      #endregion3495    }34963497    /// <summary>3498    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3499    /// </summary>3500    class ZipEntryEnumerator : IEnumerator3501    {3502      #region Constructors3503      public ZipEntryEnumerator(ZipEntry[] entries)3504      {3505        array = entries;3506      }35073508      #endregion3509      #region IEnumerator Members3510      public object Current3511      {3512        get {3513          return array[index];3514        }3515      }35163517      public void Reset()3518      {3519        index = -1;3520      }35213522      public bool MoveNext()3523      {3524        return (++index < array.Length);3525      }3526      #endregion3527      #region Instance Fields3528      ZipEntry[] array;3529      int index = -1;3530      #endregion3531    }35323533    /// <summary>3534    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3535    /// to and flush, but cannot read, seek or do anything else to.3536    /// </summary>3537    class UncompressedStream : Stream3538    {3539      #region Constructors3540      public UncompressedStream(Stream baseStream)3541      {3542        baseStream_ = baseStream;3543      }35443545      #endregion35463547      /// <summary>3548      /// Close this stream instance.3549      /// </summary>3550      public override void Close()3551      {3552        // Do nothing3553      }35543555      /// <summary>3556      /// Gets a value indicating whether the current stream supports reading.3557      /// </summary>3558      public override bool CanRead3559      {3560        get {3561          return false;3562        }3563      }35643565      /// <summary>3566      /// Write any buffered data to underlying storage.3567      /// </summary>3568      public override void Flush()3569      {3570        baseStream_.Flush();3571      }35723573      /// <summary>3574      /// Gets a value indicating whether the current stream supports writing.3575      /// </summary>3576      public override bool CanWrite3577      {3578        get {3579          return baseStream_.CanWrite;3580        }3581      }35823583      /// <summary>3584      /// Gets a value indicating whether the current stream supports seeking.3585      /// </summary>3586      public override bool CanSeek3587      {3588        get {3589          return false;3590        }3591      }35923593      /// <summary>3594      /// Get the length in bytes of the stream.3595      /// </summary>3596      public override long Length3597      {3598        get {3599          return 0;3600        }3601      }36023603      /// <summary>3604      /// Gets or sets the position within the current stream.3605      /// </summary>3606      public override long Position3607      {3608        get  {3609          return baseStream_.Position;3610        }3611                set {3612                    throw new NotImplementedException();3613                }3614            }36153616            /// <summary>3617            /// Reads a sequence of bytes from the current stream and advances the position within the stream by the num3618            /// </summary>3619            /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte3620            /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from t3621            /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3622            /// <returns>3623            /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if t3624            /// </returns>3625            /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer lengt3626            /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </ex3627            /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3628            /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3629            /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3630            /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3631            public override int Read(byte[] buffer, int offset, int count)3632      {3633        return 0;3634      }36353636      /// <summary>3637      /// Sets the position within the current stream.3638      /// </summary>3639      /// <param name="offset">A byte offset relative to the origin parameter.</param>3640      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3641      /// <returns>3642      /// The new position within the current stream.3643      /// </returns>3644      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3645      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3646      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3647      public override long Seek(long offset, SeekOrigin origin)3648      {3649        return 0;3650      }36513652      /// <summary>3653      /// Sets the length of the current stream.3654      /// </summary>3655      /// <param name="value">The desired length of the current stream in bytes.</param>3656      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3350      /// <summary>3351      /// Close this stream instance.3352      /// </summary>3353      public override void Close()3354      {3355        // Do nothing3356      }33573358      /// <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      }33663367      /// <summary>3368      /// Write any buffered data to underlying storage.3369      /// </summary>3370      public override void Flush()3371      {3372        baseStream_.Flush();3373      }33743375      /// <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      }33833384      /// <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      }33923393      /// <summary>3394      /// Get the length in bytes of the stream.3395      /// </summary>3396      public override long Length {3397        get {3398          return 0;3399        }3400      }34013402      /// <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      }34133414      /// <summary>3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3416      /// </summary>3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3419      /// <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 ma3422      /// </returns>3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3425      /// <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      }34333434      /// <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 is3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3445      public override long Seek(long offset, SeekOrigin origin)3446      {3447        return 0;3448      }34493450      /// <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 as3455      /// <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. </exceptio3457      public override void SetLength(long value)3458      {3459      }34603461      /// <summary>3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3463      /// </summary>3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3466      /// <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. </exceptio3470      /// <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      }34773478      readonly34793480      #region Instance Fields3481      Stream baseStream_;3482      #endregion3483    }34843485    /// <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 : Stream3490    {3491      #region Constructors3492      /// <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;35023503        // Although this is the only time the zipfile is used3504        // keeping a reference here prevents premature closure of3505        // this zip file and thus the baseStream_.35063507        // Code like this will cause apparently random failures depending3508        // 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      #endregion35193520      /// <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        }35303531        lock (baseStream_) {3532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);3533          return baseStream_.ReadByte();3534        }3535      }35363537      /// <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      }35473548      /// <summary>3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3550      /// </summary>3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3553      /// <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 ma3556      /// </returns>3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3559      /// <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 Seek3573          // (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      }35843585      /// <summary>3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3587      /// </summary>3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3590      /// <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. </exceptio3594      /// <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      }36013602      /// <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 as3607      /// <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. </exceptio3609      public override void SetLength(long value)3610      {3611        throw new NotSupportedException();3612      }36133614      /// <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 is3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3625      public override long Seek(long offset, SeekOrigin origin)3626      {3627        long newPos = readPos_;36283629        switch (origin) {3630          case SeekOrigin.Begin:3631            newPos = start_ + offset;3632            break;36333634          case SeekOrigin.Current:3635            newPos = readPos_ + offset;3636            break;36373638          case SeekOrigin.End:3639            newPos = end_ + offset;3640            break;3641        }36423643        if (newPos < start_) {3644          throw new ArgumentException("Negative position is invalid");3645        }36463647        if (newPos >= end_) {3648          throw new IOException("Cannot seek past end");3649        }3650        readPos_ = newPos;3651        return readPos_;3652      }36533654      /// <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      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3659      public override void SetLength(long value)3660      {3658      public override void Flush()3659      {3660        // Nothing to do.  3661      }  3662  3663      /// <summary>3664      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3664      /// Gets or sets the position within the current stream.  3665      /// </summary>3666      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3667      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3668      /// <param name="count">The number of bytes to be written to the current stream.</param>3669      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3670      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3671      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3672      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3673      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3674      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3675      public override void Write(byte[] buffer, int offset, int count)3676      {3677        baseStream_.Write(buffer, offset, count);3678      }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. </exceptio3671      public override long Position {3672        get { return readPos_ - start_; }3673        set {3674          long newPos = start_ + value;36753676          if (newPos < start_) {3677            throw new ArgumentException("Negative position is invalid");3678          }  36793680      readonly36813682      #region Instance Fields3683      Stream baseStream_;3684      #endregion3685    }3680          if (newPos >= end_) {3681            throw new InvalidOperationException("Cannot seek past end");3682          }3683          readPos_ = newPos;3684        }3685      }  36863687    /// <summary>3688    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>3689    /// whose data is only a part or subsection of a file.3690    /// </summary>3691    class PartialInputStream : Stream3692    {3693      #region Constructors3694      /// <summary>3695      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.3696      /// </summary>3697      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>3698      /// <param name="start">The start of the partial data.</param>3699      /// <param name="length">The length of the partial data.</param>3700      public PartialInputStream(ZipFile zipFile, long start, long length)3701      {3702        start_ = start;3703        length_ = length;37043705        // Although this is the only time the zipfile is used3706        // keeping a reference here prevents premature closure of3707        // this zip file and thus the baseStream_.37083709        // Code like this will cause apparently random failures depending3710        // on the size of the files and when garbage is collected.3711        //3712        // ZipFile z = new ZipFile (stream);3713        // Stream reader = z.GetInputStream(0);3714        // uses reader here....3715        zipFile_ = zipFile;3716        baseStream_ = zipFile_.baseStream_;3717        readPos_ = start;3718        end_ = start + length;3719      }3720      #endregion37213722      /// <summary>3723      /// Read a byte from this stream.3724      /// </summary>3725      /// <returns>Returns the byte read or -1 on end of stream.</returns>3726      public override int ReadByte()3727      {3728        if (readPos_ >= end_) {3729           // -1 is the correct value at end of stream.3730          return -1;3731        }37323733        lock( baseStream_ ) {3734          baseStream_.Seek(readPos_++, SeekOrigin.Begin);3735          return baseStream_.ReadByte();3736        }3737      }37383739      /// <summary>3740      /// Close this <see cref="PartialInputStream">partial input stream</see>.3741      /// </summary>3742      /// <remarks>3743      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.3744      /// </remarks>3745      public override void Close()3746      {3747        // Do nothing at all!3748      }37493750      /// <summary>3751      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3752      /// </summary>3753      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3754      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3755      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3756      /// <returns>3757      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma3758      /// </returns>3759      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3760      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3761      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3762      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3763      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3764      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3765      public override int Read(byte[] buffer, int offset, int count)3766      {3767        lock(baseStream_) {3768          if (count > end_ - readPos_) {3769            count = (int) (end_ - readPos_);3770            if (count == 0) {3771              return 0;3772            }3773          }37743775          baseStream_.Seek(readPos_, SeekOrigin.Begin);3776          int readCount = baseStream_.Read(buffer, offset, count);3777          if (readCount > 0) {3778            readPos_ += readCount;3779          }3780          return readCount;3781        }3782      }37833784      /// <summary>3785      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3786      /// </summary>3787      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3788      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3789      /// <param name="count">The number of bytes to be written to the current stream.</param>3790      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3791      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3792      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3793      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3794      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3795      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3796      public override void Write(byte[] buffer, int offset, int count)3797      {3798        throw new NotSupportedException();3799      }38003801      /// <summary>3802      /// When overridden in a derived class, sets the length of the current stream.3803      /// </summary>3804      /// <param name="value">The desired length of the current stream in bytes.</param>3805      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3806      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3807      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3808      public override void SetLength(long value)3809      {3810        throw new NotSupportedException();3811      }38123813      /// <summary>3814      /// When overridden in a derived class, sets the position within the current stream.3815      /// </summary>3816      /// <param name="offset">A byte offset relative to the origin parameter.</param>3817      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3818      /// <returns>3819      /// The new position within the current stream.3820      /// </returns>3821      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3822      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3823      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3824      public override long Seek(long offset, SeekOrigin origin)3825      {3826        long newPos = readPos_;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. </excep3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3694      public override long Length {3695        get { return length_; }3696      }36973698      /// <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      }37063707      /// <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      }37153716      /// <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      }37243725      /// <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 Fields3734      ZipFile zipFile_;3735      Stream baseStream_;3736      long start_;3737      long length_;3738      long readPos_;3739      long end_;3740      #endregion3741    }3742    #endregion3743  }37443745  #endregion37463747  #region DataSources3748  /// <summary>3749  /// Provides a static way to obtain a source of data for an entry.3750  /// </summary>3751  public interface IStaticDataSource3752  {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  }37603761  /// <summary>3762  /// Represents a source of data that can dynamically provide3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3764  /// </summary>3765  public interface IDynamicDataSource3766  {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  }37763777  /// <summary>3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3779  /// </summary>3780  public class StaticDiskDataSource : IStaticDataSource3781  {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    }37903791    #region IDataSource Members37923793    /// <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    }38013802    readonly38033804    #endregion3805    #region Instance Fields3806    string fileName_;3807    #endregion3808  }380938103811  /// <summary>3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.3813  /// </summary>3814  public class DynamicDiskDataSource : IDynamicDataSource3815  {38163817    #region IDataSource Members3818    /// <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;  38273828        switch ( origin )3829        {3830          case SeekOrigin.Begin:3831            newPos = start_ + offset;3832            break;38333834          case SeekOrigin.Current:3835            newPos = readPos_ + offset;3836            break;3828      if (name != null) {3829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);3830      }38313832      return result;3833    }38343835    #endregion3836  }  38373838          case SeekOrigin.End:3839            newPos = end_ + offset;3840            break;3841        }38423843        if ( newPos < start_ ) {3844          throw new ArgumentException("Negative position is invalid");3845        }38463847        if ( newPos >= end_ ) {3848          throw new IOException("Cannot seek past end");3849        }3850        readPos_ = newPos;3851        return readPos_;3852      }38533854      /// <summary>3855      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.3856      /// </summary>3857      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3858      public override void Flush()3859      {3860        // Nothing to do.3861      }38623863      /// <summary>3864      /// Gets or sets the position within the current stream.3865      /// </summary>3866      /// <value></value>3867      /// <returns>The current position within the stream.</returns>3868      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3869      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>3870      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3871      public override long Position {3872        get { return readPos_ - start_; }3873        set {3874          long newPos = start_ + value;38753876          if ( newPos < start_ ) {3877            throw new ArgumentException("Negative position is invalid");3878          }3838  #endregion38393840  #region Archive Storage3841  /// <summary>3842  /// Defines facilities for data storage when updating Zip Archives.3843  /// </summary>3844  public interface IArchiveStorage3845  {3846    /// <summary>3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.3848    /// </summary>3849    FileUpdateMode UpdateMode { get; }38503851    /// <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();38573858    /// <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();38643865    /// <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);38713872    /// <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);  38793880          if ( newPos >= end_ ) {3881            throw new InvalidOperationException("Cannot seek past end");3882          }3883          readPos_ = newPos;3884        }3885      }38863887      /// <summary>3888      /// Gets the length in bytes of the stream.3889      /// </summary>3890      /// <value></value>3891      /// <returns>A long value representing the length of the stream in bytes.</returns>3892      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep3893      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3894      public override long Length {3895        get { return length_; }3896      }38973898      /// <summary>3899      /// Gets a value indicating whether the current stream supports writing.3900      /// </summary>3901      /// <value>false</value>3902      /// <returns>true if the stream supports writing; otherwise, false.</returns>3903      public override bool CanWrite {3904        get { return false; }3905      }39063907      /// <summary>3908      /// Gets a value indicating whether the current stream supports seeking.3909      /// </summary>3910      /// <value>true</value>3911      /// <returns>true if the stream supports seeking; otherwise, false.</returns>3912      public override bool CanSeek {3913        get { return true; }3914      }39153916      /// <summary>3917      /// Gets a value indicating whether the current stream supports reading.3918      /// </summary>3919      /// <value>true.</value>3920      /// <returns>true if the stream supports reading; otherwise, false.</returns>3921      public override bool CanRead {3922        get { return true; }3923      }39243925#if !NET_1_0 && !NET_1_1 && !NETCF_1_03926      /// <summary>3927      /// Gets a value that determines whether the current stream can time out.3928      /// </summary>3929      /// <value></value>3930      /// <returns>A value that determines whether the current stream can time out.</returns>3931      public override bool CanTimeout {3932        get { return baseStream_.CanTimeout; }3933      }3934#endif3935      #region Instance Fields3936      ZipFile zipFile_;3937      Stream baseStream_;3938      long start_;3939      long length_;3940      long readPos_;3941      long end_;3942      #endregion3943    }3944    #endregion3945  }39463947  #endregion39483949  #region DataSources3950  /// <summary>3951  /// Provides a static way to obtain a source of data for an entry.3952  /// </summary>3953  public interface IStaticDataSource3954  {3955    /// <summary>3956    /// Get a source of data by creating a new stream.3957    /// </summary>3958    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3959    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3960    Stream GetSource();3961  }39623963  /// <summary>3964  /// Represents a source of data that can dynamically provide3965  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3966  /// </summary>3967  public interface IDynamicDataSource3968  {3969    /// <summary>3970    /// Get a data source.3971    /// </summary>3972    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>3973    /// <param name="name">The name for data if known.</param>3974    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3975    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3976    Stream GetSource(ZipEntry entry, string name);3977  }39783979  /// <summary>3980  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3981  /// </summary>3982  public class StaticDiskDataSource : IStaticDataSource3983  {3984    /// <summary>3985    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>3986    /// </summary>3987    /// <param name="fileName">The name of the file to obtain data from.</param>3988    public StaticDiskDataSource(string fileName)3989    {3990      fileName_ = fileName;3991    }39923993    #region IDataSource Members39943995    /// <summary>3996    /// Get a <see cref="Stream"/> providing data.3997    /// </summary>3998    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>3999    public Stream GetSource()4000    {4001      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4002    }3880    /// <summary>3881    /// Dispose of this instance.3882    /// </summary>3883    void Dispose();3884  }38853886  /// <summary>3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.3888  /// </summary>3889  abstract public class BaseArchiveStorage : IArchiveStorage3890  {3891    #region Constructors3892    /// <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    #endregion39013902    #region IArchiveStorage Members39033904    /// <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();39103911    /// <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 read3915    /// the final storage for the archive.</returns>3916    /// <seealso cref="GetTemporaryOutput"/>3917    public abstract Stream ConvertTemporaryToFinal();39183919    /// <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);39253926    /// <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);39323933    /// <summary>3934    /// Disposes this instance.3935    /// </summary>3936    public abstract void Dispose();39373938    /// <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    }39473948    #endregion39493950    #region Instance Fields3951    FileUpdateMode updateMode_;3952    #endregion3953  }39543955  /// <summary>3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.3957  /// </summary>3958  public class DiskArchiveStorage : BaseArchiveStorage3959  {3960    #region Constructors3961    /// <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    }39753976    /// <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    #endregion39853986    #region IArchiveStorage Members39873988    /// <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      }  40034004    readonly40054006    #endregion4007    #region Instance Fields4008    string fileName_;4009    #endregion4010  }401140124013  /// <summary>4014  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.4015  /// </summary>4016  public class DynamicDiskDataSource : IDynamicDataSource4017  {40184019    #region IDataSource Members4020    /// <summary>4021    /// Get a <see cref="Stream"/> providing data for an entry.4022    /// </summary>4023    /// <param name="entry">The entry to provide data for.</param>4024    /// <param name="name">The file name for data if known.</param>4025    /// <returns>Returns a stream providing data; or null if not available</returns>4026    public Stream GetSource(ZipEntry entry, string name)4027    {4028      Stream result = null; + 24004      return temporaryStream_;4005    }40064007    /// <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 read4011    /// 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;40224023      try { + 34024        temporaryStream_.Close(); + 34025        File.Move(fileName_, moveTempName); + 34026        File.Move(temporaryName_, fileName_); + 34027        newFileCreated = true; + 34028        File.Delete(moveTempName);  40294030      if ( name != null ) {4031        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);4032      } + 34030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read); + 34031      } catch (Exception) { + 04032        result = null;  40334034      return result;4035    }40364037    #endregion4038  }4034        // Try to roll back changes... + 04035         if (!newFileCreated) { + 04036          File.Move(moveTempName, fileName_); + 04037          File.Delete(temporaryName_);4038        }  40394040  #endregion40414042  #region Archive Storage4043  /// <summary>4044  /// Defines facilities for data storage when updating Zip Archives.4045  /// </summary>4046  public interface IArchiveStorage4047  {4048    /// <summary>4049    /// Get the <see cref="FileUpdateMode"/> to apply during updates.4050    /// </summary>4051    FileUpdateMode UpdateMode { get; }40524053    /// <summary>4054    /// Get an empty <see cref="Stream"/> that can be used for temporary output.4055    /// </summary>4056    /// <returns>Returns a temporary output <see cref="Stream"/></returns>4057    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4058    Stream GetTemporaryOutput();40594060    /// <summary>4061    /// Convert a temporary output stream to a final stream.4062    /// </summary>4063    /// <returns>The resulting final <see cref="Stream"/></returns>4064    /// <seealso cref="GetTemporaryOutput"/>4065    Stream ConvertTemporaryToFinal();40664067    /// <summary>4068    /// Make a temporary copy of the original stream.4069    /// </summary>4070    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4071    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4072    Stream MakeTemporaryCopy(Stream stream);40734074    /// <summary>4075    /// Return a stream suitable for performing direct updates on the original source.4076    /// </summary>4077    /// <param name="stream">The current stream.</param>4078    /// <returns>Returns a stream suitable for direct updating.</returns>4079    /// <remarks>This may be the current stream passed.</remarks>4080    Stream OpenForDirectUpdate(Stream stream);40814082    /// <summary>4083    /// Dispose of this instance.4084    /// </summary>4085    void Dispose();4086  } + 04040        throw;4041      }4042 + 34043      return result;4044    }40454046    /// <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    }40634064    /// <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    }  40874088  /// <summary>4089  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.4090  /// </summary>4091  abstract public class BaseArchiveStorage : IArchiveStorage4092  {4093    #region Constructors4094    /// <summary>4095    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.4096    /// </summary>4097    /// <param name="updateMode">The update mode.</param>4098    protected BaseArchiveStorage(FileUpdateMode updateMode)4099    {4100      updateMode_ = updateMode;4101    }4102    #endregion41034104    #region IArchiveStorage Members41054106    /// <summary>4107    /// Gets a temporary output <see cref="Stream"/>4108    /// </summary>4109    /// <returns>Returns the temporary output stream.</returns>4110    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4111    public abstract Stream GetTemporaryOutput();41124113    /// <summary>4114    /// Converts the temporary <see cref="Stream"/> to its final form.4115    /// </summary>4116    /// <returns>Returns a <see cref="Stream"/> that can be used to read4117    /// the final storage for the archive.</returns>4118    /// <seealso cref="GetTemporaryOutput"/>4119    public abstract Stream ConvertTemporaryToFinal();41204121    /// <summary>4122    /// Make a temporary copy of a <see cref="Stream"/>.4123    /// </summary>4124    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>4125    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4126    public abstract Stream MakeTemporaryCopy(Stream stream);41274128    /// <summary>4129    /// Return a stream suitable for performing direct updates on the original source.4130    /// </summary>4131    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>4132    /// <returns>Returns a stream suitable for direct updating.</returns>4133    public abstract Stream OpenForDirectUpdate(Stream stream);41344135    /// <summary>4136    /// Disposes this instance.4137    /// </summary>4138    public abstract void Dispose();41394140    /// <summary>4141    /// Gets the update mode applicable.4142    /// </summary>4143    /// <value>The update mode.</value>4144    public FileUpdateMode UpdateMode4145    {4146      get {4147        return updateMode_;4148      }4149    }41504151    #endregion41524153    #region Instance Fields4154    FileUpdateMode updateMode_;4155    #endregion4156  }41574158  /// <summary>4159  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.4160  /// </summary>4161  public class DiskArchiveStorage : BaseArchiveStorage4162  {4163    #region Constructors4164    /// <summary>4165    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4166    /// </summary>4167    /// <param name="file">The file.</param>4168    /// <param name="updateMode">The update mode.</param>4169    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode) - 114170      : base(updateMode)4171    { - 114172       if ( file.Name == null ) { - 04173        throw new ZipException("Cant handle non file archives");4174      }4175 - 114176      fileName_ = file.Name; - 114177    }4088    /// <summary>4089    /// Disposes this instance.4090    /// </summary>4091    public override void Dispose()4092    { + 114093       if (temporaryStream_ != null) { + 34094        temporaryStream_.Close();4095      } + 114096    }40974098    #endregion40994100    #region Internal routines4101    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    #endregion41334134    #region Instance Fields4135    Stream temporaryStream_;4136    string fileName_;4137    string temporaryName_;4138    #endregion4139  }41404141  /// <summary>4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4143  /// </summary>4144  public class MemoryArchiveStorage : BaseArchiveStorage4145  {4146    #region Constructors4147    /// <summary>4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4149    /// </summary>4150    public MemoryArchiveStorage()4151      : base(FileUpdateMode.Direct)4152    {4153    }41544155    /// <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    }41644165    #endregion41664167    #region Properties4168    /// <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    }41744175    #endregion41764177    #region IArchiveStorage Members  4178  4179    /// <summary>4180    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4180    /// Gets the temporary output <see cref="Stream"/>  4181    /// </summary>4182    /// <param name="file">The file.</param>4183    public DiskArchiveStorage(ZipFile file) - 104184      : this(file, FileUpdateMode.Safe)4185    { - 104186    }4187    #endregion4182    /// <returns>Returns the temporary output stream.</returns>4183    public override Stream GetTemporaryOutput()4184    {4185      temporaryStream_ = new MemoryStream();4186      return temporaryStream_;4187    }  41884189    #region IArchiveStorage Members41904191    /// <summary>4192    /// Gets a temporary output <see cref="Stream"/> for performing updates on.4193    /// </summary>4194    /// <returns>Returns the temporary output stream.</returns>4195    public override Stream GetTemporaryOutput()4196    { - 24197       if ( temporaryName_ != null ) { - 04198        temporaryName_ = GetTempFileName(temporaryName_, true); - 04199        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None); - 04200      }4201      else {4202        // Determine where to place files based on internal strategy.4203        // Currently this is always done in system temp directory. - 24204        temporaryName_ = Path.GetTempFileName(); - 24205        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4206      }4207 - 24208      return temporaryStream_;4209    }42104211    /// <summary>4212    /// Converts a temporary <see cref="Stream"/> to its final form.4213    /// </summary>4214    /// <returns>Returns a <see cref="Stream"/> that can be used to read4215    /// the final storage for the archive.</returns>4216    public override Stream ConvertTemporaryToFinal()4217    { - 34218       if ( temporaryStream_ == null ) { - 04219        throw new ZipException("No temporary stream has been created");4220      }4221 - 34222      Stream result = null;4223 - 34224      string moveTempName = GetTempFileName(fileName_, false); - 34225      bool newFileCreated = false;42264227      try  { - 34228        temporaryStream_.Close(); - 34229        File.Move(fileName_, moveTempName); - 34230        File.Move(temporaryName_, fileName_); - 34231        newFileCreated = true; - 34232        File.Delete(moveTempName);4233 - 34234        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read); - 34235      } - 04236      catch(Exception) { - 04237        result  = null;42384239        // Try to roll back changes... - 04240         if ( !newFileCreated ) { - 04241          File.Move(moveTempName, fileName_); - 04242          File.Delete(temporaryName_);4243        }4244 - 04245        throw;4246      }4247 - 34248      return result;4249    }42504251    /// <summary>4252    /// Make a temporary copy of a stream.4253    /// </summary>4254    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4255    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4256    public override Stream MakeTemporaryCopy(Stream stream)4257    { - 14258      stream.Close();4259 - 14260      temporaryName_ = GetTempFileName(fileName_, true); - 14261      File.Copy(fileName_, temporaryName_, true);4262 - 14263      temporaryStream_ = new FileStream(temporaryName_, - 14264        FileMode.Open, - 14265        FileAccess.ReadWrite); - 14266      return temporaryStream_;4267    }42684269    /// <summary>4270    /// Return a stream suitable for performing direct updates on the original source.4271    /// </summary>4272    /// <param name="stream">The current stream.</param>4273    /// <returns>Returns a stream suitable for direct updating.</returns>4274    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>4275    public override Stream OpenForDirectUpdate(Stream stream)4276    {4277      Stream result; - 14278       if ((stream == null) || !stream.CanWrite)4279      { - 14280         if (stream != null) { - 14281          stream.Close();4282        }4283 - 14284        result = new FileStream(fileName_, - 14285            FileMode.Open, - 14286            FileAccess.ReadWrite); - 14287      }4288      else4289      { - 04290        result = stream;4291      }4292 - 14293      return result;4294    }42954296    /// <summary>4297    /// Disposes this instance.4298    /// </summary>4299    public override void Dispose()4300    { - 114301       if ( temporaryStream_ != null ) { - 34302        temporaryStream_.Close();4303      } - 114304    }43054306    #endregion43074308    #region Internal routines4309    static string GetTempFileName(string original, bool makeTempFile)4310    { - 44311      string result = null;4312 - 44313       if ( original == null ) { - 04314        result = Path.GetTempFileName(); - 04315      }4316      else { - 44317        int counter = 0; - 44318        int suffixSeed = DateTime.Now.Second;4319 - 94320         while ( result == null ) { - 54321          counter += 1; - 54322          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter); - 54323           if ( !File.Exists(newName) ) { - 44324             if ( makeTempFile) {4325              try  {4326                // Try and create the file. - 14327                using ( FileStream stream = File.Create(newName) ) { - 14328                } - 14329                result = newName; - 14330              } - 04331              catch { - 04332                suffixSeed = DateTime.Now.Second; - 04333              }4334            }4335            else { - 34336              result = newName;4337            }4338          }4339        }4340      } - 44341      return result;4342    }4343    #endregion43444345    #region Instance Fields4346    Stream temporaryStream_;4347    string fileName_;4348    string temporaryName_;4349    #endregion4350  }43514352  /// <summary>4353  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4354  /// </summary>4355  public class MemoryArchiveStorage : BaseArchiveStorage4356  {4357    #region Constructors4358    /// <summary>4359    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4360    /// </summary>4361    public MemoryArchiveStorage()4362      : base(FileUpdateMode.Direct)4363    {4364    }43654366    /// <summary>4367    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4368    /// </summary>4369    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>4370    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>4371    public MemoryArchiveStorage(FileUpdateMode updateMode)4372      : base(updateMode)4373    {4374    }43754376    #endregion43774378    #region Properties4379    /// <summary>4380    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.4381    /// </summary>4382    public MemoryStream FinalStream4383    {4384      get { return finalStream_; }4385    }43864387    #endregion43884389    #region IArchiveStorage Members43904391    /// <summary>4392    /// Gets the temporary output <see cref="Stream"/>4393    /// </summary>4394    /// <returns>Returns the temporary output stream.</returns>4395    public override Stream GetTemporaryOutput()4396    {4397      temporaryStream_ = new MemoryStream();4398      return temporaryStream_;4399    }44004401    /// <summary>4402    /// Converts the temporary <see cref="Stream"/> to its final form.4403    /// </summary>4404    /// <returns>Returns a <see cref="Stream"/> that can be used to read4405    /// the final storage for the archive.</returns>4406    public override Stream ConvertTemporaryToFinal()4407    {4408      if ( temporaryStream_ == null ) {4409        throw new ZipException("No temporary stream has been created");4410      }44114412      finalStream_ = new MemoryStream(temporaryStream_.ToArray());4413      return finalStream_;4414    }44154416    /// <summary>4417    /// Make a temporary copy of the original stream.4418    /// </summary>4419    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4420    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4421    public override Stream MakeTemporaryCopy(Stream stream)4422    {4423      temporaryStream_ = new MemoryStream();4424      stream.Position = 0;4425      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);4426      return temporaryStream_;4427    }44284429    /// <summary>4430    /// Return a stream suitable for performing direct updates on the original source.4431    /// </summary>4432    /// <param name="stream">The original source stream</param>4433    /// <returns>Returns a stream suitable for direct updating.</returns>4434    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;4435    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>4436    public override Stream OpenForDirectUpdate(Stream stream)4437    {4438      Stream result;4439      if ((stream == null) || !stream.CanWrite) {44404441        result = new MemoryStream();44424443        if (stream != null) {4444          stream.Position = 0;4445          StreamUtils.Copy(stream, result, new byte[4096]);44464447          stream.Close();4448        }4449      }4450      else {4451        result = stream;4452      }44534454      return result;4455    }44564457    /// <summary>4458    /// Disposes this instance.4459    /// </summary>4460    public override void Dispose()4461    {4462      if ( temporaryStream_ != null ) {4463        temporaryStream_.Close();4464      }4465    }44664467    #endregion44684469    #region Instance Fields4470    MemoryStream temporaryStream_;4471    MemoryStream finalStream_;4472    #endregion4473  }44744475  #endregion4476}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 read4193    /// 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      }41994200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());4201      return finalStream_;4202    }42034204    /// <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    }42164217    /// <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) {42284229        result = new MemoryStream();42304231        if (stream != null) {4232          stream.Position = 0;4233          StreamUtils.Copy(stream, result, new byte[4096]);42344235          stream.Close();4236        }4237      } else {4238        result = stream;4239      }42404241      return result;4242    }42434244    /// <summary>4245    /// Disposes this instance.4246    /// </summary>4247    public override void Dispose()4248    {4249      if (temporaryStream_ != null) {4250        temporaryStream_.Close();4251      }4252    }42534254    #endregion42554256    #region Instance Fields4257    MemoryStream temporaryStream_;4258    MemoryStream finalStream_;4259    #endregion4260  }42614262  #endregion4263} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_DynamicDiskDataSource.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_DynamicDiskDataSource.htm index 959ed4a04..661985474 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_DynamicDiskDataSource.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_DynamicDiskDataSource.htm @@ -18,7 +18,7 @@

Summary

Covered lines:4 Uncovered lines:0 Coverable lines:4 -Total lines:4476 +Total lines:4263 Line coverage:100% Branch coverage:100% @@ -35,4484 +35,4271 @@

#LineLine coverage - 1// ZipFile.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  2009-12-22  Z-1649  Added AES support41//  2010-03-02  Z-1650  Fixed updating ODT archives in memory. Exposed exceptions in updating.42//  2010-05-25  Z-1663  Fixed exception when testing local header compressed size of -143//  2012-11-29  Z-1684  Fixed ZipFile.Add(string fileName, string entryName) losing the file TimeStamp4445using System;46using System.Collections;47using System.IO;48using System.Text;49using System.Globalization;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;1213namespace ICSharpCode.SharpZipLib.Zip14{15  #region Keys Required Event Args16  /// <summary>17  /// Arguments used with KeysRequiredEvent18  /// </summary>19  public class KeysRequiredEventArgs : EventArgs20  {21    #region Constructors22    /// <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    }3031    /// <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    }4142    #endregion43    #region Properties44    /// <summary>45    /// Gets the name of the file for which keys are required.46    /// </summary>47    public string FileName {48      get { return fileName; }49    }  5051#if !NETCF_1_052using System.Security.Cryptography;53using ICSharpCode.SharpZipLib.Encryption;54#endif5556using ICSharpCode.SharpZipLib.Core;57using ICSharpCode.SharpZipLib.Checksums;58using ICSharpCode.SharpZipLib.Zip.Compression.Streams;59using ICSharpCode.SharpZipLib.Zip.Compression;6061namespace ICSharpCode.SharpZipLib.Zip62{63  #region Keys Required Event Args64  /// <summary>65  /// Arguments used with KeysRequiredEvent66  /// </summary>67  public class KeysRequiredEventArgs : EventArgs68  {69    #region Constructors70    /// <summary>71    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>72    /// </summary>73    /// <param name="name">The name of the file for which keys are required.</param>74    public KeysRequiredEventArgs(string name)75    {76      fileName = name;77    }7879    /// <summary>80    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>81    /// </summary>82    /// <param name="name">The name of the file for which keys are required.</param>83    /// <param name="keyValue">The current key value.</param>84    public KeysRequiredEventArgs(string name, byte[] keyValue)85    {86      fileName = name;87      key = keyValue;88    }8990    #endregion91    #region Properties92    /// <summary>93    /// Gets the name of the file for which keys are required.94    /// </summary>95    public string FileName96    {97      get { return fileName; }98    }99100    /// <summary>101    /// Gets or sets the key value102    /// </summary>103    public byte[] Key104    {105      get { return key; }106      set { key = value; }107    }108    #endregion109110    #region Instance Fields111    string fileName;112    byte[] key;113    #endregion114  }115  #endregion116117  #region Test Definitions118  /// <summary>119  /// The strategy to apply to testing.120  /// </summary>121  public enum TestStrategy122  {123    /// <summary>124    /// Find the first error only.125    /// </summary>126    FindFirstError,51    /// <summary>52    /// Gets or sets the key value53    /// </summary>54    public byte[] Key {55      get { return key; }56      set { key = value; }57    }58    #endregion5960    #region Instance Fields61    string fileName;62    byte[] key;63    #endregion64  }65  #endregion6667  #region Test Definitions68  /// <summary>69  /// The strategy to apply to testing.70  /// </summary>71  public enum TestStrategy72  {73    /// <summary>74    /// Find the first error only.75    /// </summary>76    FindFirstError,77    /// <summary>78    /// Find all possible errors.79    /// </summary>80    FindAllErrors,81  }8283  /// <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 TestOperation88  {89    /// <summary>90    /// Setting up testing.91    /// </summary>92    Initialising,9394    /// <summary>95    /// Testing an individual entries header96    /// </summary>97    EntryHeader,9899    /// <summary>100    /// Testing an individual entries data101    /// </summary>102    EntryData,103104    /// <summary>105    /// Testing an individual entry has completed.106    /// </summary>107    EntryComplete,108109    /// <summary>110    /// Running miscellaneous tests111    /// </summary>112    MiscellaneousTests,113114    /// <summary>115    /// Testing is complete116    /// </summary>117    Complete,118  }119120  /// <summary>121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.122  /// </summary>123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>124  public class TestStatus125  {126    #region Constructors  127    /// <summary>128    /// Find all possible errors.128    /// Initialise a new instance of <see cref="TestStatus"/>  129    /// </summary>130    FindAllErrors,131  }132133  /// <summary>134  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.135  /// </summary>136  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>137  public enum TestOperation138  {130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>131    public TestStatus(ZipFile file)132    {133      file_ = file;134    }135    #endregion136137    #region Properties138  139    /// <summary>140    /// Setting up testing.140    /// Get the current <see cref="TestOperation"/> in progress.  141    /// </summary>142    Initialising,143144    /// <summary>145    /// Testing an individual entries header146    /// </summary>147    EntryHeader,148149    /// <summary>150    /// Testing an individual entries data151    /// </summary>152    EntryData,153154    /// <summary>155    /// Testing an individual entry has completed.156    /// </summary>157    EntryComplete,158159    /// <summary>160    /// Running miscellaneous tests161    /// </summary>162    MiscellaneousTests,163164    /// <summary>165    /// Testing is complete166    /// </summary>167    Complete,168  }169170  /// <summary>171  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.172  /// </summary>173  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>174  public class TestStatus175  {176    #region Constructors177    /// <summary>178    /// Initialise a new instance of <see cref="TestStatus"/>179    /// </summary>180    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>181    public TestStatus(ZipFile file)182    {183      file_ = file;184    }185    #endregion186187    #region Properties142    public TestOperation Operation {143      get { return operation_; }144    }145146    /// <summary>147    /// Get the <see cref="ZipFile"/> this status is applicable to.148    /// </summary>149    public ZipFile File {150      get { return file_; }151    }152153    /// <summary>154    /// Get the current/last entry tested.155    /// </summary>156    public ZipEntry Entry {157      get { return entry_; }158    }159160    /// <summary>161    /// Get the number of errors detected so far.162    /// </summary>163    public int ErrorCount {164      get { return errorCount_; }165    }166167    /// <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    }173174    /// <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    #endregion181182    #region Internal API183    internal void AddError()184    {185      errorCount_++;186      entryValid_ = false;187    }  188189    /// <summary>190    /// Get the current <see cref="TestOperation"/> in progress.191    /// </summary>192    public TestOperation Operation193    {194      get { return operation_; }195    }196197    /// <summary>198    /// Get the <see cref="ZipFile"/> this status is applicable to.199    /// </summary>200    public ZipFile File201    {202      get { return file_; }203    }204205    /// <summary>206    /// Get the current/last entry tested.207    /// </summary>208    public ZipEntry Entry209    {210      get { return entry_; }211    }212213    /// <summary>214    /// Get the number of errors detected so far.215    /// </summary>216    public int ErrorCount217    {218      get { return errorCount_; }219    }220221    /// <summary>222    /// Get the number of bytes tested so far for the current entry.223    /// </summary>224    public long BytesTested225    {226      get { return bytesTested_; }227    }228229    /// <summary>230    /// Get a value indicating wether the last entry test was valid.231    /// </summary>232    public bool EntryValid233    {234      get { return entryValid_; }235    }236    #endregion237238    #region Internal API239    internal void AddError()240    {241      errorCount_++;242      entryValid_ = false;243    }244245    internal void SetOperation(TestOperation operation)246    {247      operation_ = operation;248    }249250    internal void SetEntry(ZipEntry entry)251    {252      entry_ = entry;253      entryValid_ = true;254      bytesTested_ = 0;255    }256257    internal void SetBytesTested(long value)258    {259      bytesTested_ = value;260    }261    #endregion262263    #region Instance Fields264    ZipFile file_;265    ZipEntry entry_;266    bool entryValid_;267    int errorCount_;268    long bytesTested_;269    TestOperation operation_;270    #endregion271  }272273  /// <summary>274  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if275  /// </summary>276  /// <remarks>If the message is non-null an error has occured.  If the message is null277  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>278  public delegate void ZipTestResultHandler(TestStatus status, string message);279  #endregion280281  #region Update Definitions282  /// <summary>283  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.284  /// </summary>285  public enum FileUpdateMode286  {287    /// <summary>288    /// Perform all updates on temporary files ensuring that the original file is saved.289    /// </summary>290    Safe,291    /// <summary>292    /// Update the archive directly, which is faster but less safe.293    /// </summary>294    Direct,295  }296  #endregion189    internal void SetOperation(TestOperation operation)190    {191      operation_ = operation;192    }193194    internal void SetEntry(ZipEntry entry)195    {196      entry_ = entry;197      entryValid_ = true;198      bytesTested_ = 0;199    }200201    internal void SetBytesTested(long value)202    {203      bytesTested_ = value;204    }205    #endregion206207    #region Instance Fields208    ZipFile file_;209    ZipEntry entry_;210    bool entryValid_;211    int errorCount_;212    long bytesTested_;213    TestOperation operation_;214    #endregion215  }216217  /// <summary>218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if219  /// </summary>220  /// <remarks>If the message is non-null an error has occured.  If the message is null221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>222  public delegate void ZipTestResultHandler(TestStatus status, string message);223  #endregion224225  #region Update Definitions226  /// <summary>227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.228  /// </summary>229  public enum FileUpdateMode230  {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  #endregion241242  #region ZipFile Class243  /// <summary>244  /// This class represents a Zip archive.  You can ask for the contained245  /// entries, or get an input stream for a file entry.  The entry is246  /// 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 arbitrary251  /// entries in different threads.252  /// <br/>253  /// <br/>Author of the original java version : Jochen Hoenicke254  /// </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 MainClass265  /// {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, IDisposable287  {288    #region KeyHandling289290    /// <summary>291    /// Delegate for handling keys/password setting during compresion/decompression.292    /// </summary>293    public delegate void KeysRequiredEventHandler(294      object sender,295      KeysRequiredEventArgs e296    );  297298  #region ZipFile Class299  /// <summary>300  /// This class represents a Zip archive.  You can ask for the contained301  /// entries, or get an input stream for a file entry.  The entry is302  /// automatically decompressed.303  ///304  /// You can also update the archive adding or deleting entries.305  ///306  /// This class is thread safe for input:  You can open input streams for arbitrary307  /// entries in different threads.308  /// <br/>309  /// <br/>Author of the original java version : Jochen Hoenicke310  /// </summary>311  /// <example>312  /// <code>313  /// using System;314  /// using System.Text;315  /// using System.Collections;316  /// using System.IO;317  ///318  /// using ICSharpCode.SharpZipLib.Zip;319  ///320  /// class MainClass321  /// {322  ///   static public void Main(string[] args)323  ///   {324  ///     using (ZipFile zFile = new ZipFile(args[0])) {325  ///       Console.WriteLine("Listing of : " + zFile.Name);326  ///       Console.WriteLine("");327  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");328  ///       Console.WriteLine("--------  --------  --------  ------  ---------");329  ///       foreach (ZipEntry e in zFile) {330  ///         if ( e.IsFile ) {331  ///           DateTime d = e.DateTime;332  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,333  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),334  ///             e.Name);335  ///         }336  ///       }337  ///     }338  ///   }339  /// }340  /// </code>341  /// </example>342  public class ZipFile : IEnumerable, IDisposable343  {344    #region KeyHandling345346    /// <summary>347    /// Delegate for handling keys/password setting during compresion/decompression.348    /// </summary>349    public delegate void KeysRequiredEventHandler(350      object sender,351      KeysRequiredEventArgs e352    );353354    /// <summary>355    /// Event handler for handling encryption keys.356    /// </summary>357    public KeysRequiredEventHandler KeysRequired;358359    /// <summary>360    /// Handles getting of encryption keys when required.361    /// </summary>362    /// <param name="fileName">The file for which encryption keys are required.</param>363    void OnKeysRequired(string fileName)364    {365      if (KeysRequired != null) {366        var krea = new KeysRequiredEventArgs(fileName, key);367        KeysRequired(this, krea);368        key = krea.Key;369      }370    }371372    /// <summary>373    /// Get/set the encryption key value.374    /// </summary>375    byte[] Key376    {377      get { return key; }378      set { key = value; }379    }380381#if !NETCF_1_0382    /// <summary>383    /// Password to be used for encrypting/decrypting files.384    /// </summary>385    /// <remarks>Set to null if no password is required.</remarks>386    public string Password387    {388      set389      {390        if ( string.IsNullOrEmpty(value)) {391          key = null;392        }393        else {394          rawPassword_ = value;395          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));396        }298    /// <summary>299    /// Event handler for handling encryption keys.300    /// </summary>301    public KeysRequiredEventHandler KeysRequired;302303    /// <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    }315316    /// <summary>317    /// Get/set the encryption key value.318    /// </summary>319    byte[] Key {320      get { return key; }321      set { key = value; }322    }323324    /// <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    }338339    /// <summary>340    /// Get a value indicating wether encryption keys are currently available.341    /// </summary>342    bool HaveKeys {343      get { return key != null; }344    }345    #endregion346347    #region Constructors348    /// <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 occurs355    /// </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      }364365      name_ = name;366367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);368      isStreamOwner = true;369370      try {371        ReadEntries();372      } catch {373        DisposeInternal(true);374        throw;375      }376    }377378    /// <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      }394395      if (!file.CanSeek) {396        throw new ArgumentException("Stream is not seekable", nameof(file));  397      }398    }399#endif400401    /// <summary>402    /// Get a value indicating wether encryption keys are currently available.403    /// </summary>404    bool HaveKeys405    {406      get { return key != null; }407    }408    #endregion409410    #region Constructors398399      baseStream_ = file;400      name_ = file.Name;401      isStreamOwner = true;402403      try {404        ReadEntries();405      } catch {406        DisposeInternal(true);407        throw;408      }409    }410  411    /// <summary>412    /// Opens a Zip file with the given name for reading.412    /// Opens a Zip file reading the given <see cref="Stream"/>.  413    /// </summary>414    /// <param name="name">The name of the file to open.</param>415    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>416    /// <exception cref="IOException">417    /// An i/o error occurs418    /// </exception>419    /// <exception cref="ZipException">420    /// The file doesn't contain a valid zip archive.421    /// </exception>422    public ZipFile(string name)423    {424      if ( name == null ) {425        throw new ArgumentNullException(nameof(name));426      }427428      name_ = name;429430      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);431      isStreamOwner = true;414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>415    /// <exception cref="IOException">416    /// An i/o error occurs417    /// </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      }  432433      try {434        ReadEntries();433      if (!stream.CanSeek) {434        throw new ArgumentException("Stream is not seekable", nameof(stream));  435      }436      catch {437        DisposeInternal(true);438        throw;439      }440    }441442    /// <summary>443    /// Opens a Zip file reading the given <see cref="FileStream"/>.444    /// </summary>445    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>446    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>447    /// <exception cref="IOException">448    /// An i/o error occurs.449    /// </exception>450    /// <exception cref="ZipException">451    /// The file doesn't contain a valid zip archive.452    /// </exception>453    public ZipFile(FileStream file)454    {455      if ( file == null ) {456        throw new ArgumentNullException(nameof(file));457      }458459      if ( !file.CanSeek ) {460        throw new ArgumentException("Stream is not seekable", nameof(file));461      }462463      baseStream_  = file;464      name_ = file.Name;465      isStreamOwner = true;466467      try {468        ReadEntries();469      }470      catch {471        DisposeInternal(true);472        throw;473      }474    }475476    /// <summary>477    /// Opens a Zip file reading the given <see cref="Stream"/>.478    /// </summary>479    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>480    /// <exception cref="IOException">481    /// An i/o error occurs482    /// </exception>483    /// <exception cref="ZipException">484    /// The stream doesn't contain a valid zip archive.<br/>485    /// </exception>486    /// <exception cref="ArgumentException">487    /// The <see cref="Stream">stream</see> doesnt support seeking.488    /// </exception>489    /// <exception cref="ArgumentNullException">490    /// The <see cref="Stream">stream</see> argument is null.491    /// </exception>492    public ZipFile(Stream stream)493    {494      if ( stream == null ) {495        throw new ArgumentNullException(nameof(stream));496      }497498      if ( !stream.CanSeek ) {499        throw new ArgumentException("Stream is not seekable", nameof(stream));500      }501502      baseStream_  = stream;503      isStreamOwner = true;504505      if ( baseStream_.Length > 0 ) {506        try {507          ReadEntries();508        }509        catch {510          DisposeInternal(true);511          throw;512        }513      } else {514        entries_ = new ZipEntry[0];515        isNewArchive_ = true;516      }517    }518519    /// <summary>520    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.521    /// </summary>522    internal ZipFile()523    {524      entries_ = new ZipEntry[0];525      isNewArchive_ = true;526    }527528    #endregion529530    #region Destructors and Closing531    /// <summary>532    /// Finalize this instance.533    /// </summary>534    ~ZipFile()535    {536      Dispose(false);537    }538436437      baseStream_ = stream;438      isStreamOwner = true;439440      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    }452453    /// <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    }461462    #endregion463464    #region Destructors and Closing465    /// <summary>466    /// Finalize this instance.467    /// </summary>468    ~ZipFile()469    {470      Dispose(false);471    }472473    /// <summary>474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying475    /// 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    }485486    #endregion487488    #region Creators489    /// <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      }500501      FileStream fs = File.Create(fileName);502503      var result = new ZipFile();504      result.name_ = fileName;505      result.baseStream_ = fs;506      result.isStreamOwner = true;507      return result;508    }509510    /// <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      }522523      if (!outStream.CanWrite) {524        throw new ArgumentException("Stream is not writeable", nameof(outStream));525      }526527      if (!outStream.CanSeek) {528        throw new ArgumentException("Stream is not seekable", nameof(outStream));529      }530531      var result = new ZipFile();532      result.baseStream_ = outStream;533      return result;534    }535536    #endregion537538    #region Properties  539    /// <summary>540    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying541    /// Once closed, no further instance methods should be called.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    /// <exception cref="System.IO.IOException">544    /// An i/o error occurs.545    /// </exception>546    public void Close()547    {548      DisposeInternal(true);549      GC.SuppressFinalize(this);550    }551552    #endregion553554    #region Creators555    /// <summary>556    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.557    /// </summary>558    /// <param name="fileName">The name of the archive to create.</param>559    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>560    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>561    public static ZipFile Create(string fileName)562    {563      if ( fileName == null ) {564        throw new ArgumentNullException(nameof(fileName));565      }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    }550551    /// <summary>552    /// Get a value indicating wether553    /// this archive is embedded in another file or not.554    /// </summary>555    public bool IsEmbeddedArchive {556      // Not strictly correct in all circumstances currently557      get { return offsetOfFirstEntry > 0; }558    }559560    /// <summary>561    /// Get a value indicating that this archive is a new one.562    /// </summary>563    public bool IsNewArchive {564      get { return isNewArchive_; }565    }  566567      FileStream fs = File.Create(fileName);568569      var result = new ZipFile();570      result.name_ = fileName;571      result.baseStream_ = fs;572      result.isStreamOwner = true;573      return result;574    }575576    /// <summary>577    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.578    /// </summary>579    /// <param name="outStream">The stream providing data storage.</param>580    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>581    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>582    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>583    public static ZipFile Create(Stream outStream)584    {585      if ( outStream == null ) {586        throw new ArgumentNullException(nameof(outStream));587      }588589      if ( !outStream.CanWrite ) {590        throw new ArgumentException("Stream is not writeable", nameof(outStream));567    /// <summary>568    /// Gets the comment for the zip file.569    /// </summary>570    public string ZipFileComment {571      get { return comment_; }572    }573574    /// <summary>575    /// Gets the name of this zip file.576    /// </summary>577    public string Name {578      get { return name_; }579    }580581    /// <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      }592593      if ( !outStream.CanSeek ) {594        throw new ArgumentException("Stream is not seekable", nameof(outStream));595      }596597      var result = new ZipFile();598      result.baseStream_ = outStream;599      return result;600    }601602    #endregion603604    #region Properties605    /// <summary>606    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.607    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.608    /// </summary>609    /// <remarks>610    /// The default value is true in all cases.611    /// </remarks>612    public bool IsStreamOwner613    {614      get { return isStreamOwner; }615      set { isStreamOwner = value; }616    }617618    /// <summary>619    /// Get a value indicating wether620    /// this archive is embedded in another file or not.621    /// </summary>622    public bool IsEmbeddedArchive623    {624      // Not strictly correct in all circumstances currently625      get { return offsetOfFirstEntry > 0; }626    }627628    /// <summary>629    /// Get a value indicating that this archive is a new one.630    /// </summary>631    public bool IsNewArchive632    {633      get { return isNewArchive_; }634    }635636    /// <summary>637    /// Gets the comment for the zip file.638    /// </summary>639    public string ZipFileComment640    {641      get { return comment_; }642    }643644    /// <summary>645    /// Gets the name of this zip file.646    /// </summary>647    public string Name648    {649      get { return name_; }650    }651652    /// <summary>653    /// Gets the number of entries in this zip file.654    /// </summary>655    /// <exception cref="InvalidOperationException">656    /// The Zip file has been closed.657    /// </exception>658    [Obsolete("Use the Count property instead")]659    public int Size660    {661      get662      {663        return entries_.Length;664      }665    }666667    /// <summary>668    /// Get the number of entries contained in this <see cref="ZipFile"/>.669    /// </summary>670    public long Count671    {672      get673      {674        return entries_.Length;675      }676    }677678    /// <summary>679    /// Indexer property for ZipEntries680    /// </summary>681    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]682    public ZipEntry this[int index]683    {684      get {685        return (ZipEntry) entries_[index].Clone();686      }687    }688689    #endregion690691    #region Input Handling692    /// <summary>693    /// Gets an enumerator for the Zip entries in this Zip file.694    /// </summary>695    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>696    /// <exception cref="ObjectDisposedException">697    /// The Zip file has been closed.698    /// </exception>699    public IEnumerator GetEnumerator()700    {701      if (isDisposed_) {702        throw new ObjectDisposedException("ZipFile");703      }704705      return new ZipEntryEnumerator(entries_);706    }707708    /// <summary>709    /// Return the index of the entry with a matching name710    /// </summary>711    /// <param name="name">Entry name to find</param>712    /// <param name="ignoreCase">If true the comparison is case insensitive</param>713    /// <returns>The index position of the matching entry or -1 if not found</returns>714    /// <exception cref="ObjectDisposedException">715    /// The Zip file has been closed.716    /// </exception>717    public int FindEntry(string name, bool ignoreCase)718    {719      if (isDisposed_) {720        throw new ObjectDisposedException("ZipFile");721      }722723      // TODO: This will be slow as the next ice age for huge archives!724      for (int i = 0; i < entries_.Length; i++) {725        if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {726          return i;727        }728      }729      return -1;730    }731732    /// <summary>733    /// Searches for a zip entry in this archive with the given name.734    /// String comparisons are case insensitive735    /// </summary>736    /// <param name="name">737    /// The name to find. May contain directory components separated by slashes ('/').738    /// </param>739    /// <returns>740    /// A clone of the zip entry, or null if no entry with that name exists.741    /// </returns>742    /// <exception cref="ObjectDisposedException">743    /// The Zip file has been closed.744    /// </exception>745    public ZipEntry GetEntry(string name)746    {747      if (isDisposed_) {748        throw new ObjectDisposedException("ZipFile");749      }750751      int index = FindEntry(name, true);752      return (index >= 0) ? (ZipEntry) entries_[index].Clone() : null;753    }754755    /// <summary>756    /// Gets an input stream for reading the given zip entry data in an uncompressed form.757    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().758    /// </summary>759    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>760    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>761    /// <exception cref="ObjectDisposedException">762    /// The ZipFile has already been closed763    /// </exception>764    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">765    /// The compression method for the entry is unknown766    /// </exception>767    /// <exception cref="IndexOutOfRangeException">768    /// The entry is not found in the ZipFile769    /// </exception>770    public Stream GetInputStream(ZipEntry entry)771    {772      if ( entry == null ) {773        throw new ArgumentNullException(nameof(entry));774      }775776      if ( isDisposed_ ) {777        throw new ObjectDisposedException("ZipFile");778      }779780      long index = entry.ZipFileIndex;781      if ( (index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name) ) {782        index = FindEntry(entry.Name, true);783        if (index < 0) {784          throw new ZipException("Entry cannot be found");785        }786      }787      return GetInputStream(index);788    }789790    /// <summary>791    /// Creates an input stream reading a zip entry792    /// </summary>793    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>794    /// <returns>795    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>796    /// </returns>797    /// <exception cref="ObjectDisposedException">798    /// The ZipFile has already been closed799    /// </exception>800    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">801    /// The compression method for the entry is unknown802    /// </exception>803    /// <exception cref="IndexOutOfRangeException">804    /// The entry is not found in the ZipFile805    /// </exception>806    public Stream GetInputStream(long entryIndex)807    {808      if ( isDisposed_ ) {809        throw new ObjectDisposedException("ZipFile");810      }592    }593594    /// <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    }602603    /// <summary>604    /// Indexer property for ZipEntries605    /// </summary>606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]607    public ZipEntry this[int index] {608      get {609        return (ZipEntry)entries_[index].Clone();610      }611    }612613    #endregion614615    #region Input Handling616    /// <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      }628629      return new ZipEntryEnumerator(entries_);630    }631632    /// <summary>633    /// Return the index of the entry with a matching name634    /// </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      }646647      // 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    }655656    /// <summary>657    /// Searches for a zip entry in this archive with the given name.658    /// String comparisons are case insensitive659    /// </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      }674675      int index = FindEntry(name, true);676      return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;677    }678679    /// <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 closed687    /// </exception>688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">689    /// The compression method for the entry is unknown690    /// </exception>691    /// <exception cref="IndexOutOfRangeException">692    /// The entry is not found in the ZipFile693    /// </exception>694    public Stream GetInputStream(ZipEntry entry)695    {696      if (entry == null) {697        throw new ArgumentNullException(nameof(entry));698      }699700      if (isDisposed_) {701        throw new ObjectDisposedException("ZipFile");702      }703704      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    }713714    /// <summary>715    /// Creates an input stream reading a zip entry716    /// </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 closed723    /// </exception>724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">725    /// The compression method for the entry is unknown726    /// </exception>727    /// <exception cref="IndexOutOfRangeException">728    /// The entry is not found in the ZipFile729    /// </exception>730    public Stream GetInputStream(long entryIndex)731    {732      if (isDisposed_) {733        throw new ObjectDisposedException("ZipFile");734      }735736      long start = LocateEntry(entries_[entryIndex]);737      CompressionMethod method = entries_[entryIndex].CompressionMethod;738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);739740      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      }746747      switch (method) {748        case CompressionMethod.Stored:749          // read as is.750          break;751752        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;756757        default:758          throw new ZipException("Unsupported compression method " + method);759      }760761      return result;762    }763764    #endregion765766    #region Archive Testing767    /// <summary>768    /// Test an archive for integrity/validity769    /// </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    }777778    /// <summary>779    /// Test an archive for integrity/validity780    /// </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      }791792      var status = new TestStatus(this);793794      if (resultHandler != null) {795        resultHandler(status, null);796      }797798      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;799800      bool testing = true;801802      try {803        int entryIndex = 0;804805        while (testing && (entryIndex < Count)) {806          if (resultHandler != null) {807            status.SetEntry(this[entryIndex]);808            status.SetOperation(TestOperation.EntryHeader);809            resultHandler(status, null);810          }  811812      long start = LocateEntry(entries_[entryIndex]);813      CompressionMethod method = entries_[entryIndex].CompressionMethod;814      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);815816      if (entries_[entryIndex].IsCrypted == true) {817#if NETCF_1_0818        throw new ZipException("decryption not supported for Compact Framework 1.0");819#else820        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);821        if (result == null) {822          throw new ZipException("Unable to decrypt this entry");823        }824#endif825      }826827      switch (method) {828        case CompressionMethod.Stored:829          // read as is.830          break;831832        case CompressionMethod.Deflated:833          // No need to worry about ownership and closing as underlying stream close does nothing.834          result = new InflaterInputStream(result, new Inflater(true));835          break;836837        default:838          throw new ZipException("Unsupported compression method " + method);839      }812          try {813            TestLocalHeader(this[entryIndex], test);814          } catch (ZipException ex) {815            status.AddError();816817            if (resultHandler != null) {818              resultHandler(status,819                string.Format("Exception during test - '{0}'", ex.Message));820            }821822            testing &= strategy != TestStrategy.FindFirstError;823          }824825          if (testing && testData && this[entryIndex].IsFile) {826            if (resultHandler != null) {827              status.SetOperation(TestOperation.EntryData);828              resultHandler(status, null);829            }830831            var crc = new Crc32();832833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {834835              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);  840841      return result;842    }843844    #endregion845846    #region Archive Testing847    /// <summary>848    /// Test an archive for integrity/validity849    /// </summary>850    /// <param name="testData">Perform low level data Crc check</param>851    /// <returns>true if all tests pass, false otherwise</returns>852    /// <remarks>Testing will terminate on the first error found.</remarks>853    public bool TestArchive(bool testData)854    {855      return TestArchive(testData, TestStrategy.FindFirstError, null);856    }857858    /// <summary>859    /// Test an archive for integrity/validity860    /// </summary>861    /// <param name="testData">Perform low level data Crc check</param>862    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>863    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>864    /// <returns>true if all tests pass, false otherwise</returns>865    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>866    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)867    {868      if (isDisposed_) {869        throw new ObjectDisposedException("ZipFile");870      }871872      var status = new TestStatus(this);873874      if ( resultHandler != null ) {875        resultHandler(status, null);876      }877878      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;879880      bool testing = true;841                if (resultHandler != null) {842                  totalBytes += bytesRead;843                  status.SetBytesTested(totalBytes);844                  resultHandler(status, null);845                }846              }847            }848849            if (this[entryIndex].Crc != crc.Value) {850              status.AddError();851852              if (resultHandler != null) {853                resultHandler(status, "CRC mismatch");854              }855856              testing &= strategy != TestStrategy.FindFirstError;857            }858859            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              }866867              if (this[entryIndex].CompressedSize != data.CompressedSize) {868                status.AddError();869              }870871              if (this[entryIndex].Size != data.Size) {872                status.AddError();873              }874            }875          }876877          if (resultHandler != null) {878            status.SetOperation(TestOperation.EntryComplete);879            resultHandler(status, null);880          }  881882      try {883        int entryIndex = 0;882          entryIndex += 1;883        }  884885        while ( testing && (entryIndex < Count) ) {886          if ( resultHandler != null ) {887            status.SetEntry(this[entryIndex]);888            status.SetOperation(TestOperation.EntryHeader);889            resultHandler(status, null);890          }891892          try  {893            TestLocalHeader(this[entryIndex], test);894          }895          catch(ZipException ex) {896            status.AddError();897898            if ( resultHandler != null ) {899              resultHandler(status,900                string.Format("Exception during test - '{0}'", ex.Message));901            }902903            testing &= strategy != TestStrategy.FindFirstError;904          }885        if (resultHandler != null) {886          status.SetOperation(TestOperation.MiscellaneousTests);887          resultHandler(status, null);888        }889890        // TODO: the 'Corrina Johns' test where local headers are missing from891        // the central directory.  They are therefore invisible to many archivers.892      } catch (Exception ex) {893        status.AddError();894895        if (resultHandler != null) {896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));897        }898      }899900      if (resultHandler != null) {901        status.SetOperation(TestOperation.Complete);902        status.SetEntry(null);903        resultHandler(status, null);904      }  905906          if ( testing && testData && this[entryIndex].IsFile ) {907            if ( resultHandler != null ) {908              status.SetOperation(TestOperation.EntryData);909              resultHandler(status, null);910            }911912                        var crc = new Crc32();913914                        using (Stream entryStream = this.GetInputStream(this[entryIndex]))915                        {916917                            byte[] buffer = new byte[4096];918                            long totalBytes = 0;919                            int bytesRead;920                            while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0)921                            {922                                crc.Update(buffer, 0, bytesRead);923924                                if (resultHandler != null)925                                {926                                    totalBytes += bytesRead;927                                    status.SetBytesTested(totalBytes);928                                    resultHandler(status, null);929                                }930                            }931                        }932933            if (this[entryIndex].Crc != crc.Value) {934              status.AddError();935936              if ( resultHandler != null ) {937                resultHandler(status, "CRC mismatch");938              }939940              testing &= strategy != TestStrategy.FindFirstError;941            }942943            if (( this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0 ) {944              var helper = new ZipHelperStream(baseStream_);945              var data = new DescriptorData();946              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);947              if (this[entryIndex].Crc != data.Crc) {948                status.AddError();949              }950951              if (this[entryIndex].CompressedSize != data.CompressedSize) {952                status.AddError();953              }954955              if (this[entryIndex].Size != data.Size) {956                status.AddError();957              }958            }959          }960961          if ( resultHandler != null ) {962            status.SetOperation(TestOperation.EntryComplete);963            resultHandler(status, null);964          }965966          entryIndex += 1;967        }968969        if ( resultHandler != null ) {970          status.SetOperation(TestOperation.MiscellaneousTests);971          resultHandler(status, null);972        }973974        // TODO: the 'Corrina Johns' test where local headers are missing from975        // the central directory.  They are therefore invisible to many archivers.976      }977      catch (Exception ex) {978        status.AddError();906      return (status.ErrorCount == 0);907    }908909    [Flags]910    enum HeaderTest911    {912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted913      Header = 0x02,     // Check that this header contents are valid914    }915916    /// <summary>917    /// Test a local header against that provided from the central directory918    /// </summary>919    /// <param name="entry">920    /// The entry to test against921    /// </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;929930        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        }934935        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();945946        byte[] nameData = new byte[storedNameLength];947        StreamUtils.ReadFully(baseStream_, nameData);948949        byte[] extraData = new byte[extraDataLength];950        StreamUtils.ReadFully(baseStream_, extraData);951952        var localExtraData = new ZipExtraData(extraData);953954        // Extra data / zip64 checks955        if (localExtraData.Find(1)) {956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64957          // and size or compressedSize = MaxValue, due to rogue creators.958959          size = localExtraData.ReadLong();960          compressedSize = localExtraData.ReadLong();961962          if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {963            // These may be valid if patched later964            if ((size != -1) && (size != entry.Size)) {965              throw new ZipException("Size invalid for descriptor");966            }967968            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        }  979980        if ( resultHandler != null ) {981          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));982        }983      }984985      if ( resultHandler != null ) {986        status.SetOperation(TestOperation.Complete);987        status.SetEntry(null);988        resultHandler(status, null);989      }980        if (testData) {981          if (entry.IsFile) {982            if (!entry.IsCompressionMethodSupported()) {983              throw new ZipException("Compression method not supported");984            }985986            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})", extract989            }  990991      return (status.ErrorCount == 0);992    }993994    [Flags]995    enum HeaderTest996    {997      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted998      Header  = 0x02,     // Check that this header contents are valid999    }10001001    /// <summary>1002    /// Test a local header against that provided from the central directory1003    /// </summary>1004    /// <param name="entry">1005    /// The entry to test against1006    /// </param>1007    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>1008    /// <returns>The offset of the entries data in the file</returns>1009    long TestLocalHeader(ZipEntry entry, HeaderTest tests)1010    {1011      lock(baseStream_)1012      {1013        bool testHeader = (tests & HeaderTest.Header) != 0;1014        bool testData = (tests & HeaderTest.Extract) != 0;10151016        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);1017        if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {1018          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)1019        }10201021        var extractVersion = ( short ) (ReadLEUshort() & 0x00ff);1022        var localFlags = ( short )ReadLEUshort();1023        var compressionMethod = ( short )ReadLEUshort();1024        var fileTime = ( short )ReadLEUshort();1025        var fileDate = ( short )ReadLEUshort();1026        uint crcValue = ReadLEUint();1027        long compressedSize = ReadLEUint();1028        long size = ReadLEUint();1029        int storedNameLength = ReadLEUshort();1030        int extraDataLength = ReadLEUshort();10311032        byte[] nameData = new byte[storedNameLength];1033        StreamUtils.ReadFully(baseStream_, nameData);10341035        byte[] extraData = new byte[extraDataLength];1036        StreamUtils.ReadFully(baseStream_, extraData);991            if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance992              throw new ZipException("The library does not support the zip version required to extract this entry");993            }994          }995        }996997        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})", extractVersi1015          }10161017          // Local entry flags dont have reserved bit set on.1018          if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R1019            throw new ZipException("Reserved bit flags cannot be set.");1020          }10211022          // Encryption requires extract version >= 201023          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          }10261027          // 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            }10321033            if (extractVersion < 50) {1034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({01035            }1036          }  10371038        var localExtraData = new ZipExtraData(extraData);10391040        // Extra data / zip64 checks1041        if (localExtraData.Find(1))1042        {1043          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip641044          // and size or compressedSize = MaxValue, due to rogue creators.10451046          size = localExtraData.ReadLong();1047          compressedSize = localExtraData.ReadLong();10481049                    if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0)1050                    {1051                        // These may be valid if patched later1052                        if ( (size != -1) && (size != entry.Size)) {1053                            throw new ZipException("Size invalid for descriptor");1054                        }10551056                        if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {1057                            throw new ZipException("Compressed size invalid for descriptor");1058                        }1059                    }1060                }1061        else1062        {1063          // No zip64 extra data but entry requires it.1064          if ((extractVersion >= ZipConstants.VersionZip64) &&1065            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue)))1066          {1067            throw new ZipException("Required Zip64 extended information missing");1038          // Patched entries require extract version >= 271039          if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {1040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));1041          }10421043          // Central header flags match local entry flags.1044          if (localFlags != entry.Flags) {1045            throw new ZipException("Central header/local header flags mismatch");1046          }10471048          // Central header compression method matches local entry1049          if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {1050            throw new ZipException("Central header/local header compression method mismatch");1051          }10521053          if (entry.Version != extractVersion) {1054            throw new ZipException("Extract version mismatch");1055          }10561057          // Strong encryption and extract version match1058          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          }10631064          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        }10701071        if ( testData ) {1072          if ( entry.IsFile ) {1073            if ( !entry.IsCompressionMethodSupported() ) {1074              throw new ZipException("Compression method not supported");1075            }10761077            if ( (extractVersion > ZipConstants.VersionMadeBy)1078              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)) ) {1079              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract1080            }10811082            if ( (localFlags & ( int )(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enha1083              throw new ZipException("The library does not support the zip version required to extract this entry");1084            }1085          }1086        }10871088                if (testHeader)1089                {1090                    if ((extractVersion <= 63) &&  // Ignore later versions as we dont know about them..1091                        (extractVersion != 10) &&1092                        (extractVersion != 11) &&1093                        (extractVersion != 20) &&1094                        (extractVersion != 21) &&1095                        (extractVersion != 25) &&1096                        (extractVersion != 27) &&1097                        (extractVersion != 45) &&1098                        (extractVersion != 46) &&1099                        (extractVersion != 50) &&1100                        (extractVersion != 51) &&1101                        (extractVersion != 52) &&1102                        (extractVersion != 61) &&1103                        (extractVersion != 62) &&1104                        (extractVersion != 63)1105                        )1106                    {1107                        throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", 1108                    }11091110                    // Local entry flags dont have reserved bit set on.1111                    if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | General1112                    {1113                        throw new ZipException("Reserved bit flags cannot be set.");1114                    }11151116                    // Encryption requires extract version >= 201117                    if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20))1118                    {1119                        throw new ZipException(string.Format("Version required to extract this entry is too low for encr1120                    }11211122                    // Strong encryption requires encryption flag to be set and extract version >= 50.1123                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1124                    {1125                        if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0)1126                        {1127                            throw new ZipException("Strong encryption flag set but encryption flag is not set");1128                        }10691070          if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {1071            if (crcValue != (uint)entry.Crc) {1072              throw new ZipException("Central header/local header crc mismatch");1073            }1074          }10751076          // Crc valid for empty entry.1077          // This will also apply to streamed entries where size isnt known and the header cant be patched1078          if ((size == 0) && (compressedSize == 0)) {1079            if (crcValue != 0) {1080              throw new ZipException("Invalid CRC for empty entry");1081            }1082          }10831084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably1086          if (entry.Name.Length > storedNameLength) {1087            throw new ZipException("File name length mismatch");1088          }10891090          // Name data has already been read convert it and compare.1091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);10921093          // Central directory and local entry name match1094          if (localName != entry.Name) {1095            throw new ZipException("Central header and local header file name mismatch");1096          }10971098          // Directories have zero actual size but can have compressed size1099          if (entry.IsDirectory) {1100            if (size > 0) {1101              throw new ZipException("Directory cannot have size");1102            }11031104            // 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 bytes1112              // 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 bytes1114              throw new ZipException("Directory compressed size invalid");1115            }1116          }11171118          if (!ZipNameTransform.IsValidName(localName, true)) {1119            throw new ZipException("Name is invalid");1120          }1121        }11221123        // Tests that apply to both data and header.11241125        // 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)) {  11291130                        if (extractVersion < 50)1131                        {1132                            throw new ZipException(string.Format("Version required to extract this entry is too low for 1133                        }1134                    }11351136                    // Patched entries require extract version >= 271137                    if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27))1138                    {1139                        throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractV1140                    }11411142                    // Central header flags match local entry flags.1143                    if (localFlags != entry.Flags)1144                    {1145                        throw new ZipException("Central header/local header flags mismatch");1146                    }11471148                    // Central header compression method matches local entry1149                    if (entry.CompressionMethod != (CompressionMethod)compressionMethod)1150                    {1151                        throw new ZipException("Central header/local header compression method mismatch");1152                    }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          }11361137          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        }11441145        int extraLength = storedNameLength + extraDataLength;1146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;1147      }1148    }11491150    #endregion11511152    #region Updating  11531154                    if (entry.Version != extractVersion)1155                    {1156                        throw new ZipException("Extract version mismatch");1157                    }11581159                    // Strong encryption and extract version match1160                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1161                    {1162                        if (extractVersion < 62)1163                        {1164                            throw new ZipException("Strong encryption flag set but version not high enough");1165                        }1166                    }11671168                    if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0)1169                    {1170                        if ((fileTime != 0) || (fileDate != 0))1171                        {1172                            throw new ZipException("Header masked set but date/time values non-zero");1173                        }1174                    }11751176                    if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0)1177                    {1178                        if (crcValue != (uint)entry.Crc)1179                        {1180                            throw new ZipException("Central header/local header crc mismatch");1181                        }1182                    }11831184                    // Crc valid for empty entry.1185                    // This will also apply to streamed entries where size isnt known and the header cant be patched1186                    if ((size == 0) && (compressedSize == 0))1187                    {1188                        if (crcValue != 0)1189                        {1190                            throw new ZipException("Invalid CRC for empty entry");1191                        }1192                    }11931194                    // TODO: make test more correct...  can't compare lengths as was done originally as this can fail fo1195                    // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntr1196                    if (entry.Name.Length > storedNameLength)1197                    {1198                        throw new ZipException("File name length mismatch");1199                    }12001201                    // Name data has already been read convert it and compare.1202                    string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);12031204                    // Central directory and local entry name match1205                    if (localName != entry.Name)1206                    {1207                        throw new ZipException("Central header and local header file name mismatch");1208                    }12091210                    // Directories have zero actual size but can have compressed size1211                    if (entry.IsDirectory)1212                    {1213                        if (size > 0)1214                        {1215                            throw new ZipException("Directory cannot have size");1216                        }12171218                        // There may be other cases where the compressed size can be greater than this?1219                        // If so until details are known we will be strict.1220                        if (entry.IsCrypted)1221                        {1222                            if (compressedSize > ZipConstants.CryptoHeaderSize + 2)1223                            {1224                                throw new ZipException("Directory compressed size invalid");1225                            }1226                        }1227                        else if (compressedSize > 2)1228                        {1229                            // When not compressed the directory size can validly be 2 bytes1230                            // if the true size wasnt known when data was originally being written.1231                            // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes1232                            throw new ZipException("Directory compressed size invalid");1233                        }1234                    }12351236                    if (!ZipNameTransform.IsValidName(localName, true))1237                    {1238                        throw new ZipException("Name is invalid");1239                    }1240                }12411242        // Tests that apply to both data and header.1154    const int DefaultBufferSize = 4096;11551156    /// <summary>1157    /// The kind of update to apply.1158    /// </summary>1159    enum UpdateCommand1160    {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    }11651166    #region Properties1167    /// <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      }11741175      set {1176        updateEntryFactory_.NameTransform = value;1177      }1178    }11791180    /// <summary>1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1182    /// during updates.1183    /// </summary>1184    public IEntryFactory EntryFactory {1185      get {1186        return updateEntryFactory_;1187      }11881189      set {1190        if (value == null) {1191          updateEntryFactory_ = new ZipEntryFactory();1192        } else {1193          updateEntryFactory_ = value;1194        }1195      }1196    }11971198    /// <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        }12071208        if (bufferSize_ != value) {1209          bufferSize_ = value;1210          copyBuffer_ = null;1211        }1212      }1213    }12141215    /// <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    }12211222    /// <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    }12291230    #endregion12311232    #region Immediate updating1233    //    TBD: Direct form of updating1234    //1235    //    public void Update(IEntryMatcher deleteMatcher)1236    //    {1237    //    }1238    //1239    //    public void Update(IScanner addScanner)1240    //    {1241    //    }1242    #endregion  12431244        // Size can be verified only if it is known in the local header.1245        // it will always be known in the central header.1246        if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||1247          ((size > 0) || (compressedSize > 0))) {12481249          if (size != entry.Size) {1250            throw new ZipException(1251              string.Format("Size mismatch between central header({0}) and local header({1})",1252                entry.Size, size));1253          }12541255          if (compressedSize != entry.CompressedSize &&1256            compressedSize != 0xFFFFFFFF && compressedSize != -1) {1257            throw new ZipException(1258              string.Format("Compressed size mismatch between central header({0}) and local header({1})",1259              entry.CompressedSize, compressedSize));1260          }1261        }1244    #region Deferred Updating1245    /// <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.</p1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1250    /// <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      }12581259      if (dataSource == null) {1260        throw new ArgumentNullException(nameof(dataSource));1261      }  12621263        int extraLength = storedNameLength + extraDataLength;1264        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;1263      if (isDisposed_) {1264        throw new ObjectDisposedException("ZipFile");  1265      }1266    }12671268    #endregion12691270    #region Updating12711272    const int DefaultBufferSize = 4096;12661267      if (IsEmbeddedArchive) {1268        throw new ZipException("Cannot update embedded/SFX archives");1269      }12701271      archiveStorage_ = archiveStorage;1272      updateDataSource_ = dataSource;  12731274    /// <summary>1275    /// The kind of update to apply.1276    /// </summary>1277    enum UpdateCommand1278    {1279      Copy,       // Copy original file contents.1280      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.1281      Add,        // Add a new file to the archive.1282    }1274      // NOTE: the baseStream_ may not currently support writing or seeking.12751276      updateIndex_ = new Hashtable();12771278      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      }  12831284    #region Properties1285    /// <summary>1286    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.1287    /// </summary>1288    public INameTransform NameTransform1289    {1290      get {1291        return updateEntryFactory_.NameTransform;1292      }12931294      set {1295        updateEntryFactory_.NameTransform = value;1296      }1297    }12981299    /// <summary>1300    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1301    /// during updates.1302    /// </summary>1303    public IEntryFactory EntryFactory1304    {1305      get {1306        return updateEntryFactory_;1307      }13081309      set {1310        if (value == null) {1311          updateEntryFactory_ = new ZipEntryFactory();1312        }1313        else {1314          updateEntryFactory_ = value;1315        }1316      }1317    }13181319    /// <summary>1320    /// Get /set the buffer size to be used when updating this zip file.1321    /// </summary>1322    public int BufferSize1323    {1324      get { return bufferSize_; }1325      set {1326        if ( value < 1024 ) {1327#if NETCF_1_01328          throw new ArgumentOutOfRangeException("value");1329#else1330          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");1331#endif1332        }13331334        if ( bufferSize_ != value ) {1335          bufferSize_ = value;1336          copyBuffer_ = null;1337        }1338      }1339    }1284      // We must sort by offset before using offset's calculated sizes1285      updates_.Sort(new UpdateComparer());12861287      int idx = 0;1288      foreach (ZipUpdate update in updates_) {1289        //If last entry, there is no next entry offset to use1290        if (idx == updates_.Count - 1)1291          break;12921293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;1294        idx++;1295      }1296      updateCount_ = updates_.Count;12971298      contentsEdited_ = false;1299      commentEdited_ = false;1300      newComment_ = null;1301    }13021303    /// <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    }13111312    /// <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    }13261327    /// <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      }13381339      CheckUpdating();  13401341    /// <summary>1342    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.1343    /// </summary>1344    public bool IsUpdating1345    {1346      get { return updates_ != null; }1347    }13481349    /// <summary>1350    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.1351    /// </summary>1352    public UseZip64 UseZip641353    {1354      get { return useZip64_; }1355      set { useZip64_ = value; }1356    }13571358    #endregion13591360    #region Immediate updating1361//    TBD: Direct form of updating1362//1363//    public void Update(IEntryMatcher deleteMatcher)1364//    {1365//    }1366//1367//    public void Update(IScanner addScanner)1368//    {1369//    }1370    #endregion13711372    #region Deferred Updating1373    /// <summary>1374    /// Begin updating this <see cref="ZipFile"/> archive.1375    /// </summary>1376    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p1377    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1341      try {1342        updateIndex_.Clear();1343        updateIndex_ = null;13441345        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        }13581359      } finally {1360        PostUpdateCleanup();1361      }1362    }13631364    /// <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    }13731374    /// <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    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>1380    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1381    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)1382    {1383      if ( archiveStorage == null ) {1384        throw new ArgumentNullException(nameof(archiveStorage));1385      }1379    public void SetComment(string comment)1380    {1381      if (isDisposed_) {1382        throw new ObjectDisposedException("ZipFile");1383      }13841385      CheckUpdating();  13861387      if ( dataSource == null ) {1388        throw new ArgumentNullException(nameof(dataSource));1389      }13901391      if ( isDisposed_ ) {1392        throw new ObjectDisposedException("ZipFile");1393      }13941395      if ( IsEmbeddedArchive ) {1396        throw new ZipException ("Cannot update embedded/SFX archives");1397      }1387      newComment_ = new ZipString(comment);13881389      if (newComment_.RawLength > 0xffff) {1390        newComment_ = null;1391        throw new ZipException("Comment length exceeds maximum - 65535");1392      }13931394      // We dont take account of the original and current comment appearing to be the same1395      // as encoding may be different.1396      commentEdited_ = true;1397    }  13981399      archiveStorage_ = archiveStorage;1400      updateDataSource_ = dataSource;14011402      // NOTE: the baseStream_ may not currently support writing or seeking.14031404      updateIndex_ = new Hashtable();14051406      updates_ = new ArrayList(entries_.Length);1407      foreach(ZipEntry entry in entries_) {1408        int index = updates_.Add(new ZipUpdate(entry));1409        updateIndex_.Add(entry.Name, index);1410      }14111412      // We must sort by offset before using offset's calculated sizes1413      updates_.Sort(new UpdateComparer());14141415      int idx = 0;1416      foreach (ZipUpdate update in updates_) {1417        //If last entry, there is no next entry offset to use1418        if (idx == updates_.Count - 1)1419          break;14201421        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;1422        idx++;1423      }1424      updateCount_ = updates_.Count;14251426      contentsEdited_ = false;1427      commentEdited_ = false;1428      newComment_ = null;1429    }14301431    /// <summary>1432    /// Begin updating to this <see cref="ZipFile"/> archive.1433    /// </summary>1434    /// <param name="archiveStorage">The storage to use during the update.</param>1435    public void BeginUpdate(IArchiveStorage archiveStorage)1436    {1437      BeginUpdate(archiveStorage, new DynamicDiskDataSource());1438    }14391440    /// <summary>1441    /// Begin updating this <see cref="ZipFile"/> archive.1442    /// </summary>1443    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>1444    /// <seealso cref="CommitUpdate"></seealso>1445    /// <seealso cref="AbortUpdate"></seealso>1446    public void BeginUpdate()1447    {1448      if ( Name == null ) {1449        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());1450      }1451      else {1452        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());1453      }1399    #endregion14001401    #region Adding Entries14021403    void AddUpdate(ZipUpdate update)1404    {1405      contentsEdited_ = true;14061407      int index = FindExistingUpdate(update.Entry.Name);14081409      if (index >= 0) {1410        if (updates_[index] == null) {1411          updateCount_ += 1;1412        }14131414        // 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    }14221423    /// <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      }14371438      if (isDisposed_) {1439        throw new ObjectDisposedException("ZipFile");1440      }14411442      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1444      }14451446      CheckUpdating();1447      contentsEdited_ = true;14481449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1450      entry.IsUnicodeText = useUnicodeText;1451      entry.CompressionMethod = compressionMethod;14521453      AddUpdate(new ZipUpdate(fileName, entry));  1454    }  1455  1456    /// <summary>1457    /// Commit current updates, updating this archive.1457    /// Add a new entry to the archive.  1458    /// </summary>1459    /// <seealso cref="BeginUpdate()"></seealso>1460    /// <seealso cref="AbortUpdate"></seealso>1461    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1462    public void CommitUpdate()1463    {1464      if ( isDisposed_ ) {1465        throw new ObjectDisposedException("ZipFile");1466      }14671468      CheckUpdating();14691470      try {1471        updateIndex_.Clear();1472        updateIndex_=null;14731474        if( contentsEdited_ ) {1475          RunUpdates();1476        }1477        else if( commentEdited_ ) {1478          UpdateCommentOnly();1479        }1480        else {1481          // Create an empty archive if none existed originally.1482          if( entries_.Length==0 ) {1483            byte[] theComment=(newComment_!=null)?newComment_.RawComment:ZipConstants.ConvertToArray(comment_);1484            using( ZipHelperStream zhs=new ZipHelperStream(baseStream_) ) {1485              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);1486            }1487          }1488        }14891459    /// <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      }14681469      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1471      }14721473      CheckUpdating();1474      contentsEdited_ = true;14751476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1477      entry.CompressionMethod = compressionMethod;1478      AddUpdate(new ZipUpdate(fileName, entry));1479    }14801481    /// <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      finally {1492        PostUpdateCleanup();1493      }14911492      CheckUpdating();1493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));  1494    }  1495  1496    /// <summary>1497    /// Abort updating leaving the archive unchanged.1497    /// Add a file to the archive.  1498    /// </summary>1499    /// <seealso cref="BeginUpdate()"></seealso>1500    /// <seealso cref="CommitUpdate"></seealso>1501    public void AbortUpdate()1502    {1503      PostUpdateCleanup();1504    }15051506    /// <summary>1507    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.1508    /// </summary>1509    /// <param name="comment">The comment to record.</param>1510    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1511    public void SetComment(string comment)1512    {1513      if ( isDisposed_ ) {1514        throw new ObjectDisposedException("ZipFile");1515      }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      }15071508      if (entryName == null) {1509        throw new ArgumentNullException(nameof(entryName));1510      }15111512      CheckUpdating();1513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));1514    }1515  15161517      CheckUpdating();15181519      newComment_ = new ZipString(comment);15201521      if ( newComment_.RawLength  > 0xffff ) {1522        newComment_ = null;1523        throw new ZipException("Comment length exceeds maximum - 65535");1524      }15251526      // We dont take account of the original and current comment appearing to be the same1527      // as encoding may be different.1528      commentEdited_ = true;1529    }15301531    #endregion15321533    #region Adding Entries15341535    void AddUpdate(ZipUpdate update)1536    {1537      contentsEdited_ = true;15381539      int index = FindExistingUpdate(update.Entry.Name);15401541      if (index >= 0) {1542        if ( updates_[index] == null ) {1543          updateCount_ += 1;1544        }15451546        // Direct replacement is faster than delete and add.1547        updates_[index] = update;1548      }1549      else {1550        index = updates_.Add(update);1551        updateCount_ += 1;1552        updateIndex_.Add(update.Entry.Name, index);1553      }1554    }15551556    /// <summary>1557    /// Add a new entry to the archive.1558    /// </summary>1559    /// <param name="fileName">The name of the file to add.</param>1560    /// <param name="compressionMethod">The compression method to use.</param>1561    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>1562    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1563    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1564    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>1565    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText )1566    {1567      if (fileName == null) {1568        throw new ArgumentNullException(nameof(fileName));1569      }15701571      if ( isDisposed_ ) {1572        throw new ObjectDisposedException("ZipFile");1573      }15741575      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1576        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1577      }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      }15271528      if (entryName == null) {1529        throw new ArgumentNullException(nameof(entryName));1530      }15311532      CheckUpdating();1533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));1534    }15351536    /// <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      }15471548      if (entryName == null) {1549        throw new ArgumentNullException(nameof(entryName));1550      }15511552      CheckUpdating();15531554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1555      entry.CompressionMethod = compressionMethod;15561557      AddUpdate(new ZipUpdate(dataSource, entry));1558    }15591560    /// <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 useUnicode1568    {1569      if (dataSource == null) {1570        throw new ArgumentNullException(nameof(dataSource));1571      }15721573      if (entryName == null) {1574        throw new ArgumentNullException(nameof(entryName));1575      }15761577      CheckUpdating();  15781579      CheckUpdating();1580      contentsEdited_ = true;15811582      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1583      entry.IsUnicodeText = useUnicodeText;1584      entry.CompressionMethod = compressionMethod;1579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1580      entry.IsUnicodeText = useUnicodeText;1581      entry.CompressionMethod = compressionMethod;15821583      AddUpdate(new ZipUpdate(dataSource, entry));1584    }  15851586      AddUpdate(new ZipUpdate(fileName, entry));1587    }15881589    /// <summary>1590    /// Add a new entry to the archive.1591    /// </summary>1592    /// <param name="fileName">The name of the file to add.</param>1593    /// <param name="compressionMethod">The compression method to use.</param>1594    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>1595    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>1596    public void Add(string fileName, CompressionMethod compressionMethod)1597    {1598      if ( fileName == null ) {1599        throw new ArgumentNullException(nameof(fileName));1600      }16011602      if ( !ZipEntry.IsCompressionMethodSupported(compressionMethod) ) {1603        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1604      }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      }15961597      CheckUpdating();15981599      if ((entry.Size != 0) || (entry.CompressedSize != 0)) {1600        throw new ZipException("Entry cannot have any data");1601      }16021603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));1604    }  16051606      CheckUpdating();1607      contentsEdited_ = true;16081609      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1610      entry.CompressionMethod = compressionMethod;1611      AddUpdate(new ZipUpdate(fileName, entry));1612    }16131614    /// <summary>1615    /// Add a file to the archive.1616    /// </summary>1617    /// <param name="fileName">The name of the file to add.</param>1618    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1619    public void Add(string fileName)1620    {1621      if ( fileName == null ) {1622        throw new ArgumentNullException(nameof(fileName));1623      }16241625      CheckUpdating();1626      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));1627    }16281629    /// <summary>1630    /// Add a file to the archive.1631    /// </summary>1632    /// <param name="fileName">The name of the file to add.</param>1633    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>1634    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1635    public void Add(string fileName, string entryName)1636    {1637      if (fileName == null) {1638        throw new ArgumentNullException(nameof(fileName));1639      }16401641      if ( entryName == null ) {1642        throw new ArgumentNullException(nameof(entryName));1643      }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      }16151616      CheckUpdating();16171618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);1619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));1620    }16211622    #endregion16231624    #region Modifying Entries1625    /* 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          }16331634          if ( updated == null ) {1635            throw new ArgumentNullException("updated");1636          }16371638          CheckUpdating();1639          contentsEdited_ = true;1640          updates_.Add(new ZipUpdate(original, updated));1641        }1642    */1643    #endregion  16441645      CheckUpdating();1646      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));1647    }164816491650    /// <summary>1651    /// Add a file entry with data.1652    /// </summary>1653    /// <param name="dataSource">The source of the data for this entry.</param>1654    /// <param name="entryName">The name to give to the entry.</param>1655    public void Add(IStaticDataSource dataSource, string entryName)1656    {1657      if ( dataSource == null ) {1658        throw new ArgumentNullException(nameof(dataSource));1659      }16601661      if ( entryName == null ) {1662        throw new ArgumentNullException(nameof(entryName));1663      }16641665      CheckUpdating();1666      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));1667    }16681669    /// <summary>1670    /// Add a file entry with data.1671    /// </summary>1672    /// <param name="dataSource">The source of the data for this entry.</param>1673    /// <param name="entryName">The name to give to the entry.</param>1674    /// <param name="compressionMethod">The compression method to use.</param>1675    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)1676    {1677      if ( dataSource == null ) {1678        throw new ArgumentNullException(nameof(dataSource));1679      }16801681      if ( entryName == null ) {1682        throw new ArgumentNullException(nameof(entryName));1683      }16841685      CheckUpdating();16861687      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1688      entry.CompressionMethod = compressionMethod;16891690      AddUpdate(new ZipUpdate(dataSource, entry));1691    }16921693    /// <summary>1694    /// Add a file entry with data.1695    /// </summary>1696    /// <param name="dataSource">The source of the data for this entry.</param>1697    /// <param name="entryName">The name to give to the entry.</param>1698    /// <param name="compressionMethod">The compression method to use.</param>1699    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>1700    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode1701    {1702      if (dataSource == null) {1703        throw new ArgumentNullException(nameof(dataSource));1704      }17051706      if ( entryName == null ) {1707        throw new ArgumentNullException(nameof(entryName));1708      }17091710      CheckUpdating();17111712      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1713      entry.IsUnicodeText = useUnicodeText;1714      entry.CompressionMethod = compressionMethod;17151716      AddUpdate(new ZipUpdate(dataSource, entry));1717    }17181719    /// <summary>1720    /// Add a <see cref="ZipEntry"/> that contains no data.1721    /// </summary>1722    /// <param name="entry">The entry to add.</param>1723    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>1724    public void Add(ZipEntry entry)1725    {1726      if ( entry == null ) {1727        throw new ArgumentNullException(nameof(entry));1728      }17291730      CheckUpdating();1645    #region Deleting Entries1646    /// <summary>1647    /// Delete an entry by name1648    /// </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      }16561657      CheckUpdating();16581659      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    }16711672    /// <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      }16811682      CheckUpdating();16831684      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    }16931694    #endregion16951696    #region Update Support16971698    #region Writing Values/Headers1699    void WriteLEShort(int value)1700    {1701      baseStream_.WriteByte((byte)(value & 0xff));1702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));1703    }17041705    /// <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    }17131714    /// <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    }17221723    /// <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    }  17311732      if ( (entry.Size != 0) || (entry.CompressedSize != 0) ) {1733        throw new ZipException("Entry cannot have any data");1734      }17351736      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));1737    }17381739    /// <summary>1740    /// Add a directory entry to the archive.1741    /// </summary>1742    /// <param name="directoryName">The directory to add.</param>1743    public void AddDirectory(string directoryName)1744    {1745      if ( directoryName == null ) {1746        throw new ArgumentNullException(nameof(directoryName));1747      }17481749      CheckUpdating();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    }17401741    void WriteLEUlong(ulong value)1742    {1743      WriteLEUint((uint)(value & 0xffffffff));1744      WriteLEUint((uint)(value >> 32));1745    }17461747    void WriteLocalEntryHeader(ZipUpdate update)1748    {1749      ZipEntry entry = update.OutEntry;  17501751      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);1752      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));1753    }17541755    #endregion17561757    #region Modifying Entries1758/* Modify not yet ready for public consumption.1759   Direct modification of an entry should not overwrite original data before its read.1760   Safe mode is trivial in this sense.1761    public void Modify(ZipEntry original, ZipEntry updated)1762    {1763      if ( original == null ) {1764        throw new ArgumentNullException("original");1765      }1751      // TODO: Local offset will require adjusting for multi-disk zip files.1752      entry.Offset = baseStream_.Position;17531754      // 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        }  17661767      if ( updated == null ) {1768        throw new ArgumentNullException("updated");1769      }17701771      CheckUpdating();1772      contentsEdited_ = true;1773      updates_.Add(new ZipUpdate(original, updated));1774    }1775*/1776    #endregion17771778    #region Deleting Entries1779    /// <summary>1780    /// Delete an entry by name1781    /// </summary>1782    /// <param name="fileName">The filename to delete</param>1783    /// <returns>True if the entry was found and deleted; false otherwise.</returns>1784    public bool Delete(string fileName)1785    {1786      if ( fileName == null ) {1787        throw new ArgumentNullException(nameof(fileName));1788      }17891790      CheckUpdating();17911792      bool result = false;1793      int index = FindExistingUpdate(fileName);1794      if ( (index >= 0) && (updates_[index] != null) ) {1795        result = true;1796        contentsEdited_ = true;1797        updates_[index] = null;1798        updateCount_ -= 1;1799      }1800      else {1801        throw new ZipException("Cannot find entry to delete");1802      }1803      return result;1804    }18051806    /// <summary>1807    /// Delete a <see cref="ZipEntry"/> from the archive.1808    /// </summary>1809    /// <param name="entry">The entry to delete.</param>1810    public void Delete(ZipEntry entry)1811    {1812      if ( entry == null ) {1813        throw new ArgumentNullException(nameof(entry));1814      }18151816      CheckUpdating();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        }17751776        switch (useZip64_) {1777          case UseZip64.Dynamic:1778            if (entry.Size < 0) {1779              entry.ForceZip64();1780            }1781            break;17821783          case UseZip64.On:1784            entry.ForceZip64();1785            break;17861787          case UseZip64.Off:1788            // Do nothing.  The entry itself may be using Zip64 independantly.1789            break;1790        }1791      }17921793      // Write the local file header1794      WriteLEInt(ZipConstants.LocalHeaderSignature);17951796      WriteLEShort(entry.Version);1797      WriteLEShort(entry.Flags);17981799      WriteLEShort((byte)entry.CompressionMethod);1800      WriteLEInt((int)entry.DosTime);18011802      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      }18091810      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        }  18171818      int index = FindExistingUpdate(entry);1819      if ( index >= 0 ) {1820        contentsEdited_ = true;1821        updates_[index] = null;1822        updateCount_ -= 1;1823      }1824      else {1825        throw new ZipException("Cannot find entry to delete");1818        WriteLEInt((int)entry.CompressedSize);1819        WriteLEInt((int)entry.Size);1820      }18211822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);18231824      if (name.Length > 0xFFFF) {1825        throw new ZipException("Entry name too long.");  1826      }1827    }18281829    #endregion18301831    #region Update Support18271828      var ed = new ZipExtraData(entry.ExtraData);18291830      if (entry.LocalHeaderRequiresZip64) {1831        ed.StartNewEntry();  18321833    #region Writing Values/Headers1834    void WriteLEShort(int value)1835    {1836      baseStream_.WriteByte(( byte )(value & 0xff));1837      baseStream_.WriteByte(( byte )((value >> 8) & 0xff));1838    }18391840    /// <summary>1841    /// Write an unsigned short in little endian byte order.1842    /// </summary>1843    void WriteLEUshort(ushort value)1844    {1845      baseStream_.WriteByte(( byte )(value & 0xff));1846      baseStream_.WriteByte(( byte )(value >> 8));1847    }18481849    /// <summary>1850    /// Write an int in little endian byte order.1851    /// </summary>1852    void WriteLEInt(int value)1853    {1854      WriteLEShort(value & 0xffff);1855      WriteLEShort(value >> 16);1856    }18571858    /// <summary>1859    /// Write an unsigned int in little endian byte order.1860    /// </summary>1861    void WriteLEUint(uint value)1862    {1863      WriteLEUshort((ushort)(value & 0xffff));1864      WriteLEUshort((ushort)(value >> 16));1865    }18661867    /// <summary>1868    /// Write a long in little endian byte order.1869    /// </summary>1870    void WriteLeLong(long value)1871    {1872      WriteLEInt(( int )(value & 0xffffffff));1873      WriteLEInt(( int )(value >> 32));1874    }18751876    void WriteLEUlong(ulong value)1877    {1878      WriteLEUint(( uint )(value & 0xffffffff));1879      WriteLEUint(( uint )(value >> 32));1880    }18811882    void WriteLocalEntryHeader(ZipUpdate update)1883    {1884      ZipEntry entry = update.OutEntry;18851886      // TODO: Local offset will require adjusting for multi-disk zip files.1887      entry.Offset = baseStream_.Position;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      }18411842      entry.ExtraData = ed.GetEntryData();18431844      WriteLEShort(name.Length);1845      WriteLEShort(entry.ExtraData.Length);18461847      if (name.Length > 0) {1848        baseStream_.Write(name, 0, name.Length);1849      }18501851      if (entry.LocalHeaderRequiresZip64) {1852        if (!ed.Find(1)) {1853          throw new ZipException("Internal error cannot find extra data");1854        }18551856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1857      }18581859      if (entry.ExtraData.Length > 0) {1860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);1861      }1862    }18631864    int WriteCentralDirectoryHeader(ZipEntry entry)1865    {1866      if (entry.CompressedSize < 0) {1867        throw new ZipException("Attempt to write central directory entry with unknown csize");1868      }18691870      if (entry.Size < 0) {1871        throw new ZipException("Attempt to write central directory entry with unknown size");1872      }18731874      if (entry.Crc < 0) {1875        throw new ZipException("Attempt to write central directory entry with unknown crc");1876      }18771878      // Write the central file header1879      WriteLEInt(ZipConstants.CentralHeaderSignature);18801881      // Version made by1882      WriteLEShort(ZipConstants.VersionMadeBy);18831884      // Version required to extract1885      WriteLEShort(entry.Version);18861887      WriteLEShort(entry.Flags);  18881889      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.1890      if (update.Command != UpdateCommand.Copy) {1891        if (entry.CompressionMethod == CompressionMethod.Deflated) {1892          if (entry.Size == 0) {1893            // No need to compress - no data.1894            entry.CompressedSize = entry.Size;1895            entry.Crc = 0;1896            entry.CompressionMethod = CompressionMethod.Stored;1897          }1898        }1899        else if (entry.CompressionMethod == CompressionMethod.Stored) {1900          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;1901        }19021903        if (HaveKeys) {1904          entry.IsCrypted = true;1905          if (entry.Crc < 0) {1906            entry.Flags |= (int)GeneralBitFlags.Descriptor;1907          }1908        }1909        else {1910          entry.IsCrypted = false;1911        }1889      unchecked {1890        WriteLEShort((byte)entry.CompressionMethod);1891        WriteLEInt((int)entry.DosTime);1892        WriteLEInt((int)entry.Crc);1893      }18941895      if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {1896        WriteLEInt(-1);1897      } else {1898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));1899      }19001901      if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {1902        WriteLEInt(-1);1903      } else {1904        WriteLEInt((int)entry.Size);1905      }19061907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);19081909      if (name.Length > 0xFFFF) {1910        throw new ZipException("Entry name is too long.");1911      }  19121913        switch (useZip64_) {1914          case UseZip64.Dynamic:1915            if (entry.Size < 0) {1916              entry.ForceZip64();1917            }1918            break;19191920          case UseZip64.On:1921            entry.ForceZip64();1922            break;19231924          case UseZip64.Off:1925            // Do nothing.  The entry itself may be using Zip64 independantly.1926            break;1913      WriteLEShort(name.Length);19141915      // Central header extra data is different to local header version so regenerate.1916      var ed = new ZipExtraData(entry.ExtraData);19171918      if (entry.CentralHeaderRequiresZip64) {1919        ed.StartNewEntry();19201921        if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {1922          ed.AddLeLong(entry.Size);1923        }19241925        if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {1926          ed.AddLeLong(entry.CompressedSize);  1927        }1928      }19291930      // Write the local file header1931      WriteLEInt(ZipConstants.LocalHeaderSignature);19281929        if (entry.Offset >= 0xffffffff) {1930          ed.AddLeLong(entry.Offset);1931        }  19321933      WriteLEShort(entry.Version);1934      WriteLEShort(entry.Flags);19351936      WriteLEShort((byte)entry.CompressionMethod);1937      WriteLEInt(( int )entry.DosTime);19381939      if ( !entry.HasCrc ) {1940        // Note patch address for updating CRC later.1941        update.CrcPatchOffset = baseStream_.Position;1942        WriteLEInt(( int )0);1943      }1944      else {1945        WriteLEInt(unchecked(( int )entry.Crc));1946      }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      }19391940      byte[] centralExtraData = ed.GetEntryData();19411942      WriteLEShort(centralExtraData.Length);1943      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);19441945      WriteLEShort(0);    // disk number1946      WriteLEShort(0);    // internal file attributes  19471948      if (entry.LocalHeaderRequiresZip64) {1949        WriteLEInt(-1);1950        WriteLEInt(-1);1951      }1952      else {1953        if ( (entry.CompressedSize < 0) || (entry.Size < 0) ) {1954          update.SizePatchOffset = baseStream_.Position;1955        }19561957        WriteLEInt(( int )entry.CompressedSize);1958        WriteLEInt(( int )entry.Size);1959      }19601961      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);19621963      if ( name.Length > 0xFFFF ) {1964        throw new ZipException("Entry name too long.");1965      }19661967      var ed = new ZipExtraData(entry.ExtraData);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      }19581959      if (entry.Offset >= 0xffffffff) {1960        WriteLEUint(0xffffffff);1961      } else {1962        WriteLEUint((uint)(int)entry.Offset);1963      }19641965      if (name.Length > 0) {1966        baseStream_.Write(name, 0, name.Length);1967      }  19681969      if ( entry.LocalHeaderRequiresZip64 ) {1970        ed.StartNewEntry();19711972        // Local entry header always includes size and compressed size.1973        // NOTE the order of these fields is reversed when compared to the normal headers!1974        ed.AddLeLong(entry.Size);1975        ed.AddLeLong(entry.CompressedSize);1976        ed.AddNewEntry(1);1969      if (centralExtraData.Length > 0) {1970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);1971      }19721973      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];19741975      if (rawComment.Length > 0) {1976        baseStream_.Write(rawComment, 0, rawComment.Length);  1977      }1978      else {1979        ed.Delete(1);1980      }19811982      entry.ExtraData = ed.GetEntryData();19831984      WriteLEShort(name.Length);1985      WriteLEShort(entry.ExtraData.Length);19861987      if ( name.Length > 0 ) {1988        baseStream_.Write(name, 0, name.Length);1989      }19901991      if ( entry.LocalHeaderRequiresZip64 ) {1992        if ( !ed.Find(1) ) {1993          throw new ZipException("Internal error cannot find extra data");1994        }19951996        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1997      }19981999      if ( entry.ExtraData.Length > 0 ) {2000        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);2001      }2002    }20032004    int WriteCentralDirectoryHeader(ZipEntry entry)2005    {2006      if ( entry.CompressedSize < 0 ) {2007        throw new ZipException("Attempt to write central directory entry with unknown csize");2008      }20092010      if ( entry.Size < 0 ) {2011        throw new ZipException("Attempt to write central directory entry with unknown size");2012      }20132014      if ( entry.Crc < 0 ) {2015        throw new ZipException("Attempt to write central directory entry with unknown crc");2016      }20172018      // Write the central file header2019      WriteLEInt(ZipConstants.CentralHeaderSignature);20202021      // Version made by2022      WriteLEShort(ZipConstants.VersionMadeBy);20232024      // Version required to extract2025      WriteLEShort(entry.Version);19781979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;1980    }1981    #endregion19821983    void PostUpdateCleanup()1984    {1985      updateDataSource_ = null;1986      updates_ = null;1987      updateIndex_ = null;19881989      if (archiveStorage_ != null) {1990        archiveStorage_.Dispose();1991        archiveStorage_ = null;1992      }1993    }19941995    string GetTransformedFileName(string name)1996    {1997      INameTransform transform = NameTransform;1998      return (transform != null) ?1999        transform.TransformFile(name) :2000        name;2001    }20022003    string GetTransformedDirectoryName(string name)2004    {2005      INameTransform transform = NameTransform;2006      return (transform != null) ?2007        transform.TransformDirectory(name) :2008        name;2009    }20102011    /// <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    }20222023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2024    {2025      int bytesToCopy = GetDescriptorSize(update);  20262027      WriteLEShort(entry.Flags);20282029      unchecked {2030        WriteLEShort((byte)entry.CompressionMethod);2031        WriteLEInt((int)entry.DosTime);2032        WriteLEInt((int)entry.Crc);2033      }20342035      if ( (entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff) ) {2036        WriteLEInt(-1);2037      }2038      else {2039        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));2040      }20412042      if ( (entry.IsZip64Forced()) || (entry.Size >= 0xffffffff) ) {2043        WriteLEInt(-1);2044      }2045      else {2046        WriteLEInt((int)entry.Size);2047      }20482049      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);2027      if (bytesToCopy > 0) {2028        byte[] buffer = GetBuffer();20292030        while (bytesToCopy > 0) {2031          int readSize = Math.Min(buffer.Length, bytesToCopy);20322033          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    }20432044    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      }  20502051      if ( name.Length > 0xFFFF ) {2052        throw new ZipException("Entry name is too long.");2053      }2051      // NOTE: Compressed size is updated elsewhere.2052      var crc = new Crc32();2053      byte[] buffer = GetBuffer();  20542055      WriteLEShort(name.Length);20562057      // Central header extra data is different to local header version so regenerate.2058      var ed = new ZipExtraData(entry.ExtraData);20592060      if ( entry.CentralHeaderRequiresZip64 ) {2061        ed.StartNewEntry();20622063        if ( (entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On) )2064        {2065          ed.AddLeLong(entry.Size);2066        }20672068        if ( (entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On) )2069        {2070          ed.AddLeLong(entry.CompressedSize);2071        }20722073        if ( entry.Offset >= 0xffffffff ) {2074          ed.AddLeLong(entry.Offset);2075        }20762077        // Number of disk on which this file starts isnt supported and is never written here.2078        ed.AddNewEntry(1);2079      }2080      else {2081        // Should have already be done when local header was added.2082        ed.Delete(1);2083      }20842085      byte[] centralExtraData = ed.GetEntryData();2055      long targetBytes = bytesToCopy;2056      long totalBytesRead = 0;20572058      int bytesRead;2059      do {2060        int readSize = buffer.Length;20612062        if (bytesToCopy < readSize) {2063          readSize = (int)bytesToCopy;2064        }20652066        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));20772078      if (totalBytesRead != targetBytes) {2079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2080      }20812082      if (updateCrc) {2083        update.OutEntry.Crc = crc.Value;2084      }2085    }  20862087      WriteLEShort(centralExtraData.Length);2088      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);20892090      WriteLEShort(0);  // disk number2091      WriteLEShort(0);  // internal file attributes20922093      // External file attributes...2094      if ( entry.ExternalFileAttributes != -1 ) {2095        WriteLEInt(entry.ExternalFileAttributes);2096      }2097      else {2098        if ( entry.IsDirectory ) {2099          WriteLEUint(16);2100        }2101        else {2102          WriteLEUint(0);2103        }2104      }21052106      if ( entry.Offset >= 0xffffffff ) {2107        WriteLEUint(0xffffffff);2108      }2109      else {2110        WriteLEUint((uint)(int)entry.Offset);2111      }21122113      if ( name.Length > 0 ) {2114        baseStream_.Write(name, 0, name.Length);2115      }21162117      if ( centralExtraData.Length > 0 ) {2118        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);2119      }21202121      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];21222123      if ( rawComment.Length > 0 ) {2124        baseStream_.Write(rawComment, 0, rawComment.Length);2125      }21262127      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;2128    }2129    #endregion21302131    void PostUpdateCleanup()2132    {2133            updateDataSource_ = null;2134            updates_ = null;2135            updateIndex_ = null;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    }21032104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2105    {2106      int bytesToCopy = GetDescriptorSize(update);21072108      while (bytesToCopy > 0) {2109        var readSize = (int)bytesToCopy;2110        byte[] buffer = GetBuffer();21112112        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    }21252126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2127    {2128      long bytesToCopy = update.Entry.CompressedSize;21292130      // NOTE: Compressed size is updated elsewhere.2131      var crc = new Crc32();2132      byte[] buffer = GetBuffer();21332134      long targetBytes = bytesToCopy;2135      long totalBytesRead = 0;  21362137            if (archiveStorage_ != null)2138            {2139        archiveStorage_.Dispose();2140        archiveStorage_=null;2141      }2142    }21432144    string GetTransformedFileName(string name)2145    {2146            INameTransform transform = NameTransform;2147      return (transform != null) ?2148        transform.TransformFile(name) :2149        name;2150    }21512152    string GetTransformedDirectoryName(string name)2153    {2154            INameTransform transform = NameTransform;2155            return (transform != null) ?2156        transform.TransformDirectory(name) :2157        name;2158    }21592160    /// <summary>2161    /// Get a raw memory buffer.2162    /// </summary>2163    /// <returns>Returns a raw memory buffer.</returns>2164    byte[] GetBuffer()2165    {2166      if ( copyBuffer_ == null ) {2167        copyBuffer_ = new byte[bufferSize_];2137      int bytesRead;2138      do {2139        int readSize = buffer.Length;21402141        if (bytesToCopy < readSize) {2142          readSize = (int)bytesToCopy;2143        }21442145        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);21532154          destinationPosition += bytesRead;2155          sourcePosition += bytesRead;2156          bytesToCopy -= bytesRead;2157          totalBytesRead += bytesRead;2158        }2159      }2160      while ((bytesRead > 0) && (bytesToCopy > 0));21612162      if (totalBytesRead != targetBytes) {2163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2164      }21652166      if (updateCrc) {2167        update.OutEntry.Crc = crc.Value;  2168      }2169      return copyBuffer_;2170    }21712172    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2173    {2174      int bytesToCopy = GetDescriptorSize(update);2169    }21702171    int FindExistingUpdate(ZipEntry entry)2172    {2173      int result = -1;2174      string convertedName = GetTransformedFileName(entry.Name);  21752176      if ( bytesToCopy > 0 ) {2177        byte[] buffer = GetBuffer();21782179        while ( bytesToCopy > 0 ) {2180          int readSize = Math.Min(buffer.Length, bytesToCopy);21812182          int bytesRead = source.Read(buffer, 0, readSize);2183          if ( bytesRead > 0 ) {2184            dest.Write(buffer, 0, bytesRead);2185            bytesToCopy -= bytesRead;2186          }2187          else {2188            throw new ZipException("Unxpected end of stream");2189          }2190        }2191      }2192    }21932194    void CopyBytes(ZipUpdate update, Stream destination, Stream source,2195      long bytesToCopy, bool updateCrc)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 useful2181            // 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    }21942195    int FindExistingUpdate(string fileName)  2196    {2197      if ( destination == source ) {2198        throw new InvalidOperationException("Destination and source are the same");2199      }2197      int result = -1;21982199      string convertedName = GetTransformedFileName(fileName);  22002201      // NOTE: Compressed size is updated elsewhere.2202      var crc = new Crc32();2203      byte[] buffer = GetBuffer();2201      if (updateIndex_.ContainsKey(convertedName)) {2202        result = (int)updateIndex_[convertedName];2203      }  22042205      long targetBytes = bytesToCopy;2206      long totalBytesRead = 0;22072208      int bytesRead;2209      do {2210        int readSize = buffer.Length;22112212        if ( bytesToCopy < readSize ) {2213          readSize = (int)bytesToCopy;2214        }22152216        bytesRead = source.Read(buffer, 0, readSize);2217        if ( bytesRead > 0 ) {2218          if ( updateCrc ) {2219            crc.Update(buffer, 0, bytesRead);2220          }2221          destination.Write(buffer, 0, bytesRead);2222          bytesToCopy -= bytesRead;2223          totalBytesRead += bytesRead;2224        }2225      }2226      while ( (bytesRead > 0) && (bytesToCopy > 0) );22272228      if ( totalBytesRead != targetBytes ) {2229        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2230      }22312232      if ( updateCrc ) {2233        update.OutEntry.Crc = crc.Value;2234      }2235    }22362237    /// <summary>2238    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.2239    /// </summary>2240    /// <param name="update">The update to get the size for.</param>2241    /// <returns>The descriptor size, zero if there isnt one.</returns>2242    int GetDescriptorSize(ZipUpdate update)2243    {2244      int result = 0;2245      if ( (update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {2246        result = ZipConstants.DataDescriptorSize - 4;2247        if ( update.Entry.LocalHeaderRequiresZip64 ) {2248          result = ZipConstants.Zip64DataDescriptorSize - 4;2249        }2250      }2251      return result;2252    }2205      /*2206            // This is slow like the coming of the next ice age but takes less storage and may be useful2207            // 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       */22162217      return result;2218    }22192220    /// <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_;22282229      if (entry.IsCrypted == true) {2230        result = CreateAndInitEncryptionStream(result, entry);2231      }22322233      switch (entry.CompressionMethod) {2234        case CompressionMethod.Stored:2235          result = new UncompressedStream(result);2236          break;22372238        case CompressionMethod.Deflated:2239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));2240          dos.IsStreamOwner = false;2241          result = dos;2242          break;22432244        default:2245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2246      }2247      return result;2248    }22492250    void AddEntry(ZipFile workFile, ZipUpdate update)2251    {2252      Stream source = null;  22532254    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2255    {2256      int bytesToCopy = GetDescriptorSize(update);22572258      while ( bytesToCopy > 0 ) {2259        var readSize = (int)bytesToCopy;2260        byte[] buffer = GetBuffer();2254      if (update.Entry.IsFile) {2255        source = update.GetSource();22562257        if (source == null) {2258          source = updateDataSource_.GetSource(update.Entry, update.Filename);2259        }2260      }  22612262        stream.Position = sourcePosition;2263        int bytesRead = stream.Read(buffer, 0, readSize);2264        if ( bytesRead > 0 ) {2265          stream.Position = destinationPosition;2266          stream.Write(buffer, 0, bytesRead);2267          bytesToCopy -= bytesRead;2268          destinationPosition += bytesRead;2269          sourcePosition += bytesRead;2270        }2271        else {2272          throw new ZipException("Unxpected end of stream");2273        }2274      }2275    }22762277    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2278    {2279      long bytesToCopy = update.Entry.CompressedSize;22802281      // NOTE: Compressed size is updated elsewhere.2282      var crc = new Crc32();2283      byte[] buffer = GetBuffer();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          }22732274          workFile.WriteLocalEntryHeader(update);22752276          long dataStart = workFile.baseStream_.Position;22772278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {2279            CopyBytes(update, output, source, sourceStreamLength, true);2280          }22812282          long dataEnd = workFile.baseStream_.Position;2283          update.OutEntry.CompressedSize = dataEnd - dataStart;  22842285      long targetBytes = bytesToCopy;2286      long totalBytesRead = 0;22872288      int bytesRead;2289      do2290      {2291        int readSize = buffer.Length;22922293        if ( bytesToCopy < readSize ) {2294          readSize = (int)bytesToCopy;2295        }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      }22942295    }  22962297        stream.Position = sourcePosition;2298        bytesRead = stream.Read(buffer, 0, readSize);2299        if ( bytesRead > 0 ) {2300          if ( updateCrc ) {2301            crc.Update(buffer, 0, bytesRead);2302          }2303          stream.Position = destinationPosition;2304          stream.Write(buffer, 0, bytesRead);23052306          destinationPosition += bytesRead;2307          sourcePosition += bytesRead;2308          bytesToCopy -= bytesRead;2309          totalBytesRead += bytesRead;2310        }2311      }2312      while ( (bytesRead > 0) && (bytesToCopy > 0) );23132314      if ( totalBytesRead != targetBytes ) {2315        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2316      }23172318      if ( updateCrc ) {2319        update.OutEntry.Crc = crc.Value;2320      }2321    }23222323    int FindExistingUpdate(ZipEntry entry)2324    {2325      int result = -1;2326      string convertedName = GetTransformedFileName(entry.Name);23272328      if (updateIndex_.ContainsKey(convertedName)) {2329        result = (int)updateIndex_[convertedName];2330      }2331/*2332      // This is slow like the coming of the next ice age but takes less storage and may be useful2333      // for CF?2334      for (int index = 0; index < updates_.Count; ++index)2335      {2336        ZipUpdate zu = ( ZipUpdate )updates_[index];2337        if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&2338          (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {2339          result = index;2340          break;2341        }2342      }2343 */2344      return result;2345    }23462347    int FindExistingUpdate(string fileName)2348    {2349      int result = -1;23502351      string convertedName = GetTransformedFileName(fileName);23522353      if (updateIndex_.ContainsKey(convertedName)) {2354        result = (int)updateIndex_[convertedName];2355      }23562357/*2358      // This is slow like the coming of the next ice age but takes less storage and may be useful2359      // for CF?2360      for ( int index = 0; index < updates_.Count; ++index ) {2361        if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,2362          true, CultureInfo.InvariantCulture) == 0 ) {2363          result = index;2364          break;2365        }2366      }2367 */23682369      return result;2370    }23712372    /// <summary>2373    /// Get an output stream for the specified <see cref="ZipEntry"/>2374    /// </summary>2375    /// <param name="entry">The entry to get an output stream for.</param>2376    /// <returns>The output stream obtained for the entry.</returns>2377    Stream GetOutputStream(ZipEntry entry)2378    {2379      Stream result = baseStream_;2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)2298    {2299      workFile.WriteLocalEntryHeader(update);2300      long dataStart = workFile.baseStream_.Position;23012302      // 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      }23102311      long dataEnd = workFile.baseStream_.Position;2312      update.Entry.CompressedSize = dataEnd - dataStart;2313    }23142315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2316    {2317      bool skipOver = false || update.Entry.Offset == destinationPosition;23182319      if (!skipOver) {2320        baseStream_.Position = destinationPosition;2321        workFile.WriteLocalEntryHeader(update);2322        destinationPosition = baseStream_.Position;2323      }23242325      long sourcePosition = 0;23262327      const int NameLengthOffset = 26;23282329      // TODO: Add base for SFX friendly handling2330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;23312332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23332334      // 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();23382339      sourcePosition = baseStream_.Position + nameLength + extraLength;23402341      if (skipOver) {2342        if (update.OffsetBasedSize != -1)2343          destinationPosition += update.OffsetBasedSize;2344        else2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2346          // WinZip produces a warning on these entries:2347          // "caution: value of lrec.csize (compressed size) changed from ..."2348          destinationPosition +=2349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size2350            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    }23582359    void CopyEntry(ZipFile workFile, ZipUpdate update)2360    {2361      workFile.WriteLocalEntryHeader(update);23622363      if (update.Entry.CompressedSize > 0) {2364        const int NameLengthOffset = 26;23652366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;23672368        // TODO: This wont work for SFX files!2369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23702371        uint nameLength = ReadLEUshort();2372        uint extraLength = ReadLEUshort();23732374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);23752376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2377      }2378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);2379    }  23802381      if ( entry.IsCrypted == true ) {2382#if NETCF_1_02383        throw new ZipException("Encryption not supported for Compact Framework 1.0");2384#else2385        result = CreateAndInitEncryptionStream(result, entry);2386#endif2387      }23882389      switch ( entry.CompressionMethod ) {2390        case CompressionMethod.Stored:2391          result = new UncompressedStream(result);2392          break;23932394        case CompressionMethod.Deflated:2395          var dos = new DeflaterOutputStream(result, new Deflater(9, true));2396          dos.IsStreamOwner = false;2397          result = dos;2398          break;23992400        default:2401          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2402      }2403      return result;2404    }24052406    void AddEntry(ZipFile workFile, ZipUpdate update)2407    {2408      Stream source = null;24092410      if ( update.Entry.IsFile ) {2411        source = update.GetSource();24122413        if ( source == null ) {2414          source = updateDataSource_.GetSource(update.Entry, update.Filename);2415        }2416      }24172418      if ( source != null ) {2419        using ( source ) {2420          long sourceStreamLength = source.Length;2421          if ( update.OutEntry.Size < 0 ) {2422            update.OutEntry.Size = sourceStreamLength;2423          }2424          else {2425            // Check for errant entries.2426            if ( update.OutEntry.Size != sourceStreamLength ) {2427              throw new ZipException("Entry size/stream size mismatch");2428            }2429          }24302431          workFile.WriteLocalEntryHeader(update);24322433          long dataStart = workFile.baseStream_.Position;24342435          using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {2436            CopyBytes(update, output, source, sourceStreamLength, true);2437          }24382439          long dataEnd = workFile.baseStream_.Position;2440          update.OutEntry.CompressedSize = dataEnd - dataStart;24412442          if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor)2443          {2444            var helper = new ZipHelperStream(workFile.baseStream_);2445            helper.WriteDataDescriptor(update.OutEntry);2446          }2447        }2381    void Reopen(Stream source)2382    {2383      if (source == null) {2384        throw new ZipException("Failed to reopen archive - no source");2385      }23862387      isNewArchive_ = false;2388      baseStream_ = source;2389      ReadEntries();2390    }23912392    void Reopen()2393    {2394      if (Name == null) {2395        throw new InvalidOperationException("Name is not known cannot Reopen");2396      }23972398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));2399    }24002401    void UpdateCommentOnly()2402    {2403      long baseLength = baseStream_.Length;24042405      ZipHelperStream updateFile = null;24062407      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {2408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);2409        updateFile = new ZipHelperStream(copyStream);2410        updateFile.IsStreamOwner = true;24112412        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 doesnt2418          // 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.24212422          // 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      }24312432      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        }24392440        const int CentralHeaderCommentSizeOffset = 16;2441        updateFile.Position += CentralHeaderCommentSizeOffset;24422443        byte[] rawComment = newComment_.RawComment;24442445        updateFile.WriteLEShort(rawComment.Length);2446        updateFile.Write(rawComment, 0, rawComment.Length);2447        updateFile.SetLength(updateFile.Position);  2448      }2449      else {2450        workFile.WriteLocalEntryHeader(update);2451        update.OutEntry.CompressedSize = 0;2452      }24532454    }24552456    void ModifyEntry(ZipFile workFile, ZipUpdate update)2457    {2458      workFile.WriteLocalEntryHeader(update);2459      long dataStart = workFile.baseStream_.Position;24602461      // TODO: This is slow if the changes don't effect the data!!2462      if ( update.Entry.IsFile && (update.Filename != null) ) {2463        using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {2464          using ( Stream source = this.GetInputStream(update.Entry) ) {2465            CopyBytes(update, output, source, source.Length, true);2466          }2467        }2468      }24692470      long dataEnd = workFile.baseStream_.Position;2471      update.Entry.CompressedSize = dataEnd - dataStart;2472    }24732474    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2475    {2476      bool skipOver = false || update.Entry.Offset == destinationPosition;24492450      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {2451        Reopen(archiveStorage_.ConvertTemporaryToFinal());2452      } else {2453        ReadEntries();2454      }2455    }24562457    /// <summary>2458    /// Class used to sort updates.2459    /// </summary>2460    class UpdateComparer : IComparer2461    {2462      /// <summary>2463      /// Compares two objects and returns a value indicating whether one is2464      /// 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;24752476        int result;  24772478      if ( !skipOver ) {2479        baseStream_.Position = destinationPosition;2480        workFile.WriteLocalEntryHeader(update);2481        destinationPosition = baseStream_.Position;2482      }24832484      long sourcePosition = 0;24852486      const int NameLengthOffset = 26;24872488      // TODO: Add base for SFX friendly handling2489      long entryDataOffset = update.Entry.Offset + NameLengthOffset;24902491      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);24922493      // Clumsy way of handling retrieving the original name and extra data length for now.2494      // TODO: Stop re-reading name and data length in CopyEntryDirect.2495      uint nameLength = ReadLEUshort();2496      uint extraLength = ReadLEUshort();24972498      sourcePosition = baseStream_.Position + nameLength + extraLength;24992500      if (skipOver) {2501        if (update.OffsetBasedSize != -1)2502          destinationPosition += update.OffsetBasedSize;2503        else2504          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2505          // WinZip produces a warning on these entries:2506          // "caution: value of lrec.csize (compressed size) changed from ..."2507          destinationPosition +=2508            (sourcePosition - entryDataOffset) + NameLengthOffset +  // Header size2509            update.Entry.CompressedSize + GetDescriptorSize(update);2510      }2511      else {2512        if ( update.Entry.CompressedSize > 0 ) {2513          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition );2514        }2515        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);2516      }2517    }25182519    void CopyEntry(ZipFile workFile, ZipUpdate update)2520    {2521      workFile.WriteLocalEntryHeader(update);25222523      if ( update.Entry.CompressedSize > 0 ) {2524        const int NameLengthOffset = 26;25252526        long entryDataOffset = update.Entry.Offset + NameLengthOffset;25272528        // TODO: This wont work for SFX files!2529        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);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;24892490          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    }25052506    void RunUpdates()2507    {2508      long sizeEntries = 0;2509      long endOfStream = 0;2510      bool directUpdate = false;2511      long destinationPosition = 0; // NOT SFX friendly25122513      ZipFile workFile;25142515      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;25232524        // 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;  25302531        uint nameLength = ReadLEUshort();2532        uint extraLength = ReadLEUshort();25332534        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);2531        if (key != null) {2532          workFile.key = (byte[])key.Clone();2533        }2534      }  25352536        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2537      }2538      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);2539    }25402541    void Reopen(Stream source)2542    {2543      if ( source == null ) {2544        throw new ZipException("Failed to reopen archive - no source");2545      }25462547      isNewArchive_ = false;2548      baseStream_ = source;2549      ReadEntries();2550    }25512552    void Reopen()2553    {2554      if (Name == null) {2555        throw new InvalidOperationException("Name is not known cannot Reopen");2556      }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;25472548              case UpdateCommand.Modify:2549                // TODO: Direct modifying of an entry will take some legwork.2550                ModifyEntry(workFile, update);2551                break;25522553              case UpdateCommand.Add:2554                if (!IsNewArchive && directUpdate) {2555                  workFile.baseStream_.Position = destinationPosition;2556                }  25572558      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));2559    }25602561    void UpdateCommentOnly()2562    {2563      long baseLength = baseStream_.Length;25642565      ZipHelperStream updateFile = null;25662567      if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {2568        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);2569        updateFile = new ZipHelperStream(copyStream);2570        updateFile.IsStreamOwner = true;2558                AddEntry(workFile, update);25592560                if (directUpdate) {2561                  destinationPosition = workFile.baseStream_.Position;2562                }2563                break;2564            }2565          }2566        }25672568        if (!IsNewArchive && directUpdate) {2569          workFile.baseStream_.Position = destinationPosition;2570        }  25712572        baseStream_.Close();2573        baseStream_ = null;2574      }2575      else {2576        if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {2577          // TODO: archiveStorage wasnt originally intended for this use.2578          // Need to revisit this to tidy up handling as archive storage currently doesnt2579          // handle the original stream well.2580          // The problem is when using an existing zip archive with an in memory archive storage.2581          // The open stream wont support writing but the memory storage should open the same file not an in memory one.25822583          // Need to tidy up the archive storage interface and contract basically.2584          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);2585          updateFile = new ZipHelperStream(baseStream_);2586        }2587        else {2588          baseStream_.Close();2589          baseStream_ = null;2590          updateFile = new ZipHelperStream(Name);2591        }2592      }25932594      using ( updateFile ) {2595        long locatedCentralDirOffset =2596          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,2597                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);2598        if ( locatedCentralDirOffset < 0 ) {2599          throw new ZipException("Cannot find central directory");2600        }26012602        const int CentralHeaderCommentSizeOffset = 16;2603        updateFile.Position += CentralHeaderCommentSizeOffset;26042605        byte[] rawComment = newComment_.RawComment;26062607        updateFile.WriteLEShort(rawComment.Length);2608        updateFile.Write(rawComment, 0, rawComment.Length);2609        updateFile.SetLength(updateFile.Position);2610      }26112612      if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {2613        Reopen(archiveStorage_.ConvertTemporaryToFinal());2614      }2615      else {2616        ReadEntries();2617      }2618    }26192620    /// <summary>2621    /// Class used to sort updates.2622    /// </summary>2623    class UpdateComparer : IComparer2624    {2625      /// <summary>2626      /// Compares two objects and returns a value indicating whether one is2627      /// less than, equal to or greater than the other.2628      /// </summary>2629      /// <param name="x">First object to compare</param>2630      /// <param name="y">Second object to compare.</param>2631      /// <returns>Compare result.</returns>2632      public int Compare(2633        object x,2634        object y)2635      {2636        var zx = x as ZipUpdate;2637        var zy = y as ZipUpdate;26382639        int result;26402641        if (zx == null) {2642          if (zy == null) {2643            result = 0;2644          }2645          else {2646            result = -1;2647          }2648        }2649        else if (zy == null) {2650          result = 1;2651        }2652        else {2653          int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;2654          int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;26552656          result = xCmdValue - yCmdValue;2657          if (result == 0) {2658            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;2659            if (offsetDiff < 0) {2660              result = -1;2661            }2662            else if (offsetDiff == 0) {2663              result = 0;2664            }2665            else {2666              result = 1;2667            }2668          }2669        }2670        return result;2671      }2672    }26732674    void RunUpdates()2675    {2676      long sizeEntries = 0;2677      long endOfStream = 0;2678      bool directUpdate = false;2679      long destinationPosition = 0; // NOT SFX friendly26802681      ZipFile workFile;2572        long centralDirOffset = workFile.baseStream_.Position;25732574        foreach (ZipUpdate update in updates_) {2575          if (update != null) {2576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2577          }2578        }25792580        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        }25842585        endOfStream = workFile.baseStream_.Position;25862587        // 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            }25962597            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      }26162617      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    }26272628    void CheckUpdating()2629    {2630      if (updates_ == null) {2631        throw new InvalidOperationException("BeginUpdate has not been called");2632      }2633    }26342635    #endregion26362637    #region ZipUpdate class2638    /// <summary>2639    /// Represents a pending update to a Zip file.2640    /// </summary>2641    class ZipUpdate2642    {2643      #region Constructors2644      public ZipUpdate(string fileName, ZipEntry entry)2645      {2646        command_ = UpdateCommand.Add;2647        entry_ = entry;2648        filename_ = fileName;2649      }26502651      [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      }26592660      [Obsolete]2661      public ZipUpdate(string fileName, string entryName)2662        : this(fileName, entryName, CompressionMethod.Deflated)2663      {2664        // Do nothing.2665      }26662667      [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      }26752676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2677      {2678        command_ = UpdateCommand.Add;2679        entry_ = entry;2680        dataSource_ = dataSource;2681      }  26822683      if ( IsNewArchive ) {2684        workFile = this;2685        workFile.baseStream_.Position = 0;2686        directUpdate = true;2687      }2688      else if ( archiveStorage_.UpdateMode == FileUpdateMode.Direct ) {2689        workFile = this;2690        workFile.baseStream_.Position = 0;2691        directUpdate = true;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      }  26922693        // Sort the updates by offset within copies/modifies, then adds.2694        // This ensures that data required by copies will not be overwritten.2695        updates_.Sort(new UpdateComparer());2696      }2697      else {2698        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());2699        workFile.UseZip64 = UseZip64;27002701        if (key != null) {2702          workFile.key = (byte[])key.Clone();2703        }2704      }27052706      try {2707        foreach ( ZipUpdate update in updates_ ) {2708          if (update != null) {2709            switch (update.Command) {2710              case UpdateCommand.Copy:2711                if (directUpdate) {2712                  CopyEntryDirect(workFile, update, ref destinationPosition);2713                }2714                else {2715                  CopyEntry(workFile, update);2716                }2717                break;2693      public ZipUpdate(UpdateCommand command, ZipEntry entry)2694      {2695        command_ = command;2696        entry_ = (ZipEntry)entry.Clone();2697      }269826992700      /// <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      #endregion27102711      /// <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      }  27182719              case UpdateCommand.Modify:2720                // TODO: Direct modifying of an entry will take some legwork.2721                ModifyEntry(workFile, update);2722                break;27232724              case UpdateCommand.Add:2725                if (!IsNewArchive && directUpdate) {2726                  workFile.baseStream_.Position = destinationPosition;2727                }27282729                AddEntry(workFile, update);27302731                if (directUpdate) {2732                  destinationPosition = workFile.baseStream_.Position;2733                }2734                break;2735            }2736          }2737        }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          }27272728          return outEntry_;2729        }2730      }27312732      /// <summary>2733      /// Get the command for this update.2734      /// </summary>2735      public UpdateCommand Command {2736        get { return command_; }2737      }  27382739        if ( !IsNewArchive && directUpdate ) {2740          workFile.baseStream_.Position = destinationPosition;2741        }27422743        long centralDirOffset = workFile.baseStream_.Position;27442745        foreach ( ZipUpdate update in updates_ ) {2746          if (update != null) {2747            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2748          }2749        }27502751        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);2752        using ( ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_) ) {2753          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);2754        }27552756        endOfStream = workFile.baseStream_.Position;27572758        // And now patch entries...2759        foreach ( ZipUpdate update in updates_ ) {2760          if (update != null)2761          {2762            // If the size of the entry is zero leave the crc as 0 as well.2763            // The calculated crc will be all bits on...2764            if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {2765              workFile.baseStream_.Position = update.CrcPatchOffset;2766              workFile.WriteLEInt((int)update.OutEntry.Crc);2767            }27682769            if (update.SizePatchOffset > 0) {2770              workFile.baseStream_.Position = update.SizePatchOffset;2771              if (update.OutEntry.LocalHeaderRequiresZip64) {2772                workFile.WriteLeLong(update.OutEntry.Size);2773                workFile.WriteLeLong(update.OutEntry.CompressedSize);2774              }2775              else {2776                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);2777                workFile.WriteLEInt((int)update.OutEntry.Size);2778              }2779            }2780          }2781        }2782      }2783      catch {2784        workFile.Close();2785        if (!directUpdate && (workFile.Name != null)) {2786          File.Delete(workFile.Name);2787        }2788        throw;2789      }27902791      if (directUpdate) {2792        workFile.baseStream_.SetLength(endOfStream);2793        workFile.baseStream_.Flush();2794        isNewArchive_ = false;2795        ReadEntries();2796      }2797      else {2798        baseStream_.Close();2799        Reopen(archiveStorage_.ConvertTemporaryToFinal());2800      }2801    }28022803    void CheckUpdating()2804    {2805      if ( updates_ == null ) {2806        throw new InvalidOperationException("BeginUpdate has not been called");2807      }2808    }28092810    #endregion28112812    #region ZipUpdate class2813    /// <summary>2814    /// Represents a pending update to a Zip file.2815    /// </summary>2816    class ZipUpdate2817    {2818      #region Constructors2819      public ZipUpdate(string fileName, ZipEntry entry)2820      {2821        command_ = UpdateCommand.Add;2822        entry_ = entry;2823        filename_ = fileName;2824      }28252826      [Obsolete]2827      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)2828      {2829        command_ = UpdateCommand.Add;2830        entry_ = new ZipEntry(entryName);2831        entry_.CompressionMethod = compressionMethod;2832        filename_ = fileName;2833      }28342835      [Obsolete]2836      public ZipUpdate(string fileName, string entryName)2837        : this(fileName, entryName, CompressionMethod.Deflated)2838      {2839        // Do nothing.2840      }28412842      [Obsolete]2843      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)2844      {2845        command_ = UpdateCommand.Add;2846        entry_ = new ZipEntry(entryName);2847        entry_.CompressionMethod = compressionMethod;2848        dataSource_ = dataSource;2849      }28502851      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2852      {2853        command_ = UpdateCommand.Add;2854        entry_ = entry;2855        dataSource_ = dataSource;2856      }28572858      public ZipUpdate(ZipEntry original, ZipEntry updated)2859      {2860        throw new ZipException("Modify not currently supported");2861      /*2862        command_ = UpdateCommand.Modify;2863        entry_ = ( ZipEntry )original.Clone();2864        outEntry_ = ( ZipEntry )updated.Clone();2865      */2866      }28672868      public ZipUpdate(UpdateCommand command, ZipEntry entry)2869      {2870        command_ = command;2871        entry_ = ( ZipEntry )entry.Clone();2872      }28732739      /// <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      }27452746      /// <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      }27532754      /// <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      }27612762      /// <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      }27702771      public Stream GetSource()2772      {2773        Stream result = null;2774        if (dataSource_ != null) {2775          result = dataSource_.GetSource();2776        }27772778        return result;2779      }27802781      #region Instance Fields2782      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      #endregion2791    }27922793    #endregion2794    #endregion27952796    #region Disposing27972798    #region IDisposable Members2799    void IDisposable.Dispose()2800    {2801      Close();2802    }2803    #endregion28042805    void DisposeInternal(bool disposing)2806    {2807      if (!isDisposed_) {2808        isDisposed_ = true;2809        entries_ = new ZipEntry[0];28102811        if (IsStreamOwner && (baseStream_ != null)) {2812          lock (baseStream_) {2813            baseStream_.Close();2814          }2815        }28162817        PostUpdateCleanup();2818      }2819    }28202821    /// <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    }28302831    #endregion28322833    #region Internal routines2834    #region Reading2835    /// <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 prematurely2841    /// </exception>2842    ushort ReadLEUshort()2843    {2844      int data1 = baseStream_.ReadByte();28452846      if (data1 < 0) {2847        throw new EndOfStreamException("End of stream");2848      }28492850      int data2 = baseStream_.ReadByte();28512852      if (data2 < 0) {2853        throw new EndOfStreamException("End of stream");2854      }285528562857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));2858    }28592860    /// <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 prematurely2869    /// </exception>2870    uint ReadLEUint()2871    {2872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));2873    }  28742875      /// <summary>2876      /// Copy an existing entry.2877      /// </summary>2878      /// <param name="entry">The existing entry to copy.</param>2879      public ZipUpdate(ZipEntry entry)2880        : this(UpdateCommand.Copy, entry)2881      {2882        // Do nothing.2883      }2884      #endregion28852886      /// <summary>2887      /// Get the <see cref="ZipEntry"/> for this update.2888      /// </summary>2889      /// <remarks>This is the source or original entry.</remarks>2890      public ZipEntry Entry2891      {2892        get { return entry_; }2893      }28942895      /// <summary>2896      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.2897      /// </summary>2898      public ZipEntry OutEntry2899      {2900        get {2901          if ( outEntry_ == null ) {2902            outEntry_ = (ZipEntry)entry_.Clone();2903          }29042905          return outEntry_;2906        }2907      }2875    ulong ReadLEUlong()2876    {2877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);2878    }28792880    #endregion2881    // 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    }28882889    /// <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 found2897    /// </exception>2898    void ReadEntries()2899    {2900      // Search for the End Of Central Directory.  When a zip comment is2901      // present the directory will start earlier2902      //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 files2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then2906      // this could be invalid.2907      // Could also speed this up by reading memory in larger blocks.  29082909      /// <summary>2910      /// Get the command for this update.2911      /// </summary>2912      public UpdateCommand Command2913      {2914        get { return command_; }2915      }29162917      /// <summary>2918      /// Get the filename if any for this update.  Null if none exists.2919      /// </summary>2920      public string Filename2921      {2922        get { return filename_; }2923      }29242925      /// <summary>2926      /// Get/set the location of the size patch for this update.2927      /// </summary>2928      public long SizePatchOffset2929      {2930        get { return sizePatchOffset_; }2931        set { sizePatchOffset_ = value; }2932      }29332934      /// <summary>2935      /// Get /set the location of the crc patch for this update.2936      /// </summary>2937      public long CrcPatchOffset2938      {2939        get { return crcPatchOffset_; }2940        set { crcPatchOffset_ = value; }2941      }29422943      /// <summary>2944      /// Get/set the size calculated by offset.2945      /// Specifically, the difference between this and next entry's starting offset.2946      /// </summary>2947      public long OffsetBasedSize2948      {2949        get { return _offsetBasedSize; }2950        set { _offsetBasedSize = value; }2951      }29522953      public Stream GetSource()2954      {2955        Stream result = null;2956        if ( dataSource_ != null ) {2957          result = dataSource_.GetSource();2958        }29592960        return result;2961      }29622963      #region Instance Fields2964      ZipEntry entry_;2965      ZipEntry outEntry_;2966      UpdateCommand command_;2967      IStaticDataSource dataSource_;2968      string filename_;2969      long sizePatchOffset_ = -1;2970      long crcPatchOffset_ = -1;2971      long _offsetBasedSize = -1;2972      #endregion2973    }29742975    #endregion2976    #endregion29772978    #region Disposing29792980    #region IDisposable Members2981    void IDisposable.Dispose()2982    {2983      Close();2984    }2985    #endregion29862987    void DisposeInternal(bool disposing)2988    {2989      if ( !isDisposed_ ) {2990        isDisposed_ = true;2991        entries_ = new ZipEntry[0];29922993        if ( IsStreamOwner && (baseStream_ != null) ) {2994          lock(baseStream_) {2995            baseStream_.Close();2996          }2997        }2909      if (baseStream_.CanSeek == false) {2910        throw new ZipException("ZipFile stream must be seekable");2911      }29122913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,2914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);29152916      if (locatedEndOfCentralDir < 0) {2917        throw new ZipException("Cannot find central directory");2918      }29192920      // Read end of central directory record2921      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();29282929      if (commentSize > 0) {2930        byte[] comment = new byte[commentSize];29312932        StreamUtils.ReadFully(baseStream_, comment);2933        comment_ = ZipConstants.ConvertToString(comment);2934      } else {2935        comment_ = string.Empty;2936      }29372938      bool isZip64 = false;29392940      // 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;29482949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 2950        if (offset < 0) {2951          throw new ZipException("Cannot find Zip64 locator");2952        }29532954        // number of the disk with the start of the zip64 end of central directory 4 bytes2955        // relative offset of the zip64 end of central directory record 8 bytes2956        // total number of disks 4 bytes2957        ReadLEUint(); // startDisk64 is not currently used2958        ulong offset64 = ReadLEUlong();2959        uint totalDisks = ReadLEUint();29602961        baseStream_.Position = (long)offset64;2962        long sig64 = ReadLEUint();29632964        if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {2965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));2966        }29672968        // 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();29782979        // NOTE: zip64 extensible data sector (variable size) is ignored.2980      }29812982      entries_ = new ZipEntry[entriesForThisDisk];29832984      // SFX/embedded support, find the offset of the first entry vis the start of the stream2985      // 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 offsets2988      // 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      }29962997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);  29982999        PostUpdateCleanup();3000      }3001    }30023003    /// <summary>3004    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.3005    /// </summary>3006    /// <param name="disposing">true to release both managed and unmanaged resources;3007    /// false to release only unmanaged resources.</param>3008    protected virtual void Dispose(bool disposing)3009    {3010      DisposeInternal(disposing);3011    }30123013    #endregion30143015    #region Internal routines3016    #region Reading3017    /// <summary>3018    /// Read an unsigned short in little endian byte order.3019    /// </summary>3020    /// <returns>Returns the value read.</returns>3021    /// <exception cref="EndOfStreamException">3022    /// The stream ends prematurely3023    /// </exception>3024    ushort ReadLEUshort()3025    {3026      int data1 = baseStream_.ReadByte();30273028      if ( data1 < 0 ) {3029        throw new EndOfStreamException("End of stream");3030      }30313032      int data2 = baseStream_.ReadByte();30333034      if ( data2 < 0 ) {3035        throw new EndOfStreamException("End of stream");3036      }303730383039      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));3040    }30413042    /// <summary>3043    /// Read a uint in little endian byte order.3044    /// </summary>3045    /// <returns>Returns the value read.</returns>3046    /// <exception cref="IOException">3047    /// An i/o error occurs.3048    /// </exception>3049    /// <exception cref="System.IO.EndOfStreamException">3050    /// The file ends prematurely3051    /// </exception>3052    uint ReadLEUint()3053    {3054      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));3055    }30563057    ulong ReadLEUlong()3058    {3059      return ReadLEUint() | ((ulong)ReadLEUint() << 32);3060    }30613062    #endregion3063    // NOTE this returns the offset of the first byte after the signature.3064    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)3065    {3066      using ( ZipHelperStream les = new ZipHelperStream(baseStream_) ) {3067        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);3068      }3069    }30703071    /// <summary>3072    /// Search for and read the central directory of a zip file filling the entries array.3073    /// </summary>3074    /// <exception cref="System.IO.IOException">3075    /// An i/o error occurs.3076    /// </exception>3077    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3078    /// The central directory is malformed or cannot be found3079    /// </exception>3080    void ReadEntries()3081    {3082      // Search for the End Of Central Directory.  When a zip comment is3083      // present the directory will start earlier3084      //3085      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.3086      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files3087      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then3088      // this could be invalid.3089      // Could also speed this up by reading memory in larger blocks.2999      for (ulong i = 0; i < entriesForThisDisk; i++) {3000        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {3001          throw new ZipException("Wrong Central Directory signature");3002        }30033004        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();30153016        int diskStartNo = ReadLEUshort();  // Not currently used3017        int internalAttributes = ReadLEUshort();  // Not currently used30183019        uint externalAttributes = ReadLEUint();3020        long offset = ReadLEUint();30213022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];30233024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);3025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);30263027        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;30363037        if ((bitFlags & 8) == 0) {3038          entry.CryptoCheckValue = (byte)(crc >> 24);3039        } else {3040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3041        }30423043        if (extraLen > 0) {3044          byte[] extra = new byte[extraLen];3045          StreamUtils.ReadFully(baseStream_, extra);3046          entry.ExtraData = extra;3047        }30483049        entry.ProcessExtraData(false);30503051        if (commentLen > 0) {3052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);3053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3054        }30553056        entries_[i] = entry;3057      }3058    }30593060    /// <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 prematurely3068    /// </exception>3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3070    /// The local header signature is invalid, the entry and central header file name lengths are different3071    /// or the local and entry compression methods dont match3072    /// </exception>3073    long LocateEntry(ZipEntry entry)3074    {3075      return TestLocalHeader(entry, HeaderTest.Extract);3076    }30773078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3079    {3080      CryptoStream result = null;30813082      if ((entry.Version < ZipConstants.VersionStrongEncryption)3083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3084        var classicManaged = new PkzipClassicManaged();30853086        OnKeysRequired(entry.Name);3087        if (HaveKeys == false) {3088          throw new ZipException("No password available for encrypted stream");3089        }  30903091      if (baseStream_.CanSeek == false) {3092        throw new ZipException("ZipFile stream must be seekable");3093      }30943095      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,3096        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);30973098      if (locatedEndOfCentralDir < 0) {3099        throw new ZipException("Cannot find central directory");3100      }31013102      // Read end of central directory record3103      ushort thisDiskNumber           = ReadLEUshort();3104      ushort startCentralDirDisk      = ReadLEUshort();3105      ulong entriesForThisDisk        = ReadLEUshort();3106      ulong entriesForWholeCentralDir = ReadLEUshort();3107      ulong centralDirSize            = ReadLEUint();3108      long offsetOfCentralDir         = ReadLEUint();3109      uint commentSize                = ReadLEUshort();31103111      if ( commentSize > 0 ) {3112        byte[] comment = new byte[commentSize];31133114        StreamUtils.ReadFully(baseStream_, comment);3115        comment_ = ZipConstants.ConvertToString(comment);3116      }3117      else {3118        comment_ = string.Empty;3119      }31203121      bool isZip64 = false;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 bytes31093110          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      }31193120      return result;3121    }  31223123      // Check if zip64 header information is required.3124      if ( (thisDiskNumber == 0xffff) ||3125        (startCentralDirDisk == 0xffff) ||3126        (entriesForThisDisk == 0xffff) ||3127        (entriesForWholeCentralDir == 0xffff) ||3128        (centralDirSize == 0xffffffff) ||3129        (offsetOfCentralDir == 0xffffffff) ) {3130        isZip64 = true;31313132        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 3133        if ( offset < 0 ) {3134          throw new ZipException("Cannot find Zip64 locator");3135        }31363137        // number of the disk with the start of the zip64 end of central directory 4 bytes3138        // relative offset of the zip64 end of central directory record 8 bytes3139        // total number of disks 4 bytes3140        ReadLEUint(); // startDisk64 is not currently used3141        ulong offset64 = ReadLEUlong();3142        uint totalDisks = ReadLEUint();31433144        baseStream_.Position = (long)offset64;3145        long sig64 = ReadLEUint();31463147        if ( sig64 != ZipConstants.Zip64CentralFileHeaderSignature ) {3148          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));3149        }31503151        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.3152        ulong recordSize = ReadLEUlong();3153        int versionMadeBy = ReadLEUshort();3154        int versionToExtract = ReadLEUshort();3155        uint thisDisk = ReadLEUint();3156        uint centralDirDisk = ReadLEUint();3157        entriesForThisDisk = ReadLEUlong();3158        entriesForWholeCentralDir = ReadLEUlong();3159        centralDirSize = ReadLEUlong();3160        offsetOfCentralDir = (long)ReadLEUlong();31613162        // NOTE: zip64 extensible data sector (variable size) is ignored.3163      }31643165      entries_ = new ZipEntry[entriesForThisDisk];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();31293130        OnKeysRequired(entry.Name);3131        if (HaveKeys == false) {3132          throw new ZipException("No password available for encrypted stream");3133        }31343135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3136        // which doesnt do this.3137        result = new CryptoStream(new UncompressedStream(baseStream),3138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);31393140        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    }31483149    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    }31573158    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    }  31663167      // SFX/embedded support, find the offset of the first entry vis the start of the stream3168      // This applies to Zip files that are appended to the end of an SFX stub.3169      // Or are appended as a resource to an executable.3170      // Zip files created by some archivers have the offsets altered to reflect the true offsets3171      // and so dont require any adjustment here...3172      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?3173      if ( !isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize)) ) {3174        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);3175        if (offsetOfFirstEntry <= 0) {3176          throw new ZipException("Invalid embedded zip archive");3177        }3178      }31793180      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);31813182      for (ulong i = 0; i < entriesForThisDisk; i++) {3183        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {3184          throw new ZipException("Wrong Central Directory signature");3185        }3167    #endregion31683169    #region Instance Fields3170    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_;31803181    // Default is dynamic which is not backwards compatible and can cause problems3182    // 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;  31863187        int versionMadeBy      = ReadLEUshort();3188        int versionToExtract   = ReadLEUshort();3189        int bitFlags           = ReadLEUshort();3190        int method             = ReadLEUshort();3191        uint dostime           = ReadLEUint();3192        uint crc               = ReadLEUint();3193        var csize             = (long)ReadLEUint();3194        var size              = (long)ReadLEUint();3195        int nameLen            = ReadLEUshort();3196        int extraLen           = ReadLEUshort();3197        int commentLen         = ReadLEUshort();31983199        int diskStartNo        = ReadLEUshort();  // Not currently used3200        int internalAttributes = ReadLEUshort();  // Not currently used3187    #region Zip Update Instance Fields3188    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    #endregion3200    #endregion  32013202        uint externalAttributes = ReadLEUint();3203        long offset             = ReadLEUint();32043205        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];32063207        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);3208        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);32093210        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);3211        entry.Crc = crc & 0xffffffffL;3212        entry.Size = size & 0xffffffffL;3213        entry.CompressedSize = csize & 0xffffffffL;3214        entry.Flags = bitFlags;3215        entry.DosTime = (uint)dostime;3216        entry.ZipFileIndex = (long)i;3217        entry.Offset = offset;3218        entry.ExternalFileAttributes = (int)externalAttributes;32193220        if ((bitFlags & 8) == 0) {3221          entry.CryptoCheckValue = (byte)(crc >> 24);3222        }3223        else {3224          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3225        }32263227        if (extraLen > 0) {3228          byte[] extra = new byte[extraLen];3229          StreamUtils.ReadFully(baseStream_, extra);3230          entry.ExtraData = extra;3231        }32323233        entry.ProcessExtraData(false);32343235        if (commentLen > 0) {3236          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);3237          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3238        }32393240        entries_[i] = entry;3241      }3242    }32433244    /// <summary>3245    /// Locate the data for a given entry.3246    /// </summary>3247    /// <returns>3248    /// The start offset of the data.3249    /// </returns>3250    /// <exception cref="System.IO.EndOfStreamException">3251    /// The stream ends prematurely3252    /// </exception>3253    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3254    /// The local header signature is invalid, the entry and central header file name lengths are different3255    /// or the local and entry compression methods dont match3256    /// </exception>3257    long LocateEntry(ZipEntry entry)3258    {3259      return TestLocalHeader(entry, HeaderTest.Extract);3260    }32613262#if !NETCF_1_03263    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3264    {3265      CryptoStream result = null;32663267      if ( (entry.Version < ZipConstants.VersionStrongEncryption)3268        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3269        var classicManaged = new PkzipClassicManaged();32703271        OnKeysRequired(entry.Name);3272        if (HaveKeys == false) {3273          throw new ZipException("No password available for encrypted stream");3274        }3202    #region Support Classes3203    /// <summary>3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3205    /// </summary>3206    class ZipString3207    {3208      #region Constructors3209      /// <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      }32183219      /// <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      #endregion32283229      /// <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      }32363237      /// <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      }32463247      /// <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      }32563257      /// <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      }32683269      void MakeTextAvailable()3270      {3271        if (comment_ == null) {3272          comment_ = ZipConstants.ConvertToString(rawComment_);3273        }3274      }  32753276        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);3277        CheckClassicPassword(result, entry);3278      }3279      else {3280#if !NET_1_1 && !NETCF_2_03281        if (entry.Version == ZipConstants.VERSION_AES) {3282          //3283          OnKeysRequired(entry.Name);3284          if (HaveKeys == false) {3285            throw new ZipException("No password available for AES encrypted stream");3286          }3287          int saltLen = entry.AESSaltLen;3288          byte[] saltBytes = new byte[saltLen];3289          int saltIn = baseStream.Read(saltBytes, 0, saltLen);3290          if (saltIn != saltLen)3291            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);3292          //3293          byte[] pwdVerifyRead = new byte[2];3294          baseStream.Read(pwdVerifyRead, 0, 2);3295          int blockSize = entry.AESKeySize / 8;  // bits to bytes32963297          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);3298          byte[] pwdVerifyCalc = decryptor.PwdVerifier;3299          if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])3300            throw new Exception("Invalid password for AES");3301          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);3302        }3303        else3304#endif3305        {3306          throw new ZipException("Decryption method not supported");3307        }3308      }33093310      return result;3311    }33123313    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)3314    {3315      CryptoStream result = null;3316      if ( (entry.Version < ZipConstants.VersionStrongEncryption)3317        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3318        var classicManaged = new PkzipClassicManaged();3276      void MakeBytesAvailable()3277      {3278        if (rawComment_ == null) {3279          rawComment_ = ZipConstants.ConvertToArray(comment_);3280        }3281      }32823283      /// <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      }32933294      #region Instance Fields3295      string comment_;3296      byte[] rawComment_;3297      bool isSourceString_;3298      #endregion3299    }33003301    /// <summary>3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3303    /// </summary>3304    class ZipEntryEnumerator : IEnumerator3305    {3306      #region Constructors3307      public ZipEntryEnumerator(ZipEntry[] entries)3308      {3309        array = entries;3310      }33113312      #endregion3313      #region IEnumerator Members3314      public object Current {3315        get {3316          return array[index];3317        }3318      }  33193320        OnKeysRequired(entry.Name);3321        if (HaveKeys == false) {3322          throw new ZipException("No password available for encrypted stream");3323        }3320      public void Reset()3321      {3322        index = -1;3323      }  33243325        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3326        // which doesnt do this.3327        result = new CryptoStream(new UncompressedStream(baseStream),3328          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);33293330        if ( (entry.Crc < 0) || (entry.Flags & 8) != 0) {3331          WriteEncryptionHeader(result, entry.DosTime << 16);3332        }3333        else {3334          WriteEncryptionHeader(result, entry.Crc);3335        }3336      }3337      return result;3338    }33393340    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)3325      public bool MoveNext()3326      {3327        return (++index < array.Length);3328      }3329      #endregion3330      #region Instance Fields3331      ZipEntry[] array;3332      int index = -1;3333      #endregion3334    }33353336    /// <summary>3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3338    /// to and flush, but cannot read, seek or do anything else to.3339    /// </summary>3340    class UncompressedStream : Stream  3341    {3342      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];3343      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);3344      if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {3345        throw new ZipException("Invalid password");3342      #region Constructors3343      public UncompressedStream(Stream baseStream)3344      {3345        baseStream_ = baseStream;  3346      }3347    }3348#endif33473348      #endregion  33493350    static void WriteEncryptionHeader(Stream stream, long crcValue)3351    {3352      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];3353      var rnd = new Random();3354      rnd.NextBytes(cryptBuffer);3355      cryptBuffer[11] = (byte)(crcValue >> 24);3356      stream.Write(cryptBuffer, 0, cryptBuffer.Length);3357    }33583359    #endregion33603361    #region Instance Fields3362    bool       isDisposed_;3363    string     name_;3364    string     comment_;3365    string     rawPassword_;3366    Stream     baseStream_;3367    bool       isStreamOwner;3368    long       offsetOfFirstEntry;3369    ZipEntry[] entries_;3370    byte[] key;3371    bool isNewArchive_;33723373    // Default is dynamic which is not backwards compatible and can cause problems3374    // with XP's built in compression which cant read Zip64 archives.3375    // However it does avoid the situation were a large file is added and cannot be completed correctly.3376    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.3377    UseZip64 useZip64_ = UseZip64.Dynamic ;33783379    #region Zip Update Instance Fields3380    ArrayList updates_;3381    long updateCount_; // Count is managed manually as updates_ can contain nulls!3382    Hashtable updateIndex_;3383    IArchiveStorage archiveStorage_;3384    IDynamicDataSource updateDataSource_;3385    bool contentsEdited_;3386    int bufferSize_ = DefaultBufferSize;3387    byte[] copyBuffer_;3388    ZipString newComment_;3389    bool commentEdited_;3390    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();3391    #endregion3392    #endregion33933394    #region Support Classes3395    /// <summary>3396    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3397    /// </summary>3398    class ZipString3399    {3400      #region Constructors3401      /// <summary>3402      /// Initialise a <see cref="ZipString"/> with a string.3403      /// </summary>3404      /// <param name="comment">The textual string form.</param>3405      public ZipString(string comment)3406      {3407        comment_ = comment;3408        isSourceString_ = true;3409      }34103411      /// <summary>3412      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.3413      /// </summary>3414      /// <param name="rawString"></param>3415      public ZipString(byte[] rawString)3416      {3417        rawComment_ = rawString;3418      }3419      #endregion34203421      /// <summary>3422      /// Get a value indicating the original source of data for this instance.3423      /// True if the source was a string; false if the source was binary data.3424      /// </summary>3425      public bool IsSourceString3426      {3427        get { return isSourceString_; }3428      }34293430      /// <summary>3431      /// Get the length of the comment when represented as raw bytes.3432      /// </summary>3433      public int RawLength3434      {3435        get {3436          MakeBytesAvailable();3437          return rawComment_.Length;3438        }3439      }34403441      /// <summary>3442      /// Get the comment in its 'raw' form as plain bytes.3443      /// </summary>3444      public byte[] RawComment3445      {3446        get {3447          MakeBytesAvailable();3448          return (byte[])rawComment_.Clone();3449        }3450      }34513452      /// <summary>3453      /// Reset the comment to its initial state.3454      /// </summary>3455      public void Reset()3456      {3457        if ( isSourceString_ ) {3458          rawComment_ = null;3459        }3460        else {3461          comment_ = null;3462        }3463      }34643465      void MakeTextAvailable()3466      {3467        if ( comment_ == null ) {3468          comment_ = ZipConstants.ConvertToString(rawComment_);3469        }3470      }34713472      void MakeBytesAvailable()3473      {3474        if ( rawComment_ == null ) {3475          rawComment_ = ZipConstants.ConvertToArray(comment_);3476        }3477      }34783479      /// <summary>3480      /// Implicit conversion of comment to a string.3481      /// </summary>3482      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>3483      /// <returns>The textual equivalent for the input value.</returns>3484      static public implicit operator string(ZipString zipString)3485      {3486        zipString.MakeTextAvailable();3487        return zipString.comment_;3488      }34893490      #region Instance Fields3491      string comment_;3492      byte[] rawComment_;3493      bool isSourceString_;3494      #endregion3495    }34963497    /// <summary>3498    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3499    /// </summary>3500    class ZipEntryEnumerator : IEnumerator3501    {3502      #region Constructors3503      public ZipEntryEnumerator(ZipEntry[] entries)3504      {3505        array = entries;3506      }35073508      #endregion3509      #region IEnumerator Members3510      public object Current3511      {3512        get {3513          return array[index];3514        }3515      }35163517      public void Reset()3518      {3519        index = -1;3520      }35213522      public bool MoveNext()3523      {3524        return (++index < array.Length);3525      }3526      #endregion3527      #region Instance Fields3528      ZipEntry[] array;3529      int index = -1;3530      #endregion3531    }35323533    /// <summary>3534    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3535    /// to and flush, but cannot read, seek or do anything else to.3536    /// </summary>3537    class UncompressedStream : Stream3538    {3539      #region Constructors3540      public UncompressedStream(Stream baseStream)3541      {3542        baseStream_ = baseStream;3543      }35443545      #endregion35463547      /// <summary>3548      /// Close this stream instance.3549      /// </summary>3550      public override void Close()3551      {3552        // Do nothing3553      }35543555      /// <summary>3556      /// Gets a value indicating whether the current stream supports reading.3557      /// </summary>3558      public override bool CanRead3559      {3560        get {3561          return false;3562        }3563      }35643565      /// <summary>3566      /// Write any buffered data to underlying storage.3567      /// </summary>3568      public override void Flush()3569      {3570        baseStream_.Flush();3571      }35723573      /// <summary>3574      /// Gets a value indicating whether the current stream supports writing.3575      /// </summary>3576      public override bool CanWrite3577      {3578        get {3579          return baseStream_.CanWrite;3580        }3581      }35823583      /// <summary>3584      /// Gets a value indicating whether the current stream supports seeking.3585      /// </summary>3586      public override bool CanSeek3587      {3588        get {3589          return false;3590        }3591      }35923593      /// <summary>3594      /// Get the length in bytes of the stream.3595      /// </summary>3596      public override long Length3597      {3598        get {3599          return 0;3600        }3601      }36023603      /// <summary>3604      /// Gets or sets the position within the current stream.3605      /// </summary>3606      public override long Position3607      {3608        get  {3609          return baseStream_.Position;3610        }3611                set {3612                    throw new NotImplementedException();3613                }3614            }36153616            /// <summary>3617            /// Reads a sequence of bytes from the current stream and advances the position within the stream by the num3618            /// </summary>3619            /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte3620            /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from t3621            /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3622            /// <returns>3623            /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if t3624            /// </returns>3625            /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer lengt3626            /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </ex3627            /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3628            /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3629            /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3630            /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3631            public override int Read(byte[] buffer, int offset, int count)3632      {3633        return 0;3634      }36353636      /// <summary>3637      /// Sets the position within the current stream.3638      /// </summary>3639      /// <param name="offset">A byte offset relative to the origin parameter.</param>3640      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3641      /// <returns>3642      /// The new position within the current stream.3643      /// </returns>3644      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3645      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3646      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3647      public override long Seek(long offset, SeekOrigin origin)3648      {3649        return 0;3650      }36513652      /// <summary>3653      /// Sets the length of the current stream.3654      /// </summary>3655      /// <param name="value">The desired length of the current stream in bytes.</param>3656      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3350      /// <summary>3351      /// Close this stream instance.3352      /// </summary>3353      public override void Close()3354      {3355        // Do nothing3356      }33573358      /// <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      }33663367      /// <summary>3368      /// Write any buffered data to underlying storage.3369      /// </summary>3370      public override void Flush()3371      {3372        baseStream_.Flush();3373      }33743375      /// <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      }33833384      /// <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      }33923393      /// <summary>3394      /// Get the length in bytes of the stream.3395      /// </summary>3396      public override long Length {3397        get {3398          return 0;3399        }3400      }34013402      /// <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      }34133414      /// <summary>3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3416      /// </summary>3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3419      /// <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 ma3422      /// </returns>3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3425      /// <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      }34333434      /// <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 is3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3445      public override long Seek(long offset, SeekOrigin origin)3446      {3447        return 0;3448      }34493450      /// <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 as3455      /// <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. </exceptio3457      public override void SetLength(long value)3458      {3459      }34603461      /// <summary>3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3463      /// </summary>3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3466      /// <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. </exceptio3470      /// <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      }34773478      readonly34793480      #region Instance Fields3481      Stream baseStream_;3482      #endregion3483    }34843485    /// <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 : Stream3490    {3491      #region Constructors3492      /// <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;35023503        // Although this is the only time the zipfile is used3504        // keeping a reference here prevents premature closure of3505        // this zip file and thus the baseStream_.35063507        // Code like this will cause apparently random failures depending3508        // 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      #endregion35193520      /// <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        }35303531        lock (baseStream_) {3532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);3533          return baseStream_.ReadByte();3534        }3535      }35363537      /// <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      }35473548      /// <summary>3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3550      /// </summary>3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3553      /// <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 ma3556      /// </returns>3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3559      /// <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 Seek3573          // (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      }35843585      /// <summary>3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3587      /// </summary>3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3590      /// <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. </exceptio3594      /// <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      }36013602      /// <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 as3607      /// <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. </exceptio3609      public override void SetLength(long value)3610      {3611        throw new NotSupportedException();3612      }36133614      /// <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 is3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3625      public override long Seek(long offset, SeekOrigin origin)3626      {3627        long newPos = readPos_;36283629        switch (origin) {3630          case SeekOrigin.Begin:3631            newPos = start_ + offset;3632            break;36333634          case SeekOrigin.Current:3635            newPos = readPos_ + offset;3636            break;36373638          case SeekOrigin.End:3639            newPos = end_ + offset;3640            break;3641        }36423643        if (newPos < start_) {3644          throw new ArgumentException("Negative position is invalid");3645        }36463647        if (newPos >= end_) {3648          throw new IOException("Cannot seek past end");3649        }3650        readPos_ = newPos;3651        return readPos_;3652      }36533654      /// <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      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3659      public override void SetLength(long value)3660      {3658      public override void Flush()3659      {3660        // Nothing to do.  3661      }  3662  3663      /// <summary>3664      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3664      /// Gets or sets the position within the current stream.  3665      /// </summary>3666      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3667      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3668      /// <param name="count">The number of bytes to be written to the current stream.</param>3669      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3670      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3671      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3672      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3673      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3674      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3675      public override void Write(byte[] buffer, int offset, int count)3676      {3677        baseStream_.Write(buffer, offset, count);3678      }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. </exceptio3671      public override long Position {3672        get { return readPos_ - start_; }3673        set {3674          long newPos = start_ + value;36753676          if (newPos < start_) {3677            throw new ArgumentException("Negative position is invalid");3678          }  36793680      readonly36813682      #region Instance Fields3683      Stream baseStream_;3684      #endregion3685    }3680          if (newPos >= end_) {3681            throw new InvalidOperationException("Cannot seek past end");3682          }3683          readPos_ = newPos;3684        }3685      }  36863687    /// <summary>3688    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>3689    /// whose data is only a part or subsection of a file.3690    /// </summary>3691    class PartialInputStream : Stream3692    {3693      #region Constructors3694      /// <summary>3695      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.3696      /// </summary>3697      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>3698      /// <param name="start">The start of the partial data.</param>3699      /// <param name="length">The length of the partial data.</param>3700      public PartialInputStream(ZipFile zipFile, long start, long length)3701      {3702        start_ = start;3703        length_ = length;37043705        // Although this is the only time the zipfile is used3706        // keeping a reference here prevents premature closure of3707        // this zip file and thus the baseStream_.37083709        // Code like this will cause apparently random failures depending3710        // on the size of the files and when garbage is collected.3711        //3712        // ZipFile z = new ZipFile (stream);3713        // Stream reader = z.GetInputStream(0);3714        // uses reader here....3715        zipFile_ = zipFile;3716        baseStream_ = zipFile_.baseStream_;3717        readPos_ = start;3718        end_ = start + length;3719      }3720      #endregion37213722      /// <summary>3723      /// Read a byte from this stream.3724      /// </summary>3725      /// <returns>Returns the byte read or -1 on end of stream.</returns>3726      public override int ReadByte()3727      {3728        if (readPos_ >= end_) {3729           // -1 is the correct value at end of stream.3730          return -1;3731        }37323733        lock( baseStream_ ) {3734          baseStream_.Seek(readPos_++, SeekOrigin.Begin);3735          return baseStream_.ReadByte();3736        }3737      }37383739      /// <summary>3740      /// Close this <see cref="PartialInputStream">partial input stream</see>.3741      /// </summary>3742      /// <remarks>3743      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.3744      /// </remarks>3745      public override void Close()3746      {3747        // Do nothing at all!3748      }37493750      /// <summary>3751      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3752      /// </summary>3753      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3754      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3755      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3756      /// <returns>3757      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma3758      /// </returns>3759      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3760      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3761      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3762      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3763      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3764      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3765      public override int Read(byte[] buffer, int offset, int count)3766      {3767        lock(baseStream_) {3768          if (count > end_ - readPos_) {3769            count = (int) (end_ - readPos_);3770            if (count == 0) {3771              return 0;3772            }3773          }37743775          baseStream_.Seek(readPos_, SeekOrigin.Begin);3776          int readCount = baseStream_.Read(buffer, offset, count);3777          if (readCount > 0) {3778            readPos_ += readCount;3779          }3780          return readCount;3781        }3782      }37833784      /// <summary>3785      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3786      /// </summary>3787      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3788      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3789      /// <param name="count">The number of bytes to be written to the current stream.</param>3790      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3791      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3792      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3793      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3794      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3795      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3796      public override void Write(byte[] buffer, int offset, int count)3797      {3798        throw new NotSupportedException();3799      }38003801      /// <summary>3802      /// When overridden in a derived class, sets the length of the current stream.3803      /// </summary>3804      /// <param name="value">The desired length of the current stream in bytes.</param>3805      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3806      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3807      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3808      public override void SetLength(long value)3809      {3810        throw new NotSupportedException();3811      }38123813      /// <summary>3814      /// When overridden in a derived class, sets the position within the current stream.3815      /// </summary>3816      /// <param name="offset">A byte offset relative to the origin parameter.</param>3817      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3818      /// <returns>3819      /// The new position within the current stream.3820      /// </returns>3821      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3822      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3823      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3824      public override long Seek(long offset, SeekOrigin origin)3825      {3826        long newPos = readPos_;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. </excep3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3694      public override long Length {3695        get { return length_; }3696      }36973698      /// <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      }37063707      /// <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      }37153716      /// <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      }37243725      /// <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 Fields3734      ZipFile zipFile_;3735      Stream baseStream_;3736      long start_;3737      long length_;3738      long readPos_;3739      long end_;3740      #endregion3741    }3742    #endregion3743  }37443745  #endregion37463747  #region DataSources3748  /// <summary>3749  /// Provides a static way to obtain a source of data for an entry.3750  /// </summary>3751  public interface IStaticDataSource3752  {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  }37603761  /// <summary>3762  /// Represents a source of data that can dynamically provide3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3764  /// </summary>3765  public interface IDynamicDataSource3766  {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  }37763777  /// <summary>3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3779  /// </summary>3780  public class StaticDiskDataSource : IStaticDataSource3781  {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    }37903791    #region IDataSource Members37923793    /// <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    }38013802    readonly38033804    #endregion3805    #region Instance Fields3806    string fileName_;3807    #endregion3808  }380938103811  /// <summary>3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.3813  /// </summary>3814  public class DynamicDiskDataSource : IDynamicDataSource3815  {38163817    #region IDataSource Members3818    /// <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;  38273828        switch ( origin )3829        {3830          case SeekOrigin.Begin:3831            newPos = start_ + offset;3832            break;38333834          case SeekOrigin.Current:3835            newPos = readPos_ + offset;3836            break; + 655403828       if (name != null) { + 33829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);3830      }3831 + 655403832      return result;3833    }38343835    #endregion3836  }  38373838          case SeekOrigin.End:3839            newPos = end_ + offset;3840            break;3841        }38423843        if ( newPos < start_ ) {3844          throw new ArgumentException("Negative position is invalid");3845        }38463847        if ( newPos >= end_ ) {3848          throw new IOException("Cannot seek past end");3849        }3850        readPos_ = newPos;3851        return readPos_;3852      }38533854      /// <summary>3855      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.3856      /// </summary>3857      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3858      public override void Flush()3859      {3860        // Nothing to do.3861      }38623863      /// <summary>3864      /// Gets or sets the position within the current stream.3865      /// </summary>3866      /// <value></value>3867      /// <returns>The current position within the stream.</returns>3868      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3869      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>3870      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3871      public override long Position {3872        get { return readPos_ - start_; }3873        set {3874          long newPos = start_ + value;38753876          if ( newPos < start_ ) {3877            throw new ArgumentException("Negative position is invalid");3878          }3838  #endregion38393840  #region Archive Storage3841  /// <summary>3842  /// Defines facilities for data storage when updating Zip Archives.3843  /// </summary>3844  public interface IArchiveStorage3845  {3846    /// <summary>3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.3848    /// </summary>3849    FileUpdateMode UpdateMode { get; }38503851    /// <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();38573858    /// <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();38643865    /// <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);38713872    /// <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);  38793880          if ( newPos >= end_ ) {3881            throw new InvalidOperationException("Cannot seek past end");3882          }3883          readPos_ = newPos;3884        }3885      }38863887      /// <summary>3888      /// Gets the length in bytes of the stream.3889      /// </summary>3890      /// <value></value>3891      /// <returns>A long value representing the length of the stream in bytes.</returns>3892      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep3893      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3894      public override long Length {3895        get { return length_; }3896      }38973898      /// <summary>3899      /// Gets a value indicating whether the current stream supports writing.3900      /// </summary>3901      /// <value>false</value>3902      /// <returns>true if the stream supports writing; otherwise, false.</returns>3903      public override bool CanWrite {3904        get { return false; }3905      }39063907      /// <summary>3908      /// Gets a value indicating whether the current stream supports seeking.3909      /// </summary>3910      /// <value>true</value>3911      /// <returns>true if the stream supports seeking; otherwise, false.</returns>3912      public override bool CanSeek {3913        get { return true; }3914      }39153916      /// <summary>3917      /// Gets a value indicating whether the current stream supports reading.3918      /// </summary>3919      /// <value>true.</value>3920      /// <returns>true if the stream supports reading; otherwise, false.</returns>3921      public override bool CanRead {3922        get { return true; }3923      }39243925#if !NET_1_0 && !NET_1_1 && !NETCF_1_03926      /// <summary>3927      /// Gets a value that determines whether the current stream can time out.3928      /// </summary>3929      /// <value></value>3930      /// <returns>A value that determines whether the current stream can time out.</returns>3931      public override bool CanTimeout {3932        get { return baseStream_.CanTimeout; }3933      }3934#endif3935      #region Instance Fields3936      ZipFile zipFile_;3937      Stream baseStream_;3938      long start_;3939      long length_;3940      long readPos_;3941      long end_;3942      #endregion3943    }3944    #endregion3945  }39463947  #endregion39483949  #region DataSources3950  /// <summary>3951  /// Provides a static way to obtain a source of data for an entry.3952  /// </summary>3953  public interface IStaticDataSource3954  {3955    /// <summary>3956    /// Get a source of data by creating a new stream.3957    /// </summary>3958    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3959    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3960    Stream GetSource();3961  }39623963  /// <summary>3964  /// Represents a source of data that can dynamically provide3965  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3966  /// </summary>3967  public interface IDynamicDataSource3968  {3969    /// <summary>3970    /// Get a data source.3971    /// </summary>3972    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>3973    /// <param name="name">The name for data if known.</param>3974    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3975    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3976    Stream GetSource(ZipEntry entry, string name);3977  }39783979  /// <summary>3980  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3981  /// </summary>3982  public class StaticDiskDataSource : IStaticDataSource3983  {3984    /// <summary>3985    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>3986    /// </summary>3987    /// <param name="fileName">The name of the file to obtain data from.</param>3988    public StaticDiskDataSource(string fileName)3989    {3990      fileName_ = fileName;3991    }39923993    #region IDataSource Members39943995    /// <summary>3996    /// Get a <see cref="Stream"/> providing data.3997    /// </summary>3998    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>3999    public Stream GetSource()4000    {4001      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4002    }3880    /// <summary>3881    /// Dispose of this instance.3882    /// </summary>3883    void Dispose();3884  }38853886  /// <summary>3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.3888  /// </summary>3889  abstract public class BaseArchiveStorage : IArchiveStorage3890  {3891    #region Constructors3892    /// <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    #endregion39013902    #region IArchiveStorage Members39033904    /// <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();39103911    /// <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 read3915    /// the final storage for the archive.</returns>3916    /// <seealso cref="GetTemporaryOutput"/>3917    public abstract Stream ConvertTemporaryToFinal();39183919    /// <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);39253926    /// <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);39323933    /// <summary>3934    /// Disposes this instance.3935    /// </summary>3936    public abstract void Dispose();39373938    /// <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    }39473948    #endregion39493950    #region Instance Fields3951    FileUpdateMode updateMode_;3952    #endregion3953  }39543955  /// <summary>3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.3957  /// </summary>3958  public class DiskArchiveStorage : BaseArchiveStorage3959  {3960    #region Constructors3961    /// <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      }39723973      fileName_ = file.Name;3974    }39753976    /// <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    #endregion39853986    #region IArchiveStorage Members39873988    /// <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      }  40034004    readonly40054006    #endregion4007    #region Instance Fields4008    string fileName_;4009    #endregion4010  }401140124013  /// <summary>4014  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.4015  /// </summary>4016  public class DynamicDiskDataSource : IDynamicDataSource4017  {40184019    #region IDataSource Members4020    /// <summary>4021    /// Get a <see cref="Stream"/> providing data for an entry.4022    /// </summary>4023    /// <param name="entry">The entry to provide data for.</param>4024    /// <param name="name">The file name for data if known.</param>4025    /// <returns>Returns a stream providing data; or null if not available</returns>4026    public Stream GetSource(ZipEntry entry, string name)4027    { - 655404028      Stream result = null;4004      return temporaryStream_;4005    }40064007    /// <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 read4011    /// 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      }40174018      Stream result = null;40194020      string moveTempName = GetTempFileName(fileName_, false);4021      bool newFileCreated = false;40224023      try {4024        temporaryStream_.Close();4025        File.Move(fileName_, moveTempName);4026        File.Move(temporaryName_, fileName_);4027        newFileCreated = true;4028        File.Delete(moveTempName);  4029 - 655404030       if ( name != null ) { - 34031        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);4032      }4030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4031      } catch (Exception) {4032        result = null;  4033 - 655404034      return result;4035    }40364037    #endregion4038  }4034        // Try to roll back changes...4035        if (!newFileCreated) {4036          File.Move(moveTempName, fileName_);4037          File.Delete(temporaryName_);4038        }  40394040  #endregion40414042  #region Archive Storage4043  /// <summary>4044  /// Defines facilities for data storage when updating Zip Archives.4045  /// </summary>4046  public interface IArchiveStorage4047  {4048    /// <summary>4049    /// Get the <see cref="FileUpdateMode"/> to apply during updates.4050    /// </summary>4051    FileUpdateMode UpdateMode { get; }40524053    /// <summary>4054    /// Get an empty <see cref="Stream"/> that can be used for temporary output.4055    /// </summary>4056    /// <returns>Returns a temporary output <see cref="Stream"/></returns>4057    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4058    Stream GetTemporaryOutput();40594060    /// <summary>4061    /// Convert a temporary output stream to a final stream.4062    /// </summary>4063    /// <returns>The resulting final <see cref="Stream"/></returns>4064    /// <seealso cref="GetTemporaryOutput"/>4065    Stream ConvertTemporaryToFinal();40664067    /// <summary>4068    /// Make a temporary copy of the original stream.4069    /// </summary>4070    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4071    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4072    Stream MakeTemporaryCopy(Stream stream);40734074    /// <summary>4075    /// Return a stream suitable for performing direct updates on the original source.4076    /// </summary>4077    /// <param name="stream">The current stream.</param>4078    /// <returns>Returns a stream suitable for direct updating.</returns>4079    /// <remarks>This may be the current stream passed.</remarks>4080    Stream OpenForDirectUpdate(Stream stream);40814082    /// <summary>4083    /// Dispose of this instance.4084    /// </summary>4085    void Dispose();4086  }4040        throw;4041      }40424043      return result;4044    }40454046    /// <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();40544055      temporaryName_ = GetTempFileName(fileName_, true);4056      File.Copy(fileName_, temporaryName_, true);40574058      temporaryStream_ = new FileStream(temporaryName_,4059        FileMode.Open,4060        FileAccess.ReadWrite);4061      return temporaryStream_;4062    }40634064    /// <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        }40774078        result = new FileStream(fileName_,4079            FileMode.Open,4080            FileAccess.ReadWrite);4081      } else {4082        result = stream;4083      }40844085      return result;4086    }  40874088  /// <summary>4089  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.4090  /// </summary>4091  abstract public class BaseArchiveStorage : IArchiveStorage4092  {4093    #region Constructors4094    /// <summary>4095    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.4096    /// </summary>4097    /// <param name="updateMode">The update mode.</param>4098    protected BaseArchiveStorage(FileUpdateMode updateMode)4099    {4100      updateMode_ = updateMode;4101    }4102    #endregion41034104    #region IArchiveStorage Members41054106    /// <summary>4107    /// Gets a temporary output <see cref="Stream"/>4108    /// </summary>4109    /// <returns>Returns the temporary output stream.</returns>4110    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4111    public abstract Stream GetTemporaryOutput();41124113    /// <summary>4114    /// Converts the temporary <see cref="Stream"/> to its final form.4115    /// </summary>4116    /// <returns>Returns a <see cref="Stream"/> that can be used to read4117    /// the final storage for the archive.</returns>4118    /// <seealso cref="GetTemporaryOutput"/>4119    public abstract Stream ConvertTemporaryToFinal();41204121    /// <summary>4122    /// Make a temporary copy of a <see cref="Stream"/>.4123    /// </summary>4124    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>4125    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4126    public abstract Stream MakeTemporaryCopy(Stream stream);41274128    /// <summary>4129    /// Return a stream suitable for performing direct updates on the original source.4130    /// </summary>4131    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>4132    /// <returns>Returns a stream suitable for direct updating.</returns>4133    public abstract Stream OpenForDirectUpdate(Stream stream);41344135    /// <summary>4136    /// Disposes this instance.4137    /// </summary>4138    public abstract void Dispose();41394140    /// <summary>4141    /// Gets the update mode applicable.4142    /// </summary>4143    /// <value>The update mode.</value>4144    public FileUpdateMode UpdateMode4145    {4146      get {4147        return updateMode_;4148      }4149    }41504151    #endregion41524153    #region Instance Fields4154    FileUpdateMode updateMode_;4155    #endregion4156  }41574158  /// <summary>4159  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.4160  /// </summary>4161  public class DiskArchiveStorage : BaseArchiveStorage4162  {4163    #region Constructors4164    /// <summary>4165    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4166    /// </summary>4167    /// <param name="file">The file.</param>4168    /// <param name="updateMode">The update mode.</param>4169    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)4170      : base(updateMode)4171    {4172      if ( file.Name == null ) {4173        throw new ZipException("Cant handle non file archives");4174      }41754176      fileName_ = file.Name;4177    }4088    /// <summary>4089    /// Disposes this instance.4090    /// </summary>4091    public override void Dispose()4092    {4093      if (temporaryStream_ != null) {4094        temporaryStream_.Close();4095      }4096    }40974098    #endregion40994100    #region Internal routines4101    static string GetTempFileName(string original, bool makeTempFile)4102    {4103      string result = null;41044105      if (original == null) {4106        result = Path.GetTempFileName();4107      } else {4108        int counter = 0;4109        int suffixSeed = DateTime.Now.Second;41104111        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    #endregion41334134    #region Instance Fields4135    Stream temporaryStream_;4136    string fileName_;4137    string temporaryName_;4138    #endregion4139  }41404141  /// <summary>4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4143  /// </summary>4144  public class MemoryArchiveStorage : BaseArchiveStorage4145  {4146    #region Constructors4147    /// <summary>4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4149    /// </summary>4150    public MemoryArchiveStorage()4151      : base(FileUpdateMode.Direct)4152    {4153    }41544155    /// <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    }41644165    #endregion41664167    #region Properties4168    /// <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    }41744175    #endregion41764177    #region IArchiveStorage Members  4178  4179    /// <summary>4180    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4180    /// Gets the temporary output <see cref="Stream"/>  4181    /// </summary>4182    /// <param name="file">The file.</param>4183    public DiskArchiveStorage(ZipFile file)4184      : this(file, FileUpdateMode.Safe)4185    {4186    }4187    #endregion4182    /// <returns>Returns the temporary output stream.</returns>4183    public override Stream GetTemporaryOutput()4184    {4185      temporaryStream_ = new MemoryStream();4186      return temporaryStream_;4187    }  41884189    #region IArchiveStorage Members41904191    /// <summary>4192    /// Gets a temporary output <see cref="Stream"/> for performing updates on.4193    /// </summary>4194    /// <returns>Returns the temporary output stream.</returns>4195    public override Stream GetTemporaryOutput()4196    {4197      if ( temporaryName_ != null ) {4198        temporaryName_ = GetTempFileName(temporaryName_, true);4199        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4200      }4201      else {4202        // Determine where to place files based on internal strategy.4203        // Currently this is always done in system temp directory.4204        temporaryName_ = Path.GetTempFileName();4205        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4206      }42074208      return temporaryStream_;4209    }42104211    /// <summary>4212    /// Converts a temporary <see cref="Stream"/> to its final form.4213    /// </summary>4214    /// <returns>Returns a <see cref="Stream"/> that can be used to read4215    /// the final storage for the archive.</returns>4216    public override Stream ConvertTemporaryToFinal()4217    {4218      if ( temporaryStream_ == null ) {4219        throw new ZipException("No temporary stream has been created");4220      }42214222      Stream result = null;42234224      string moveTempName = GetTempFileName(fileName_, false);4225      bool newFileCreated = false;42264227      try  {4228        temporaryStream_.Close();4229        File.Move(fileName_, moveTempName);4230        File.Move(temporaryName_, fileName_);4231        newFileCreated = true;4232        File.Delete(moveTempName);42334234        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4235      }4236      catch(Exception) {4237        result  = null;42384239        // Try to roll back changes...4240        if ( !newFileCreated ) {4241          File.Move(moveTempName, fileName_);4242          File.Delete(temporaryName_);4243        }42444245        throw;4246      }42474248      return result;4249    }42504251    /// <summary>4252    /// Make a temporary copy of a stream.4253    /// </summary>4254    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4255    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4256    public override Stream MakeTemporaryCopy(Stream stream)4257    {4258      stream.Close();42594260      temporaryName_ = GetTempFileName(fileName_, true);4261      File.Copy(fileName_, temporaryName_, true);42624263      temporaryStream_ = new FileStream(temporaryName_,4264        FileMode.Open,4265        FileAccess.ReadWrite);4266      return temporaryStream_;4267    }42684269    /// <summary>4270    /// Return a stream suitable for performing direct updates on the original source.4271    /// </summary>4272    /// <param name="stream">The current stream.</param>4273    /// <returns>Returns a stream suitable for direct updating.</returns>4274    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>4275    public override Stream OpenForDirectUpdate(Stream stream)4276    {4277      Stream result;4278      if ((stream == null) || !stream.CanWrite)4279      {4280        if (stream != null) {4281          stream.Close();4282        }42834284        result = new FileStream(fileName_,4285            FileMode.Open,4286            FileAccess.ReadWrite);4287      }4288      else4289      {4290        result = stream;4291      }42924293      return result;4294    }42954296    /// <summary>4297    /// Disposes this instance.4298    /// </summary>4299    public override void Dispose()4300    {4301      if ( temporaryStream_ != null ) {4302        temporaryStream_.Close();4303      }4304    }43054306    #endregion43074308    #region Internal routines4309    static string GetTempFileName(string original, bool makeTempFile)4310    {4311      string result = null;43124313      if ( original == null ) {4314        result = Path.GetTempFileName();4315      }4316      else {4317        int counter = 0;4318        int suffixSeed = DateTime.Now.Second;43194320        while ( result == null ) {4321          counter += 1;4322          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);4323          if ( !File.Exists(newName) ) {4324            if ( makeTempFile) {4325              try  {4326                // Try and create the file.4327                using ( FileStream stream = File.Create(newName) ) {4328                }4329                result = newName;4330              }4331              catch {4332                suffixSeed = DateTime.Now.Second;4333              }4334            }4335            else {4336              result = newName;4337            }4338          }4339        }4340      }4341      return result;4342    }4343    #endregion43444345    #region Instance Fields4346    Stream temporaryStream_;4347    string fileName_;4348    string temporaryName_;4349    #endregion4350  }43514352  /// <summary>4353  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4354  /// </summary>4355  public class MemoryArchiveStorage : BaseArchiveStorage4356  {4357    #region Constructors4358    /// <summary>4359    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4360    /// </summary>4361    public MemoryArchiveStorage()4362      : base(FileUpdateMode.Direct)4363    {4364    }43654366    /// <summary>4367    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4368    /// </summary>4369    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>4370    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>4371    public MemoryArchiveStorage(FileUpdateMode updateMode)4372      : base(updateMode)4373    {4374    }43754376    #endregion43774378    #region Properties4379    /// <summary>4380    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.4381    /// </summary>4382    public MemoryStream FinalStream4383    {4384      get { return finalStream_; }4385    }43864387    #endregion43884389    #region IArchiveStorage Members43904391    /// <summary>4392    /// Gets the temporary output <see cref="Stream"/>4393    /// </summary>4394    /// <returns>Returns the temporary output stream.</returns>4395    public override Stream GetTemporaryOutput()4396    {4397      temporaryStream_ = new MemoryStream();4398      return temporaryStream_;4399    }44004401    /// <summary>4402    /// Converts the temporary <see cref="Stream"/> to its final form.4403    /// </summary>4404    /// <returns>Returns a <see cref="Stream"/> that can be used to read4405    /// the final storage for the archive.</returns>4406    public override Stream ConvertTemporaryToFinal()4407    {4408      if ( temporaryStream_ == null ) {4409        throw new ZipException("No temporary stream has been created");4410      }44114412      finalStream_ = new MemoryStream(temporaryStream_.ToArray());4413      return finalStream_;4414    }44154416    /// <summary>4417    /// Make a temporary copy of the original stream.4418    /// </summary>4419    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4420    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4421    public override Stream MakeTemporaryCopy(Stream stream)4422    {4423      temporaryStream_ = new MemoryStream();4424      stream.Position = 0;4425      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);4426      return temporaryStream_;4427    }44284429    /// <summary>4430    /// Return a stream suitable for performing direct updates on the original source.4431    /// </summary>4432    /// <param name="stream">The original source stream</param>4433    /// <returns>Returns a stream suitable for direct updating.</returns>4434    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;4435    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>4436    public override Stream OpenForDirectUpdate(Stream stream)4437    {4438      Stream result;4439      if ((stream == null) || !stream.CanWrite) {44404441        result = new MemoryStream();44424443        if (stream != null) {4444          stream.Position = 0;4445          StreamUtils.Copy(stream, result, new byte[4096]);44464447          stream.Close();4448        }4449      }4450      else {4451        result = stream;4452      }44534454      return result;4455    }44564457    /// <summary>4458    /// Disposes this instance.4459    /// </summary>4460    public override void Dispose()4461    {4462      if ( temporaryStream_ != null ) {4463        temporaryStream_.Close();4464      }4465    }44664467    #endregion44684469    #region Instance Fields4470    MemoryStream temporaryStream_;4471    MemoryStream finalStream_;4472    #endregion4473  }44744475  #endregion4476}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 read4193    /// 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      }41994200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());4201      return finalStream_;4202    }42034204    /// <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    }42164217    /// <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) {42284229        result = new MemoryStream();42304231        if (stream != null) {4232          stream.Position = 0;4233          StreamUtils.Copy(stream, result, new byte[4096]);42344235          stream.Close();4236        }4237      } else {4238        result = stream;4239      }42404241      return result;4242    }42434244    /// <summary>4245    /// Disposes this instance.4246    /// </summary>4247    public override void Dispose()4248    {4249      if (temporaryStream_ != null) {4250        temporaryStream_.Close();4251      }4252    }42534254    #endregion42554256    #region Instance Fields4257    MemoryStream temporaryStream_;4258    MemoryStream finalStream_;4259    #endregion4260  }42614262  #endregion4263} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_EntryPatchData.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_EntryPatchData.htm index 1ea4f3903..7df2ab838 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_EntryPatchData.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_EntryPatchData.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:4 Coverable lines:4 -Total lines:623 +Total lines:560 Line coverage:0% @@ -27,631 +27,568 @@

#LineLine coverage - 1// ZipHelperStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.1using System;2using System.IO;3using System.Text;45namespace ICSharpCode.SharpZipLib.Zip6{7  /// <summary>8  /// Holds data pertinent to a data descriptor.9  /// </summary>10  public class DescriptorData11  {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    }1920    /// <summary>21    /// Get / set the uncompressed size of data22    /// </summary>23    public long Size {24      get { return size; }25      set { size = value; }26    }2728    /// <summary>29    /// Get /set the crc value.30    /// </summary>31    public long Crc {32      get { return crc; }33      set { crc = (value & 0xffffffff); }34    }  3536using System;37using System.IO;38using System.Text;3940namespace ICSharpCode.SharpZipLib.Zip41{36    #region Instance Fields37    long size;38    long compressedSize;39    long crc;40    #endregion41  }  4243  /// <summary>44  /// Holds data pertinent to a data descriptor.45  /// </summary>46  public class DescriptorData47  {48    /// <summary>49    /// Get /set the compressed size of data.50    /// </summary>51    public long CompressedSize52    {53      get { return compressedSize; }54      set { compressedSize = value; }55    }5657    /// <summary>58    /// Get / set the uncompressed size of data59    /// </summary>60    public long Size61    {62      get { return size; }63      set { size = value; }64    }6566    /// <summary>67    /// Get /set the crc value.68    /// </summary>69    public long Crc70    {71      get { return crc; }72      set { crc = (value & 0xffffffff); }73    }7475    #region Instance Fields76    long size;77    long compressedSize;78    long crc;79    #endregion80  }8182  class EntryPatchData83  {84    public long SizePatchOffset85    { - 086      get { return sizePatchOffset_; } - 087      set { sizePatchOffset_ = value; }88    }8990    public long CrcPatchOffset91    { - 092      get { return crcPatchOffset_; } - 093      set { crcPatchOffset_ = value; }43  class EntryPatchData44  {45    public long SizePatchOffset { + 046      get { return sizePatchOffset_; } + 047      set { sizePatchOffset_ = value; }48    }4950    public long CrcPatchOffset { + 051      get { return crcPatchOffset_; } + 052      set { crcPatchOffset_ = value; }53    }5455    #region Instance Fields56    long sizePatchOffset_;57    long crcPatchOffset_;58    #endregion59  }6061  /// <summary>62  /// This class assists with writing/reading from Zip files.63  /// </summary>64  internal class ZipHelperStream : Stream65  {66    #region Constructors67    /// <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    }7677    /// <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    #endregion8687    /// <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    }  9596    #region Instance Fields97    long sizePatchOffset_;98    long crcPatchOffset_;99    #endregion100  }101102  /// <summary>103  /// This class assists with writing/reading from Zip files.104  /// </summary>105  internal class ZipHelperStream : Stream106  {107    #region Constructors108    /// <summary>109    /// Initialise an instance of this class.110    /// </summary>111    /// <param name="name">The name of the file to open.</param>112    public ZipHelperStream(string name)113    {114      stream_ = new FileStream(name, FileMode.Open, FileAccess.ReadWrite);115      isOwner_ = true;96    #region Base Stream Methods97    public override bool CanRead {98      get { return stream_.CanRead; }99    }100101    public override bool CanSeek {102      get { return stream_.CanSeek; }103    }104105    public override bool CanTimeout {106      get { return stream_.CanTimeout; }107    }108109    public override long Length {110      get { return stream_.Length; }111    }112113    public override long Position {114      get { return stream_.Position; }115      set { stream_.Position = value; }  116    }  117118    /// <summary>119    /// Initialise a new instance of <see cref="ZipHelperStream"/>.120    /// </summary>121    /// <param name="stream">The stream to use.</param>122    public ZipHelperStream(Stream stream)118    public override bool CanWrite {119      get { return stream_.CanWrite; }120    }121122    public override void Flush()  123    {124      stream_ = stream;124      stream_.Flush();  125    }126    #endregion127128    /// <summary>129    /// Get / set a value indicating wether the the underlying stream is owned or not.130    /// </summary>131    /// <remarks>If the stream is owned it is closed when this instance is closed.</remarks>132    public bool IsStreamOwner126127    public override long Seek(long offset, SeekOrigin origin)128    {129      return stream_.Seek(offset, origin);130    }131132    public override void SetLength(long value)  133    {134      get { return isOwner_; }135      set { isOwner_ = value; }136    }137138    #region Base Stream Methods139    public override bool CanRead140    {141      get { return stream_.CanRead; }142    }143144    public override bool CanSeek145    {146      get { return stream_.CanSeek; }147    }148149#if !NET_1_0 && !NET_1_1 && !NETCF_1_0150    public override bool CanTimeout151    {152      get { return stream_.CanTimeout; }153    }154#endif155156    public override long Length157    {158      get { return stream_.Length; }159    }160161    public override long Position162    {163      get { return stream_.Position; }164      set { stream_.Position = value;  }165    }166167    public override bool CanWrite168    {169      get { return stream_.CanWrite; }170    }134      stream_.SetLength(value);135    }136137    public override int Read(byte[] buffer, int offset, int count)138    {139      return stream_.Read(buffer, offset, count);140    }141142    public override void Write(byte[] buffer, int offset, int count)143    {144      stream_.Write(buffer, offset, count);145    }146147    /// <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    #endregion163164    // Write the local file header165    // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage166    void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)167    {168      CompressionMethod method = entry.CompressionMethod;169      bool headerInfoAvailable = true; // How to get this?170      bool patchEntryHeader = false;  171172    public override void Flush()173    {174      stream_.Flush();175    }176177    public override long Seek(long offset, SeekOrigin origin)178    {179      return stream_.Seek(offset, origin);180    }181182    public override void SetLength(long value)183    {184      stream_.SetLength(value);185    }186187    public override int Read(byte[] buffer, int offset, int count)188    {189      return stream_.Read(buffer, offset, count);190    }191192    public override void Write(byte[] buffer, int offset, int count)193    {194      stream_.Write(buffer, offset, count);195    }196197    /// <summary>198    /// Close the stream.199    /// </summary>200    /// <remarks>201    /// The underlying stream is closed only if <see cref="IsStreamOwner"/> is true.202    /// </remarks>203    override public void Close()204    {205      Stream toClose = stream_;206      stream_ = null;207      if (isOwner_ && (toClose != null))208      {209        isOwner_ = false;210        toClose.Close();211      }212    }213    #endregion214215    // Write the local file header216    // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage217    void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)218    {219      CompressionMethod method = entry.CompressionMethod;220      bool headerInfoAvailable = true; // How to get this?221      bool patchEntryHeader = false;222223      WriteLEInt(ZipConstants.LocalHeaderSignature);224225      WriteLEShort(entry.Version);226      WriteLEShort(entry.Flags);227      WriteLEShort((byte)method);228      WriteLEInt((int)entry.DosTime);229230      if (headerInfoAvailable == true) {231        WriteLEInt((int)entry.Crc);232        if ( entry.LocalHeaderRequiresZip64 ) {233          WriteLEInt(-1);234          WriteLEInt(-1);235        }236        else {237          WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.Compressed238          WriteLEInt((int)entry.Size);239        }240      } else {241        if (patchData != null) {242          patchData.CrcPatchOffset = stream_.Position;243        }244        WriteLEInt(0);  // Crc245246        if ( patchData != null ) {247          patchData.SizePatchOffset = stream_.Position;248        }249250        // For local header both sizes appear in Zip64 Extended Information251        if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) {252          WriteLEInt(-1);253          WriteLEInt(-1);254        }255        else {256          WriteLEInt(0);  // Compressed size257          WriteLEInt(0);  // Uncompressed size258        }259      }260261      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);262263      if (name.Length > 0xFFFF) {264        throw new ZipException("Entry name too long.");265      }266267      var ed = new ZipExtraData(entry.ExtraData);268269      if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader)) {270        ed.StartNewEntry();271        if (headerInfoAvailable) {272          ed.AddLeLong(entry.Size);273          ed.AddLeLong(entry.CompressedSize);274        }275        else {276          ed.AddLeLong(-1);277          ed.AddLeLong(-1);278        }279        ed.AddNewEntry(1);172      WriteLEInt(ZipConstants.LocalHeaderSignature);173174      WriteLEShort(entry.Version);175      WriteLEShort(entry.Flags);176      WriteLEShort((byte)method);177      WriteLEInt((int)entry.DosTime);178179      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.Compressed186          WriteLEInt((int)entry.Size);187        }188      } else {189        if (patchData != null) {190          patchData.CrcPatchOffset = stream_.Position;191        }192        WriteLEInt(0);  // Crc193194        if (patchData != null) {195          patchData.SizePatchOffset = stream_.Position;196        }197198        // For local header both sizes appear in Zip64 Extended Information199        if (entry.LocalHeaderRequiresZip64 && patchEntryHeader) {200          WriteLEInt(-1);201          WriteLEInt(-1);202        } else {203          WriteLEInt(0);  // Compressed size204          WriteLEInt(0);  // Uncompressed size205        }206      }207208      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);209210      if (name.Length > 0xFFFF) {211        throw new ZipException("Entry name too long.");212      }213214      var ed = new ZipExtraData(entry.ExtraData);215216      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);226227        if (!ed.Find(1)) {228          throw new ZipException("Internal error cant find extra data");229        }230231        if (patchData != null) {232          patchData.SizePatchOffset = ed.CurrentReadIndex;233        }234      } else {235        ed.Delete(1);236      }237238      byte[] extra = ed.GetEntryData();239240      WriteLEShort(name.Length);241      WriteLEShort(extra.Length);242243      if (name.Length > 0) {244        stream_.Write(name, 0, name.Length);245      }246247      if (entry.LocalHeaderRequiresZip64 && patchEntryHeader) {248        patchData.SizePatchOffset += stream_.Position;249      }250251      if (extra.Length > 0) {252        stream_.Write(extra, 0, extra.Length);253      }254    }255256    /// <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      }270271      long giveUpMarker = Math.Max(pos - maximumVariableData, 0);272273      // 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);  280281        if ( !ed.Find(1) ) {282          throw new ZipException("Internal error cant find extra data");283        }284285        if ( patchData != null ) {286          patchData.SizePatchOffset = ed.CurrentReadIndex;287        }288      }289      else {290        ed.Delete(1);291      }292293      byte[] extra = ed.GetEntryData();294295      WriteLEShort(name.Length);296      WriteLEShort(extra.Length);297298      if ( name.Length > 0 ) {299        stream_.Write(name, 0, name.Length);300      }301302      if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) {303        patchData.SizePatchOffset += stream_.Position;304      }305306      if ( extra.Length > 0 ) {307        stream_.Write(extra, 0, extra.Length);308      }309    }281      return Position;282    }283284    /// <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 by296      WriteLEShort(ZipConstants.VersionZip64);   // Version to extract297      WriteLEInt(0);      // Number of this disk298      WriteLEInt(0);      // number of the disk with the start of the central directory299      WriteLELong(noOfEntries);       // No of entries on this disk300      WriteLELong(noOfEntries);       // Total No of entries in central directory301      WriteLELong(sizeEntries);       // Size of the central directory302      WriteLELong(centralDirOffset);  // offset of start of central directory303                      // zip64 extensible data sector not catered for here (variable size)304305      // Write the Zip64 end of central directory locator306      WriteLEInt(ZipConstants.Zip64CentralDirLocatorSignature);307308      // no of the disk with the start of the zip64 end of central directory309      WriteLEInt(0);  310311    /// <summary>312    /// Locates a block with the desired <paramref name="signature"/>.313    /// </summary>314    /// <param name="signature">The signature to find.</param>315    /// <param name="endLocation">Location, marking the end of block.</param>316    /// <param name="minimumBlockSize">Minimum size of the block.</param>317    /// <param name="maximumVariableData">The maximum variable data.</param>318    /// <returns>Eeturns the offset of the first byte after the signature; -1 if not found</returns>319    public long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)320    {321      long pos = endLocation - minimumBlockSize;322      if ( pos < 0 ) {323        return -1;324      }325326      long giveUpMarker = Math.Max(pos - maximumVariableData, 0);327328      // TODO: This loop could be optimised for speed.329      do {330        if ( pos < giveUpMarker ) {331          return -1;332        }333        Seek(pos--, SeekOrigin.Begin);334      } while ( ReadLEInt() != signature );335336      return Position;337    }338339    /// <summary>340    /// Write Zip64 end of central directory records (File header and locator).341    /// </summary>342    /// <param name="noOfEntries">The number of entries in the central directory.</param>343    /// <param name="sizeEntries">The size of entries in the central directory.</param>344    /// <param name="centralDirOffset">The offset of the dentral directory.</param>345    public void WriteZip64EndOfCentralDirectory(long noOfEntries, long sizeEntries, long centralDirOffset)346    {347      long centralSignatureOffset = stream_.Position;348      WriteLEInt(ZipConstants.Zip64CentralFileHeaderSignature);349      WriteLELong(44);    // Size of this record (total size of remaining fields in header or full size - 12)350      WriteLEShort(ZipConstants.VersionMadeBy);   // Version made by351      WriteLEShort(ZipConstants.VersionZip64);   // Version to extract352      WriteLEInt(0);      // Number of this disk353      WriteLEInt(0);      // number of the disk with the start of the central directory354      WriteLELong(noOfEntries);       // No of entries on this disk355      WriteLELong(noOfEntries);       // Total No of entries in central directory356      WriteLELong(sizeEntries);       // Size of the central directory357      WriteLELong(centralDirOffset);  // offset of start of central directory358      // zip64 extensible data sector not catered for here (variable size)359360      // Write the Zip64 end of central directory locator361      WriteLEInt(ZipConstants.Zip64CentralDirLocatorSignature);362363      // no of the disk with the start of the zip64 end of central directory364      WriteLEInt(0);311      // relative offset of the zip64 end of central directory record312      WriteLELong(centralSignatureOffset);313314      // total number of disks315      WriteLEInt(1);316    }317318    /// <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    {328329      if ((noOfEntries >= 0xffff) ||330        (startOfCentralDirectory >= 0xffffffff) ||331        (sizeEntries >= 0xffffffff)) {332        WriteZip64EndOfCentralDirectory(noOfEntries, sizeEntries, startOfCentralDirectory);333      }334335      WriteLEInt(ZipConstants.EndOfCentralDirectorySignature);336337      // TODO: ZipFile Multi disk handling not done338      WriteLEShort(0);                    // number of this disk339      WriteLEShort(0);                    // no of disk with start of central dir340341342      // Number of entries343      if (noOfEntries >= 0xffff) {344        WriteLEUshort(0xffff);  // Zip64 marker345        WriteLEUshort(0xffff);346      } else {347        WriteLEShort((short)noOfEntries);          // entries in central dir for this disk348        WriteLEShort((short)noOfEntries);          // total entries in central directory349      }350351      // Size of the central directory352      if (sizeEntries >= 0xffffffff) {353        WriteLEUint(0xffffffff);    // Zip64 marker354      } else {355        WriteLEInt((int)sizeEntries);356      }357358359      // offset of start of central directory360      if (startOfCentralDirectory >= 0xffffffff) {361        WriteLEUint(0xffffffff);    // Zip64 marker362      } else {363        WriteLEInt((int)startOfCentralDirectory);364      }  365366      // relative offset of the zip64 end of central directory record367      WriteLELong(centralSignatureOffset);368369      // total number of disks370      WriteLEInt(1);371    }372373    /// <summary>374    /// Write the required records to end the central directory.375    /// </summary>376    /// <param name="noOfEntries">The number of entries in the directory.</param>377    /// <param name="sizeEntries">The size of the entries in the directory.</param>378    /// <param name="startOfCentralDirectory">The start of the central directory.</param>379    /// <param name="comment">The archive comment.  (This can be null).</param>380    public void WriteEndOfCentralDirectory(long noOfEntries, long sizeEntries,381      long startOfCentralDirectory, byte[] comment)382    {383384      if ( (noOfEntries >= 0xffff) ||385        (startOfCentralDirectory >= 0xffffffff) ||386        (sizeEntries >= 0xffffffff) ) {387        WriteZip64EndOfCentralDirectory(noOfEntries, sizeEntries, startOfCentralDirectory);388      }389390      WriteLEInt(ZipConstants.EndOfCentralDirectorySignature);391392      // TODO: ZipFile Multi disk handling not done393      WriteLEShort(0);                    // number of this disk394      WriteLEShort(0);                    // no of disk with start of central dir395396397      // Number of entries398      if ( noOfEntries >= 0xffff ) {399        WriteLEUshort(0xffff);  // Zip64 marker400        WriteLEUshort(0xffff);366      int commentLength = (comment != null) ? comment.Length : 0;367368      if (commentLength > 0xffff) {369        throw new ZipException(string.Format("Comment length({0}) is too long can only be 64K", commentLength));370      }371372      WriteLEShort(commentLength);373374      if (commentLength > 0) {375        Write(comment, 0, comment.Length);376      }377    }378379    #region LE value reading/writing380    /// <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 prematurely389    /// </exception>390    public int ReadLEShort()391    {392      int byteValue1 = stream_.ReadByte();393394      if (byteValue1 < 0) {395        throw new EndOfStreamException();396      }397398      int byteValue2 = stream_.ReadByte();399      if (byteValue2 < 0) {400        throw new EndOfStreamException();  401      }402      else {403        WriteLEShort(( short )noOfEntries);          // entries in central dir for this disk404        WriteLEShort(( short )noOfEntries);          // total entries in central directory405      }406407      // Size of the central directory408      if ( sizeEntries >= 0xffffffff ) {409        WriteLEUint(0xffffffff);    // Zip64 marker410      }411      else {412        WriteLEInt(( int )sizeEntries);413      }414415416      // offset of start of central directory417      if ( startOfCentralDirectory >= 0xffffffff ) {418        WriteLEUint(0xffffffff);    // Zip64 marker419      }420      else {421        WriteLEInt(( int )startOfCentralDirectory);422      }423424      int commentLength = (comment != null) ? comment.Length : 0;425426      if ( commentLength > 0xffff ) {427        throw new ZipException(string.Format("Comment length({0}) is too long can only be 64K", commentLength));428      }402403      return byteValue1 | (byteValue2 << 8);404    }405406    /// <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 prematurely415    /// </exception>416    public int ReadLEInt()417    {418      return ReadLEShort() | (ReadLEShort() << 16);419    }420421    /// <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    }  429430      WriteLEShort(commentLength);431432      if ( commentLength > 0 ) {433        Write(comment, 0, comment.Length);434      }435    }436437    #region LE value reading/writing438    /// <summary>439    /// Read an unsigned short in little endian byte order.440    /// </summary>441    /// <returns>Returns the value read.</returns>442    /// <exception cref="IOException">443    /// An i/o error occurs.444    /// </exception>445    /// <exception cref="EndOfStreamException">446    /// The file ends prematurely447    /// </exception>448    public int ReadLEShort()449    {450      int byteValue1 = stream_.ReadByte();451452      if (byteValue1 < 0) {453        throw new EndOfStreamException();454      }455456      int byteValue2 = stream_.ReadByte();457      if (byteValue2 < 0) {458        throw new EndOfStreamException();459      }460461      return byteValue1 | (byteValue2 << 8);462    }463464    /// <summary>465    /// Read an int in little endian byte order.466    /// </summary>467    /// <returns>Returns the value read.</returns>468    /// <exception cref="IOException">469    /// An i/o error occurs.470    /// </exception>471    /// <exception cref="System.IO.EndOfStreamException">472    /// The file ends prematurely473    /// </exception>474    public int ReadLEInt()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    }439440    /// <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    }449450    /// <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    }459460    /// <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    }469470    /// <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      return ReadLEShort() | (ReadLEShort() << 16);477    }478479    /// <summary>480    /// Read a long in little endian byte order.481    /// </summary>482    /// <returns>The value read.</returns>483    public long ReadLELong()484    {485      return (uint)ReadLEInt() | ((long)ReadLEInt() << 32);486    }487488    /// <summary>489    /// Write an unsigned short in little endian byte order.490    /// </summary>491    /// <param name="value">The value to write.</param>492    public void WriteLEShort(int value)493    {494      stream_.WriteByte(( byte )(value & 0xff));495      stream_.WriteByte(( byte )((value >> 8) & 0xff));496    }497498    /// <summary>499    /// Write a ushort in little endian byte order.500    /// </summary>501    /// <param name="value">The value to write.</param>502    public void WriteLEUshort(ushort value)503    {504      stream_.WriteByte(( byte )(value & 0xff));505      stream_.WriteByte(( byte )(value >> 8));506    }507508    /// <summary>509    /// Write an int in little endian byte order.510    /// </summary>511    /// <param name="value">The value to write.</param>512    public void WriteLEInt(int value)513    {514      WriteLEShort(value);515      WriteLEShort(value >> 16);516    }517518    /// <summary>519    /// Write a uint in little endian byte order.520    /// </summary>521    /// <param name="value">The value to write.</param>522    public void WriteLEUint(uint value)523    {524      WriteLEUshort(( ushort )(value & 0xffff));525      WriteLEUshort(( ushort )(value >> 16));476      WriteLEInt((int)value);477      WriteLEInt((int)(value >> 32));478    }479480    /// <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    }489490    #endregion491492    /// <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      }502503      int result = 0;504505      // Add data descriptor if flagged as required506      if ((entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {507        // The signature is not PKZIP originally but is now described as optional508        // in the PKZIP Appnote documenting trhe format.509        WriteLEInt(ZipConstants.DataDescriptorSignature);510        WriteLEInt(unchecked((int)(entry.Crc)));511512        result += 8;513514        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      }524525      return result;  526    }  527  528    /// <summary>529    /// Write a long in little endian byte order.529    /// Read data descriptor at the end of compressed data.  530    /// </summary>531    /// <param name="value">The value to write.</param>532    public void WriteLELong(long value)533    {534      WriteLEInt(( int )value);535      WriteLEInt(( int )(value >> 32));536    }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();  537538    /// <summary>539    /// Write a ulong in little endian byte order.540    /// </summary>541    /// <param name="value">The value to write.</param>542    public void WriteLEUlong(ulong value)543    {544      WriteLEUint(( uint )(value & 0xffffffff));545      WriteLEUint(( uint )(value >> 32));546    }547548    #endregion549550    /// <summary>551    /// Write a data descriptor.552    /// </summary>553    /// <param name="entry">The entry to write a descriptor for.</param>554    /// <returns>Returns the number of descriptor bytes written.</returns>555    public int WriteDataDescriptor(ZipEntry entry)556    {557      if (entry == null) {558        throw new ArgumentNullException(nameof(entry));559      }560561      int result=0;562563      // Add data descriptor if flagged as required564      if ((entry.Flags & (int)GeneralBitFlags.Descriptor) != 0)565      {566        // The signature is not PKZIP originally but is now described as optional567        // in the PKZIP Appnote documenting trhe format.568        WriteLEInt(ZipConstants.DataDescriptorSignature);569        WriteLEInt(unchecked((int)(entry.Crc)));570571        result+=8;572573        if (entry.LocalHeaderRequiresZip64)574        {575          WriteLELong(entry.CompressedSize);576          WriteLELong(entry.Size);577          result+=16;578        }579        else580        {581          WriteLEInt((int)entry.CompressedSize);582          WriteLEInt((int)entry.Size);583          result+=8;584        }585      }586587      return result;588    }589590    /// <summary>591    /// Read data descriptor at the end of compressed data.592    /// </summary>593    /// <param name="zip64">if set to <c>true</c> [zip64].</param>594    /// <param name="data">The data to fill in.</param>595    /// <returns>Returns the number of bytes read in the descriptor.</returns>596    public void ReadDataDescriptor(bool zip64, DescriptorData data)597    {598      int intValue = ReadLEInt();599600      // In theory this may not be a descriptor according to PKZIP appnote.601      // In practise its always there.602      if (intValue != ZipConstants.DataDescriptorSignature) {603        throw new ZipException("Data descriptor signature not found");604      }605606      data.Crc = ReadLEInt();607608      if (zip64) {609        data.CompressedSize = ReadLELong();610        data.Size = ReadLELong();611      }612      else {613        data.CompressedSize = ReadLEInt();614        data.Size = ReadLEInt();615      }616    }617618    #region Instance Fields619    bool isOwner_;620    Stream stream_;621    #endregion622  }623}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      }543544      data.Crc = ReadLEInt();545546      if (zip64) {547        data.CompressedSize = ReadLELong();548        data.Size = ReadLELong();549      } else {550        data.CompressedSize = ReadLEInt();551        data.Size = ReadLEInt();552      }553    }554555    #region Instance Fields556    bool isOwner_;557    Stream stream_;558    #endregion559  }560} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ExtendedPathFilter.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ExtendedPathFilter.htm index 610f36dfe..09e74b972 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ExtendedPathFilter.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ExtendedPathFilter.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:47 Coverable lines:47 -Total lines:336 +Total lines:280 Line coverage:0% Branch coverage:0% @@ -38,344 +38,288 @@

#LineLine coverage - 1// PathFilter.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;37using System.IO;3839namespace ICSharpCode.SharpZipLib.Core40{41  /// <summary>42  /// PathFilter filters directories and files using a form of <see cref="System.Text.RegularExpressions.Regex">regular 43  /// by full path name.44  /// See <see cref="NameFilter">NameFilter</see> for more detail on filtering.45  /// </summary>46  public class PathFilter : IScanFilter47  {48    #region Constructors49    /// <summary>50    /// Initialise a new instance of <see cref="PathFilter"></see>.51    /// </summary>52    /// <param name="filter">The <see cref="NameFilter">filter</see> expression to apply.</param>53    public PathFilter(string filter)54    {55      nameFilter_ = new NameFilter(filter);56    }57    #endregion5859    #region IScanFilter Members60    /// <summary>61    /// Test a name to see if it matches the filter.62    /// </summary>63    /// <param name="name">The name to test.</param>64    /// <returns>True if the name matches, false otherwise.</returns>65    /// <remarks><see cref="Path.GetFullPath(string)"/> is used to get the full path before matching.</remarks>66    public virtual bool IsMatch(string name)67    {68      bool result = false;6970      if ( name != null ) {71        string cooked = (name.Length > 0) ? Path.GetFullPath(name) : "";72        result = nameFilter_.IsMatch(cooked);73      }74      return result;75    }7677    readonly78    #endregion7980    #region Instance Fields81    NameFilter nameFilter_;82    #endregion83  }1using System;2using System.IO;34namespace ICSharpCode.SharpZipLib.Core5{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 : IScanFilter12  {13    #region Constructors14    /// <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    #endregion2324    #region IScanFilter Members25    /// <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;3435      if (name != null) {36        string cooked = (name.Length > 0) ? Path.GetFullPath(name) : "";37        result = nameFilter_.IsMatch(cooked);38      }39      return result;40    }4142    readonly43    #endregion4445    #region Instance Fields46    NameFilter nameFilter_;47    #endregion48  }4950  /// <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 : PathFilter55  {56    #region Constructors57    /// <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    }7071    /// <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    }  8485  /// <summary>86  /// ExtendedPathFilter filters based on name, file size, and the last write time of the file.87  /// </summary>88  /// <remarks>Provides an example of how to customise filtering.</remarks>89  public class ExtendedPathFilter : PathFilter90  {91    #region Constructors92    /// <summary>93    /// Initialise a new instance of ExtendedPathFilter.94    /// </summary>95    /// <param name="filter">The filter to apply.</param>96    /// <param name="minSize">The minimum file size to include.</param>97    /// <param name="maxSize">The maximum file size to include.</param>98    public ExtendedPathFilter(string filter,99      long minSize, long maxSize) - 0100      : base(filter)101    { - 0102      MinSize = minSize; - 0103      MaxSize = maxSize; - 0104    }10585    /// <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    #endregion104105    #region IScanFilter Members  106    /// <summary>107    /// Initialise a new instance of ExtendedPathFilter.107    /// Test a filename to see if it matches the filter.  108    /// </summary>109    /// <param name="filter">The filter to apply.</param>110    /// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>111    /// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>112    public ExtendedPathFilter(string filter,113      DateTime minDate, DateTime maxDate) - 0114      : base(filter)115    { - 0116      MinDate = minDate; - 0117      MaxDate = maxDate; - 0118    }119120    /// <summary>121    /// Initialise a new instance of ExtendedPathFilter.122    /// </summary>123    /// <param name="filter">The filter to apply.</param>124    /// <param name="minSize">The minimum file size to include.</param>125    /// <param name="maxSize">The maximum file size to include.</param>126    /// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>127    /// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>128    public ExtendedPathFilter(string filter,129      long minSize, long maxSize,130      DateTime minDate, DateTime maxDate) - 0131      : base(filter)132    { - 0133      MinSize = minSize; - 0134      MaxSize = maxSize; - 0135      MinDate = minDate; - 0136      MaxDate = maxDate; - 0137    }138    #endregion139140    #region IScanFilter Members141    /// <summary>142    /// Test a filename to see if it matches the filter.143    /// </summary>144    /// <param name="name">The filename to test.</param>145    /// <returns>True if the filter matches, false otherwise.</returns>146    /// <exception cref="System.IO.FileNotFoundException">The <see paramref="fileName"/> doesnt exist</exception>147    public override bool IsMatch(string name)148    { - 0149      bool result = base.IsMatch(name);150 - 0151       if ( result ) { - 0152        var fileInfo = new FileInfo(name); - 0153        result = - 0154          (MinSize <= fileInfo.Length) && - 0155          (MaxSize >= fileInfo.Length) && - 0156          (MinDate <= fileInfo.LastWriteTime) && - 0157          (MaxDate >= fileInfo.LastWriteTime) - 0158          ;159      } - 0160      return result;161    }162    #endregion163164    #region Properties165    /// <summary>166    /// Get/set the minimum size/length for a file that will match this filter.167    /// </summary>168    /// <remarks>The default value is zero.</remarks>169    /// <exception cref="ArgumentOutOfRangeException">value is less than zero; greater than <see cref="MaxSize"/></excep170    public long MinSize171    { - 0172      get { return minSize_; }173      set174      { - 0175         if ( (value < 0) || (maxSize_ < value) ) { - 0176          throw new ArgumentOutOfRangeException(nameof(value));177        }178 - 0179        minSize_ = value; - 0180      }181    }182183    /// <summary>184    /// Get/set the maximum size/length for a file that will match this filter.185    /// </summary>186    /// <remarks>The default value is <see cref="System.Int64.MaxValue"/></remarks>187    /// <exception cref="ArgumentOutOfRangeException">value is less than zero or less than <see cref="MinSize"/></except188    public long MaxSize189    { - 0190      get { return maxSize_; }191      set192      { - 0193         if ( (value < 0) || (minSize_ > value) ) { - 0194          throw new ArgumentOutOfRangeException(nameof(value));195        }196 - 0197        maxSize_ = value; - 0198      }199    }200201    /// <summary>202    /// Get/set the minimum <see cref="DateTime"/> value that will match for this filter.203    /// </summary>204    /// <remarks>Files with a LastWrite time less than this value are excluded by the filter.</remarks>205    public DateTime MinDate206    {207      get208      { - 0209        return minDate_;210      }211212      set213      { - 0214         if ( value > maxDate_ ) {215#if NETCF_1_0216          throw new ArgumentOutOfRangeException("value");217#else - 0218          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MaxDate");219#endif220        }221 - 0222        minDate_ = value; - 0223      }224    }225226    /// <summary>227    /// Get/set the maximum <see cref="DateTime"/> value that will match for this filter.228    /// </summary>229    /// <remarks>Files with a LastWrite time greater than this value are excluded by the filter.</remarks>230    public DateTime MaxDate231    {232      get233      { - 0234        return maxDate_;235      }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    #endregion128129    #region Properties130    /// <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"/></excep135    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    }145146    /// <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"/></except151    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    }161162    /// <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      }170171      set { + 0172         if (value > maxDate_) { + 0173          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MaxDate");174        }175 + 0176        minDate_ = value; + 0177      }178    }179180    /// <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      }188189      set { + 0190         if (minDate_ > value) { + 0191          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MinDate");192        }193 + 0194        maxDate_ = value; + 0195      }196    }197    #endregion198199    #region Instance Fields200    long minSize_; + 0201    long maxSize_ = long.MaxValue; + 0202    DateTime minDate_ = DateTime.MinValue; + 0203    DateTime maxDate_ = DateTime.MaxValue;204    #endregion205  }206207  /// <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 : PathFilter213  {214215    /// <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    }227228    /// <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);  236237      set238      { - 0239         if ( minDate_ > value ) {240#if NETCF_1_0241          throw new ArgumentOutOfRangeException("value");242#else - 0243          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MinDate");244#endif245        }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 - 0247        maxDate_ = value; - 0248      }249    }250    #endregion251252    #region Instance Fields253    long minSize_; - 0254    long maxSize_ = long.MaxValue; - 0255    DateTime minDate_ = DateTime.MinValue; - 0256    DateTime maxDate_ = DateTime.MaxValue;257    #endregion258  }259260  /// <summary>261  /// NameAndSizeFilter filters based on name and file size.262  /// </summary>263  /// <remarks>A sample showing how filters might be extended.</remarks>264  [Obsolete("Use ExtendedPathFilter instead")]265  public class NameAndSizeFilter : PathFilter266  {267268    /// <summary>269    /// Initialise a new instance of NameAndSizeFilter.270    /// </summary>271    /// <param name="filter">The filter to apply.</param>272    /// <param name="minSize">The minimum file size to include.</param>273    /// <param name="maxSize">The maximum file size to include.</param>274    public NameAndSizeFilter(string filter, long minSize, long maxSize)275      : base(filter)276    {277      MinSize = minSize;278      MaxSize = maxSize;279    }280281    /// <summary>282    /// Test a filename to see if it matches the filter.283    /// </summary>284    /// <param name="name">The filename to test.</param>285    /// <returns>True if the filter matches, false otherwise.</returns>286    public override bool IsMatch(string name)287    {288      bool result = base.IsMatch(name);289290      if ( result ) {291        var fileInfo = new FileInfo(name);292        long length = fileInfo.Length;293        result =294          (MinSize <= length) &&295          (MaxSize >= length);296      }297      return result;298    }299300    /// <summary>301    /// Get/set the minimum size for a file that will match this filter.302    /// </summary>303    public long MinSize304    {305      get { return minSize_; }306      set {307        if ( (value < 0) || (maxSize_ < value) ) {308          throw new ArgumentOutOfRangeException(nameof(value));309        }310311        minSize_ = value;312      }313    }314315    /// <summary>316    /// Get/set the maximum size for a file that will match this filter.317    /// </summary>318    public long MaxSize319    {320      get { return maxSize_; }321      set322      {323        if ( (value < 0) || (minSize_ > value) ) {324          throw new ArgumentOutOfRangeException(nameof(value));325        }326327        maxSize_ = value;328      }329    }330331    #region Instance Fields332    long minSize_;333    long maxSize_ = long.MaxValue;334    #endregion335  }336}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        }256257        minSize_ = value;258      }259    }260261    /// <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        }270271        maxSize_ = value;272      }273    }274275    #region Instance Fields276    long minSize_;277    long maxSize_ = long.MaxValue;278    #endregion279  }280} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ExtendedUnixData.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ExtendedUnixData.htm index a7cfcfbe9..bf33abe79 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ExtendedUnixData.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ExtendedUnixData.htm @@ -15,19 +15,19 @@

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:34 -Uncovered lines:27 -Coverable lines:61 -Total lines:987 -Line coverage:55.7% -Branch coverage:40% +Covered lines:32 +Uncovered lines:30 +Coverable lines:62 +Total lines:896 +Line coverage:51.6% +Branch coverage:30%

Metrics

- + @@ -38,995 +38,904 @@

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
SetData(...)771.4355.56
SetData(...)756.2533.33
GetData()666.6757.14
IsValidValue(...)2100100
.ctor()1100100
#LineLine coverage
 1//
 2// ZipExtraData.cs
 3//
 4// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team
 5//
 6// This program is free software; you can redistribute it and/or
 7// modify it under the terms of the GNU General Public License
 8// as published by the Free Software Foundation; either version 2
 9// of the License, or (at your option) any later version.
 10//
 11// This program is distributed in the hope that it will be useful,
 12// but WITHOUT ANY WARRANTY; without even the implied warranty of
 13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14// GNU General Public License for more details.
 15//
 16// You should have received a copy of the GNU General Public License
 17// along with this program; if not, write to the Free Software
 18// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 19//
 20// Linking this library statically or dynamically with other modules is
 21// making a combined work based on this library.  Thus, the terms and
 22// conditions of the GNU General Public License cover the whole
 23// combination.
 24//
 25// As a special exception, the copyright holders of this library give you
 26// permission to link this library with independent modules to produce an
 27// executable, regardless of the license terms of these independent
 28// modules, and to copy and distribute the resulting executable under
 29// terms of your choice, provided that you also meet, for each linked
 30// independent module, the terms and conditions of the license of that
 31// module.  An independent module is a module which is not derived from
 32// or based on this library.  If you modify this library, you may extend
 33// this exception to your version of the library, but you are not
 34// obligated to do so.  If you do not wish to do so, delete this
 35// exception statement from your version.
 36
 37using System;
 38using System.IO;
 39
 40namespace ICSharpCode.SharpZipLib.Zip
 41{
 42  // TODO: Sort out wether tagged data is useful and what a good implementation might look like.
 43  // Its just a sketch of an idea at the moment.
 44
 45  /// <summary>
 46  /// ExtraData tagged value interface.
 47  /// </summary>
 48  public interface ITaggedData
 49  {
 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    short TagID { get; }
 54
 55    /// <summary>
 56    /// Set the contents of this instance from the data passed.
 57    /// </summary>
 58    /// <param name="data">The data to extract contents from.</param>
 59    /// <param name="offset">The offset to begin extracting data from.</param>
 60    /// <param name="count">The number of bytes to extract.</param>
 61    void SetData(byte[] data, int offset, int count);
 62
 63    /// <summary>
 64    /// Get the data representing this instance.
 65    /// </summary>
 66    /// <returns>Returns the data for this instance.</returns>
 67    byte[] GetData();
 68  }
 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  /// <summary>
 71  /// A raw binary tagged value
 72  /// </summary>
 73  public class RawTaggedData : ITaggedData
 74  {
 75    /// <summary>
 76    /// Initialise a new instance.
 77    /// </summary>
 78    /// <param name="tag">The tag ID.</param>
 79    public RawTaggedData(short tag)
 80    {
 81      _tag = tag;
 82    }
 83
 84    #region ITaggedData Members
 85
 86    /// <summary>
 87    /// Get the ID for this tagged data value.
 88    /// </summary>
 89    public short TagID
 90    {
 91      get { return _tag; }
 92      set { _tag = value; }
 93    }
 94
 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    /// Set the data from the raw values provided.
 96    /// The tag ID for this instance.
 97    /// </summary>
 98    /// <param name="data">The raw data to extract values from.</param>
 99    /// <param name="offset">The index to start extracting values from.</param>
 100    /// <param name="count">The number of bytes available.</param>
 101    public void SetData(byte[] data, int offset, int count)
 102    {
 103      if( data==null )
 104      {
 105        throw new ArgumentNullException(nameof(data));
 106      }
 107
 108      _data=new byte[count];
 109      Array.Copy(data, offset, _data, 0, count);
 110    }
 111
 112    /// <summary>
 113    /// Get the binary data representing this instance.
 114    /// </summary>
 115    /// <returns>The raw binary data representing this instance.</returns>
 116    public byte[] GetData()
 117    {
 118      return _data;
 119    }
 120
 121    #endregion
 122
 123    /// <summary>
 124    /// Get /set the binary data representing this instance.
 125    /// </summary>
 126    /// <returns>The raw binary data representing this instance.</returns>
 127    public byte[] Data
 128    {
 129      get { return _data; }
 130      set { _data=value; }
 131    }
 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    #region Instance Fields
 134    /// <summary>
 135    /// The tag ID for this instance.
 136    /// </summary>
 137    short _tag;
 138
 139    byte[] _data;
 140    #endregion
 141  }
 142
 143  /// <summary>
 144  /// Class representing extended unix date time values.
 145  /// </summary>
 146  public class ExtendedUnixData : ITaggedData
 147  {
 148    /// <summary>
 149    /// Flags indicate which values are included in this instance.
 150    /// </summary>
 151    [Flags]
 152    public enum Flags : byte
 153    {
 154      /// <summary>
 155      /// The modification time is included
 156      /// </summary>
 157      ModificationTime = 0x01,
 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
 159      /// <summary>
 160      /// The access time is included
 161      /// </summary>
 162      AccessTime = 0x02,
 163
 164      /// <summary>
 165      /// The create time is included.
 166      /// </summary>
 167      CreateTime = 0x04,
 168    }
 169
 170    #region ITaggedData Members
 171
 172    /// <summary>
 173    /// Get the ID
 174    /// </summary>
 175    public short TagID
 176    {
 1177      get { return 0x5455; }
 178    }
 179
 180    /// <summary>
 181    /// Set the data from the raw values provided.
 182    /// </summary>
 183    /// <param name="data">The raw data to extract values from.</param>
 184    /// <param name="index">The index to start extracting values from.</param>
 185    /// <param name="count">The number of bytes available.</param>
 186    public void SetData(byte[] data, int index, int count)
 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(data, index, count, false))
 1189      using (ZipHelperStream helperStream = new ZipHelperStream(ms))
 190      {
 191        // bit 0           if set, modification time is present
 192        // bit 1           if set, access time is present
 193        // bit 2           if set, creation time is present
 194
 1195        _flags = (Flags)helperStream.ReadByte();
 1196         if (((_flags & Flags.ModificationTime) != 0) && (count >= 5))
 197        {
 1198          int iTime = helperStream.ReadLEInt();
 199
 1200          _modificationTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
 1201            new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
 202        }
 203
 1204         if ((_flags & Flags.AccessTime) != 0)
 205        {
 0206          int iTime = helperStream.ReadLEInt();
 207
 0208          _lastAccessTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
 0209            new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
 210        }
 211
 1212         if ((_flags & Flags.CreateTime) != 0)
 213        {
 0214          int iTime = helperStream.ReadLEInt();
 215
 0216          _createTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
 0217            new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
 218        }
 1219      }
 1220    }
 221
 222    /// <summary>
 223    /// Get the binary data representing this instance.
 224    /// </summary>
 225    /// <returns>The raw binary data representing this instance.</returns>
 226    public byte[] GetData()
 227    {
 1228      using (MemoryStream ms = new MemoryStream())
 1229      using (ZipHelperStream helperStream = new ZipHelperStream(ms))
 230      {
 1231        helperStream.IsStreamOwner = false;
 1232        helperStream.WriteByte((byte)_flags);     // Flags
 1233         if ( (_flags & Flags.ModificationTime) != 0) {
 1234          TimeSpan span = _modificationTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
 1235          var seconds = (int)span.TotalSeconds;
 1236          helperStream.WriteLEInt(seconds);
 237        }
 1238         if ( (_flags & Flags.AccessTime) != 0) {
 0239          TimeSpan span = _lastAccessTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
 0240          var seconds = (int)span.TotalSeconds;
 0241          helperStream.WriteLEInt(seconds);
 242        }
 1243         if ( (_flags & Flags.CreateTime) != 0) {
 0244          TimeSpan span = _createTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
 0245          var seconds = (int)span.TotalSeconds;
 0246          helperStream.WriteLEInt(seconds);
 247        }
 1248        return ms.ToArray();
 249      }
 1250    }
 251
 252    #endregion
 253
 254    /// <summary>
 255    /// Test a <see cref="DateTime"> value to see if is valid and can be represented here.</see>
 256    /// </summary>
 257    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>
 258    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>
 259    /// <remarks>The standard Unix time is a signed integer data type, directly encoding the Unix time number,
 260    /// which is the number of seconds since 1970-01-01.
 261    /// Being 32 bits means the values here cover a range of about 136 years.
 262    /// The minimum representable time is 1901-12-13 20:45:52,
 263    /// and the maximum representable time is 2038-01-19 03:14:07.
 264    /// </remarks>
 265    public static bool IsValidValue(DateTime value)
 266    {
 2267      return (( value >= new DateTime(1901, 12, 13, 20, 45, 52)) ||
 2268          ( value <= new DateTime(2038, 1, 19, 03, 14, 07) ));
 269    }
 270
 271    /// <summary>
 272    /// Get /set the Modification Time
 273    /// </summary>
 274    /// <exception cref="ArgumentOutOfRangeException"></exception>
 275    /// <seealso cref="IsValidValue"></seealso>
 276    public DateTime ModificationTime
 277    {
 4278      get { return _modificationTime; }
 279      set
 280      {
 2281         if ( !IsValidValue(value) ) {
 0282          throw new ArgumentOutOfRangeException(nameof(value));
 283        }
 284
 2285        _flags |= Flags.ModificationTime;
 2286        _modificationTime=value;
 2287      }
 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    /// <summary>
 291    /// Get / set the Access Time
 292    /// </summary>
 293    /// <exception cref="ArgumentOutOfRangeException"></exception>
 294    /// <seealso cref="IsValidValue"></seealso>
 295    public DateTime AccessTime
 296    {
 0297      get { return _lastAccessTime; }
 298      set {
 0299         if ( !IsValidValue(value) ) {
 0300          throw new ArgumentOutOfRangeException(nameof(value));
 301        }
 302
 0303        _flags |= Flags.AccessTime;
 0304        _lastAccessTime=value;
 0305      }
 306    }
 307
 308    /// <summary>
 309    /// Get / Set the Create Time
 310    /// </summary>
 311    /// <exception cref="ArgumentOutOfRangeException"></exception>
 312    /// <seealso cref="IsValidValue"></seealso>
 313    public DateTime CreateTime
 314    {
 0315      get { return _createTime; }
 316      set {
 0317         if ( !IsValidValue(value) ) {
 0318          throw new ArgumentOutOfRangeException(nameof(value));
 319        }
 320
 0321        _flags |= Flags.CreateTime;
 0322        _createTime=value;
 0323      }
 324    }
 325
 326    /// <summary>
 327    /// Get/set the <see cref="Flags">values</see> to include.
 328    /// </summary>
 329    Flags Include
 330    {
 0331      get { return _flags; }
 0332      set { _flags = value; }
 333    }
 334
 335    #region Instance Fields
 336    Flags _flags;
 1337    DateTime _modificationTime = new DateTime(1970,1,1);
 1338    DateTime _lastAccessTime = new DateTime(1970, 1, 1);
 1339    DateTime _createTime = new DateTime(1970, 1, 1);
 340    #endregion
 341  }
 342
 343  /// <summary>
 344  /// Class handling NT date time values.
 345  /// </summary>
 346  public class NTTaggedData : ITaggedData
 347  {
 348    /// <summary>
 349    /// Get the ID for this tagged data value.
 350    /// </summary>
 351    public short TagID
 352    {
 353      get { return 10; }
 354    }
 355
 356    /// <summary>
 357    /// Set the data from the raw values provided.
 358    /// </summary>
 359    /// <param name="data">The raw data to extract values from.</param>
 360    /// <param name="index">The index to start extracting values from.</param>
 361    /// <param name="count">The number of bytes available.</param>
 362    public void SetData(byte[] data, int index, int count)
 363    {
 364      using (MemoryStream ms = new MemoryStream(data, index, count, false))
 365      using (ZipHelperStream helperStream = new ZipHelperStream(ms))
 366      {
 367        helperStream.ReadLEInt(); // Reserved
 368        while (helperStream.Position < helperStream.Length)
 369        {
 370          int ntfsTag = helperStream.ReadLEShort();
 371          int ntfsLength = helperStream.ReadLEShort();
 372          if (ntfsTag == 1)
 373          {
 374            if (ntfsLength >= 24)
 375            {
 376              long lastModificationTicks = helperStream.ReadLELong();
 377              _lastModificationTime = DateTime.FromFileTime(lastModificationTicks);
 378
 379              long lastAccessTicks = helperStream.ReadLELong();
 380              _lastAccessTime = DateTime.FromFileTime(lastAccessTicks);
 381
 382              long createTimeTicks = helperStream.ReadLELong();
 383              _createTime = DateTime.FromFileTime(createTimeTicks);
 384            }
 385            break;
 386          }
 387          else
 388          {
 389            // An unknown NTFS tag so simply skip it.
 390            helperStream.Seek(ntfsLength, SeekOrigin.Current);
 391          }
 392        }
 393      }
 394    }
 395
 396    /// <summary>
 397    /// Get the binary data representing this instance.
 398    /// </summary>
 399    /// <returns>The raw binary data representing this instance.</returns>
 400    public byte[] GetData()
 401    {
 402      using (MemoryStream ms = new MemoryStream())
 403      using (ZipHelperStream helperStream = new ZipHelperStream(ms))
 404      {
 405        helperStream.IsStreamOwner = false;
 406        helperStream.WriteLEInt(0);       // Reserved
 407        helperStream.WriteLEShort(1);     // Tag
 408        helperStream.WriteLEShort(24);    // Length = 3 x 8.
 409        helperStream.WriteLELong(_lastModificationTime.ToFileTime());
 410        helperStream.WriteLELong(_lastAccessTime.ToFileTime());
 411        helperStream.WriteLELong(_createTime.ToFileTime());
 412        return ms.ToArray();
 413      }
 414    }
 415
 416    /// <summary>
 417    /// Test a <see cref="DateTime"> valuie to see if is valid and can be represented here.</see>
 418    /// </summary>
 419    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>
 420    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>
 421    /// <remarks>
 422    /// NTFS filetimes are 64-bit unsigned integers, stored in Intel
 423    /// (least significant byte first) byte order. They determine the
 424    /// number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",
 425    /// which is "01-Jan-1601 00:00:00 UTC". 28 May 60056 is the upper limit
 426    /// </remarks>
 427    public static bool IsValidValue(DateTime value)
 428    {
 429      bool result = true;
 430      try
 431      {
 432        value.ToFileTimeUtc();
 433      }
 434      catch
 435      {
 436        result = false;
 437      }
 438      return result;
 439    }
 440
 441    /// <summary>
 442    /// Get/set the <see cref="DateTime">last modification time</see>.
 443    /// </summary>
 444    public DateTime LastModificationTime
 445    {
 446      get { return _lastModificationTime; }
 447      set {
 448        if (! IsValidValue(value))
 449        {
 450          throw new ArgumentOutOfRangeException(nameof(value));
 451        }
 452        _lastModificationTime = value;
 453      }
 454    }
 455
 456    /// <summary>
 457    /// Get /set the <see cref="DateTime">create time</see>
 458    /// </summary>
 459    public DateTime CreateTime
 460    {
 461      get { return _createTime; }
 462      set {
 463        if ( !IsValidValue(value)) {
 464          throw new ArgumentOutOfRangeException(nameof(value));
 465        }
 466        _createTime = value;
 467      }
 468    }
 469
 470    /// <summary>
 471    /// Get /set the <see cref="DateTime">last access time</see>.
 472    /// </summary>
 473    public DateTime LastAccessTime
 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      get { return _lastAccessTime; }
 476      set {
 477        if (!IsValidValue(value)) {
 478          throw new ArgumentOutOfRangeException(nameof(value));
 479        }
 480        _lastAccessTime = value;
 481      }
 482    }
 483
 484    #region Instance Fields
 485    DateTime _lastAccessTime = DateTime.FromFileTime(0);
 486    DateTime _lastModificationTime = DateTime.FromFileTime(0);
 487    DateTime _createTime = DateTime.FromFileTime(0);
 488    #endregion
 489  }
 490
 491  /// <summary>
 492  /// A factory that creates <see cref="ITaggedData">tagged data</see> instances.
 493  /// </summary>
 494  interface ITaggedDataFactory
 495  {
 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    /// Get data for a specific tag value.
 497    /// Clear the stored data.
 498    /// </summary>
 499    /// <param name="tag">The tag ID to find.</param>
 500    /// <param name="data">The data to search.</param>
 501    /// <param name="offset">The offset to begin extracting data from.</param>
 502    /// <param name="count">The number of bytes to extract.</param>
 503    /// <returns>The located <see cref="ITaggedData">value found</see>, or null if not found.</returns>
 504    ITaggedData Create(short tag, byte[] data, int offset, int count);
 505  }
 506
 507  ///
 508  /// <summary>
 509  /// A class to handle the extra data field for Zip entries
 510  /// </summary>
 511  /// <remarks>
 512  /// Extra data contains 0 or more values each prefixed by a header tag and length.
 513  /// They contain zero or more bytes of actual data.
 514  /// The data is held internally using a copy on write strategy.  This is more efficient but
 515  /// means that for extra data created by passing in data can have the values modified by the caller
 516  /// in some circumstances.
 517  /// </remarks>
 518  sealed public class ZipExtraData : IDisposable
 519  {
 520    #region Constructors
 521    /// <summary>
 522    /// Initialise a default instance.
 523    /// </summary>
 524    public ZipExtraData()
 525    {
 526      Clear();
 527    }
 528
 529    /// <summary>
 530    /// Initialise with known extra data.
 531    /// </summary>
 532    /// <param name="data">The extra data.</param>
 533    public ZipExtraData(byte[] data)
 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      if ( data == null )
 536      {
 537        _data = new byte[0];
 538      }
 539      else
 540      {
 541        _data = data;
 542      }
 543    }
 544    #endregion
 545
 546    /// <summary>
 547    /// Get the raw extra data value
 548    /// </summary>
 549    /// <returns>Returns the raw byte[] extra data this instance represents.</returns>
 550    public byte[] GetEntryData()
 551    {
 552      if ( Length > ushort.MaxValue ) {
 553        throw new ZipException("Data exceeds maximum length");
 554      }
 555
 556      return (byte[])_data.Clone();
 557    }
 558
 559    /// <summary>
 560    /// Clear the stored data.
 561    /// </summary>
 562    public void Clear()
 563    {
 564      if ( (_data == null) || (_data.Length != 0) ) {
 565        _data = new byte[0];
 566      }
 567    }
 568
 569    /// <summary>
 570    /// Gets the current extra data length.
 571    /// </summary>
 572    public int Length
 573    {
 574      get { return _data.Length; }
 575    }
 576
 577    /// <summary>
 578    /// Get a read-only <see cref="Stream"/> for the associated tag.
 579    /// </summary>
 580    /// <param name="tag">The tag to locate data for.</param>
 581    /// <returns>Returns a <see cref="Stream"/> containing tag data or null if no tag was found.</returns>
 582    public Stream GetStreamForTag(int tag)
 583    {
 584      Stream result = null;
 585      if ( Find(tag) ) {
 586        result = new MemoryStream(_data, _index, _readValueLength, false);
 587      }
 588      return result;
 589    }
 590
 591    /// <summary>
 592    /// Get the <see cref="ITaggedData">tagged data</see> for a tag.
 593    /// </summary>
 594    /// <param name="tag">The tag to search for.</param>
 595    /// <returns>Returns a <see cref="ITaggedData">tagged value</see> or null if none found.</returns>
 596    private ITaggedData GetData(short tag)
 597    {
 598      ITaggedData result = null;
 599      if (Find(tag))
 600      {
 601        result = Create(tag, _data, _readValueStart, _readValueLength);
 602      }
 603      return result;
 604    }
 605
 606    static ITaggedData Create(short tag, byte[] data, int offset, int count)
 607    {
 608      ITaggedData result = null;
 609      switch ( tag )
 610      {
 611        case 0x000A:
 612          result = new NTTaggedData();
 613          break;
 614        case 0x5455:
 615          result = new ExtendedUnixData();
 616          break;
 617        default:
 618          result = new RawTaggedData(tag);
 619          break;
 620      }
 621      result.SetData(data, offset, count);
 622      return result;
 623    }
 624
 625    /// <summary>
 626    /// Get the length of the last value found by <see cref="Find"/>
 627    /// </summary>
 628    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.</remarks>
 629    public int ValueLength
 630    {
 631      get { return _readValueLength; }
 632    }
 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    /// <summary>
 635    /// Get the index for the current read value.
 636    /// </summary>
 637    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.
 638    /// Initially the result will be the index of the first byte of actual data.  The value is updated after calls to
 639    /// <see cref="ReadInt"/>, <see cref="ReadShort"/> and <see cref="ReadLong"/>. </remarks>
 640    public int CurrentReadIndex
 641    {
 642      get { return _index; }
 643    }
 644
 645    /// <summary>
 646    /// Get the number of bytes remaining to be read for the current value;
 647    /// </summary>
 648    public int UnreadCount
 649    {
 650      get
 651      {
 652        if ((_readValueStart > _data.Length) ||
 653          (_readValueStart < 4) ) {
 654          throw new ZipException("Find must be called before calling a Read method");
 655        }
 656
 657        return _readValueStart + _readValueLength - _index;
 658      }
 659    }
 660
 661    /// <summary>
 662    /// Find an extra data value
 663    /// </summary>
 664    /// <param name="headerID">The identifier for the value to find.</param>
 665    /// <returns>Returns true if the value was found; false otherwise.</returns>
 666    public bool Find(int headerID)
 667    {
 668      _readValueStart = _data.Length;
 669      _readValueLength = 0;
 670      _index = 0;
 671
 672      int localLength = _readValueStart;
 673      int localTag = headerID - 1;
 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      // Trailing bytes that cant make up an entry (as there arent enough
 676      // bytes for a tag and length) are ignored!
 677      while ( (localTag != headerID) && (_index < _data.Length - 3) ) {
 678        localTag = ReadShortInternal();
 679        localLength = ReadShortInternal();
 680        if ( localTag != headerID ) {
 681          _index += localLength;
 682        }
 683      }
 684
 685      bool result = (localTag == headerID) && ((_index + localLength) <= _data.Length);
 686
 687      if ( result ) {
 688        _readValueStart = _index;
 689        _readValueLength = localLength;
 690      }
 691
 692      return result;
 693    }
 694
 695    /// <summary>
 696    /// Add a new entry to extra data.
 697    /// </summary>
 698    /// <param name="taggedData">The <see cref="ITaggedData"/> value to add.</param>
 699    public void AddEntry(ITaggedData taggedData)
 700    {
 701      if (taggedData == null)
 702      {
 703        throw new ArgumentNullException(nameof(taggedData));
 704      }
 705      AddEntry(taggedData.TagID, taggedData.GetData());
 706    }
 707
 708    /// <summary>
 709    /// Add a new entry to extra data
 710    /// </summary>
 711    /// <param name="headerID">The ID for this entry.</param>
 712    /// <param name="fieldData">The data to add.</param>
 713    /// <remarks>If the ID already exists its contents are replaced.</remarks>
 714    public void AddEntry(int headerID, byte[] fieldData)
 715    {
 716      if ( (headerID > ushort.MaxValue) || (headerID < 0)) {
 717        throw new ArgumentOutOfRangeException(nameof(headerID));
 718      }
 719
 720      int addLength = (fieldData == null) ? 0 : fieldData.Length;
 721
 722      if ( addLength > ushort.MaxValue ) {
 723#if NETCF_1_0
 724        throw new ArgumentOutOfRangeException("fieldData");
 725#else
 726        throw new ArgumentOutOfRangeException(nameof(fieldData), "exceeds maximum length");
 727#endif
 728      }
 729
 730      // Test for new length before adjusting data.
 731      int newLength = _data.Length + addLength + 4;
 732
 733      if ( Find(headerID) )
 734      {
 735        newLength -= (ValueLength + 4);
 736      }
 737
 738      if ( newLength > ushort.MaxValue ) {
 739        throw new ZipException("Data exceeds maximum length");
 740      }
 741
 742      Delete(headerID);
 743
 744      byte[] newData = new byte[newLength];
 745      _data.CopyTo(newData, 0);
 746      int index = _data.Length;
 747      _data = newData;
 748      SetShort(ref index, headerID);
 749      SetShort(ref index, addLength);
 750      if ( fieldData != null ) {
 751        fieldData.CopyTo(newData, index);
 752      }
 753    }
 754
 755    /// <summary>
 756    /// Start adding a new entry.
 757    /// </summary>
 758    /// <remarks>Add data using <see cref="AddData(byte[])"/>, <see cref="AddLeShort"/>, <see cref="AddLeInt"/>, or <see
 759    /// The new entry is completed and actually added by calling <see cref="AddNewEntry"/></remarks>
 760    /// <seealso cref="AddEntry(ITaggedData)"/>
 761    public void StartNewEntry()
 762    {
 763      _newEntry = new MemoryStream();
 764    }
 765
 766    /// <summary>
 767    /// Add entry data added since <see cref="StartNewEntry"/> using the ID passed.
 768    /// </summary>
 769    /// <param name="headerID">The identifier to use for this entry.</param>
 770    public void AddNewEntry(int headerID)
 771    {
 772      byte[] newData = _newEntry.ToArray();
 773      _newEntry = null;
 774      AddEntry(headerID, newData);
 775    }
 776
 777    /// <summary>
 778    /// Add a byte of data to the pending new entry.
 779    /// </summary>
 780    /// <param name="data">The byte to add.</param>
 781    /// <seealso cref="StartNewEntry"/>
 782    public void AddData(byte data)
 783    {
 784      _newEntry.WriteByte(data);
 785    }
 786
 787    /// <summary>
 788    /// Add data to a pending new entry.
 789    /// </summary>
 790    /// <param name="data">The data to add.</param>
 791    /// <seealso cref="StartNewEntry"/>
 792    public void AddData(byte[] data)
 793    {
 794      if ( data == null ) {
 795        throw new ArgumentNullException(nameof(data));
 796      }
 797
 798      _newEntry.Write(data, 0, data.Length);
 799    }
 800
 801    /// <summary>
 802    /// Add a short value in little endian order to the pending new entry.
 803    /// </summary>
 804    /// <param name="toAdd">The data to add.</param>
 805    /// <seealso cref="StartNewEntry"/>
 806    public void AddLeShort(int toAdd)
 807    {
 808      unchecked {
 809        _newEntry.WriteByte(( byte )toAdd);
 810        _newEntry.WriteByte(( byte )(toAdd >> 8));
 811      }
 812    }
 813
 814    /// <summary>
 815    /// Add an integer value in little endian order to the pending new entry.
 816    /// </summary>
 817    /// <param name="toAdd">The data to add.</param>
 818    /// <seealso cref="StartNewEntry"/>
 819    public void AddLeInt(int toAdd)
 820    {
 821      unchecked {
 822        AddLeShort(( short )toAdd);
 823        AddLeShort(( short )(toAdd >> 16));
 824      }
 825    }
 826
 827    /// <summary>
 828    /// Add a long value in little endian order to the pending new entry.
 829    /// </summary>
 830    /// <param name="toAdd">The data to add.</param>
 831    /// <seealso cref="StartNewEntry"/>
 832    public void AddLeLong(long toAdd)
 833    {
 834      unchecked {
 835        AddLeInt(( int )(toAdd & 0xffffffff));
 836        AddLeInt(( int )(toAdd >> 32));
 837      }
 838    }
 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    /// <summary>
 841    /// Delete an extra data field.
 842    /// </summary>
 843    /// <param name="headerID">The identifier of the field to delete.</param>
 844    /// <returns>Returns true if the field was found and deleted.</returns>
 845    public bool Delete(int headerID)
 846    {
 847      bool result = false;
 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      if ( Find(headerID) ) {
 850        result = true;
 851        int trueStart = _readValueStart - 4;
 852
 853        byte[] newData = new byte[_data.Length - (ValueLength + 4)];
 854        Array.Copy(_data, 0, newData, 0, trueStart);
 855
 856        int trueEnd = trueStart + ValueLength + 4;
 857        Array.Copy(_data, trueEnd, newData, trueStart, _data.Length - trueEnd);
 858        _data = newData;
 859      }
 860      return result;
 861    }
 862
 863    #region Reading Support
 864    /// <summary>
 865    /// Read a long in little endian form from the last <see cref="Find">found</see> data value
 866    /// </summary>
 867    /// <returns>Returns the long value read.</returns>
 868    public long ReadLong()
 869    {
 870      ReadCheck(8);
 871      return (ReadInt() & 0xffffffff) | ((( long )ReadInt()) << 32);
 872    }
 873
 874    /// <summary>
 875    /// Read an integer in little endian form from the last <see cref="Find">found</see> data value.
 876    /// </summary>
 877    /// <returns>Returns the integer read.</returns>
 878    public int ReadInt()
 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      ReadCheck(4);
 881
 882      int result = _data[_index] + (_data[_index + 1] << 8) +
 883        (_data[_index + 2] << 16) + (_data[_index + 3] << 24);
 884      _index += 4;
 885      return result;
 886    }
 887
 888    /// <summary>
 889    /// Read a short value in little endian form from the last <see cref="Find">found</see> data value.
 890    /// </summary>
 891    /// <returns>Returns the short value read.</returns>
 892    public int ReadShort()
 893    {
 894      ReadCheck(2);
 895      int result = _data[_index] + (_data[_index + 1] << 8);
 896      _index += 2;
 897      return result;
 898    }
 899
 900    /// <summary>
 901    /// Read a byte from an extra data
 902    /// </summary>
 903    /// <returns>The byte value read or -1 if the end of data has been reached.</returns>
 904    public int ReadByte()
 905    {
 906      int result = -1;
 907      if ( (_index < _data.Length) && (_readValueStart + _readValueLength > _index) ) {
 908        result = _data[_index];
 909        _index += 1;
 910      }
 911      return result;
 912    }
 913
 914    /// <summary>
 915    /// Skip data during reading.
 916    /// </summary>
 917    /// <param name="amount">The number of bytes to skip.</param>
 918    public void Skip(int amount)
 919    {
 920      ReadCheck(amount);
 921      _index += amount;
 922    }
 923
 924    void ReadCheck(int length)
 925    {
 926      if ((_readValueStart > _data.Length) ||
 927        (_readValueStart < 4) ) {
 928        throw new ZipException("Find must be called before calling a Read method");
 929      }
 930
 931      if (_index > _readValueStart + _readValueLength - length ) {
 932        throw new ZipException("End of extra data");
 933      }
 934
 935            if ( _index + length < 4 ) {
 936                throw new ZipException("Cannot read before start of tag");
 937            }
 938    }
 939
 940    /// <summary>
 941    /// Internal form of <see cref="ReadShort"/> that reads data at any location.
 942    /// </summary>
 943    /// <returns>Returns the short value read.</returns>
 944    int ReadShortInternal()
 945    {
 946      if ( _index > _data.Length - 2) {
 947        throw new ZipException("End of extra data");
 948      }
 949
 950      int result = _data[_index] + (_data[_index + 1] << 8);
 951      _index += 2;
 952      return result;
 953    }
 954
 955    void SetShort(ref int index, int source)
 956    {
 957      _data[index] = (byte)source;
 958      _data[index + 1] = (byte)(source >> 8);
 959      index += 2;
 960    }
 961
 962    #endregion
 963
 964    #region IDisposable Members
 965
 966    /// <summary>
 967    /// Dispose of this instance.
 968    /// </summary>
 969    public void Dispose()
 970    {
 971      if ( _newEntry != null ) {
 972        _newEntry.Close();
 973      }
 974    }
 975
 976    #endregion
 977
 978    #region Instance Fields
 979    int _index;
 980    int _readValueStart;
 981    int _readValueLength;
 982
 983    MemoryStream _newEntry;
 984    byte[] _data;
 985    #endregion
 986  }
 987}
 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/Documentation/opencover/ICSharpCode.SharpZipLib_FastZip.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_FastZip.htm index 42185e1bd..dee5d59d8 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_FastZip.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_FastZip.htm @@ -15,12 +15,12 @@

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:90 +Covered lines:85 Uncovered lines:99 -Coverable lines:189 -Total lines:728 -Line coverage:47.6% -Branch coverage:29.1% +Coverable lines:184 +Total lines:648 +Line coverage:46.1% +Branch coverage:28.3%

Metrics

@@ -30,13 +30,13 @@

Metrics

.ctor()1100100 .ctor(...)100 CreateZip(...)100 -CreateZip(...)150100 +CreateZip(...)100 CreateZip(...)772.2245.45 ExtractZip(...)1100100 ExtractZip(...)1100100 ExtractZip(...)138047.83 ProcessDirectory(...)600 -ProcessFile(...)676.4755.56 +ProcessFile(...)652.9444.44 AddFileContents(...)663.6454.55 ExtractFileEntry(...)1800 ExtractEntry(...)1454.5544.44 @@ -49,114 +49,114 @@

#LineLine coverage - 1// FastZip.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;37using System.IO;38using ICSharpCode.SharpZipLib.Core;3940namespace ICSharpCode.SharpZipLib.Zip41{42  /// <summary>43  /// FastZipEvents supports all events applicable to <see cref="FastZip">FastZip</see> operations.44  /// </summary>45  public class FastZipEvents46  {47    /// <summary>48    /// Delegate to invoke when processing directories.49    /// </summary>50    public event EventHandler<DirectoryEventArgs> ProcessDirectory;5152    /// <summary>53    /// Delegate to invoke when processing files.54    /// </summary>55    public ProcessFileHandler ProcessFile;5657    /// <summary>58    /// Delegate to invoke during processing of files.59    /// </summary>60    public ProgressHandler Progress;6162    /// <summary>63    /// Delegate to invoke when processing for a file has been completed.64    /// </summary>65    public CompletedFileHandler CompletedFile;6667    /// <summary>68    /// Delegate to invoke when processing directory failures.69    /// </summary>70    public DirectoryFailureHandler DirectoryFailure;1using System;2using System.IO;3using ICSharpCode.SharpZipLib.Core;45namespace ICSharpCode.SharpZipLib.Zip6{7  /// <summary>8  /// FastZipEvents supports all events applicable to <see cref="FastZip">FastZip</see> operations.9  /// </summary>10  public class FastZipEvents11  {12    /// <summary>13    /// Delegate to invoke when processing directories.14    /// </summary>15    public event EventHandler<DirectoryEventArgs> ProcessDirectory;1617    /// <summary>18    /// Delegate to invoke when processing files.19    /// </summary>20    public ProcessFileHandler ProcessFile;2122    /// <summary>23    /// Delegate to invoke during processing of files.24    /// </summary>25    public ProgressHandler Progress;2627    /// <summary>28    /// Delegate to invoke when processing for a file has been completed.29    /// </summary>30    public CompletedFileHandler CompletedFile;3132    /// <summary>33    /// Delegate to invoke when processing directory failures.34    /// </summary>35    public DirectoryFailureHandler DirectoryFailure;3637    /// <summary>38    /// Delegate to invoke when processing file failures.39    /// </summary>40    public FileFailureHandler FileFailure;4142    /// <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;5253      if (handler != null) {54        var args = new ScanFailureEventArgs(directory, e);55        handler(this, args);56        result = args.ContinueRunning;57      }58      return result;59    }6061    /// <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);  7172    /// <summary>73    /// Delegate to invoke when processing file failures.74    /// </summary>75    public FileFailureHandler FileFailure;7677    /// <summary>78    /// Raise the <see cref="DirectoryFailure">directory failure</see> event.79    /// </summary>80    /// <param name="directory">The directory causing the failure.</param>81    /// <param name="e">The exception for this event.</param>82    /// <returns>A boolean indicating if execution should continue or not.</returns>83    public bool OnDirectoryFailure(string directory, Exception e)84    {85      bool result = false;86      DirectoryFailureHandler handler = DirectoryFailure;8788      if ( handler != null ) {89        var args = new ScanFailureEventArgs(directory, e);90        handler(this, args);91        result = args.ContinueRunning;92      }93      return result;94    }9596    /// <summary>97    /// Fires the <see cref="FileFailure"> file failure handler delegate</see>.98    /// </summary>99    /// <param name="file">The file causing the failure.</param>100    /// <param name="e">The exception for this failure.</param>101    /// <returns>A boolean indicating if execution should continue or not.</returns>102    public bool OnFileFailure(string file, Exception e)103    {104      FileFailureHandler handler = FileFailure;105            bool result = (handler != null);106107      if ( result ) {108        var args = new ScanFailureEventArgs(file, e);72      if (result) {73        var args = new ScanFailureEventArgs(file, e);74        handler(this, args);75        result = args.ContinueRunning;76      }77      return result;78    }7980    /// <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;8990      if (handler != null) {91        var args = new ScanEventArgs(file);92        handler(this, args);93        result = args.ContinueRunning;94      }95      return result;96    }9798    /// <summary>99    /// Fires the <see cref="CompletedFile"/> delegate100    /// </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      } @@ -164,17 +164,17 @@

 113    }  114  115    /// <summary>116    /// Fires the <see cref="ProcessFile">ProcessFile delegate</see>.116    /// Fires the <see cref="ProcessDirectory">process directory</see> delegate.  117    /// </summary>118    /// <param name="file">The file being processed.</param>119    /// <returns>A boolean indicating if execution should continue or not.</returns>120    public bool OnProcessFile(string file)121    {122      bool result = true;123      ProcessFileHandler handler = ProcessFile;124125      if ( handler != null ) {126        var args = new ScanEventArgs(file);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      } @@ -182,603 +182,523 @@

 131    }  132  133    /// <summary>134        /// Fires the <see cref="CompletedFile"/> delegate134    /// The minimum timespan between <see cref="Progress"/> events.  135    /// </summary>136    /// <param name="file">The file whose processing has been completed.</param>137    /// <returns>A boolean indicating if execution should continue or not.</returns>138    public bool OnCompletedFile(string file)139    {140      bool result = true;141      CompletedFileHandler handler = CompletedFile;142      if ( handler != null ) {143        var args = new ScanEventArgs(file);144        handler(this, args);145        result = args.ContinueRunning;146      }147      return result;148    }149150    /// <summary>151    /// Fires the <see cref="ProcessDirectory">process directory</see> delegate.152    /// </summary>153    /// <param name="directory">The directory being processed.</param>154    /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files as determined by the current 155    /// <returns>A <see cref="bool"/> of true if the operation should continue; false otherwise.</returns>156    public bool OnProcessDirectory(string directory, bool hasMatchingFiles)157    {158      bool result = true;159      EventHandler<DirectoryEventArgs> handler = ProcessDirectory;160      if ( handler != null ) {161        var args = new DirectoryEventArgs(directory, hasMatchingFiles);162        handler(this, args);163        result = args.ContinueRunning;164      }165      return result;166    }167168    /// <summary>169    /// The minimum timespan between <see cref="Progress"/> events.170    /// </summary>171    /// <value>The minimum period of time between <see cref="Progress"/> events.</value>172    /// <seealso cref="Progress"/>173        /// <remarks>The default interval is three seconds.</remarks>174    public TimeSpan ProgressInterval175    {176      get { return progressInterval_; }177      set { progressInterval_ = value; }178    }179180    #region Instance Fields181    TimeSpan progressInterval_ = TimeSpan.FromSeconds(3);182    #endregion183  }184185  /// <summary>186  /// FastZip provides facilities for creating and extracting zip files.187  /// </summary>188  public class FastZip189  {190    #region Enumerations191    /// <summary>192    /// Defines the desired handling when overwriting files during extraction.193    /// </summary>194    public enum Overwrite195    {196      /// <summary>197      /// Prompt the user to confirm overwriting198      /// </summary>199      Prompt,200      /// <summary>201      /// Never overwrite files.202      /// </summary>203      Never,204      /// <summary>205      /// Always overwrite files.206      /// </summary>207      Always136    /// <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    }143144    #region Instance Fields145    TimeSpan progressInterval_ = TimeSpan.FromSeconds(3);146    #endregion147  }148149  /// <summary>150  /// FastZip provides facilities for creating and extracting zip files.151  /// </summary>152  public class FastZip153  {154    #region Enumerations155    /// <summary>156    /// Defines the desired handling when overwriting files during extraction.157    /// </summary>158    public enum Overwrite159    {160      /// <summary>161      /// Prompt the user to confirm overwriting162      /// </summary>163      Prompt,164      /// <summary>165      /// Never overwrite files.166      /// </summary>167      Never,168      /// <summary>169      /// Always overwrite files.170      /// </summary>171      Always172    }173    #endregion174175    #region Constructors176    /// <summary>177    /// Initialise a default instance of <see cref="FastZip"/>.178    /// </summary> + 5179    public FastZip()180    { + 5181    }182183    /// <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    #endregion192193    #region Properties194    /// <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    }201202    /// <summary>203    /// Get / set the password value.204    /// </summary>205    public string Password { + 0206      get { return password_; } + 4207      set { password_ = value; }  208    }209    #endregion210211    #region Constructors212    /// <summary>213    /// Initialise a default instance of <see cref="FastZip"/>.214    /// </summary> - 8215    public FastZip()216    { - 8217    }218219    /// <summary>220    /// Initialise a new instance of <see cref="FastZip"/>221    /// </summary>222    /// <param name="events">The <see cref="FastZipEvents">events</see> to use during operations.</param> - 0223    public FastZip(FastZipEvents events)224    { - 0225      events_ = events; - 0226    }227    #endregion228229    #region Properties230    /// <summary>231    /// Get/set a value indicating wether empty directories should be created.232    /// </summary>233    public bool CreateEmptyDirectories234    { - 8235      get { return createEmptyDirectories_; } - 2236      set { createEmptyDirectories_ = value; }237    }238239#if !NETCF_1_0240    /// <summary>241    /// Get / set the password value.242    /// </summary>243    public string Password244    { - 0245      get { return password_; } - 4246      set { password_ = value; }247    }248#endif249250    /// <summary>251    /// Get or set the <see cref="INameTransform"></see> active when creating Zip files.252    /// </summary>253    /// <seealso cref="EntryFactory"></seealso>254    public INameTransform NameTransform255    { - 0256      get { return entryFactory_.NameTransform; }257      set { - 6258        entryFactory_.NameTransform = value; - 6259      }260    }261262    /// <summary>263    /// Get or set the <see cref="IEntryFactory"></see> active when creating Zip files.264    /// </summary>265    public IEntryFactory EntryFactory266    { - 0267      get { return entryFactory_; }268      set { - 1269         if ( value == null ) { - 0270          entryFactory_ = new ZipEntryFactory(); - 0271        }272        else { - 1273          entryFactory_ = value;274        } - 1275      }276    }277278    /// <summary>279    /// Gets or sets the setting for <see cref="UseZip64">Zip64 handling when writing.</see>280    /// </summary>281        /// <remarks>282        /// The default value is dynamic which is not backwards compatible with old283        /// programs and can cause problems with XP's built in compression which cant284        /// read Zip64 archives. However it does avoid the situation were a large file285        /// is added and cannot be completed correctly.286        /// NOTE: Setting the size for entries before they are added is the best solution!287        /// By default the EntryFactory used by FastZip will set fhe file size.288        /// </remarks>289    public UseZip64 UseZip64290    { - 6291      get { return useZip64_; } - 0292      set { useZip64_ = value; }293    }294295    /// <summary>296    /// Get/set a value indicating wether file dates and times should297    /// be restored when extracting files from an archive.298    /// </summary>299    /// <remarks>The default value is false.</remarks>300    public bool RestoreDateTimeOnExtract301    {302      get { - 0303        return restoreDateTimeOnExtract_;304      }305      set { - 0306        restoreDateTimeOnExtract_ = value; - 0307      }308    }309310    /// <summary>311    /// Get/set a value indicating wether file attributes should312    /// be restored during extract operations313    /// </summary>314    public bool RestoreAttributesOnExtract315    { - 0316      get { return restoreAttributesOnExtract_; } - 0317      set { restoreAttributesOnExtract_ = value; }318    }319    #endregion320321    #region Delegates322    /// <summary>323    /// Delegate called when confirming overwriting of files.324    /// </summary>325    public delegate bool ConfirmOverwriteDelegate(string fileName);326    #endregion327328    #region CreateZip329    /// <summary>330    /// Create a zip file.331    /// </summary>332    /// <param name="zipFileName">The name of the zip file to create.</param>333    /// <param name="sourceDirectory">The directory to source files from.</param>334    /// <param name="recurse">True to recurse directories, false for no recursion.</param>335    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>336    /// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>337    public void CreateZip(string zipFileName, string sourceDirectory,338      bool recurse, string fileFilter, string directoryFilter)339    { - 0340      CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, directoryFilter); - 0341    }342343    /// <summary>344    /// Create a zip file/archive.345    /// </summary>346    /// <param name="zipFileName">The name of the zip file to create.</param>347    /// <param name="sourceDirectory">The directory to obtain files and directories from.</param>348    /// <param name="recurse">True to recurse directories, false for no recursion.</param>349    /// <param name="fileFilter">The file filter to apply.</param>350    public void CreateZip(string zipFileName, string sourceDirectory, bool recurse, string fileFilter)351    { - 1352      CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, null); - 0353    }354355    /// <summary>356    /// Create a zip archive sending output to the <paramref name="outputStream"/> passed.357    /// </summary>358    /// <param name="outputStream">The stream to write archive data to.</param>359    /// <param name="sourceDirectory">The directory to source files from.</param>360    /// <param name="recurse">True to recurse directories, false for no recursion.</param>361    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>362    /// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>363        /// <remarks>The <paramref name="outputStream"/> is closed after creation.</remarks>364    public void CreateZip(Stream outputStream, string sourceDirectory, bool recurse, string fileFilter, string directory365    { - 6366      NameTransform = new ZipNameTransform(sourceDirectory); - 6367      sourceDirectory_ = sourceDirectory;368 - 6369      using ( outputStream_ = new ZipOutputStream(outputStream) ) {370371#if !NETCF_1_0 - 6372         if ( password_ != null ) { - 2373          outputStream_.Password = password_;374        }375#endif376 - 6377        outputStream_.UseZip64 = UseZip64; - 6378        var scanner = new FileSystemScanner(fileFilter, directoryFilter); - 6379        scanner.ProcessFile += ProcessFile; - 6380         if ( this.CreateEmptyDirectories ) { - 0381          scanner.ProcessDirectory += ProcessDirectory;382        }383 - 6384         if (events_ != null) { - 0385           if ( events_.FileFailure != null ) { - 0386            scanner.FileFailure += events_.FileFailure;387          }388 - 0389           if ( events_.DirectoryFailure != null ) { - 0390            scanner.DirectoryFailure += events_.DirectoryFailure;391          }392        }393 - 6394        scanner.Scan(sourceDirectory, recurse); - 4395      } - 4396    }397398    #endregion399400    #region ExtractZip401    /// <summary>402    /// Extract the contents of a zip file.403    /// </summary>404    /// <param name="zipFileName">The zip file to extract from.</param>405    /// <param name="targetDirectory">The directory to save extracted information in.</param>406    /// <param name="fileFilter">A filter to apply to files.</param>407    public void ExtractZip(string zipFileName, string targetDirectory, string fileFilter)408    { - 2409      ExtractZip(zipFileName, targetDirectory, Overwrite.Always, null, fileFilter, null, restoreDateTimeOnExtract_); - 1410    }411412    /// <summary>413    /// Extract the contents of a zip file.414    /// </summary>415    /// <param name="zipFileName">The zip file to extract from.</param>416    /// <param name="targetDirectory">The directory to save extracted information in.</param>417    /// <param name="overwrite">The style of <see cref="Overwrite">overwriting</see> to apply.</param>418    /// <param name="confirmDelegate">A delegate to invoke when confirming overwriting.</param>419    /// <param name="fileFilter">A filter to apply to files.</param>420    /// <param name="directoryFilter">A filter to apply to directories.</param>421    /// <param name="restoreDateTime">Flag indicating whether to restore the date and time for extracted files.</param>422    public void ExtractZip(string zipFileName, string targetDirectory,423                 Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,424                 string fileFilter, string directoryFilter, bool restoreDateTime)425    { - 2426      Stream inputStream = File.Open(zipFileName, FileMode.Open, FileAccess.Read, FileShare.Read); - 1427      ExtractZip(inputStream, targetDirectory, overwrite, confirmDelegate, fileFilter, directoryFilter, restoreDateTime, - 1428    }429430    /// <summary>431    /// Extract the contents of a zip file held in a stream.432    /// </summary>433    /// <param name="inputStream">The seekable input stream containing the zip to extract from.</param>434    /// <param name="targetDirectory">The directory to save extracted information in.</param>435    /// <param name="overwrite">The style of <see cref="Overwrite">overwriting</see> to apply.</param>436    /// <param name="confirmDelegate">A delegate to invoke when confirming overwriting.</param>437    /// <param name="fileFilter">A filter to apply to files.</param>438    /// <param name="directoryFilter">A filter to apply to directories.</param>439    /// <param name="restoreDateTime">Flag indicating whether to restore the date and time for extracted files.</param>440    /// <param name="isStreamOwner">Flag indicating whether the inputStream will be closed by this method.</param>441    public void ExtractZip(Stream inputStream, string targetDirectory,442             Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,443             string fileFilter, string directoryFilter, bool restoreDateTime,444             bool isStreamOwner)445    { - 1446       if ((overwrite == Overwrite.Prompt) && (confirmDelegate == null)) { - 0447        throw new ArgumentNullException(nameof(confirmDelegate));448      }449 - 1450      continueRunning_ = true; - 1451      overwrite_ = overwrite; - 1452      confirmDelegate_ = confirmDelegate; - 1453      extractNameTransform_ = new WindowsNameTransform(targetDirectory);454 - 1455      fileFilter_ = new NameFilter(fileFilter); - 1456      directoryFilter_ = new NameFilter(directoryFilter); - 1457      restoreDateTimeOnExtract_ = restoreDateTime;458 - 1459      using (zipFile_ = new ZipFile(inputStream)) {460461#if !NETCF_1_0 - 1462         if (password_ != null) { - 0463          zipFile_.Password = password_;464        }465#endif - 1466        zipFile_.IsStreamOwner = isStreamOwner; - 1467        System.Collections.IEnumerator enumerator = zipFile_.GetEnumerator(); - 2468         while (continueRunning_ && enumerator.MoveNext()) { - 1469          var entry = (ZipEntry)enumerator.Current; - 1470           if (entry.IsFile)471          {472            // TODO Path.GetDirectory can fail here on invalid characters. - 0473             if (directoryFilter_.IsMatch(Path.GetDirectoryName(entry.Name)) && fileFilter_.IsMatch(entry.Name)) { - 0474              ExtractEntry(entry);475            } - 0476          } - 1477           else if (entry.IsDirectory) { - 1478             if (directoryFilter_.IsMatch(entry.Name) && CreateEmptyDirectories) { - 1479              ExtractEntry(entry);480            }481          }482          else {483            // Do nothing for volume labels etc...484          }485        } - 1486      } - 1487    }488    #endregion489490    #region Internal Processing491    void ProcessDirectory(object sender, DirectoryEventArgs e)492    { - 0493       if ( !e.HasMatchingFiles && CreateEmptyDirectories ) { - 0494         if ( events_ != null ) { - 0495          events_.OnProcessDirectory(e.Name, e.HasMatchingFiles);496        }209210    /// <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    }220221    /// <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    }234235    /// <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 old240    /// programs and can cause problems with XP's built in compression which cant241    /// read Zip64 archives. However it does avoid the situation were a large file242    /// 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    }250251    /// <summary>252    /// Get/set a value indicating wether file dates and times should253    /// 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    }264265    /// <summary>266    /// Get/set a value indicating wether file attributes should267    /// be restored during extract operations268    /// </summary>269    public bool RestoreAttributesOnExtract { + 0270      get { return restoreAttributesOnExtract_; } + 0271      set { restoreAttributesOnExtract_ = value; }272    }273    #endregion274275    #region Delegates276    /// <summary>277    /// Delegate called when confirming overwriting of files.278    /// </summary>279    public delegate bool ConfirmOverwriteDelegate(string fileName);280    #endregion281282    #region CreateZip283    /// <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    }296297    /// <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    }308309    /// <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 directory319    { + 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    }349350    #endregion351352    #region ExtractZip353    /// <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    }363364    /// <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    }381382    /// <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    #endregion436437    #region Internal Processing438    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    }453454    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 the463          // file will not be changed by subsequent openers, but precludes opening in some cases464          // 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    }480481    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 - 0498         if ( e.ContinueRunning ) { - 0499           if (e.Name != sourceDirectory_) { - 0500            ZipEntry entry = entryFactory_.MakeDirectoryEntry(e.Name); - 0501            outputStream_.PutNextEntry(entry);502          }503        }504      } - 0505    }506507    void ProcessFile(object sender, ScanEventArgs e)508    { - 5509       if ( (events_ != null) && (events_.ProcessFile != null) ) { - 0510        events_.ProcessFile(sender, e);511      }512 - 5513       if ( e.ContinueRunning ) {514                try {515                    // The open below is equivalent to OpenRead which gaurantees that if opened the516                    // file will not be changed by subsequent openers, but precludes opening in some cases517                    // were it could succeed. ie the open may fail as its already open for writing and the share mode sh - 5518                    using (FileStream stream = File.Open(e.Name, FileMode.Open, FileAccess.Read, FileShare.Read)) { - 4519                        ZipEntry entry = entryFactory_.MakeFileEntry(e.Name); - 4520                        outputStream_.PutNextEntry(entry); - 4521                        AddFileContents(e.Name, stream); - 4522                    } - 4523                } - 1524                catch(Exception ex) { - 1525                     if (events_ != null) { - 0526                        continueRunning_ = events_.OnFileFailure(e.Name, ex); - 0527                    }528                    else { - 1529                        continueRunning_ = false; - 1530                        throw;531                    } - 0532                }533      } - 4534    }535536    void AddFileContents(string name, Stream stream)537    { - 4538       if( stream==null ) { - 0539        throw new ArgumentNullException(nameof(stream));540      }541 - 4542       if( buffer_==null ) { - 4543        buffer_=new byte[4096];544      }545 - 4546       if( (events_!=null)&&(events_.Progress!=null) ) { - 0547        StreamUtils.Copy(stream, outputStream_, buffer_, - 0548          events_.Progress, events_.ProgressInterval, this, name); - 0549      }550      else { - 4551        StreamUtils.Copy(stream, outputStream_, buffer_);552      }553 - 4554       if( events_!=null ) { - 0555        continueRunning_=events_.OnCompletedFile(name);556      } - 4557    }558559    void ExtractFileEntry(ZipEntry entry, string targetName)560    { - 0561      bool proceed = true; - 0562       if ( overwrite_ != Overwrite.Always ) { - 0563         if ( File.Exists(targetName) ) { - 0564           if ( (overwrite_ == Overwrite.Prompt) && (confirmDelegate_ != null) ) { - 0565            proceed = confirmDelegate_(targetName); - 0566          }567          else { - 0568            proceed = false;569          }570        }571      } + 4498       if (events_ != null) { + 0499        continueRunning_ = events_.OnCompletedFile(name);500      } + 4501    }502503    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    }560561    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 - 0573       if ( proceed ) { - 0574         if ( events_ != null ) { - 0575          continueRunning_ = events_.OnProcessFile(entry.Name);576        } + 1573        doExtraction = !(string.IsNullOrEmpty(targetName));574      }575576      // TODO: Fire delegate/throw exception were compression method not supported, or name is invalid?  577 - 0578         if ( continueRunning_ ) {579          try { - 0580            using ( FileStream outputStream = File.Create(targetName) ) { - 0581               if ( buffer_ == null ) { - 0582                buffer_ = new byte[4096];583              } - 0584               if ((events_ != null) && (events_.Progress != null))585              { - 0586                StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_, - 0587                  events_.Progress, events_.ProgressInterval, this, entry.Name, entry.Size); - 0588              }589              else590              { - 0591                StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_);592              }593 - 0594               if (events_ != null) { - 0595                continueRunning_ = events_.OnCompletedFile(entry.Name);596              } - 0597            }598599#if !NETCF_1_0 && !NETCF_2_0 - 0600             if ( restoreDateTimeOnExtract_ ) { - 0601              File.SetLastWriteTime(targetName, entry.DateTime);602            }603 - 0604             if ( RestoreAttributesOnExtract && entry.IsDOSEntry && (entry.ExternalFileAttributes != -1)) { - 0605              var fileAttributes = (FileAttributes) entry.ExternalFileAttributes;606              // TODO: FastZip - Setting of other file attributes on extraction is a little trickier. - 0607              fileAttributes &= (FileAttributes.Archive | FileAttributes.Normal | FileAttributes.ReadOnly | FileAttribut - 0608              File.SetAttributes(targetName, fileAttributes);609            }610#endif - 0611          } - 0612          catch(Exception ex) { - 0613             if ( events_ != null ) { - 0614              continueRunning_ = events_.OnFileFailure(targetName, ex); - 0615            }616            else { - 0617                            continueRunning_ = false; - 0618                            throw;619            } - 0620          }621        }622      } - 0623    } + 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    }612613    static int MakeExternalAttributes(FileInfo info)614    { + 0615      return (int)info.Attributes;616    }617618    static bool NameIsValid(string name)619    { + 0620      return !string.IsNullOrEmpty(name) && + 0621        (name.IndexOfAny(Path.GetInvalidPathChars()) < 0);622    }623    #endregion  624625    void ExtractEntry(ZipEntry entry)626    { - 1627      bool doExtraction = entry.IsCompressionMethodSupported(); - 1628      string targetName = entry.Name;629 - 1630       if ( doExtraction ) { - 1631         if ( entry.IsFile ) { - 0632          targetName = extractNameTransform_.TransformFile(targetName); - 0633        } - 1634         else if ( entry.IsDirectory ) { - 1635          targetName = extractNameTransform_.TransformDirectory(targetName);636        }637 - 1638        doExtraction = !(string.IsNullOrEmpty(targetName));639      }640641      // TODO: Fire delegate/throw exception were compression method not supported, or name is invalid?642 - 1643      string dirName = null;644 - 1645       if ( doExtraction ) { - 1646           if ( entry.IsDirectory ) { - 1647            dirName = targetName; - 1648          }649          else { - 0650            dirName = Path.GetDirectoryName(Path.GetFullPath(targetName));651          }652      }653 - 1654       if ( doExtraction && !Directory.Exists(dirName) ) { - 1655         if ( !entry.IsDirectory || CreateEmptyDirectories ) {656          try { - 1657            Directory.CreateDirectory(dirName); - 1658          } - 0659          catch (Exception ex) { - 0660            doExtraction = false; - 0661             if ( events_ != null ) { - 0662               if ( entry.IsDirectory ) { - 0663                continueRunning_ = events_.OnDirectoryFailure(targetName, ex); - 0664              }665              else { - 0666                continueRunning_ = events_.OnFileFailure(targetName, ex);667              } - 0668            }669            else { - 0670              continueRunning_ = false; - 0671                            throw;672            } - 0673          }674        }675      }676 - 1677       if ( doExtraction && entry.IsFile ) { - 0678        ExtractFileEntry(entry, targetName);679      } - 1680    }681682    static int MakeExternalAttributes(FileInfo info)683    { - 0684      return (int)info.Attributes;685    }686687#if NET_1_0 || NET_1_1 || NETCF_1_0688    static bool NameIsValid(string name)689    {690      return (name != null) &&691        (name.Length > 0) &&692        (name.IndexOfAny(Path.InvalidPathChars) < 0);693    }694#else695    static bool NameIsValid(string name)696    { - 0697      return !string.IsNullOrEmpty(name)&& - 0698        (name.IndexOfAny(Path.GetInvalidPathChars()) < 0);699    }700#endif701    #endregion702703    #region Instance Fields704    bool continueRunning_;705    byte[] buffer_;706    ZipOutputStream outputStream_;707    ZipFile zipFile_;708    string sourceDirectory_;709    NameFilter fileFilter_;710    NameFilter directoryFilter_;711    Overwrite overwrite_;712    ConfirmOverwriteDelegate confirmDelegate_;713714    bool restoreDateTimeOnExtract_;715    bool restoreAttributesOnExtract_;716    bool createEmptyDirectories_;717    FastZipEvents events_; - 8718    IEntryFactory entryFactory_ = new ZipEntryFactory();719    INameTransform extractNameTransform_; - 8720    UseZip64 useZip64_=UseZip64.Dynamic;721722#if !NETCF_1_0723    string password_;724#endif725726    #endregion727  }728}625    #region Instance Fields626    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_;635636    bool restoreDateTimeOnExtract_;637    bool restoreAttributesOnExtract_;638    bool createEmptyDirectories_;639    FastZipEvents events_; + 5640    IEntryFactory entryFactory_ = new ZipEntryFactory();641    INameTransform extractNameTransform_; + 5642    UseZip64 useZip64_ = UseZip64.Dynamic;643644    string password_;645646    #endregion647  }648} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_FastZipEvents.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_FastZipEvents.htm index b0e143233..98f6d3671 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_FastZipEvents.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_FastZipEvents.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:38 Coverable lines:38 -Total lines:728 +Total lines:648 Line coverage:0% Branch coverage:0% @@ -40,114 +40,114 @@

#LineLine coverage - 1// FastZip.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;37using System.IO;38using ICSharpCode.SharpZipLib.Core;3940namespace ICSharpCode.SharpZipLib.Zip41{42  /// <summary>43  /// FastZipEvents supports all events applicable to <see cref="FastZip">FastZip</see> operations.44  /// </summary>45  public class FastZipEvents46  {47    /// <summary>48    /// Delegate to invoke when processing directories.49    /// </summary>50    public event EventHandler<DirectoryEventArgs> ProcessDirectory;5152    /// <summary>53    /// Delegate to invoke when processing files.54    /// </summary>55    public ProcessFileHandler ProcessFile;5657    /// <summary>58    /// Delegate to invoke during processing of files.59    /// </summary>60    public ProgressHandler Progress;6162    /// <summary>63    /// Delegate to invoke when processing for a file has been completed.64    /// </summary>65    public CompletedFileHandler CompletedFile;6667    /// <summary>68    /// Delegate to invoke when processing directory failures.69    /// </summary>70    public DirectoryFailureHandler DirectoryFailure;1using System;2using System.IO;3using ICSharpCode.SharpZipLib.Core;45namespace ICSharpCode.SharpZipLib.Zip6{7  /// <summary>8  /// FastZipEvents supports all events applicable to <see cref="FastZip">FastZip</see> operations.9  /// </summary>10  public class FastZipEvents11  {12    /// <summary>13    /// Delegate to invoke when processing directories.14    /// </summary>15    public event EventHandler<DirectoryEventArgs> ProcessDirectory;1617    /// <summary>18    /// Delegate to invoke when processing files.19    /// </summary>20    public ProcessFileHandler ProcessFile;2122    /// <summary>23    /// Delegate to invoke during processing of files.24    /// </summary>25    public ProgressHandler Progress;2627    /// <summary>28    /// Delegate to invoke when processing for a file has been completed.29    /// </summary>30    public CompletedFileHandler CompletedFile;3132    /// <summary>33    /// Delegate to invoke when processing directory failures.34    /// </summary>35    public DirectoryFailureHandler DirectoryFailure;3637    /// <summary>38    /// Delegate to invoke when processing file failures.39    /// </summary>40    public FileFailureHandler FileFailure;4142    /// <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    }6061    /// <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);  7172    /// <summary>73    /// Delegate to invoke when processing file failures.74    /// </summary>75    public FileFailureHandler FileFailure;7677    /// <summary>78    /// Raise the <see cref="DirectoryFailure">directory failure</see> event.79    /// </summary>80    /// <param name="directory">The directory causing the failure.</param>81    /// <param name="e">The exception for this event.</param>82    /// <returns>A boolean indicating if execution should continue or not.</returns>83    public bool OnDirectoryFailure(string directory, Exception e)84    { - 085      bool result = false; - 086      DirectoryFailureHandler handler = DirectoryFailure;87 - 088       if ( handler != null ) { - 089        var args = new ScanFailureEventArgs(directory, e); - 090        handler(this, args); - 091        result = args.ContinueRunning;92      } - 093      return result;94    }9596    /// <summary>97    /// Fires the <see cref="FileFailure"> file failure handler delegate</see>.98    /// </summary>99    /// <param name="file">The file causing the failure.</param>100    /// <param name="e">The exception for this failure.</param>101    /// <returns>A boolean indicating if execution should continue or not.</returns>102    public bool OnFileFailure(string file, Exception e)103    { - 0104      FileFailureHandler handler = FileFailure; - 0105            bool result = (handler != null);106 - 0107       if ( result ) { - 0108        var args = new ScanFailureEventArgs(file, e); + 072       if (result) { + 073        var args = new ScanFailureEventArgs(file, e); + 074        handler(this, args); + 075        result = args.ContinueRunning;76      } + 077      return result;78    }7980    /// <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    }9798    /// <summary>99    /// Fires the <see cref="CompletedFile"/> delegate100    /// </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      } @@ -155,17 +155,17 @@

 113    }  114  115    /// <summary>116    /// Fires the <see cref="ProcessFile">ProcessFile delegate</see>.116    /// Fires the <see cref="ProcessDirectory">process directory</see> delegate.  117    /// </summary>118    /// <param name="file">The file being processed.</param>119    /// <returns>A boolean indicating if execution should continue or not.</returns>120    public bool OnProcessFile(string file)121    { - 0122      bool result = true; - 0123      ProcessFileHandler handler = ProcessFile;124 - 0125       if ( handler != null ) { - 0126        var args = new ScanEventArgs(file);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      } @@ -173,603 +173,523 @@

 131    }  132  133    /// <summary>134        /// Fires the <see cref="CompletedFile"/> delegate134    /// The minimum timespan between <see cref="Progress"/> events.  135    /// </summary>136    /// <param name="file">The file whose processing has been completed.</param>137    /// <returns>A boolean indicating if execution should continue or not.</returns>138    public bool OnCompletedFile(string file)139    { - 0140      bool result = true; - 0141      CompletedFileHandler handler = CompletedFile; - 0142       if ( handler != null ) { - 0143        var args = new ScanEventArgs(file); - 0144        handler(this, args); - 0145        result = args.ContinueRunning;146      } - 0147      return result;148    }149150    /// <summary>151    /// Fires the <see cref="ProcessDirectory">process directory</see> delegate.152    /// </summary>153    /// <param name="directory">The directory being processed.</param>154    /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files as determined by the current 155    /// <returns>A <see cref="bool"/> of true if the operation should continue; false otherwise.</returns>156    public bool OnProcessDirectory(string directory, bool hasMatchingFiles)157    { - 0158      bool result = true; - 0159      EventHandler<DirectoryEventArgs> handler = ProcessDirectory; - 0160       if ( handler != null ) { - 0161        var args = new DirectoryEventArgs(directory, hasMatchingFiles); - 0162        handler(this, args); - 0163        result = args.ContinueRunning;164      } - 0165      return result;166    }167168    /// <summary>169    /// The minimum timespan between <see cref="Progress"/> events.170    /// </summary>171    /// <value>The minimum period of time between <see cref="Progress"/> events.</value>172    /// <seealso cref="Progress"/>173        /// <remarks>The default interval is three seconds.</remarks>174    public TimeSpan ProgressInterval175    { - 0176      get { return progressInterval_; } - 0177      set { progressInterval_ = value; }178    }179180    #region Instance Fields - 0181    TimeSpan progressInterval_ = TimeSpan.FromSeconds(3);182    #endregion183  }184185  /// <summary>186  /// FastZip provides facilities for creating and extracting zip files.187  /// </summary>188  public class FastZip189  {190    #region Enumerations191    /// <summary>192    /// Defines the desired handling when overwriting files during extraction.193    /// </summary>194    public enum Overwrite195    {196      /// <summary>197      /// Prompt the user to confirm overwriting198      /// </summary>199      Prompt,200      /// <summary>201      /// Never overwrite files.202      /// </summary>203      Never,204      /// <summary>205      /// Always overwrite files.206      /// </summary>207      Always136    /// <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    }143144    #region Instance Fields + 0145    TimeSpan progressInterval_ = TimeSpan.FromSeconds(3);146    #endregion147  }148149  /// <summary>150  /// FastZip provides facilities for creating and extracting zip files.151  /// </summary>152  public class FastZip153  {154    #region Enumerations155    /// <summary>156    /// Defines the desired handling when overwriting files during extraction.157    /// </summary>158    public enum Overwrite159    {160      /// <summary>161      /// Prompt the user to confirm overwriting162      /// </summary>163      Prompt,164      /// <summary>165      /// Never overwrite files.166      /// </summary>167      Never,168      /// <summary>169      /// Always overwrite files.170      /// </summary>171      Always172    }173    #endregion174175    #region Constructors176    /// <summary>177    /// Initialise a default instance of <see cref="FastZip"/>.178    /// </summary>179    public FastZip()180    {181    }182183    /// <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    #endregion192193    #region Properties194    /// <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    }201202    /// <summary>203    /// Get / set the password value.204    /// </summary>205    public string Password {206      get { return password_; }207      set { password_ = value; }  208    }209    #endregion210211    #region Constructors212    /// <summary>213    /// Initialise a default instance of <see cref="FastZip"/>.214    /// </summary>215    public FastZip()216    {217    }218219    /// <summary>220    /// Initialise a new instance of <see cref="FastZip"/>221    /// </summary>222    /// <param name="events">The <see cref="FastZipEvents">events</see> to use during operations.</param>223    public FastZip(FastZipEvents events)224    {225      events_ = events;226    }227    #endregion228229    #region Properties230    /// <summary>231    /// Get/set a value indicating wether empty directories should be created.232    /// </summary>233    public bool CreateEmptyDirectories234    {235      get { return createEmptyDirectories_; }236      set { createEmptyDirectories_ = value; }237    }238239#if !NETCF_1_0240    /// <summary>241    /// Get / set the password value.242    /// </summary>243    public string Password244    {245      get { return password_; }246      set { password_ = value; }247    }248#endif249250    /// <summary>251    /// Get or set the <see cref="INameTransform"></see> active when creating Zip files.252    /// </summary>253    /// <seealso cref="EntryFactory"></seealso>254    public INameTransform NameTransform255    {256      get { return entryFactory_.NameTransform; }257      set {258        entryFactory_.NameTransform = value;209210    /// <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    }220221    /// <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    }234235    /// <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 old240    /// programs and can cause problems with XP's built in compression which cant241    /// read Zip64 archives. However it does avoid the situation were a large file242    /// 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    }250251    /// <summary>252    /// Get/set a value indicating wether file dates and times should253    /// 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    }261262    /// <summary>263    /// Get or set the <see cref="IEntryFactory"></see> active when creating Zip files.264    /// </summary>265    public IEntryFactory EntryFactory266    {267      get { return entryFactory_; }268      set {269        if ( value == null ) {270          entryFactory_ = new ZipEntryFactory();271        }272        else {273          entryFactory_ = value;274        }275      }276    }277278    /// <summary>279    /// Gets or sets the setting for <see cref="UseZip64">Zip64 handling when writing.</see>280    /// </summary>281        /// <remarks>282        /// The default value is dynamic which is not backwards compatible with old283        /// programs and can cause problems with XP's built in compression which cant284        /// read Zip64 archives. However it does avoid the situation were a large file285        /// is added and cannot be completed correctly.286        /// NOTE: Setting the size for entries before they are added is the best solution!287        /// By default the EntryFactory used by FastZip will set fhe file size.288        /// </remarks>289    public UseZip64 UseZip64290    {291      get { return useZip64_; }292      set { useZip64_ = value; }293    }294295    /// <summary>296    /// Get/set a value indicating wether file dates and times should297    /// be restored when extracting files from an archive.298    /// </summary>299    /// <remarks>The default value is false.</remarks>300    public bool RestoreDateTimeOnExtract301    {302      get {303        return restoreDateTimeOnExtract_;304      }305      set {306        restoreDateTimeOnExtract_ = value;307      }308    }309310    /// <summary>311    /// Get/set a value indicating wether file attributes should312    /// be restored during extract operations313    /// </summary>314    public bool RestoreAttributesOnExtract315    {316      get { return restoreAttributesOnExtract_; }317      set { restoreAttributesOnExtract_ = value; }318    }319    #endregion320321    #region Delegates322    /// <summary>323    /// Delegate called when confirming overwriting of files.324    /// </summary>325    public delegate bool ConfirmOverwriteDelegate(string fileName);326    #endregion327328    #region CreateZip329    /// <summary>330    /// Create a zip file.331    /// </summary>332    /// <param name="zipFileName">The name of the zip file to create.</param>333    /// <param name="sourceDirectory">The directory to source files from.</param>334    /// <param name="recurse">True to recurse directories, false for no recursion.</param>335    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>336    /// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>337    public void CreateZip(string zipFileName, string sourceDirectory,338      bool recurse, string fileFilter, string directoryFilter)339    {340      CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, directoryFilter);341    }342343    /// <summary>344    /// Create a zip file/archive.345    /// </summary>346    /// <param name="zipFileName">The name of the zip file to create.</param>347    /// <param name="sourceDirectory">The directory to obtain files and directories from.</param>348    /// <param name="recurse">True to recurse directories, false for no recursion.</param>349    /// <param name="fileFilter">The file filter to apply.</param>350    public void CreateZip(string zipFileName, string sourceDirectory, bool recurse, string fileFilter)351    {352      CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, null);353    }354355    /// <summary>356    /// Create a zip archive sending output to the <paramref name="outputStream"/> passed.357    /// </summary>358    /// <param name="outputStream">The stream to write archive data to.</param>359    /// <param name="sourceDirectory">The directory to source files from.</param>360    /// <param name="recurse">True to recurse directories, false for no recursion.</param>361    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>362    /// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>363        /// <remarks>The <paramref name="outputStream"/> is closed after creation.</remarks>364    public void CreateZip(Stream outputStream, string sourceDirectory, bool recurse, string fileFilter, string directory365    {366      NameTransform = new ZipNameTransform(sourceDirectory);367      sourceDirectory_ = sourceDirectory;368369      using ( outputStream_ = new ZipOutputStream(outputStream) ) {370371#if !NETCF_1_0372        if ( password_ != null ) {373          outputStream_.Password = password_;374        }375#endif376377        outputStream_.UseZip64 = UseZip64;378        var scanner = new FileSystemScanner(fileFilter, directoryFilter);379        scanner.ProcessFile += ProcessFile;380        if ( this.CreateEmptyDirectories ) {381          scanner.ProcessDirectory += ProcessDirectory;382        }383384        if (events_ != null) {385          if ( events_.FileFailure != null ) {386            scanner.FileFailure += events_.FileFailure;387          }388389          if ( events_.DirectoryFailure != null ) {390            scanner.DirectoryFailure += events_.DirectoryFailure;391          }392        }393394        scanner.Scan(sourceDirectory, recurse);395      }396    }397398    #endregion399400    #region ExtractZip401    /// <summary>402    /// Extract the contents of a zip file.403    /// </summary>404    /// <param name="zipFileName">The zip file to extract from.</param>405    /// <param name="targetDirectory">The directory to save extracted information in.</param>406    /// <param name="fileFilter">A filter to apply to files.</param>407    public void ExtractZip(string zipFileName, string targetDirectory, string fileFilter)408    {409      ExtractZip(zipFileName, targetDirectory, Overwrite.Always, null, fileFilter, null, restoreDateTimeOnExtract_);410    }411412    /// <summary>413    /// Extract the contents of a zip file.414    /// </summary>415    /// <param name="zipFileName">The zip file to extract from.</param>416    /// <param name="targetDirectory">The directory to save extracted information in.</param>417    /// <param name="overwrite">The style of <see cref="Overwrite">overwriting</see> to apply.</param>418    /// <param name="confirmDelegate">A delegate to invoke when confirming overwriting.</param>419    /// <param name="fileFilter">A filter to apply to files.</param>420    /// <param name="directoryFilter">A filter to apply to directories.</param>421    /// <param name="restoreDateTime">Flag indicating whether to restore the date and time for extracted files.</param>422    public void ExtractZip(string zipFileName, string targetDirectory,423                 Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,424                 string fileFilter, string directoryFilter, bool restoreDateTime)425    {426      Stream inputStream = File.Open(zipFileName, FileMode.Open, FileAccess.Read, FileShare.Read);427      ExtractZip(inputStream, targetDirectory, overwrite, confirmDelegate, fileFilter, directoryFilter, restoreDateTime,428    }429430    /// <summary>431    /// Extract the contents of a zip file held in a stream.432    /// </summary>433    /// <param name="inputStream">The seekable input stream containing the zip to extract from.</param>434    /// <param name="targetDirectory">The directory to save extracted information in.</param>435    /// <param name="overwrite">The style of <see cref="Overwrite">overwriting</see> to apply.</param>436    /// <param name="confirmDelegate">A delegate to invoke when confirming overwriting.</param>437    /// <param name="fileFilter">A filter to apply to files.</param>438    /// <param name="directoryFilter">A filter to apply to directories.</param>439    /// <param name="restoreDateTime">Flag indicating whether to restore the date and time for extracted files.</param>440    /// <param name="isStreamOwner">Flag indicating whether the inputStream will be closed by this method.</param>441    public void ExtractZip(Stream inputStream, string targetDirectory,442             Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,443             string fileFilter, string directoryFilter, bool restoreDateTime,444             bool isStreamOwner)445    {446      if ((overwrite == Overwrite.Prompt) && (confirmDelegate == null)) {447        throw new ArgumentNullException(nameof(confirmDelegate));448      }449450      continueRunning_ = true;451      overwrite_ = overwrite;452      confirmDelegate_ = confirmDelegate;453      extractNameTransform_ = new WindowsNameTransform(targetDirectory);454455      fileFilter_ = new NameFilter(fileFilter);456      directoryFilter_ = new NameFilter(directoryFilter);457      restoreDateTimeOnExtract_ = restoreDateTime;458459      using (zipFile_ = new ZipFile(inputStream)) {460461#if !NETCF_1_0462        if (password_ != null) {463          zipFile_.Password = password_;464        }465#endif466        zipFile_.IsStreamOwner = isStreamOwner;467        System.Collections.IEnumerator enumerator = zipFile_.GetEnumerator();468        while (continueRunning_ && enumerator.MoveNext()) {469          var entry = (ZipEntry)enumerator.Current;470          if (entry.IsFile)471          {472            // TODO Path.GetDirectory can fail here on invalid characters.473            if (directoryFilter_.IsMatch(Path.GetDirectoryName(entry.Name)) && fileFilter_.IsMatch(entry.Name)) {474              ExtractEntry(entry);475            }260      set {261        restoreDateTimeOnExtract_ = value;262      }263    }264265    /// <summary>266    /// Get/set a value indicating wether file attributes should267    /// be restored during extract operations268    /// </summary>269    public bool RestoreAttributesOnExtract {270      get { return restoreAttributesOnExtract_; }271      set { restoreAttributesOnExtract_ = value; }272    }273    #endregion274275    #region Delegates276    /// <summary>277    /// Delegate called when confirming overwriting of files.278    /// </summary>279    public delegate bool ConfirmOverwriteDelegate(string fileName);280    #endregion281282    #region CreateZip283    /// <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    }296297    /// <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    }308309    /// <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 directory319    {320      NameTransform = new ZipNameTransform(sourceDirectory);321      sourceDirectory_ = sourceDirectory;322323      using (outputStream_ = new ZipOutputStream(outputStream)) {324325        if (password_ != null) {326          outputStream_.Password = password_;327        }328329        outputStream_.UseZip64 = UseZip64;330        var scanner = new FileSystemScanner(fileFilter, directoryFilter);331        scanner.ProcessFile += ProcessFile;332        if (this.CreateEmptyDirectories) {333          scanner.ProcessDirectory += ProcessDirectory;334        }335336        if (events_ != null) {337          if (events_.FileFailure != null) {338            scanner.FileFailure += events_.FileFailure;339          }340341          if (events_.DirectoryFailure != null) {342            scanner.DirectoryFailure += events_.DirectoryFailure;343          }344        }345346        scanner.Scan(sourceDirectory, recurse);347      }348    }349350    #endregion351352    #region ExtractZip353    /// <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    }363364    /// <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    }381382    /// <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      }401402      continueRunning_ = true;403      overwrite_ = overwrite;404      confirmDelegate_ = confirmDelegate;405      extractNameTransform_ = new WindowsNameTransform(targetDirectory);406407      fileFilter_ = new NameFilter(fileFilter);408      directoryFilter_ = new NameFilter(directoryFilter);409      restoreDateTimeOnExtract_ = restoreDateTime;410411      using (zipFile_ = new ZipFile(inputStream)) {412413        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    #endregion436437    #region Internal Processing438    void ProcessDirectory(object sender, DirectoryEventArgs e)439    {440      if (!e.HasMatchingFiles && CreateEmptyDirectories) {441        if (events_ != null) {442          events_.OnProcessDirectory(e.Name, e.HasMatchingFiles);443        }444445        if (e.ContinueRunning) {446          if (e.Name != sourceDirectory_) {447            ZipEntry entry = entryFactory_.MakeDirectoryEntry(e.Name);448            outputStream_.PutNextEntry(entry);449          }450        }451      }452    }453454    void ProcessFile(object sender, ScanEventArgs e)455    {456      if ((events_ != null) && (events_.ProcessFile != null)) {457        events_.ProcessFile(sender, e);458      }459460      if (e.ContinueRunning) {461        try {462          // The open below is equivalent to OpenRead which gaurantees that if opened the463          // file will not be changed by subsequent openers, but precludes opening in some cases464          // were it could succeed. ie the open may fail as its already open for writing and the share mode should refle465          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          else if (entry.IsDirectory) {478            if (directoryFilter_.IsMatch(entry.Name) && CreateEmptyDirectories) {479              ExtractEntry(entry);480            }481          }482          else {483            // Do nothing for volume labels etc...484          }485        }486      }487    }488    #endregion489490    #region Internal Processing491    void ProcessDirectory(object sender, DirectoryEventArgs e)492    {493      if ( !e.HasMatchingFiles && CreateEmptyDirectories ) {494        if ( events_ != null ) {495          events_.OnProcessDirectory(e.Name, e.HasMatchingFiles);496        }477        }478      }479    }480481    void AddFileContents(string name, Stream stream)482    {483      if (stream == null) {484        throw new ArgumentNullException(nameof(stream));485      }486487      if (buffer_ == null) {488        buffer_ = new byte[4096];489      }490491      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      }  497498        if ( e.ContinueRunning ) {499          if (e.Name != sourceDirectory_) {500            ZipEntry entry = entryFactory_.MakeDirectoryEntry(e.Name);501            outputStream_.PutNextEntry(entry);502          }503        }504      }505    }506507    void ProcessFile(object sender, ScanEventArgs e)508    {509      if ( (events_ != null) && (events_.ProcessFile != null) ) {510        events_.ProcessFile(sender, e);511      }512513      if ( e.ContinueRunning ) {514                try {515                    // The open below is equivalent to OpenRead which gaurantees that if opened the516                    // file will not be changed by subsequent openers, but precludes opening in some cases517                    // were it could succeed. ie the open may fail as its already open for writing and the share mode sh518                    using (FileStream stream = File.Open(e.Name, FileMode.Open, FileAccess.Read, FileShare.Read)) {519                        ZipEntry entry = entryFactory_.MakeFileEntry(e.Name);520                        outputStream_.PutNextEntry(entry);521                        AddFileContents(e.Name, stream);522                    }523                }524                catch(Exception ex) {525                    if (events_ != null) {526                        continueRunning_ = events_.OnFileFailure(e.Name, ex);527                    }528                    else {529                        continueRunning_ = false;530                        throw;531                    }532                }533      }534    }535536    void AddFileContents(string name, Stream stream)537    {538      if( stream==null ) {539        throw new ArgumentNullException(nameof(stream));540      }541542      if( buffer_==null ) {543        buffer_=new byte[4096];544      }545546      if( (events_!=null)&&(events_.Progress!=null) ) {547        StreamUtils.Copy(stream, outputStream_, buffer_,548          events_.Progress, events_.ProgressInterval, this, name);549      }550      else {551        StreamUtils.Copy(stream, outputStream_, buffer_);552      }553554      if( events_!=null ) {555        continueRunning_=events_.OnCompletedFile(name);556      }557    }558559    void ExtractFileEntry(ZipEntry entry, string targetName)560    {561      bool proceed = true;562      if ( overwrite_ != Overwrite.Always ) {563        if ( File.Exists(targetName) ) {564          if ( (overwrite_ == Overwrite.Prompt) && (confirmDelegate_ != null) ) {565            proceed = confirmDelegate_(targetName);566          }567          else {568            proceed = false;569          }570        }571      }498      if (events_ != null) {499        continueRunning_ = events_.OnCompletedFile(name);500      }501    }502503    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      }515516      if (proceed) {517        if (events_ != null) {518          continueRunning_ = events_.OnProcessFile(entry.Name);519        }520521        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              }533534              if (events_ != null) {535                continueRunning_ = events_.OnCompletedFile(entry.Name);536              }537            }538539            if (restoreDateTimeOnExtract_) {540              File.SetLastWriteTime(targetName, entry.DateTime);541            }542543            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 | FileAttribut547              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    }560561    void ExtractEntry(ZipEntry entry)562    {563      bool doExtraction = entry.IsCompressionMethodSupported();564      string targetName = entry.Name;565566      if (doExtraction) {567        if (entry.IsFile) {568          targetName = extractNameTransform_.TransformFile(targetName);569        } else if (entry.IsDirectory) {570          targetName = extractNameTransform_.TransformDirectory(targetName);571        }  572573      if ( proceed ) {574        if ( events_ != null ) {575          continueRunning_ = events_.OnProcessFile(entry.Name);576        }573        doExtraction = !(string.IsNullOrEmpty(targetName));574      }575576      // TODO: Fire delegate/throw exception were compression method not supported, or name is invalid?  577578        if ( continueRunning_ ) {579          try {580            using ( FileStream outputStream = File.Create(targetName) ) {581              if ( buffer_ == null ) {582                buffer_ = new byte[4096];583              }584              if ((events_ != null) && (events_.Progress != null))585              {586                StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_,587                  events_.Progress, events_.ProgressInterval, this, entry.Name, entry.Size);588              }589              else590              {591                StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_);592              }593594              if (events_ != null) {595                continueRunning_ = events_.OnCompletedFile(entry.Name);596              }597            }598599#if !NETCF_1_0 && !NETCF_2_0600            if ( restoreDateTimeOnExtract_ ) {601              File.SetLastWriteTime(targetName, entry.DateTime);602            }603604            if ( RestoreAttributesOnExtract && entry.IsDOSEntry && (entry.ExternalFileAttributes != -1)) {605              var fileAttributes = (FileAttributes) entry.ExternalFileAttributes;606              // TODO: FastZip - Setting of other file attributes on extraction is a little trickier.607              fileAttributes &= (FileAttributes.Archive | FileAttributes.Normal | FileAttributes.ReadOnly | FileAttribut608              File.SetAttributes(targetName, fileAttributes);609            }610#endif611          }612          catch(Exception ex) {613            if ( events_ != null ) {614              continueRunning_ = events_.OnFileFailure(targetName, ex);615            }616            else {617                            continueRunning_ = false;618                            throw;619            }620          }621        }622      }623    }578      string dirName = null;579580      if (doExtraction) {581        if (entry.IsDirectory) {582          dirName = targetName;583        } else {584          dirName = Path.GetDirectoryName(Path.GetFullPath(targetName));585        }586      }587588      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      }607608      if (doExtraction && entry.IsFile) {609        ExtractFileEntry(entry, targetName);610      }611    }612613    static int MakeExternalAttributes(FileInfo info)614    {615      return (int)info.Attributes;616    }617618    static bool NameIsValid(string name)619    {620      return !string.IsNullOrEmpty(name) &&621        (name.IndexOfAny(Path.GetInvalidPathChars()) < 0);622    }623    #endregion  624625    void ExtractEntry(ZipEntry entry)626    {627      bool doExtraction = entry.IsCompressionMethodSupported();628      string targetName = entry.Name;629630      if ( doExtraction ) {631        if ( entry.IsFile ) {632          targetName = extractNameTransform_.TransformFile(targetName);633        }634        else if ( entry.IsDirectory ) {635          targetName = extractNameTransform_.TransformDirectory(targetName);636        }637638        doExtraction = !(string.IsNullOrEmpty(targetName));639      }640641      // TODO: Fire delegate/throw exception were compression method not supported, or name is invalid?642643      string dirName = null;644645      if ( doExtraction ) {646          if ( entry.IsDirectory ) {647            dirName = targetName;648          }649          else {650            dirName = Path.GetDirectoryName(Path.GetFullPath(targetName));651          }652      }653654      if ( doExtraction && !Directory.Exists(dirName) ) {655        if ( !entry.IsDirectory || CreateEmptyDirectories ) {656          try {657            Directory.CreateDirectory(dirName);658          }659          catch (Exception ex) {660            doExtraction = false;661            if ( events_ != null ) {662              if ( entry.IsDirectory ) {663                continueRunning_ = events_.OnDirectoryFailure(targetName, ex);664              }665              else {666                continueRunning_ = events_.OnFileFailure(targetName, ex);667              }668            }669            else {670              continueRunning_ = false;671                            throw;672            }673          }674        }675      }676677      if ( doExtraction && entry.IsFile ) {678        ExtractFileEntry(entry, targetName);679      }680    }681682    static int MakeExternalAttributes(FileInfo info)683    {684      return (int)info.Attributes;685    }686687#if NET_1_0 || NET_1_1 || NETCF_1_0688    static bool NameIsValid(string name)689    {690      return (name != null) &&691        (name.Length > 0) &&692        (name.IndexOfAny(Path.InvalidPathChars) < 0);693    }694#else695    static bool NameIsValid(string name)696    {697      return !string.IsNullOrEmpty(name)&&698        (name.IndexOfAny(Path.GetInvalidPathChars()) < 0);699    }700#endif701    #endregion702703    #region Instance Fields704    bool continueRunning_;705    byte[] buffer_;706    ZipOutputStream outputStream_;707    ZipFile zipFile_;708    string sourceDirectory_;709    NameFilter fileFilter_;710    NameFilter directoryFilter_;711    Overwrite overwrite_;712    ConfirmOverwriteDelegate confirmDelegate_;713714    bool restoreDateTimeOnExtract_;715    bool restoreAttributesOnExtract_;716    bool createEmptyDirectories_;717    FastZipEvents events_;718    IEntryFactory entryFactory_ = new ZipEntryFactory();719    INameTransform extractNameTransform_;720    UseZip64 useZip64_=UseZip64.Dynamic;721722#if !NETCF_1_0723    string password_;724#endif725726    #endregion727  }728}625    #region Instance Fields626    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_;635636    bool restoreDateTimeOnExtract_;637    bool restoreAttributesOnExtract_;638    bool createEmptyDirectories_;639    FastZipEvents events_;640    IEntryFactory entryFactory_ = new ZipEntryFactory();641    INameTransform extractNameTransform_;642    UseZip64 useZip64_ = UseZip64.Dynamic;643644    string password_;645646    #endregion647  }648} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_FileFailureHandler.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_FileFailureHandler.htm index d25e4c002..9585a8faf 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_FileFailureHandler.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_FileFailureHandler.htm @@ -24,6 +24,6 @@

Summary

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/Documentation/opencover/ICSharpCode.SharpZipLib_FileSystemScanner.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_FileSystemScanner.htm index 33a4211af..908420467 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_FileSystemScanner.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_FileSystemScanner.htm @@ -15,12 +15,12 @@

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:47 -Uncovered lines:38 -Coverable lines:85 -Total lines:530 -Line coverage:55.2% -Branch coverage:44.1% +Covered lines:33 +Uncovered lines:49 +Coverable lines:82 +Total lines:475 +Line coverage:40.2% +Branch coverage:32.3%

Metrics

@@ -31,13 +31,13 @@

Metrics

.ctor(...)1100100 .ctor(...)100 .ctor(...)100 -OnDirectoryFailure(...)257.1466.67 -OnFileFailure(...)257.1466.67 +OnDirectoryFailure(...)200 +OnFileFailure(...)200 OnProcessFile(...)210066.67 OnCompleteFile(...)200 OnProcessDirectory(...)25066.67 Scan(...)1100100 -ScanDir(...)1564.2948 +ScanDir(...)155040

File(s)

@@ -45,538 +45,483 @@

#LineLine coverage - 1// FileSystemScanner.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.351using System;23namespace ICSharpCode.SharpZipLib.Core4{5  #region EventArgs6  /// <summary>7  /// Event arguments for scanning.8  /// </summary>9  public class ScanEventArgs : EventArgs10  {11    #region Constructors12    /// <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    #endregion2122    /// <summary>23    /// The file or directory name for this event.24    /// </summary>25    public string Name {26      get { return name_; }27    }2829    /// <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    }  3637using System;3839namespace ICSharpCode.SharpZipLib.Core40{41  #region EventArgs42  /// <summary>43  /// Event arguments for scanning.44  /// </summary>45  public class ScanEventArgs : EventArgs46  {47    #region Constructors48    /// <summary>49    /// Initialise a new instance of <see cref="ScanEventArgs"/>50    /// </summary>51    /// <param name="name">The file or directory name.</param>52    public ScanEventArgs(string name)53    {54      name_ = name;55    }56    #endregion5758    /// <summary>59    /// The file or directory name for this event.60    /// </summary>61    public string Name62    {63      get { return name_; }64    }6566    /// <summary>67    /// Get set a value indicating if scanning should continue or not.68    /// </summary>69    public bool ContinueRunning70    {71      get { return continueRunning_; }72      set { continueRunning_ = value; }73    }7475    #region Instance Fields76    string name_;77    bool continueRunning_ = true;78    #endregion79  }8081  /// <summary>82  /// Event arguments during processing of a single file or directory.83  /// </summary>84  public class ProgressEventArgs : EventArgs85  {86    #region Constructors87    /// <summary>88    /// Initialise a new instance of <see cref="ScanEventArgs"/>89    /// </summary>90    /// <param name="name">The file or directory name if known.</param>91    /// <param name="processed">The number of bytes processed so far</param>92    /// <param name="target">The total number of bytes to process, 0 if not known</param>93    public ProgressEventArgs(string name, long processed, long target)94    {95      name_ = name;96      processed_ = processed;97      target_ = target;98    }99    #endregion37    #region Instance Fields38    string name_;39    bool continueRunning_ = true;40    #endregion41  }4243  /// <summary>44  /// Event arguments during processing of a single file or directory.45  /// </summary>46  public class ProgressEventArgs : EventArgs47  {48    #region Constructors49    /// <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    #endregion6263    /// <summary>64    /// The name for this event if known.65    /// </summary>66    public string Name {67      get { return name_; }68    }6970    /// <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    }7778    /// <summary>79    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed80    /// </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    }9394    /// <summary>95    /// The number of bytes processed so far96    /// </summary>97    public long Processed {98      get { return processed_; }99    }  100  101    /// <summary>102    /// The name for this event if known.102    /// The number of bytes to process.  103    /// </summary>104    public string Name105    {106      get { return name_; }104    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>105    public long Target {106      get { return target_; }  107    }  108109    /// <summary>110    /// Get set a value indicating wether scanning should continue or not.111    /// </summary>112    public bool ContinueRunning113    {114      get { return continueRunning_; }115      set { continueRunning_ = value; }116    }117118    /// <summary>119    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed120    /// </summary>121    /// <value>0.0 to 100.0 percent; 0 if target is not known.</value>122    public float PercentComplete123    {124      get125      {126          float result;127        if (target_ <= 0)128        {129          result = 0;130        }131        else132        {133          result = ((float)processed_ / (float)target_) * 100.0f;134        }135          return result;136      }137    }138139    /// <summary>140    /// The number of bytes processed so far141    /// </summary>142    public long Processed143    {144      get { return processed_; }145    }146147    /// <summary>148    /// The number of bytes to process.149    /// </summary>150    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>151    public long Target152    {153      get { return target_; }154    }155156    #region Instance Fields157    string name_;158    long processed_;159    long target_;160    bool continueRunning_ = true;161    #endregion162  }163164  /// <summary>165  /// Event arguments for directories.166  /// </summary>167  public class DirectoryEventArgs : ScanEventArgs168  {169    #region Constructors170    /// <summary>171    /// Initialize an instance of <see cref="DirectoryEventArgs"></see>.172    /// </summary>173    /// <param name="name">The name for this directory.</param>174    /// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</par175    public DirectoryEventArgs(string name, bool hasMatchingFiles)176      : base (name)177    {178      hasMatchingFiles_ = hasMatchingFiles;179    }180    #endregion109    #region Instance Fields110    string name_;111    long processed_;112    long target_;113    bool continueRunning_ = true;114    #endregion115  }116117  /// <summary>118  /// Event arguments for directories.119  /// </summary>120  public class DirectoryEventArgs : ScanEventArgs121  {122    #region Constructors123    /// <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.</par128    public DirectoryEventArgs(string name, bool hasMatchingFiles)129      : base(name)130    {131      hasMatchingFiles_ = hasMatchingFiles;132    }133    #endregion134135    /// <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    }141142    readonly143144    #region Instance Fields145    bool hasMatchingFiles_;146    #endregion147  }148149  /// <summary>150  /// Arguments passed when scan failures are detected.151  /// </summary>152  public class ScanFailureEventArgs : EventArgs153  {154    #region Constructors155    /// <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    #endregion167168    /// <summary>169    /// The applicable name.170    /// </summary>171    public string Name {172      get { return name_; }173    }174175    /// <summary>176    /// The applicable exception.177    /// </summary>178    public Exception Exception {179      get { return exception_; }180    }  181  182    /// <summary>183    /// Get a value indicating if the directory contains any matching files or not.183    /// Get / set a value indicating wether scanning should continue.  184    /// </summary>185    public bool HasMatchingFiles186    {187      get { return hasMatchingFiles_; }185    public bool ContinueRunning {186      get { return continueRunning_; }187      set { continueRunning_ = value; }  188    }  189190    readonly191192    #region Instance Fields193    bool hasMatchingFiles_;190    #region Instance Fields191    string name_;192    Exception exception_;193    bool continueRunning_;  194    #endregion  195  }  196197  /// <summary>198  /// Arguments passed when scan failures are detected.199  /// </summary>200  public class ScanFailureEventArgs : EventArgs201  {202    #region Constructors203    /// <summary>204    /// Initialise a new instance of <see cref="ScanFailureEventArgs"></see>205    /// </summary>206    /// <param name="name">The name to apply.</param>207    /// <param name="e">The exception to use.</param>208    public ScanFailureEventArgs(string name, Exception e)209    {210      name_ = name;211      exception_ = e;212      continueRunning_ = true;213    }214    #endregion215216    /// <summary>217    /// The applicable name.218    /// </summary>219    public string Name220    {221      get { return name_; }222    }223224    /// <summary>225    /// The applicable exception.226    /// </summary>227    public Exception Exception228    {229      get { return exception_; }230    }231232    /// <summary>233    /// Get / set a value indicating wether scanning should continue.234    /// </summary>235    public bool ContinueRunning236    {237      get { return continueRunning_; }238      set { continueRunning_ = value; }239    }240241    #region Instance Fields242    string name_;243    Exception exception_;244    bool continueRunning_;245    #endregion246  }247248  #endregion249250  #region Delegates251  /// <summary>252  /// Delegate invoked before starting to process a file.253  /// </summary>254  /// <param name="sender">The source of the event</param>255  /// <param name="e">The event arguments.</param>256  public delegate void ProcessFileHandler(object sender, ScanEventArgs e);257258  /// <summary>259  /// Delegate invoked during processing of a file or directory260  /// </summary>261  /// <param name="sender">The source of the event</param>262  /// <param name="e">The event arguments.</param>263  public delegate void ProgressHandler(object sender, ProgressEventArgs e);264265  /// <summary>266  /// Delegate invoked when a file has been completely processed.267  /// </summary>268  /// <param name="sender">The source of the event</param>269  /// <param name="e">The event arguments.</param>270  public delegate void CompletedFileHandler(object sender, ScanEventArgs e);271272  /// <summary>273  /// Delegate invoked when a directory failure is detected.274  /// </summary>275  /// <param name="sender">The source of the event</param>276  /// <param name="e">The event arguments.</param>277  public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e);278279  /// <summary>280  /// Delegate invoked when a file failure is detected.281  /// </summary>282  /// <param name="sender">The source of the event</param>283  /// <param name="e">The event arguments.</param>284  public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e);285  #endregion286287  /// <summary>288  /// FileSystemScanner provides facilities scanning of files and directories.289  /// </summary>290  public class FileSystemScanner291  {292    #region Constructors293    /// <summary>294    /// Initialise a new instance of <see cref="FileSystemScanner"></see>295    /// </summary>296    /// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param> - 0297    public FileSystemScanner(string filter)298    { - 0299      fileFilter_ = new PathFilter(filter); - 0300    }301302    /// <summary>303    /// Initialise a new instance of <see cref="FileSystemScanner"></see>304    /// </summary>305    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>306    /// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param> - 6307    public FileSystemScanner(string fileFilter, string directoryFilter)308    { - 6309      fileFilter_ = new PathFilter(fileFilter); - 6310      directoryFilter_ = new PathFilter(directoryFilter); - 6311    }312313    /// <summary>314    /// Initialise a new instance of <see cref="FileSystemScanner"></see>315    /// </summary>316    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param> - 0317    public FileSystemScanner(IScanFilter fileFilter)318    { - 0319      fileFilter_ = fileFilter; - 0320    }321322    /// <summary>323    /// Initialise a new instance of <see cref="FileSystemScanner"></see>324    /// </summary>325    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see>  to apply.</param>326    /// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see>  to apply.</param> - 0327    public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter)328    { - 0329      fileFilter_ = fileFilter; - 0330      directoryFilter_ = directoryFilter; - 0331    }332    #endregion333334    #region Delegates335    /// <summary>336    /// Delegate to invoke when a directory is processed.337    /// </summary>338    public event EventHandler<DirectoryEventArgs> ProcessDirectory;339340    /// <summary>341    /// Delegate to invoke when a file is processed.342    /// </summary>343    public ProcessFileHandler ProcessFile;344345    /// <summary>346    /// Delegate to invoke when processing for a file has finished.347    /// </summary>348    public CompletedFileHandler CompletedFile;349350    /// <summary>351    /// Delegate to invoke when a directory failure is detected.352    /// </summary>353    public DirectoryFailureHandler DirectoryFailure;354355    /// <summary>356    /// Delegate to invoke when a file failure is detected.357    /// </summary>358    public FileFailureHandler FileFailure;359    #endregion197  #endregion198199  #region Delegates200  /// <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);206207  /// <summary>208  /// Delegate invoked during processing of a file or directory209  /// </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);213214  /// <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);220221  /// <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);227228  /// <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  #endregion235236  /// <summary>237  /// FileSystemScanner provides facilities scanning of files and directories.238  /// </summary>239  public class FileSystemScanner240  {241    #region Constructors242    /// <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    }250251    /// <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    }261262    /// <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    }270271    /// <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    #endregion282283    #region Delegates284    /// <summary>285    /// Delegate to invoke when a directory is processed.286    /// </summary>287    public event EventHandler<DirectoryEventArgs> ProcessDirectory;288289    /// <summary>290    /// Delegate to invoke when a file is processed.291    /// </summary>292    public ProcessFileHandler ProcessFile;293294    /// <summary>295    /// Delegate to invoke when processing for a file has finished.296    /// </summary>297    public CompletedFileHandler CompletedFile;298299    /// <summary>300    /// Delegate to invoke when a directory failure is detected.301    /// </summary>302    public DirectoryFailureHandler DirectoryFailure;303304    /// <summary>305    /// Delegate to invoke when a file failure is detected.306    /// </summary>307    public FileFailureHandler FileFailure;308    #endregion309310    /// <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    }326327    /// <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    }345346    /// <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 DirectoryFailure event.362    /// Raise the complete file event  363    /// </summary>364    /// <param name="directory">The directory name.</param>365    /// <param name="e">The exception detected.</param>366    bool OnDirectoryFailure(string directory, Exception e)367    { - 2368            DirectoryFailureHandler handler = DirectoryFailure; - 2369            bool result = (handler != null); - 2370             if ( result ) { - 0371        var args = new ScanFailureEventArgs(directory, e); - 0372        handler(this, args); - 0373        alive_ = args.ContinueRunning;374      } - 2375            return result;376    }377378    /// <summary>379    /// Raise the FileFailure event.380    /// </summary>381    /// <param name="file">The file name.</param>382    /// <param name="e">The exception detected.</param>383    bool OnFileFailure(string file, Exception e)384    { - 1385            FileFailureHandler handler = FileFailure;386 - 1387            bool result = (handler != null);388 - 1389       if ( result ){ - 0390        var args = new ScanFailureEventArgs(file, e); - 0391        FileFailure(this, args); - 0392        alive_ = args.ContinueRunning;393      } - 1394            return result;395    }396397    /// <summary>398    /// Raise the ProcessFile event.399    /// </summary>400    /// <param name="file">The file name.</param>401    void OnProcessFile(string file)402    { - 5403      ProcessFileHandler handler = ProcessFile;404 - 5405       if ( handler!= null ) { - 5406        var args = new ScanEventArgs(file); - 5407        handler(this, args); - 4408        alive_ = args.ContinueRunning;409      } - 4410    }411412    /// <summary>413    /// Raise the complete file event414    /// </summary>415    /// <param name="file">The file name</param>416    void OnCompleteFile(string file)417    { - 0418      CompletedFileHandler handler = CompletedFile;419 - 0420       if (handler != null)421      { - 0422        var args = new ScanEventArgs(file); - 0423        handler(this, args); - 0424        alive_ = args.ContinueRunning;425      } - 0426    }427428    /// <summary>429    /// Raise the ProcessDirectory event.430    /// </summary>431    /// <param name="directory">The directory name.</param>432    /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param>433    void OnProcessDirectory(string directory, bool hasMatchingFiles)434    { - 5435      EventHandler<DirectoryEventArgs> handler = ProcessDirectory;436 - 5437       if ( handler != null ) { - 0438        var args = new DirectoryEventArgs(directory, hasMatchingFiles); - 0439        handler(this, args); - 0440        alive_ = args.ContinueRunning;441      } - 5442    }443444    /// <summary>445    /// Scan a directory.446    /// </summary>447    /// <param name="directory">The base directory to scan.</param>448    /// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param>449    public void Scan(string directory, bool recurse)450    { - 6451      alive_ = true; - 6452      ScanDir(directory, recurse); - 4453    }454455    void ScanDir(string directory, bool recurse)456    {457458      try { - 6459        string[] names = System.IO.Directory.GetFiles(directory); - 5460        bool hasMatch = false; - 28178461         for (int fileIndex = 0; fileIndex < names.Length; ++fileIndex) { - 14084462           if ( !fileFilter_.IsMatch(names[fileIndex]) ) { - 14079463            names[fileIndex] = null; - 14079464          } else { - 5465            hasMatch = true;466          }467        }468 - 5469        OnProcessDirectory(directory, hasMatch);470 - 5471         if ( alive_ && hasMatch ) { - 22673472          foreach (string fileName in names) {473            try { - 11332474               if ( fileName != null ) { - 5475                OnProcessFile(fileName); - 4476                 if ( !alive_ ) { - 0477                  break;478                }479              } - 11331480            } - 1481            catch (Exception e) { - 1482                             if (!OnFileFailure(fileName, e)) { - 1483                                throw;484                            } - 0485            }486          }487        } - 4488      } - 2489      catch (Exception e) { - 2490                 if (!OnDirectoryFailure(directory, e)) { - 2491                    throw;492                } - 0493      }494 - 4495       if ( alive_ && recurse ) {496        try { - 0497          string[] names = System.IO.Directory.GetDirectories(directory); - 0498          foreach (string fulldir in names) { - 0499             if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir))) { - 0500              ScanDir(fulldir, true); - 0501               if ( !alive_ ) {502                break;503              }504            }505          } - 0506        } - 0507        catch (Exception e) { - 0508                     if (!OnDirectoryFailure(directory, e)) { - 0509                        throw;510                    } - 0511        }512      } - 4513    }514515    #region Instance Fields516    /// <summary>517    /// The file filter currently in use.518    /// </summary>519    IScanFilter fileFilter_;520    /// <summary>521    /// The directory filter currently in use.522    /// </summary>523    IScanFilter directoryFilter_;524    /// <summary>525    /// Flag indicating if scanning should continue running.526    /// </summary>527    bool alive_;528    #endregion529  }530}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    }375376    /// <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    }391392    /// <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    }402403    void ScanDir(string directory, bool recurse)404    {405406      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    }459460    #region Instance Fields461    /// <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    #endregion474  }475} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_GZip.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_GZip.htm new file mode 100644 index 000000000..b0a579d5f --- /dev/null +++ b/Documentation/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/Documentation/opencover/ICSharpCode.SharpZipLib_GZipConstants.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_GZipConstants.htm index cb15e974a..08e7a5e30 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_GZipConstants.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_GZipConstants.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:2 Coverable lines:2 -Total lines:97 +Total lines:58 Line coverage:0% @@ -34,105 +34,66 @@

#LineLine coverage - 1// GZipConstants.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839namespace ICSharpCode.SharpZipLib.GZip40{4142  /// <summary>43  /// This class contains constants used for gzip.44  /// </summary>45  sealed public class GZipConstants46  {47    /// <summary>48    /// Magic number found at start of GZIP header49    /// </summary>50    public const int GZIP_MAGIC = 0x1F8B;5152    /*  The flag byte is divided into individual bits as follows:5354      bit 0   FTEXT55      bit 1   FHCRC56      bit 2   FEXTRA57      bit 3   FNAME58      bit 4   FCOMMENT59      bit 5   reserved60      bit 6   reserved61      bit 7   reserved62     */6364    /// <summary>65    /// Flag bit mask for text66    /// </summary>67    public const int FTEXT    = 0x1;6869    /// <summary>70    /// Flag bitmask for Crc71    /// </summary>72    public const int FHCRC    = 0x2;7374    /// <summary>75    /// Flag bit mask for extra76    /// </summary>77    public const int FEXTRA   = 0x4;7879    /// <summary>80    /// flag bitmask for name81    /// </summary>82    public const int FNAME    = 0x8;8384    /// <summary>85    /// flag bit mask indicating comment is present86    /// </summary>87    public const int FCOMMENT = 0x10;8889    /// <summary>90    /// Initialise default instance.91    /// </summary>92    /// <remarks>Constructor is private to prevent instances being created.</remarks> - 093    GZipConstants()94    { - 095    }96  }97}1namespace ICSharpCode.SharpZipLib.GZip2{3  /// <summary>4  /// This class contains constants used for gzip.5  /// </summary>6  sealed public class GZipConstants7  {8    /// <summary>9    /// Magic number found at start of GZIP header10    /// </summary>11    public const int GZIP_MAGIC = 0x1F8B;1213    /*  The flag byte is divided into individual bits as follows:1415      bit 0   FTEXT16      bit 1   FHCRC17      bit 2   FEXTRA18      bit 3   FNAME19      bit 4   FCOMMENT20      bit 5   reserved21      bit 6   reserved22      bit 7   reserved23     */2425    /// <summary>26    /// Flag bit mask for text27    /// </summary>28    public const int FTEXT = 0x1;2930    /// <summary>31    /// Flag bitmask for Crc32    /// </summary>33    public const int FHCRC = 0x2;3435    /// <summary>36    /// Flag bit mask for extra37    /// </summary>38    public const int FEXTRA = 0x4;3940    /// <summary>41    /// flag bitmask for name42    /// </summary>43    public const int FNAME = 0x8;4445    /// <summary>46    /// flag bit mask indicating comment is present47    /// </summary>48    public const int FCOMMENT = 0x10;4950    /// <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/Documentation/opencover/ICSharpCode.SharpZipLib_GZipException.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_GZipException.htm index 1d384066f..6599d235c 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_GZipException.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_GZipException.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:8 Coverable lines:8 -Total lines:91 +Total lines:48 Line coverage:0% @@ -37,99 +37,56 @@

#LineLine coverage - 1// GZipException.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;1using System;2using System.Runtime.Serialization;34namespace ICSharpCode.SharpZipLib.GZip5{6  /// <summary>7  /// GZipException represents exceptions specific to GZip classes and code.8  /// </summary>9  [Serializable]10  public class GZipException : SharpZipBaseException11  {12    /// <summary>13    /// Deserialization constructor14    /// </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    }2122    /// <summary>23    /// Initialise a new instance of <see cref="GZipException" />.24    /// </summary> + 025    public GZipException()26    { + 027    }2829    /// <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    }  3738#if !NETCF_1_0 && !NETCF_2_039using System.Runtime.Serialization;40#endif4142namespace ICSharpCode.SharpZipLib.GZip43{44  /// <summary>45  /// GZipException represents a Gzip specific exception46  /// </summary>47#if !NETCF_1_0 && !NETCF_2_048  [Serializable]49#endif50  public class GZipException : SharpZipBaseException51  {52#if !NETCF_1_0 && !NETCF_2_053    /// <summary>54    /// Deserialization constructor55    /// </summary>56    /// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>57    /// <param name="context"><see cref="StreamingContext"/> for this constructor</param>58    protected GZipException(SerializationInfo info, StreamingContext context) - 059      : base(info, context)6061    { - 062    }63#endif6465    /// <summary>66    /// Initialise a new instance of GZipException67    /// </summary> - 068    public GZipException()69    { - 070    }7172    /// <summary>73    /// Initialise a new instance of GZipException with its message string.74    /// </summary>75    /// <param name="message">A <see cref="string"/> that describes the error.</param>76    public GZipException(string message) - 077      : base(message)78    { - 079    }8081    /// <summary>82    /// Initialise a new instance of <see cref="GZipException"></see>.83    /// </summary>84    /// <param name="message">A <see cref="string"/> that describes the error.</param>85    /// <param name="innerException">The <see cref="Exception"/> that caused this exception.</param>86    public GZipException(string message, Exception innerException) - 087      : base (message, innerException)88    { - 089    }90  }91}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/Documentation/opencover/ICSharpCode.SharpZipLib_GZipInputStream.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_GZipInputStream.htm index 76738cb91..c3440d273 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_GZipInputStream.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_GZipInputStream.htm @@ -15,12 +15,12 @@

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:65 -Uncovered lines:43 +Covered lines:4 +Uncovered lines:104 Coverable lines:108 -Total lines:374 -Line coverage:60.1% -Branch coverage:45.8% +Total lines:330 +Line coverage:3.7% +Branch coverage:0%

Metrics

@@ -29,9 +29,9 @@

Metrics

.ctor(...)1100100 .ctor(...)1100100 -Read(...)5100100 -ReadHeader()2844.7434.55 -ReadFooter()583.3366.67 +Read(...)500 +ReadHeader()2800 +ReadFooter()500

File(s)

@@ -39,382 +39,338 @@

#LineLine coverage - 1// GzipInputStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  2009-08-11  T9121  Geoff Hart Added Multi-member gzip support41//  2012-06-03  Z-1802  Incorrect endianness and subfield in FEXTRA handling.4243using System;44using System.IO;4546using ICSharpCode.SharpZipLib.Checksums;47using ICSharpCode.SharpZipLib.Zip.Compression;48using ICSharpCode.SharpZipLib.Zip.Compression.Streams;4950namespace ICSharpCode.SharpZipLib.GZip51{5253  /// <summary>54  /// This filter stream is used to decompress a "GZIP" format stream.55  /// The "GZIP" format is described baseInputStream RFC 1952.56  ///57  /// author of the original java version : John Leuner58  /// </summary>59  /// <example> This sample shows how to unzip a gzipped file60  /// <code>61  /// using System;62  /// using System.IO;63  ///64  /// using ICSharpCode.SharpZipLib.Core;65  /// using ICSharpCode.SharpZipLib.GZip;66  ///67  /// class MainClass68  /// {69  ///   public static void Main(string[] args)70  ///   {71  ///      using (Stream inStream = new GZipInputStream(File.OpenRead(args[0])))72  ///      using (FileStream outStream = File.Create(Path.GetFileNameWithoutExtension(args[0]))) {73  ///        byte[] buffer = new byte[4096];74  ///        StreamUtils.Copy(inStream, outStream, buffer);75  ///     }76  ///   }77  /// }78  /// </code>79  /// </example>80  public class GZipInputStream : InflaterInputStream81  {82    #region Instance Fields83    /// <summary>84    /// CRC-32 value for uncompressed data85    /// </summary>86        protected Crc32 crc;8788        /// <summary>89        /// Flag to indicate if we've read the GZIP header yet for the current member (block of compressed data).90        /// This is tracked per-block as the file is parsed.91        /// </summary>92    bool readGZIPHeader;93    #endregion9495    #region Constructors96    /// <summary>97    /// Creates a GZipInputStream with the default buffer size98    /// </summary>99    /// <param name="baseInputStream">100    /// The stream to read compressed data from (baseInputStream GZIP format)101    /// </param>102    public GZipInputStream(Stream baseInputStream) - 4103      : this(baseInputStream, 4096)104    { - 4105    }106107    /// <summary>108    /// Creates a GZIPInputStream with the specified buffer size109    /// </summary>110    /// <param name="baseInputStream">111    /// The stream to read compressed data from (baseInputStream GZIP format)112    /// </param>113    /// <param name="size">114    /// Size of the buffer to use115    /// </param>116    public GZipInputStream(Stream baseInputStream, int size) - 4117      : base(baseInputStream, new Inflater(true), size)118    { - 4119    }120    #endregion121122    #region Stream overrides123    /// <summary>124    /// Reads uncompressed data into an array of bytes125    /// </summary>126    /// <param name="buffer">127    /// The buffer to read uncompressed data into128    /// </param>129    /// <param name="offset">130    /// The offset indicating where the data should be placed131    /// </param>132    /// <param name="count">133    /// The number of uncompressed bytes to be read134    /// </param>135    /// <returns>Returns the number of bytes actually read.</returns>136    public override int Read(byte[] buffer, int offset, int count)137    {138      // A GZIP file can contain multiple blocks of compressed data, although this is quite rare.139      // A compressed block could potentially be empty, so we need to loop until we reach EOF or140      // we find data.141      while (true) {142143        // If we haven't read the header for this block, read it - 4144         if (! readGZIPHeader) {145146          // Try to read header. If there is no header (0 bytes available), this is EOF. If there is147          // an incomplete header, this will throw an exception. - 3148           if (! ReadHeader()) { - 2149            return 0;150          }151        }152153        // Try to read compressed data - 2154        int bytesRead = base.Read(buffer, offset, count); - 2155         if (bytesRead > 0) { - 1156          crc.Update(buffer, offset, bytesRead);157        }158159        // If this is the end of stream, read the footer - 2160         if (inf.IsFinished) { - 1161          ReadFooter();162        }1using System;2using System.IO;3using ICSharpCode.SharpZipLib.Checksum;4using ICSharpCode.SharpZipLib.Zip.Compression;5using ICSharpCode.SharpZipLib.Zip.Compression.Streams;67namespace ICSharpCode.SharpZipLib.GZip8{910  /// <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 Leuner15  /// </summary>16  /// <example> This sample shows how to unzip a gzipped file17  /// <code>18  /// using System;19  /// using System.IO;20  ///21  /// using ICSharpCode.SharpZipLib.Core;22  /// using ICSharpCode.SharpZipLib.GZip;23  ///24  /// class MainClass25  /// {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 : InflaterInputStream38  {39    #region Instance Fields40    /// <summary>41    /// CRC-32 value for uncompressed data42    /// </summary>43    protected Crc32 crc;4445    /// <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    #endregion5152    #region Constructors53    /// <summary>54    /// Creates a GZipInputStream with the default buffer size55    /// </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    }6364    /// <summary>65    /// Creates a GZIPInputStream with the specified buffer size66    /// </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 use72    /// </param>73    public GZipInputStream(Stream baseInputStream, int size) + 274      : base(baseInputStream, new Inflater(true), size)75    { + 276    }77    #endregion7879    #region Stream overrides80    /// <summary>81    /// Reads uncompressed data into an array of bytes82    /// </summary>83    /// <param name="buffer">84    /// The buffer to read uncompressed data into85    /// </param>86    /// <param name="offset">87    /// The offset indicating where the data should be placed88    /// </param>89    /// <param name="count">90    /// The number of uncompressed bytes to be read91    /// </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 or97      // we find data.98      while (true) {99100        // If we haven't read the header for this block, read it + 0101         if (!readGZIPHeader) {102103          // Try to read header. If there is no header (0 bytes available), this is EOF. If there is104          // an incomplete header, this will throw an exception. + 0105           if (!ReadHeader()) { + 0106            return 0;107          }108        }109110        // Try to read compressed data + 0111        int bytesRead = base.Read(buffer, offset, count); + 0112         if (bytesRead > 0) { + 0113          crc.Update(buffer, offset, bytesRead);114        }115116        // 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    #endregion127128    #region Support routines129    bool ReadHeader()130    {131      // Initialize CRC for this block + 0132      crc = new Crc32();133134      // 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      }143144      // 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      }156157      //magic = baseInputStream.ReadByte(); + 0158      magic = inputBuffer.ReadLeByte();159 + 0160       if (magic < 0) { + 0161        throw new EndOfStreamException("EOS reading GZIP header");162      }  163 - 2164         if (bytesRead > 0) { - 1165          return bytesRead;166        }167      }168    }169    #endregion170171    #region Support routines172    bool ReadHeader()173    {174      // Initialize CRC for this block - 3175      crc = new Crc32(); + 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);169170      // 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      }  176177      // Make sure there is data in file. We can't rely on ReadLeByte() to fill the buffer, as this could be EOF,178      // which is fine, but ReadLeByte() throws an exception if it doesn't find data, so we do this part ourselves. - 3179       if (inputBuffer.Available <= 0) { - 3180        inputBuffer.Fill(); - 3181         if (inputBuffer.Available <= 0) {182          // No header, EOF. - 2183          return false;184        }185      }186187      // 1. Check the two magic bytes - 1188      var headCRC = new Crc32(); - 1189      int magic = inputBuffer.ReadLeByte(); + 0177       if (compressionType != 8) { + 0178        throw new GZipException("Error GZIP header, data not in deflate format");179      } + 0180      headCRC.Update(compressionType);181182      // 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);188189      /*    This flag byte is divided into individual bits as follows:  190 - 1191       if (magic < 0) { - 0192        throw new EndOfStreamException("EOS reading GZIP header");193      }194 - 1195      headCRC.Update(magic); - 1196       if (magic != (GZipConstants.GZIP_MAGIC >> 8)) { - 0197        throw new GZipException("Error GZIP header, first magic byte doesn't match");198      }199200      //magic = baseInputStream.ReadByte(); - 1201      magic = inputBuffer.ReadLeByte();191      bit 0   FTEXT192      bit 1   FHCRC193      bit 2   FEXTRA194      bit 3   FNAME195      bit 4   FCOMMENT196      bit 5   reserved197      bit 6   reserved198      bit 7   reserved199      */200201      // 3.1 Check the reserved bits are zero  202 - 1203       if (magic < 0) { - 0204        throw new EndOfStreamException("EOS reading GZIP header"); + 0203       if ((flags & 0xE0) != 0) { + 0204        throw new GZipException("Reserved flag bits in GZIP header != 0");  205      }  206 - 1207       if (magic != (GZipConstants.GZIP_MAGIC & 0xFF)) { - 0208        throw new GZipException("Error GZIP header,  second magic byte doesn't match");209      }210 - 1211      headCRC.Update(magic);212213      // 2. Check the compression type (must be 8) - 1214      int compressionType = inputBuffer.ReadLeByte();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 - 1216       if ( compressionType < 0 ) { - 0217        throw new EndOfStreamException("EOS reading GZIP header");218      }219 - 1220       if ( compressionType != 8 ) { - 0221        throw new GZipException("Error GZIP header, data not in deflate format");222      } - 1223      headCRC.Update(compressionType);224225      // 3. Check the flags - 1226      int flags = inputBuffer.ReadLeByte(); - 1227       if (flags < 0) { - 0228        throw new EndOfStreamException("EOS reading GZIP header");229      } - 1230      headCRC.Update(flags);231232      /*    This flag byte is divided into individual bits as follows:233234      bit 0   FTEXT235      bit 1   FHCRC236      bit 2   FEXTRA237      bit 3   FNAME238      bit 4   FCOMMENT239      bit 5   reserved240      bit 6   reserved241      bit 7   reserved242      */243244      // 3.1 Check the reserved bits are zero216      // 7. Read extra field + 0217       if ((flags & GZipConstants.FEXTRA) != 0) {218219        // XLEN is total length of extra subfields, we will skip them all220        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      }238239      // 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 - 1246       if ((flags & 0xE0) != 0) { - 0247        throw new GZipException("Reserved flag bits in GZIP header != 0");248      }249250      // 4.-6. Skip the modification time, extra flags, and OS type - 14251       for (int i=0; i< 6; i++) { - 6252        int readByte = inputBuffer.ReadLeByte(); - 6253         if (readByte < 0) { - 0254          throw new EndOfStreamException("EOS reading GZIP header");255        } - 6256        headCRC.Update(readByte);257      } + 0246         if (readByte < 0) { + 0247          throw new EndOfStreamException("EOS reading GZIP header");248        } + 0249        headCRC.Update(readByte);250      }251252      // 9. Read comment + 0253       if ((flags & GZipConstants.FCOMMENT) != 0) {254        int readByte; + 0255         while ((readByte = inputBuffer.ReadLeByte()) > 0) { + 0256          headCRC.Update(readByte);257        }  258259      // 7. Read extra field - 1260       if ((flags & GZipConstants.FEXTRA) != 0) {261262        // XLEN is total length of extra subfields, we will skip them all263        int len1, len2; - 0264        len1 = inputBuffer.ReadLeByte(); - 0265        len2 = inputBuffer.ReadLeByte(); - 0266         if ((len1 < 0) || (len2 < 0)) { - 0267          throw new EndOfStreamException("EOS reading GZIP header");268        } - 0269        headCRC.Update(len1); - 0270        headCRC.Update(len2);271 - 0272        int extraLen = (len2 << 8) | len1;    // gzip is LSB first - 0273         for (int i = 0; i < extraLen;i++) { - 0274          int readByte = inputBuffer.ReadLeByte(); - 0275           if (readByte < 0)276          { - 0277            throw new EndOfStreamException("EOS reading GZIP header");278          } - 0279          headCRC.Update(readByte);280        }281      }282283      // 8. Read file name - 1284       if ((flags & GZipConstants.FNAME) != 0) {285        int readByte; - 0286         while ( (readByte = inputBuffer.ReadLeByte()) > 0) { - 0287          headCRC.Update(readByte);288        }289 - 0290         if (readByte < 0) { - 0291          throw new EndOfStreamException("EOS reading GZIP header");292        } - 0293        headCRC.Update(readByte);294      }295296      // 9. Read comment - 1297       if ((flags & GZipConstants.FCOMMENT) != 0) {298        int readByte; - 0299         while ( (readByte = inputBuffer.ReadLeByte()) > 0) { - 0300          headCRC.Update(readByte);301        }302 - 0303         if (readByte < 0) { - 0304          throw new EndOfStreamException("EOS reading GZIP header");305        }306 - 0307        headCRC.Update(readByte);308      }309310      // 10. Read header CRC - 1311       if ((flags & GZipConstants.FHCRC) != 0) {312        int tempByte; - 0313        int crcval = inputBuffer.ReadLeByte(); - 0314         if (crcval < 0) { - 0315          throw new EndOfStreamException("EOS reading GZIP header");316        }317 - 0318        tempByte = inputBuffer.ReadLeByte(); - 0319         if (tempByte < 0) { - 0320          throw new EndOfStreamException("EOS reading GZIP header");321        }322 - 0323        crcval = (crcval << 8) | tempByte; - 0324         if (crcval != ((int) headCRC.Value & 0xffff)) { - 0325          throw new GZipException("Header CRC value mismatch");326        }327      }328 - 1329      readGZIPHeader = true; - 1330      return true;331    }332333    void ReadFooter()334    { - 1335      byte[] footer = new byte[8];336337      // End of stream; reclaim all bytes from inf, read the final byte count, and reset the inflator - 1338      long bytesRead = inf.TotalOut & 0xffffffff; - 1339      inputBuffer.Available += inf.RemainingInput; - 1340      inf.Reset();341342      // Read footer from inputBuffer - 1343      int needed = 8; - 2344       while (needed > 0) { - 1345        int count = inputBuffer.ReadClearTextBuffer(footer, 8 - needed, needed); - 1346         if (count <= 0) { - 0347          throw new EndOfStreamException("EOS reading GZIP footer");348        } - 1349        needed -= count; // Jewel Jan 16350      }351352      // Calculate CRC - 1353      int crcval = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8) | ((footer[2] & 0xff) << 16) | (footer[3] << 24); - 1354       if (crcval != (int) crc.Value) { - 0355        throw new GZipException("GZIP crc sum mismatch, theirs \"" + crcval + "\" and ours \"" + (int) crc.Value);356      }357358      // NOTE The total here is the original total modulo 2 ^ 32. - 1359      uint total = - 1360        (uint)((uint)footer[4] & 0xff) | - 1361        (uint)(((uint)footer[5] & 0xff) << 8) | - 1362        (uint)(((uint)footer[6] & 0xff) << 16) | - 1363        (uint)((uint)footer[7] << 24);364 - 1365       if (bytesRead != total) { - 0366        throw new GZipException("Number of bytes mismatch in footer");367      }368369      // Mark header read as false so if another header exists, we'll continue reading through the file - 1370      readGZIPHeader = false; - 1371    }372    #endregion373  }374} + 0259         if (readByte < 0) { + 0260          throw new EndOfStreamException("EOS reading GZIP header");261        }262 + 0263        headCRC.Update(readByte);264      }265266      // 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    }288289    void ReadFooter()290    { + 0291      byte[] footer = new byte[8];292293      // 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();297298      // 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 16306      }307308      // 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      }313314      // 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      }324325      // Mark header read as false so if another header exists, we'll continue reading through the file + 0326      readGZIPHeader = false; + 0327    }328    #endregion329  }330} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_GZipOutputStream.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_GZipOutputStream.htm index bb0bbabf5..4a2396cf9 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_GZipOutputStream.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_GZipOutputStream.htm @@ -15,11 +15,11 @@

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:61 +Covered lines:63 Uncovered lines:5 -Coverable lines:66 -Total lines:261 -Line coverage:92.4% +Coverable lines:68 +Total lines:227 +Line coverage:92.6% Branch coverage:81.2% @@ -29,6 +29,7 @@

Metrics

.ctor(...)1100100 .ctor(...)1100100 +Finalize()1100100 SetLevel(...)200 GetLevel()100 Write(...)3100100 @@ -42,269 +43,235 @@

#LineLine coverage - 1// GZipOutputStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839using System;40using System.IO;4142using ICSharpCode.SharpZipLib.Checksums;43using ICSharpCode.SharpZipLib.Zip.Compression;44using ICSharpCode.SharpZipLib.Zip.Compression.Streams;4546namespace ICSharpCode.SharpZipLib.GZip47{4849  /// <summary>50  /// This filter stream is used to compress a stream into a "GZIP" stream.51  /// The "GZIP" format is described in RFC 1952.52  ///53  /// author of the original java version : John Leuner54  /// </summary>55  /// <example> This sample shows how to gzip a file56  /// <code>57  /// using System;58  /// using System.IO;59  ///60  /// using ICSharpCode.SharpZipLib.GZip;61  /// using ICSharpCode.SharpZipLib.Core;62  ///63  /// class MainClass64  /// {65  ///   public static void Main(string[] args)66  ///   {67  ///       using (Stream s = new GZipOutputStream(File.Create(args[0] + ".gz")))68  ///       using (FileStream fs = File.OpenRead(args[0])) {69  ///         byte[] writeData = new byte[4096];70  ///         Streamutils.Copy(s, fs, writeData);71  ///       }72  ///     }73  ///   }74  /// }75  /// </code>76  /// </example>77  public class GZipOutputStream : DeflaterOutputStream78  {79        enum OutputState80        {81            Header,82            Footer,83            Finished,84            Closed,85        };8687    #region Instance Fields88    /// <summary>89    /// CRC-32 value for uncompressed data90    /// </summary> - 1091    protected Crc32 crc = new Crc32();92        OutputState state_ = OutputState.Header;93    #endregion9495    #region Constructors96    /// <summary>97    /// Creates a GzipOutputStream with the default buffer size98    /// </summary>99    /// <param name="baseOutputStream">100    /// The stream to read data (to be compressed) from101    /// </param>102    public GZipOutputStream(Stream baseOutputStream) - 10103      : this(baseOutputStream, 4096)104    { - 10105    }106107    /// <summary>108    /// Creates a GZipOutputStream with the specified buffer size109    /// </summary>110    /// <param name="baseOutputStream">111    /// The stream to read data (to be compressed) from112    /// </param>113    /// <param name="size">114    /// Size of the buffer to use115    /// </param> - 10116    public GZipOutputStream(Stream baseOutputStream, int size) : base(baseOutputStream, new Deflater(Deflater.DEFAULT_CO117    { - 10118    }119    #endregion120121    #region Public API122    /// <summary>123    /// Sets the active compression level (1-9).  The new level will be activated124    /// immediately.125    /// </summary>126    /// <param name="level">The compression level to set.</param>127    /// <exception cref="ArgumentOutOfRangeException">128    /// Level specified is not supported.129    /// </exception>130    /// <see cref="Deflater"/>131    public void SetLevel(int level)132    { - 0133       if (level < Deflater.BEST_SPEED) { - 0134        throw new ArgumentOutOfRangeException(nameof(level));1using System;2using System.IO;3using ICSharpCode.SharpZipLib.Checksum;4using ICSharpCode.SharpZipLib.Zip.Compression;5using ICSharpCode.SharpZipLib.Zip.Compression.Streams;67namespace ICSharpCode.SharpZipLib.GZip8{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 Leuner14  /// </summary>15  /// <example> This sample shows how to gzip a file16  /// <code>17  /// using System;18  /// using System.IO;19  ///20  /// using ICSharpCode.SharpZipLib.GZip;21  /// using ICSharpCode.SharpZipLib.Core;22  ///23  /// class MainClass24  /// {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 : DeflaterOutputStream38  {39    enum OutputState40    {41      Header,42      Footer,43      Finished,44      Closed,45    };4647    #region Instance Fields48    /// <summary>49    /// CRC-32 value for uncompressed data50    /// </summary> + 951    protected Crc32 crc = new Crc32();52    OutputState state_ = OutputState.Header;53    #endregion5455    #region Constructors56    /// <summary>57    /// Creates a GzipOutputStream with the default buffer size58    /// </summary>59    /// <param name="baseOutputStream">60    /// The stream to read data (to be compressed) from61    /// </param>62    public GZipOutputStream(Stream baseOutputStream) + 963      : this(baseOutputStream, 4096)64    { + 965    }6667    /// <summary>68    /// Creates a GZipOutputStream with the specified buffer size69    /// </summary>70    /// <param name="baseOutputStream">71    /// The stream to read data (to be compressed) from72    /// </param>73    /// <param name="size">74    /// Size of the buffer to use75    /// </param> + 976    public GZipOutputStream(Stream baseOutputStream, int size) : base(baseOutputStream, new Deflater(Deflater.DEFAULT_CO77    { + 978    }79    #endregion8081    #region Destructor82    /// <summary>83    /// Ensures that resources are freed and other cleanup operations84    /// are performed when the garbage collector reclaims the GZipOutputStream.85    /// </summary>86    ~GZipOutputStream()87    { + 988      Dispose(false); + 1889    }90    #endregion9192    #region Public API93    /// <summary>94    /// Sets the active compression level (1-9).  The new level will be activated95    /// 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    }109110    /// <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    #endregion119120    #region Stream overrides121    /// <summary>122    /// Write given buffer to output updating crc123    /// </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      } - 0136      deflater_.SetLevel(level); - 0137    }138139    /// <summary>140    /// Get the current compression level.141    /// </summary>142    /// <returns>The current compression level.</returns>143    public int GetLevel()144    { - 0145      return deflater_.GetLevel();146    }147    #endregion148149    #region Stream overrides150    /// <summary>151    /// Write given buffer to output updating crc152    /// </summary>153    /// <param name="buffer">Buffer to write</param>154    /// <param name="offset">Offset of first byte in buf to write</param>155    /// <param name="count">Number of bytes to write</param>156    public override void Write(byte[] buffer, int offset, int count)157    { - 4158       if ( state_ == OutputState.Header ) { - 2159        WriteHeader();160      }161 - 4162             if( state_!=OutputState.Footer )163            { - 2164                throw new InvalidOperationException("Write not permitted in current state");165            }166 - 2167      crc.Update(buffer, offset, count); - 2168      base.Write(buffer, offset, count); - 2169    }136 + 1137      crc.Update(buffer, offset, count); + 1138      base.Write(buffer, offset, count); + 1139    }140141    /// <summary>142    /// Writes remaining compressed output data to the output stream143    /// 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    #endregion159160    #region DeflaterOutputStream overrides161    /// <summary>162    /// Finish compression and write any footer information required to stream163    /// </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      }  170171    /// <summary>172    /// Writes remaining compressed output data to the output stream173    /// and closes it.174    /// </summary>175    public override void Close()176    {177      try { - 10178        Finish(); - 10179      }180      finally { - 10181                 if ( state_ != OutputState.Closed ) { - 8182                    state_ = OutputState.Closed; - 8183             if( IsStreamOwner ) { - 7184              baseOutputStream_.Close();185            }186                } - 10187      } - 10188    }189    #endregion190191    #region DeflaterOutputStream overrides192    /// <summary>193    /// Finish compression and write any footer information required to stream194    /// </summary>195    public override void Finish()196    {197      // If no data has been written a header should be added. - 14198       if ( state_ == OutputState.Header ) { - 8199        WriteHeader();200      }201 - 14202             if( state_ == OutputState.Footer)203            { - 10204                state_=OutputState.Finished; - 10205                base.Finish();206 - 10207                var totalin=(uint)(deflater_.TotalIn&0xffffffff); - 10208                var crcval=(uint)(crc.Value&0xffffffff);209210                byte[] gzipFooter;211212                unchecked213                { - 10214                    gzipFooter=new byte[] { - 10215          (byte) crcval, (byte) (crcval >> 8), - 10216          (byte) (crcval >> 16), (byte) (crcval >> 24), - 10217 - 10218          (byte) totalin, (byte) (totalin >> 8), - 10219          (byte) (totalin >> 16), (byte) (totalin >> 24) - 10220        };221                }222 - 10223                baseOutputStream_.Write(gzipFooter, 0, gzipFooter.Length);224            } - 14225    }226    #endregion227228    #region Support Routines229    void WriteHeader()230    { - 10231       if ( state_ == OutputState.Header )232      { - 10233                state_=OutputState.Footer;234 - 10235        var mod_time = (int)((DateTime.Now.Ticks - new DateTime(1970, 1, 1).Ticks) / 10000000L);  // Ticks give back 100 - 10236        byte[] gzipHeader = { - 10237          // The two magic bytes - 10238          (byte) (GZipConstants.GZIP_MAGIC >> 8), (byte) (GZipConstants.GZIP_MAGIC & 0xff), - 10239 - 10240          // The compression type - 10241          (byte) Deflater.DEFLATED, - 10242 - 10243          // The flags (not set) - 10244          0, - 10245 - 10246          // The modification time - 10247          (byte) mod_time, (byte) (mod_time >> 8), - 10248          (byte) (mod_time >> 16), (byte) (mod_time >> 24), - 10249 - 10250          // The extra flags - 10251          0, - 10252 - 10253          // The OS type (unknown) - 10254          (byte) 255 - 10255        }; - 10256        baseOutputStream_.Write(gzipHeader, 0, gzipHeader.Length);257      } - 10258    }259    #endregion260  }261} + 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);177178        byte[] gzipFooter;179180        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    #endregion194195    #region Support Routines196    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    #endregion226  }227} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_Inflater.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_Inflater.htm index 3408e0e1c..204a3f1e7 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_Inflater.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_Inflater.htm @@ -16,10 +16,10 @@

Summary

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:59 -Coverable lines:232 -Total lines:860 -Line coverage:74.5% +Uncovered lines:57 +Coverable lines:230 +Total lines:788 +Line coverage:75.2% Branch coverage:59.8% @@ -49,868 +49,796 @@

#LineLine coverage - 1// Inflater.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839using System;4041using ICSharpCode.SharpZipLib.Checksums;42using ICSharpCode.SharpZipLib.Zip.Compression.Streams;4344namespace ICSharpCode.SharpZipLib.Zip.Compression45{46  /// <summary>47  /// Inflater is used to decompress data that has been compressed according48  /// to the "deflate" standard described in rfc1951.49  ///50  /// By default Zlib (rfc1950) headers and footers are expected in the input.51  /// You can use constructor <code> public Inflater(bool noHeader)</code> passing true52  /// if there is no Zlib header information53  ///54  /// The usage is as following.  First you have to set some input with55  /// <code>SetInput()</code>, then Inflate() it.  If inflate doesn't56  /// inflate any bytes there may be three reasons:57  /// <ul>58  /// <li>IsNeedingInput() returns true because the input buffer is empty.59  /// You have to provide more input with <code>SetInput()</code>.60  /// NOTE: IsNeedingInput() also returns true when, the stream is finished.61  /// </li>62  /// <li>IsNeedingDictionary() returns true, you have to provide a preset63  ///    dictionary with <code>SetDictionary()</code>.</li>64  /// <li>IsFinished returns true, the inflater has finished.</li>65  /// </ul>66  /// Once the first output byte is produced, a dictionary will not be67  /// needed at a later stage.68  ///69  /// author of the original java version : John Leuner, Jochen Hoenicke70  /// </summary>71  public class Inflater72  {73    #region Constants/Readonly74    /// <summary>75    /// Copy lengths for literal codes 257..28576    /// </summary> - 177    static readonly int[] CPLENS = { - 178                  3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 179                  35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 - 180                };8182    /// <summary>83    /// Extra bits for literal codes 257..28584    /// </summary> - 185    static readonly int[] CPLEXT = { - 186                  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 187                  3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 - 188                };8990    /// <summary>91    /// Copy offsets for distance codes 0..2992    /// </summary> - 193    static readonly int[] CPDIST = { - 194                1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 195                257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 196                8193, 12289, 16385, 24577 - 197                };9899    /// <summary>100    /// Extra bits for distance codes101    /// </summary> - 1102    static readonly int[] CPDEXT = { - 1103                0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 1104                7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 1105                12, 12, 13, 13 - 1106                };107108    /// <summary>109    /// These are the possible states for an inflater110    /// </summary>111    const int DECODE_HEADER           = 0;112    const int DECODE_DICT             = 1;113    const int DECODE_BLOCKS           = 2;114    const int DECODE_STORED_LEN1      = 3;115    const int DECODE_STORED_LEN2      = 4;116    const int DECODE_STORED           = 5;117    const int DECODE_DYN_HEADER       = 6;118    const int DECODE_HUFFMAN          = 7;119    const int DECODE_HUFFMAN_LENBITS  = 8;120    const int DECODE_HUFFMAN_DIST     = 9;121    const int DECODE_HUFFMAN_DISTBITS = 10;122    const int DECODE_CHKSUM           = 11;123    const int FINISHED                = 12;124    #endregion125126    #region Instance Fields127    /// <summary>128    /// This variable contains the current state.129    /// </summary>130    int mode;131132    /// <summary>133    /// The adler checksum of the dictionary or of the decompressed134    /// stream, as it is written in the header resp. footer of the135    /// compressed stream.136    /// Only valid if mode is DECODE_DICT or DECODE_CHKSUM.137    /// </summary>138    int readAdler;139140    /// <summary>141    /// The number of bits needed to complete the current state.  This142    /// is valid, if mode is DECODE_DICT, DECODE_CHKSUM,143    /// DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.144    /// </summary>145    int neededBits;146    int repLength;147    int repDist;148    int uncomprLen;149150    /// <summary>151    /// True, if the last block flag was set in the last block of the152    /// inflated stream.  This means that the stream ends after the153    /// current block.1using System;2using ICSharpCode.SharpZipLib.Checksum;3using ICSharpCode.SharpZipLib.Zip.Compression.Streams;45namespace ICSharpCode.SharpZipLib.Zip.Compression6{7  /// <summary>8  /// Inflater is used to decompress data that has been compressed according9  /// 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 true13  /// if there is no Zlib header information14  ///15  /// The usage is as following.  First you have to set some input with16  /// <code>SetInput()</code>, then Inflate() it.  If inflate doesn't17  /// 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 preset24  ///    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 be28  /// needed at a later stage.29  ///30  /// author of the original java version : John Leuner, Jochen Hoenicke31  /// </summary>32  public class Inflater33  {34    #region Constants/Readonly35    /// <summary>36    /// Copy lengths for literal codes 257..28537    /// </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                };4243    /// <summary>44    /// Extra bits for literal codes 257..28545    /// </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                };5051    /// <summary>52    /// Copy offsets for distance codes 0..2953    /// </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                };5960    /// <summary>61    /// Extra bits for distance codes62    /// </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                };6869    /// <summary>70    /// These are the possible states for an inflater71    /// </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    #endregion8687    #region Instance Fields88    /// <summary>89    /// This variable contains the current state.90    /// </summary>91    int mode;9293    /// <summary>94    /// The adler checksum of the dictionary or of the decompressed95    /// stream, as it is written in the header resp. footer of the96    /// compressed stream.97    /// Only valid if mode is DECODE_DICT or DECODE_CHKSUM.98    /// </summary>99    int readAdler;100101    /// <summary>102    /// The number of bits needed to complete the current state.  This103    /// 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;110111    /// <summary>112    /// True, if the last block flag was set in the last block of the113    /// inflated stream.  This means that the stream ends after the114    /// current block.115    /// </summary>116    bool isLastBlock;117118    /// <summary>119    /// The total number of inflated bytes.120    /// </summary>121    long totalOut;122123    /// <summary>124    /// The total number of bytes set with setInput().  This is not the125    /// value returned by the TotalIn property, since this also includes the126    /// unprocessed input.127    /// </summary>128    long totalIn;129130    /// <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 or133    /// footer.134    /// </summary>135    bool noHeader;136    readonly StreamManipulator input;137    OutputWindow outputWindow;138    InflaterDynHeader dynHeader;139    InflaterHuffmanTree litlenTree, distTree;140    Adler32 adler;141    #endregion142143    #region Constructors144    /// <summary>145    /// Creates a new inflater or RFC1951 decompressor146    /// RFC1950/Zlib headers and footers will be expected in the input data147    /// </summary> + 3148    public Inflater() : this(false)149    { + 3150    }151152    /// <summary>153    /// Creates a new inflater.  154    /// </summary>155    bool isLastBlock;156157    /// <summary>158    /// The total number of inflated bytes.159    /// </summary>160    long totalOut;161162    /// <summary>163    /// The total number of bytes set with setInput().  This is not the164    /// value returned by the TotalIn property, since this also includes the165    /// unprocessed input.166    /// </summary>167    long totalIn;168169    /// <summary>170    /// This variable stores the noHeader flag that was given to the constructor.171    /// True means, that the inflated stream doesn't contain a Zlib header or172    /// footer.173    /// </summary>174    bool noHeader;175    readonly StreamManipulator input;176    OutputWindow outputWindow;177    InflaterDynHeader dynHeader;178    InflaterHuffmanTree litlenTree, distTree;179    Adler32 adler;180    #endregion181182    #region Constructors183    /// <summary>184    /// Creates a new inflater or RFC1951 decompressor185    /// RFC1950/Zlib headers and footers will be expected in the input data186    /// </summary> - 3187    public Inflater() : this(false)188    { - 3189    }190191    /// <summary>192    /// Creates a new inflater.193    /// </summary>194    /// <param name="noHeader">195    /// True if no RFC1950/Zlib header and footer fields are expected in the input data196    ///197    /// This is used for GZIPed/Zipped input.198    ///199    /// For compatibility with200    /// Sun JDK you should provide one byte of input more than needed in201    /// this case.202    /// </param> - 441203    public Inflater(bool noHeader)204    { - 441205      this.noHeader = noHeader; - 441206      this.adler = new Adler32(); - 441207      input = new StreamManipulator(); - 441208      outputWindow = new OutputWindow(); - 441209       mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER; - 441210    }211    #endregion212213    /// <summary>214    /// Resets the inflater so that a new stream can be decompressed.  All215    /// pending input and output will be discarded.216    /// </summary>217    public void Reset()218    { - 44219       mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER; - 44220      totalIn = 0; - 44221      totalOut = 0; - 44222      input.Reset(); - 44223      outputWindow.Reset(); - 44224      dynHeader = null; - 44225      litlenTree = null; - 44226      distTree = null; - 44227      isLastBlock = false; - 44228      adler.Reset(); - 44229    }230231    /// <summary>232    /// Decodes a zlib/RFC1950 header.233    /// </summary>234    /// <returns>235    /// False if more input is needed.236    /// </returns>237    /// <exception cref="SharpZipBaseException">238    /// The header is invalid.239    /// </exception>240    private bool DecodeHeader()241    { - 22242      int header = input.PeekBits(16); - 22243       if (header < 0) { - 11244        return false;245      } - 11246      input.DropBits(16);247248      // The header is written in "wrong" byte order - 11249      header = ((header << 8) | (header >> 8)) & 0xffff; - 11250       if (header % 31 != 0) { - 0251        throw new SharpZipBaseException("Header checksum illegal");252      }253 - 11254       if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) { - 0255        throw new SharpZipBaseException("Compression Method unknown");256      }257258      /* Maximum size of the backwards window in bits.259      * We currently ignore this, but we could use it to make the260      * inflater window more space efficient. On the other hand the261      * full window (15 bits) is needed most times, anyway.262      int max_wbits = ((header & 0x7000) >> 12) + 8;263      */264 - 11265       if ((header & 0x0020) == 0) { // Dictionary flag? - 11266        mode = DECODE_BLOCKS; - 11267      } else { - 0268        mode = DECODE_DICT; - 0269        neededBits = 32;270      } - 11271      return true;272    }273274    /// <summary>275    /// Decodes the dictionary checksum after the deflate header.276    /// </summary>277    /// <returns>278    /// False if more input is needed.279    /// </returns>280    private bool DecodeDict()281    { - 0282       while (neededBits > 0) { - 0283        int dictByte = input.PeekBits(8); - 0284         if (dictByte < 0) { - 0285          return false;286        } - 0287        input.DropBits(8); - 0288        readAdler = (readAdler << 8) | dictByte; - 0289        neededBits -= 8;290      } - 0291      return false;292    }293294    /// <summary>295    /// Decodes the huffman encoded symbols in the input stream.296    /// </summary>297    /// <returns>298    /// false if more input is needed, true if output window is299    /// full or the current block ends.300    /// </returns>301    /// <exception cref="SharpZipBaseException">302    /// if deflated stream is invalid.303    /// </exception>304    private bool DecodeHuffman()305    { - 373306      int free = outputWindow.GetFreeSpace(); - 474307       while (free >= 258)308      {309        int symbol; - 474310         switch (mode)311        {312          case DECODE_HUFFMAN:313            // This is the inner loop so it is optimized a bit - 9713314             while (((symbol = litlenTree.GetSymbol(input)) & ~0xff) == 0)315            { - 9239316              outputWindow.Write(symbol); - 9239317               if (--free < 258)318              { - 0319                return true;320              }321            }322 - 474323             if (symbol < 257)324            { - 373325               if (symbol < 0)326              { - 0327                return false;328              }329              else330              {331                // symbol == 256: end of block - 373332                distTree = null; - 373333                litlenTree = null; - 373334                mode = DECODE_BLOCKS; - 373335                return true;336              }155    /// <param name="noHeader">156    /// True if no RFC1950/Zlib header and footer fields are expected in the input data157    ///158    /// This is used for GZIPed/Zipped input.159    ///160    /// For compatibility with161    /// Sun JDK you should provide one byte of input more than needed in162    /// 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    #endregion173174    /// <summary>175    /// Resets the inflater so that a new stream can be decompressed.  All176    /// 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    }191192    /// <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);208209      // 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      }218219      /* Maximum size of the backwards window in bits.220      * We currently ignore this, but we could use it to make the221      * inflater window more space efficient. On the other hand the222      * 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    }234235    /// <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    }254255    /// <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 is260    /// 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            }291292            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 through299300          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 through312313          case DECODE_HUFFMAN_DIST: + 97314            symbol = distTree.GetSymbol(input); + 97315             if (symbol < 0) { + 0316              return false;317            }318319            try { + 97320              repDist = CPDIST[symbol]; + 97321              neededBits = CPDEXT[symbol]; + 97322            } catch (Exception) { + 0323              throw new SharpZipBaseException("Illegal rep dist code");324            }325326            goto case DECODE_HUFFMAN_DISTBITS; // fall through327328          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            }  338339            try340            { - 101341              repLength = CPLENS[symbol - 257]; - 101342              neededBits = CPLEXT[symbol - 257]; - 101343            } - 0344            catch (Exception)345            { - 0346              throw new SharpZipBaseException("Illegal rep length code");347            }348            goto case DECODE_HUFFMAN_LENBITS; // fall through349350          case DECODE_HUFFMAN_LENBITS: - 101351             if (neededBits > 0)352            { - 25353              mode = DECODE_HUFFMAN_LENBITS; - 25354              int i = input.PeekBits(neededBits); - 25355               if (i < 0)356              { - 0357                return false;358              } - 25359              input.DropBits(neededBits); - 25360              repLength += i;361            } - 101362            mode = DECODE_HUFFMAN_DIST;363            goto case DECODE_HUFFMAN_DIST; // fall through364365          case DECODE_HUFFMAN_DIST: - 101366            symbol = distTree.GetSymbol(input); - 101367             if (symbol < 0)368            { - 0369              return false;370            } + 97339            outputWindow.Repeat(repLength, repDist); + 97340            free -= repLength; + 97341            mode = DECODE_HUFFMAN; + 97342            break;343344          default: + 0345            throw new SharpZipBaseException("Inflater unknown mode");346        }347      } + 0348      return true;349    }350351    /// <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      }  371372            try373            { - 101374              repDist = CPDIST[symbol]; - 101375              neededBits = CPDEXT[symbol]; - 101376            } - 0377            catch (Exception)378            { - 0379              throw new SharpZipBaseException("Illegal rep dist code");380            }381382            goto case DECODE_HUFFMAN_DISTBITS; // fall through383384          case DECODE_HUFFMAN_DISTBITS: - 101385             if (neededBits > 0)386            { - 70387              mode = DECODE_HUFFMAN_DISTBITS; - 70388              int i = input.PeekBits(neededBits); - 70389               if (i < 0)390              { - 0391                return false;392              } - 70393              input.DropBits(neededBits); - 70394              repDist += i;395            }396 - 101397            outputWindow.Repeat(repLength, repDist); - 101398            free -= repLength; - 101399            mode = DECODE_HUFFMAN; - 101400            break;401402          default: - 0403            throw new SharpZipBaseException("Inflater unknown mode");404        }405      } - 0406      return true;407    }408409    /// <summary>410    /// Decodes the adler checksum after the deflate stream.411    /// </summary>412    /// <returns>413    /// false if more input is needed.414    /// </returns>415    /// <exception cref="SharpZipBaseException">416    /// If checksum doesn't match.417    /// </exception>418    private bool DecodeChksum()419    { - 5420       while (neededBits > 0) { - 4421        int chkByte = input.PeekBits(8); - 4422         if (chkByte < 0) { - 0423          return false;424        } - 4425        input.DropBits(8); - 4426        readAdler = (readAdler << 8) | chkByte; - 4427        neededBits -= 8;428      }429 - 1430       if ((int) adler.Value != readAdler) { - 0431        throw new SharpZipBaseException("Adler chksum doesn't match: " + (int)adler.Value + " vs. " + readAdler);432      }433 - 1434      mode = FINISHED; - 1435      return false;436    }437438    /// <summary>439    /// Decodes the deflated stream.440    /// </summary>441    /// <returns>442    /// false if more input is needed, or if finished.443    /// </returns>444    /// <exception cref="SharpZipBaseException">445    /// if deflated stream is invalid.446    /// </exception>447    private bool Decode()448    { - 4491449       switch (mode) {450        case DECODE_HEADER: - 22451          return DecodeHeader();452453        case DECODE_DICT: - 0454          return DecodeDict();455456        case DECODE_CHKSUM: - 1457          return DecodeChksum();458459        case DECODE_BLOCKS: - 1424460           if (isLastBlock) { - 389461             if (noHeader) { - 378462              mode = FINISHED; - 378463              return false;464            } else { - 11465              input.SkipToByteBoundary(); - 11466              neededBits = 32; - 11467              mode = DECODE_CHKSUM; - 11468              return true;469            } + 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    }379380    /// <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();394395        case DECODE_DICT: + 0396          return DecodeDict();397398        case DECODE_CHKSUM: + 1399          return DecodeChksum();400401        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;439440        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 through448449        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 through461462        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 - 1035472          int type = input.PeekBits(3); - 1035473           if (type < 0) { - 363474            return false;472        case DECODE_DYN_HEADER: + 1473           if (!dynHeader.Decode(input)) { + 0474            return false;  475          } - 672476          input.DropBits(3);477 - 672478          isLastBlock |= (type & 1) != 0; - 672479           switch (type >> 1){480            case DeflaterConstants.STORED_BLOCK: - 299481              input.SkipToByteBoundary(); - 299482              mode = DECODE_STORED_LEN1; - 299483              break;484            case DeflaterConstants.STATIC_TREES: - 372485              litlenTree = InflaterHuffmanTree.defLitLenTree; - 372486              distTree = InflaterHuffmanTree.defDistTree; - 372487              mode = DECODE_HUFFMAN; - 372488              break;489            case DeflaterConstants.DYN_TREES: - 1490              dynHeader = new InflaterDynHeader(); - 1491              mode = DECODE_DYN_HEADER; - 1492              break;493            default: - 0494              throw new SharpZipBaseException("Unknown block type " + type);495          } - 672496          return true;497498        case DECODE_STORED_LEN1:499        { - 299500           if ((uncomprLen = input.PeekBits(16)) < 0) { - 0501            return false;502          } - 299503          input.DropBits(16); - 299504          mode = DECODE_STORED_LEN2;505        }506          goto case DECODE_STORED_LEN2; // fall through507508        case DECODE_STORED_LEN2:509        { - 299510          int nlen = input.PeekBits(16); - 299511           if (nlen < 0) { - 0512            return false;513          } - 299514          input.DropBits(16); - 299515           if (nlen != (uncomprLen ^ 0xffff)) { - 0516            throw new SharpZipBaseException("broken uncompressed block");517          } - 299518          mode = DECODE_STORED;519        }520          goto case DECODE_STORED; // fall through521522        case DECODE_STORED:523        { - 2335524          int more = outputWindow.CopyStored(input, uncomprLen); - 2335525          uncomprLen -= more; - 2335526           if (uncomprLen == 0) { - 299527            mode = DECODE_BLOCKS; - 299528            return true;529          } - 2036530          return !input.IsNeedingInput;531        }532533        case DECODE_DYN_HEADER: - 1534           if (!dynHeader.Decode(input)) { - 0535            return false;536          }537 - 1538          litlenTree = dynHeader.BuildLitLenTree(); - 1539          distTree = dynHeader.BuildDistTree(); - 1540          mode = DECODE_HUFFMAN;541          goto case DECODE_HUFFMAN; // fall through542543        case DECODE_HUFFMAN:544        case DECODE_HUFFMAN_LENBITS:545        case DECODE_HUFFMAN_DIST:546        case DECODE_HUFFMAN_DISTBITS: - 373547          return DecodeHuffman();476 + 1477          litlenTree = dynHeader.BuildLitLenTree(); + 1478          distTree = dynHeader.BuildDistTree(); + 1479          mode = DECODE_HUFFMAN;480          goto case DECODE_HUFFMAN; // fall through481482        case DECODE_HUFFMAN:483        case DECODE_HUFFMAN_LENBITS:484        case DECODE_HUFFMAN_DIST:485        case DECODE_HUFFMAN_DISTBITS: + 371486          return DecodeHuffman();487488        case FINISHED: + 336489          return false;490491        default: + 0492          throw new SharpZipBaseException("Inflater.Decode unknown mode");493      }494    }495496    /// <summary>497    /// Sets the preset dictionary.  This should only be called, if498    /// needsDictionary() returns true and it should set the same499    /// 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    }509510    /// <summary>511    /// Sets the preset dictionary.  This should only be called, if512    /// needsDictionary() returns true and it should set the same513    /// 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 invalid530    /// </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      }  548549        case FINISHED: - 336550          return false;551552        default: - 0553          throw new SharpZipBaseException("Inflater.Decode unknown mode");554      }555    }556557    /// <summary>558    /// Sets the preset dictionary.  This should only be called, if559    /// needsDictionary() returns true and it should set the same560    /// dictionary, that was used for deflating.  The getAdler()561    /// function returns the checksum of the dictionary needed. + 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    }558559    /// <summary>560    /// Sets the input.  This should only be called, if needsInput()561    /// returns true.  562    /// </summary>  563    /// <param name="buffer">564    /// The dictionary.564    /// the input.  565    /// </param>566    public void SetDictionary(byte[] buffer)566    public void SetInput(byte[] buffer)  567    { - 0568      SetDictionary(buffer, 0, buffer.Length); + 0568      SetInput(buffer, 0, buffer.Length);  0569    }  570  571    /// <summary>572    /// Sets the preset dictionary.  This should only be called, if573    /// needsDictionary() returns true and it should set the same574    /// dictionary, that was used for deflating.  The getAdler()575    /// function returns the checksum of the dictionary needed.576    /// </summary>577    /// <param name="buffer">578    /// The dictionary.579    /// </param>580    /// <param name="index">581    /// The index into buffer where the dictionary starts.582    /// </param>583    /// <param name="count">584    /// The number of bytes in the dictionary.585    /// </param>586    /// <exception cref="System.InvalidOperationException">587    /// No dictionary is needed.588    /// </exception>589    /// <exception cref="SharpZipBaseException">590    /// The adler checksum for the buffer is invalid591    /// </exception>592    public void SetDictionary(byte[] buffer, int index, int count)593    { - 0594       if ( buffer == null ) { - 0595        throw new ArgumentNullException(nameof(buffer));596      }597 - 0598       if ( index < 0 ) { - 0599        throw new ArgumentOutOfRangeException(nameof(index));600      }601 - 0602       if ( count < 0 ) { - 0603        throw new ArgumentOutOfRangeException(nameof(count));604      }605 - 0606       if (!IsNeedingDictionary) { - 0607        throw new InvalidOperationException("Dictionary is not needed");608      }609 - 0610      adler.Update(buffer, index, count);611 - 0612       if ((int)adler.Value != readAdler) { - 0613        throw new SharpZipBaseException("Wrong adler checksum");614      } - 0615      adler.Reset(); - 0616      outputWindow.CopyDict(buffer, index, count); - 0617      mode = DECODE_BLOCKS; - 0618    }619620    /// <summary>621    /// Sets the input.  This should only be called, if needsInput()622    /// returns true.623    /// </summary>624    /// <param name="buffer">625    /// the input.626    /// </param>627    public void SetInput(byte[] buffer)628    { - 0629      SetInput(buffer, 0, buffer.Length); - 0630    }631632    /// <summary>633    /// Sets the input.  This should only be called, if needsInput()634    /// returns true.635    /// </summary>636    /// <param name="buffer">637    /// The source of input data572    /// Sets the input.  This should only be called, if needsInput()573    /// returns true.574    /// </summary>575    /// <param name="buffer">576    /// The source of input data577    /// </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    }595596    /// <summary>597    /// Inflates the compressed stream to the output buffer.  If this598    /// returns 0, you should check, whether IsNeedingDictionary(),599    /// IsNeedingInput() or IsFinished() returns true, to determine why no600    /// 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 further607    /// 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    }623624    /// <summary>625    /// Inflates the compressed stream to the output buffer.  If this626    /// returns 0, you should check, whether needsDictionary(),627    /// needsInput() or finished() returns true, to determine why no628    /// 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    /// <param name="index">640    /// The index into buffer where the input starts.641    /// </param>642    /// <param name="count">643    /// The number of bytes of input to use.644    /// </param>645    /// <exception cref="System.InvalidOperationException">646    /// No input is needed.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.ArgumentOutOfRangeException">649    /// The index and/or count are wrong.648    /// <exception cref="System.FormatException">649    /// if deflated stream is invalid.  650    /// </exception>651    public void SetInput(byte[] buffer, int index, int count)651    public int Inflate(byte[] buffer, int offset, int count)  652    { - 1460653      input.SetInput(buffer, index, count); - 1460654      totalIn += (long)count; - 1460655    } + 2212653       if (buffer == null) { + 0654        throw new ArgumentNullException(nameof(buffer));655      }  656657    /// <summary>658    /// Inflates the compressed stream to the output buffer.  If this659    /// returns 0, you should check, whether IsNeedingDictionary(),660    /// IsNeedingInput() or IsFinished() returns true, to determine why no661    /// further output is produced.662    /// </summary>663    /// <param name="buffer">664    /// the output buffer.665    /// </param>666    /// <returns>667    /// The number of bytes written to the buffer, 0 if no further668    /// output can be produced.669    /// </returns>670    /// <exception cref="System.ArgumentOutOfRangeException">671    /// if buffer has length 0.672    /// </exception>673    /// <exception cref="System.FormatException">674    /// if deflated stream is invalid.675    /// </exception>676    public int Inflate(byte[] buffer)677    { - 0678       if ( buffer == null )679      { - 0680        throw new ArgumentNullException(nameof(buffer));681      }682 - 0683      return Inflate(buffer, 0, buffer.Length);684    }685686    /// <summary>687    /// Inflates the compressed stream to the output buffer.  If this688    /// returns 0, you should check, whether needsDictionary(),689    /// needsInput() or finished() returns true, to determine why no690    /// further output is produced.691    /// </summary>692    /// <param name="buffer">693    /// the output buffer.694    /// </param>695    /// <param name="offset">696    /// the offset in buffer where storing starts.697    /// </param>698    /// <param name="count">699    /// the maximum number of bytes to output.700    /// </param>701    /// <returns>702    /// the number of bytes written to the buffer, 0 if no further output can be produced.703    /// </returns>704    /// <exception cref="System.ArgumentOutOfRangeException">705    /// if count is less than 0.706    /// </exception>707    /// <exception cref="System.ArgumentOutOfRangeException">708    /// if the index and / or count are wrong.709    /// </exception>710    /// <exception cref="System.FormatException">711    /// if deflated stream is invalid.712    /// </exception>713    public int Inflate(byte[] buffer, int offset, int count)714    { - 2247715       if ( buffer == null )716      { - 0717        throw new ArgumentNullException(nameof(buffer));718      }719 - 2247720       if ( count < 0 ) {721#if NETCF_1_0722        throw new ArgumentOutOfRangeException("count");723#else - 0724        throw new ArgumentOutOfRangeException(nameof(count), "count cannot be negative");725#endif726      }727 - 2247728       if ( offset < 0 ) {729#if NETCF_1_0730        throw new ArgumentOutOfRangeException("offset");731#else - 0732        throw new ArgumentOutOfRangeException(nameof(offset), "offset cannot be negative");733#endif734      }735 - 2247736       if ( offset + count > buffer.Length ) { - 0737        throw new ArgumentException("count exceeds buffer bounds");738      }739740      // Special case: count may be zero - 2247741       if (count == 0)742      { - 21743         if (!IsFinished) { // -jr- 08-Nov-2003 INFLATE_BUG fix.. - 21744          Decode();745        } - 21746        return 0;747      } + 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      }668669      // 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;678679      do { + 4524680         if (mode != DECODE_CHKSUM) {681          /* Don't give away any output, if we are waiting for the682          * 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    }703704    /// <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    }714715    /// <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    }723724    /// <summary>725    /// Returns true, if the inflater has finished.  This means, that no726    /// 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    }733734    /// <summary>735    /// Gets the adler checksum.  This is either the checksum of all736    /// uncompressed bytes returned by inflate(), or if needsDictionary()737    /// returns true (and thus no output was yet produced) this is the738    /// 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 - 2226749      int bytesCopied = 0;750751      do { - 4600752         if (mode != DECODE_CHKSUM) {753          /* Don't give away any output, if we are waiting for the754          * checksum in the input stream.755          *756          * With this trick we have always:757          *   IsNeedingInput() and not IsFinished()758          *   implies more output can be produced.759          */ - 4599760          int more = outputWindow.CopyOutput(buffer, offset, count); - 4599761           if ( more > 0 ) { - 1717762            adler.Update(buffer, offset, more); - 1717763            offset += more; - 1717764            bytesCopied += more; - 1717765            totalOut += (long)more; - 1717766            count -= more; - 1717767             if (count == 0) { - 130768              return bytesCopied;769            }770          }771        } - 4470772       } while (Decode() || ((outputWindow.GetAvailable() > 0) && (mode != DECODE_CHKSUM))); - 2096773      return bytesCopied;774    }775776    /// <summary>777    /// Returns true, if the input buffer is empty.778    /// You should then call setInput().779    /// NOTE: This method also returns true when the stream is finished.780    /// </summary>781    public bool IsNeedingInput {782      get { - 1392783        return input.IsNeedingInput;784      }785    }786787    /// <summary>788    /// Returns true, if a preset dictionary is needed to inflate the input.789    /// </summary>790    public bool IsNeedingDictionary {791      get { - 855792        return mode == DECODE_DICT && neededBits == 0;793      }794    }795796    /// <summary>797    /// Returns true, if the inflater has finished.  This means, that no798    /// input is needed and no output can be produced.799    /// </summary>800    public bool IsFinished {801      get { - 2136802        return mode == FINISHED && outputWindow.GetAvailable() == 0;803      }804    }805806    /// <summary>807    /// Gets the adler checksum.  This is either the checksum of all808    /// uncompressed bytes returned by inflate(), or if needsDictionary()809    /// returns true (and thus no output was yet produced) this is the810    /// adler checksum of the expected dictionary.811    /// </summary>812    /// <returns>813    /// the adler checksum.814    /// </returns>815    public int Adler {816      get { - 0817        return IsNeedingDictionary ? readAdler : (int) adler.Value;818      }819    }820821    /// <summary>822    /// Gets the total number of output bytes returned by Inflate().823    /// </summary>824    /// <returns>825    /// the total number of output bytes.826    /// </returns>827    public long TotalOut {828      get { - 14829        return totalOut;830      }831    }832833    /// <summary>834    /// Gets the total number of processed compressed input bytes.835    /// </summary>836    /// <returns>837    /// The total number of bytes of processed input bytes.838    /// </returns>839    public long TotalIn {840      get { - 22841        return totalIn - (long)RemainingInput;842      }843    }844845    /// <summary>846    /// Gets the number of unprocessed input bytes.  Useful, if the end of the847    /// stream is reached and you want to further process the bytes after848    /// the deflate stream.849    /// </summary>850    /// <returns>851    /// The number of bytes of the input which have not been processed.852    /// </returns>853    public int RemainingInput {854      // TODO: This should be a long?855      get { - 49856        return input.AvailableBytes;857      }858    }859  }860}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    }760761    /// <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    }772773    /// <summary>774    /// Gets the number of unprocessed input bytes.  Useful, if the end of the775    /// stream is reached and you want to further process the bytes after776    /// 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/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterDynHeader.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterDynHeader.htm index 6fd8d0774..5255f42ae 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterDynHeader.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterDynHeader.htm @@ -18,7 +18,7 @@

Summary

Covered lines:63 Uncovered lines:10 Coverable lines:73 -Total lines:211 +Total lines:170 Line coverage:86.3% Branch coverage:54.2% @@ -38,219 +38,178 @@

#LineLine coverage - 1// InflaterDynHeader.cs2// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team3//4// This file was translated from java, it was part of the GNU Classpath5// Copyright (C) 2001 Free Software Foundation, Inc.6//7// This program is free software; you can redistribute it and/or8// modify it under the terms of the GNU General Public License9// as published by the Free Software Foundation; either version 210// of the License, or (at your option) any later version.11//12// This program is distributed in the hope that it will be useful,13// but WITHOUT ANY WARRANTY; without even the implied warranty of14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the15// GNU General Public License for more details.16//17// You should have received a copy of the GNU General Public License18// along with this program; if not, write to the Free Software19// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.20//21// Linking this library statically or dynamically with other modules is22// making a combined work based on this library.  Thus, the terms and23// conditions of the GNU General Public License cover the whole24// combination.25//26// As a special exception, the copyright holders of this library give you27// permission to link this library with independent modules to produce an28// executable, regardless of the license terms of these independent29// modules, and to copy and distribute the resulting executable under30// terms of your choice, provided that you also meet, for each linked31// independent module, the terms and conditions of the license of that32// module.  An independent module is a module which is not derived from33// or based on this library.  If you modify this library, you may extend34// this exception to your version of the library, but you are not35// obligated to do so.  If you do not wish to do so, delete this36// exception statement from your version.3738using System;3940using ICSharpCode.SharpZipLib.Zip.Compression.Streams;4142namespace ICSharpCode.SharpZipLib.Zip.Compression43{4445  class InflaterDynHeader46  {47    #region Constants48    const int LNUM   = 0;49    const int DNUM   = 1;50    const int BLNUM  = 2;51    const int BLLENS = 3;52    const int LENS   = 4;53    const int REPS   = 5;54 - 155    static readonly int[] repMin  = { 3, 3, 11 }; - 156    static readonly int[] repBits = { 2, 3,  7 };57 - 158    static readonly int[] BL_ORDER = - 159    { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };60    #endregion6162    public bool Decode(StreamManipulator input)63    {64      decode_loop:65        for (;;) { - 1066           switch (mode) {67            case LNUM: - 168              lnum = input.PeekBits(5); - 169               if (lnum < 0) { - 070                return false;71              } - 172              lnum += 257; - 173              input.DropBits(5);74              //        System.err.println("LNUM: "+lnum); - 175              mode = DNUM;76              goto case DNUM; // fall through77            case DNUM: - 178              dnum = input.PeekBits(5); - 179               if (dnum < 0) { - 080                return false;81              } - 182              dnum++; - 183              input.DropBits(5);84              //        System.err.println("DNUM: "+dnum); - 185              num = lnum+dnum; - 186              litdistLens = new byte[num]; - 187              mode = BLNUM;88              goto case BLNUM; // fall through89            case BLNUM: - 190              blnum = input.PeekBits(4); - 191               if (blnum < 0) { - 092                return false;93              } - 194              blnum += 4; - 195              input.DropBits(4); - 196              blLens = new byte[19]; - 197              ptr = 0;98              //        System.err.println("BLNUM: "+blnum); - 199              mode = BLLENS; - 1100              goto case BLLENS; // fall through101            case BLLENS: - 19102               while (ptr < blnum) { - 18103                int len = input.PeekBits(3); - 18104                 if (len < 0) { - 0105                  return false;106                } - 18107                input.DropBits(3);108                //      System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len); - 18109                blLens[BL_ORDER[ptr]] = (byte) len; - 18110                ptr++;111              } - 1112              blTree = new InflaterHuffmanTree(blLens); - 1113              blLens = null; - 1114              ptr = 0; - 1115              mode = LENS; - 1116              goto case LENS; // fall through117            case LENS:118            {119              int symbol; - 45120               while (((symbol = blTree.GetSymbol(input)) & ~15) == 0) {121                /* Normal case: symbol in [0..15] */122123                //        System.err.println("litdistLens["+ptr+"]: "+symbol); - 36124                litdistLens[ptr++] = lastLen = (byte)symbol;125 - 36126                 if (ptr == num) {127                  /* Finished */ - 1128                  return true;129                }130              }131132              /* need more input ? */ - 9133               if (symbol < 0) { - 0134                return false;135              }136137              /* otherwise repeat code */ - 9138               if (symbol >= 17) {139                /* repeat zero */140                //        System.err.println("repeating zero"); - 9141                lastLen = 0; - 9142              } else { - 0143                 if (ptr == 0) { - 0144                  throw new SharpZipBaseException();145                }146              } - 9147              repSymbol = symbol-16;148            } - 9149              mode = REPS;150              goto case REPS; // fall through151            case REPS:152            { - 9153              int bits = repBits[repSymbol]; - 9154              int count = input.PeekBits(bits); - 9155               if (count < 0) { - 0156                return false;157              } - 9158              input.DropBits(bits); - 9159              count += repMin[repSymbol];160              //          System.err.println("litdistLens repeated: "+count);161 - 9162               if (ptr + count > num) { - 0163                throw new SharpZipBaseException();164              } - 239165               while (count-- > 0) { - 230166                litdistLens[ptr++] = lastLen;167              }1using System;2using ICSharpCode.SharpZipLib.Zip.Compression.Streams;34namespace ICSharpCode.SharpZipLib.Zip.Compression5{6  class InflaterDynHeader7  {8    #region Constants9    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    #endregion2223    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 through38          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 through50          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 through62          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 through78          case LENS: {79              int symbol; + 4580               while (((symbol = blTree.GetSymbol(input)) & ~15) == 0) {81                /* Normal case: symbol in [0..15] */8283                //        System.err.println("litdistLens["+ptr+"]: "+symbol); + 3684                litdistLens[ptr++] = lastLen = (byte)symbol;85 + 3686                 if (ptr == num) {87                  /* Finished */ + 188                  return true;89                }90              }9192              /* need more input ? */ + 993               if (symbol < 0) { + 094                return false;95              }9697              /* 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 through111          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    }138139    public InflaterHuffmanTree BuildLitLenTree()140    { + 1141      byte[] litlenLens = new byte[lnum]; + 1142      Array.Copy(litdistLens, 0, litlenLens, 0, lnum); + 1143      return new InflaterHuffmanTree(litlenLens);144    }145146    public InflaterHuffmanTree BuildDistTree()147    { + 1148      byte[] distLens = new byte[dnum]; + 1149      Array.Copy(litdistLens, lnum, distLens, 0, dnum); + 1150      return new InflaterHuffmanTree(distLens);151    }152153    #region Instance Fields154    byte[] blLens;155    byte[] litdistLens;156157    InflaterHuffmanTree blTree;158159    /// <summary>160    /// The current decode mode161    /// </summary>162    int mode;163    int lnum, dnum, blnum, num;164    int repSymbol;165    byte lastLen;166    int ptr;167    #endregion  168 - 9169               if (ptr == num) {170                /* Finished */ - 0171                return true;172              }173            } - 9174            mode = LENS; - 9175            goto decode_loop;176          }177        }178    }179180    public InflaterHuffmanTree BuildLitLenTree()181    { - 1182      byte[] litlenLens = new byte[lnum]; - 1183      Array.Copy(litdistLens, 0, litlenLens, 0, lnum); - 1184      return new InflaterHuffmanTree(litlenLens);185    }186187    public InflaterHuffmanTree BuildDistTree()188    { - 1189      byte[] distLens = new byte[dnum]; - 1190      Array.Copy(litdistLens, lnum, distLens, 0, dnum); - 1191      return new InflaterHuffmanTree(distLens);192    }193194    #region Instance Fields195    byte[] blLens;196    byte[] litdistLens;197198    InflaterHuffmanTree blTree;199200        /// <summary>201        /// The current decode mode202        /// </summary>203    int mode;204    int lnum, dnum, blnum, num;205    int repSymbol;206    byte lastLen;207    int ptr;208    #endregion209210  }211}169  }170} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterHuffmanTree.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterHuffmanTree.htm index c2be3b45f..9ce45e0ba 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterHuffmanTree.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterHuffmanTree.htm @@ -18,7 +18,7 @@

Summary

Covered lines:65 Uncovered lines:23 Coverable lines:88 -Total lines:232 +Total lines:193 Line coverage:73.8% Branch coverage:75% @@ -38,240 +38,201 @@

#LineLine coverage - 1// InflaterHuffmanTree.cs2// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team3//4// This file was translated from java, it was part of the GNU Classpath5// Copyright (C) 2001 Free Software Foundation, Inc.6//7// This program is free software; you can redistribute it and/or8// modify it under the terms of the GNU General Public License9// as published by the Free Software Foundation; either version 210// of the License, or (at your option) any later version.11//12// This program is distributed in the hope that it will be useful,13// but WITHOUT ANY WARRANTY; without even the implied warranty of14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the15// GNU General Public License for more details.16//17// You should have received a copy of the GNU General Public License18// along with this program; if not, write to the Free Software19// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.20//21// Linking this library statically or dynamically with other modules is22// making a combined work based on this library.  Thus, the terms and23// conditions of the GNU General Public License cover the whole24// combination.25//26// As a special exception, the copyright holders of this library give you27// permission to link this library with independent modules to produce an28// executable, regardless of the license terms of these independent29// modules, and to copy and distribute the resulting executable under30// terms of your choice, provided that you also meet, for each linked31// independent module, the terms and conditions of the license of that32// module.  An independent module is a module which is not derived from33// or based on this library.  If you modify this library, you may extend34// this exception to your version of the library, but you are not35// obligated to do so.  If you do not wish to do so, delete this36// exception statement from your version.3738using System;3940using ICSharpCode.SharpZipLib.Zip.Compression.Streams;4142namespace ICSharpCode.SharpZipLib.Zip.Compression43{4445  /// <summary>46  /// Huffman tree used for inflation47  /// </summary>48  public class InflaterHuffmanTree49  {50    #region Constants51    const int MAX_BITLEN = 15;52    #endregion5354    #region Instance Fields55    short[] tree;56    #endregion5758    /// <summary>59    /// Literal length tree60    /// </summary>61    public static InflaterHuffmanTree defLitLenTree;6263    /// <summary>64    /// Distance tree65    /// </summary>66    public static InflaterHuffmanTree defDistTree;6768    static InflaterHuffmanTree()69    {70      try { - 171        byte[] codeLengths = new byte[288]; - 172        int i = 0; - 14573         while (i < 144) { - 14474          codeLengths[i++] = 8;75        } - 11376         while (i < 256) { - 11277          codeLengths[i++] = 9;78        } - 2579         while (i < 280) { - 2480          codeLengths[i++] = 7;1using System;2using ICSharpCode.SharpZipLib.Zip.Compression.Streams;34namespace ICSharpCode.SharpZipLib.Zip.Compression5{6  /// <summary>7  /// Huffman tree used for inflation8  /// </summary>9  public class InflaterHuffmanTree10  {11    #region Constants12    const int MAX_BITLEN = 15;13    #endregion1415    #region Instance Fields16    short[] tree;17    #endregion1819    /// <summary>20    /// Literal length tree21    /// </summary>22    public static InflaterHuffmanTree defLitLenTree;2324    /// <summary>25    /// Distance tree26    /// </summary>27    public static InflaterHuffmanTree defDistTree;2829    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    }5859    #region Constructors60    /// <summary>61    /// Constructs a Huffman tree from the array of code lengths.62    /// </summary>63    /// <param name = "codeLengths">64    /// the array of code lengths65    /// </param> + 566    public InflaterHuffmanTree(byte[] codeLengths)67    { + 568      BuildTree(codeLengths); + 569    }70    #endregion7172    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        } - 982         while (i < 288) { - 883          codeLengths[i++] = 8;84        } - 185        defLitLenTree = new InflaterHuffmanTree(codeLengths);86 - 187        codeLengths = new byte[32]; - 188        i = 0; - 3389         while (i < 32) { - 3290          codeLengths[i++] = 5;91        } - 192        defDistTree = new InflaterHuffmanTree(codeLengths); - 193      } catch (Exception) { - 094        throw new SharpZipBaseException("InflaterHuffmanTree: static tree length illegal");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      } - 196    }9798    #region Constructors99    /// <summary>100    /// Constructs a Huffman tree from the array of code lengths.101    /// </summary>102    /// <param name = "codeLengths">103    /// the array of code lengths104    /// </param> - 5105    public InflaterHuffmanTree(byte[] codeLengths)106    { - 5107      BuildTree(codeLengths); - 5108    }109    #endregion110111    void BuildTree(byte[] codeLengths)112    { - 5113      int[] blCount  = new int[MAX_BITLEN + 1]; - 5114      int[] nextCode = new int[MAX_BITLEN + 1];115 - 1220116       for (int i = 0; i < codeLengths.Length; i++) { - 605117        int bits = codeLengths[i]; - 605118         if (bits > 0) { - 358119          blCount[bits]++;120        }121      }122 - 5123      int code = 0; - 5124      int treeSize = 512; - 160125       for (int bits = 1; bits <= MAX_BITLEN; bits++) { - 75126        nextCode[bits] = code; - 75127        code += blCount[bits] << (16 - bits); - 75128         if (bits >= 10) {129          /* We need an extra table for bit lengths >= 10. */ - 30130          int start = nextCode[bits] & 0x1ff80; - 30131          int end   = code & 0x1ff80; - 30132          treeSize += (end - start) >> (16 - bits);133        }134      }135136/* -jr comment this out! doesnt work for dynamic trees and pkzip 2.04g137      if (code != 65536)138      {139        throw new SharpZipBaseException("Code lengths don't add up properly.");9697      /* -jr comment this out! doesnt work for dynamic trees and pkzip 2.04g98            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 shortest104      * 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*/142      /* Now create and fill the extra tables from longest to shortest143      * bit len.  This way the sub trees will be aligned.144      */ - 5145      tree = new short[treeSize]; - 5146      int treePtr = 512; - 70147       for (int bits = MAX_BITLEN; bits >= 10; bits--) { - 30148        int end   = code & 0x1ff80; - 30149        code -= blCount[bits] << (16 - bits); - 30150        int start = code & 0x1ff80; - 60151         for (int i = start; i < end; i += 1 << 7) { - 0152          tree[DeflaterHuffman.BitReverse(i)] = (short) ((-treePtr << 4) | bits); - 0153          treePtr += 1 << (bits-9);154        }155      }156 - 1220157       for (int i = 0; i < codeLengths.Length; i++) { - 605158        int bits = codeLengths[i]; - 605159         if (bits == 0) {160          continue;141 + 5142    }143144    /// <summary>145    /// Reads the next symbol from input.  The symbol is encoded using the146    /// 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        } - 358162        code = nextCode[bits]; - 358163        int revcode = DeflaterHuffman.BitReverse(code); - 358164         if (bits <= 9) {165          do { - 2560166            tree[revcode] = (short) ((i << 4) | bits); - 2560167            revcode += 1 << bits; - 2560168           } while (revcode < 512); - 358169        } else { - 0170          int subTree = tree[revcode & 511]; - 0171          int treeLen = 1 << (subTree & 15); - 0172          subTree = -(subTree >> 4);173          do { - 0174            tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits); - 0175            revcode += 1 << bits; - 0176           } while (revcode < treeLen);177        } - 358178        nextCode[bits] = code + (1 << (16 - bits));179      }180 - 5181    }182183    /// <summary>184    /// Reads the next symbol from input.  The symbol is encoded using the185    /// huffman tree.186    /// </summary>187    /// <param name="input">188    /// input the input source.189    /// </param>190    /// <returns>191    /// the next symbol, or -1 if not enough input is available.192    /// </returns>193    public int GetSymbol(StreamManipulator input)194    {195      int lookahead, symbol; - 9859196       if ((lookahead = input.PeekBits(9)) >= 0) { - 9836197         if ((symbol = tree[lookahead]) >= 0) { - 9836198          input.DropBits(symbol & 15); - 9836199          return symbol >> 4;200        } - 0201        int subtree = -(symbol >> 4); - 0202        int bitlen = symbol & 15; - 0203         if ((lookahead = input.PeekBits(bitlen)) >= 0) { - 0204          symbol = tree[subtree | (lookahead >> 9)]; - 0205          input.DropBits(symbol & 15); - 0206          return symbol >> 4;207        } else { - 0208          int bits = input.AvailableBits; - 0209          lookahead = input.PeekBits(bits); - 0210          symbol = tree[subtree | (lookahead >> 9)]; - 0211           if ((symbol & 15) <= bits) { - 0212            input.DropBits(symbol & 15); - 0213            return symbol >> 4;214          } else { - 0215            return -1;216          }217        }218      } else { - 23219        int bits = input.AvailableBits; - 23220        lookahead = input.PeekBits(bits); - 23221        symbol = tree[lookahead]; - 23222         if (symbol >= 0 && (symbol & 15) <= bits) { - 23223          input.DropBits(symbol & 15); - 23224          return symbol >> 4;225        } else { - 0226          return -1;227        }228      }229    }230  }231}232 + 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/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterInputBuffer.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterInputBuffer.htm index 519b72362..b5886cf83 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterInputBuffer.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterInputBuffer.htm @@ -18,7 +18,7 @@

Summary

Covered lines:72 Uncovered lines:14 Coverable lines:86 -Total lines:731 +Total lines:662 Line coverage:83.7% Branch coverage:71% @@ -45,739 +45,670 @@

#LineLine coverage - 1// InflaterInputStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  11-08-2009  GeoffHart  T9121  Added Multi-member gzip support4142using System;43using System.IO;4445#if !NETCF_1_046using System.Security.Cryptography;47#endif4849namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams50{5152  /// <summary>53  /// An input buffer customised for use by <see cref="InflaterInputStream"/>54  /// </summary>55  /// <remarks>56  /// The buffer supports decryption of incoming data.57  /// </remarks>58  public class InflaterInputBuffer59  {60    #region Constructors61    /// <summary>62    /// Initialise a new instance of <see cref="InflaterInputBuffer"/> with a default buffer size63    /// </summary>64    /// <param name="stream">The stream to buffer.</param> - 065    public InflaterInputBuffer(Stream stream) : this(stream , 4096)66    { - 067    }1using System;2using System.IO;3using System.Security.Cryptography;45namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams6{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 InflaterInputBuffer14  {15    #region Constructors16    /// <summary>17    /// Initialise a new instance of <see cref="InflaterInputBuffer"/> with a default buffer size18    /// </summary>19    /// <param name="stream">The stream to buffer.</param> + 020    public InflaterInputBuffer(Stream stream) : this(stream, 4096)21    { + 022    }2324    /// <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    #endregion4041    /// <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    }4950    /// <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    }5960    /// <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    /// Initialise a new instance of <see cref="InflaterInputBuffer"/>70    /// Get the contents of the clear text buffer.  71    /// </summary>72    /// <param name="stream">The stream to buffer.</param>73    /// <param name="bufferSize">The size to use for the buffer</param>74    /// <remarks>A minimum buffer size of 1KB is permitted.  Lower sizes are treated as 1KB.</remarks> - 44175    public InflaterInputBuffer(Stream stream, int bufferSize)76    { - 44177      inputStream = stream; - 44178       if ( bufferSize < 1024 ) { - 079        bufferSize = 1024;80      } - 44181      rawData = new byte[bufferSize]; - 44182      clearText = rawData; - 44183    }84    #endregion72    public byte[] ClearText {73      get { + 074        return clearText;75      }76    }7778    /// <summary>79    /// Get/set the number of bytes available80    /// </summary>81    public int Available { + 283782      get { return available; } + 7883      set { available = value; }84    }  85  86    /// <summary>87    /// Get the length of bytes bytes in the <see cref="RawData"/>87    /// Call <see cref="Inflater.SetInput(byte[], int, int)"/> passing the current clear text buffer contents.  88    /// </summary>89    public int RawLength90    {91      get { - 092        return rawLength;93      }94    }9596    /// <summary>97    /// Get the contents of the raw data buffer.98    /// </summary>99    /// <remarks>This may contain encrypted data.</remarks>100    public byte[] RawData101    {102      get { - 0103        return rawData;104      }105    }106107    /// <summary>108    /// Get the number of useable bytes in <see cref="ClearText"/>109    /// </summary>110    public int ClearTextLength111    {112      get { - 0113        return clearTextLength;114      }115    }116117    /// <summary>118    /// Get the contents of the clear text buffer.119    /// </summary>120    public byte[] ClearText121    {122      get { - 0123        return clearText;124      }125    }126127    /// <summary>128    /// Get/set the number of bytes available129    /// </summary>130    public int Available131    { - 2895132      get { return available; } - 82133      set { available = value; }134    }135136    /// <summary>137    /// Call <see cref="Inflater.SetInput(byte[], int, int)"/> passing the current clear text buffer contents.138    /// </summary>139    /// <param name="inflater">The inflater to set input for.</param>140    public void SetInflaterInput(Inflater inflater)141    { - 1460142       if ( available > 0 ) { - 1460143        inflater.SetInput(clearText, clearTextLength - available, available); - 1460144        available = 0;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    }9798    /// <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    }123124    /// <summary>125    /// Read a buffer directly from the input stream126    /// </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    }133134    /// <summary>135    /// Read a buffer directly from the input stream136    /// </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      } - 1460146    }147148    /// <summary>149    /// Fill the buffer from the underlying input stream.150    /// </summary>151    public void Fill()152    { - 1479153      rawLength = 0; - 1479154      int toRead = rawData.Length;155 - 2956156       while (toRead > 0) { - 1913157        int count = inputStream.Read(rawData, rawLength, toRead); - 1913158         if ( count <= 0 ) {159          break;160        } - 1477161        rawLength += count; - 1477162        toRead -= count;163      }164165#if !NETCF_1_0 - 1479166       if ( cryptoTransform != null ) { - 264167        clearTextLength = cryptoTransform.TransformBlock(rawData, 0, rawLength, clearText, 0); - 264168      }169      else170#endif171      { - 1215172        clearTextLength = rawLength;173      }174 - 1479175      available = clearTextLength; - 1479176    }177178    /// <summary>179    /// Read a buffer directly from the input stream180    /// </summary>181    /// <param name="buffer">The buffer to fill</param>182    /// <returns>Returns the number of bytes read.</returns>183    public int ReadRawBuffer(byte[] buffer)184    { - 167185      return ReadRawBuffer(buffer, 0, buffer.Length);186    }187188    /// <summary>189    /// Read a buffer directly from the input stream190    /// </summary>191    /// <param name="outBuffer">The buffer to read into</param>192    /// <param name="offset">The offset to start reading data into.</param>193    /// <param name="length">The number of bytes to read.</param>194    /// <returns>Returns the number of bytes read.</returns>195    public int ReadRawBuffer(byte[] outBuffer, int offset, int length)196    { - 167197       if ( length < 0 ) { - 0198        throw new ArgumentOutOfRangeException(nameof(length));199      }200 - 167201      int currentOffset = offset; - 167202      int currentLength = length;203 - 334204       while ( currentLength > 0 ) { - 167205         if ( available <= 0 ) { - 0206          Fill(); - 0207           if (available <= 0) { - 0208            return 0;209          }210        } - 167211        int toCopy = Math.Min(currentLength, available); - 167212        System.Array.Copy(rawData, rawLength - (int)available, outBuffer, currentOffset, toCopy); - 167213        currentOffset += toCopy; - 167214        currentLength -= toCopy; - 167215        available -= toCopy;216      } - 167217      return length;218    }219220    /// <summary>221    /// Read clear text data from the input stream.222    /// </summary>223    /// <param name="outBuffer">The buffer to add data to.</param>224    /// <param name="offset">The offset to start adding data at.</param>225    /// <param name="length">The number of bytes to read.</param>226    /// <returns>Returns the number of bytes actually read.</returns>227    public int ReadClearTextBuffer(byte[] outBuffer, int offset, int length)228    { - 31229       if ( length < 0 ) { - 0230        throw new ArgumentOutOfRangeException(nameof(length));231      }232 - 31233      int currentOffset = offset; - 31234      int currentLength = length;235 - 86236       while ( currentLength > 0 ) { - 55237         if ( available <= 0 ) { - 24238          Fill(); - 24239           if (available <= 0) { - 0240            return 0;241          }242        }243 - 55244        int toCopy = Math.Min(currentLength, available); - 55245        Array.Copy(clearText, clearTextLength - (int)available, outBuffer, currentOffset, toCopy); - 55246        currentOffset += toCopy; - 55247        currentLength -= toCopy; - 55248        available -= toCopy;249      } - 31250      return length;251    }252253    /// <summary>254    /// Read a <see cref="byte"/> from the input stream.255    /// </summary>256    /// <returns>Returns the byte read.</returns>257    public int ReadLeByte()258    { - 2728259       if (available <= 0) { - 61260        Fill(); - 61261         if (available <= 0) { - 0262          throw new ZipException("EOF in header");263        }264      } - 2728265      byte result = rawData[rawLength - available]; - 2728266      available -= 1; - 2728267      return result;268    }269270    /// <summary>271    /// Read an <see cref="short"/> in little endian byte order.272    /// </summary>273    /// <returns>The short value read case to an int.</returns>274    public int ReadLeShort()275    { - 1359276      return ReadLeByte() | (ReadLeByte() << 8);277    }278279    /// <summary>280    /// Read an <see cref="int"/> in little endian byte order.281    /// </summary>282    /// <returns>The int value read.</returns>283    public int ReadLeInt()284    { - 467285      return ReadLeShort() | (ReadLeShort() << 16);286    }287288    /// <summary>289    /// Read a <see cref="long"/> in little endian byte order.290    /// </summary>291    /// <returns>The long value read.</returns>292    public long ReadLeLong()293    { - 12294      return (uint)ReadLeInt() | ((long)ReadLeInt() << 32);295    }296297#if !NETCF_1_0298    /// <summary>299    /// Get/set the <see cref="ICryptoTransform"/> to apply to any data.300    /// </summary>301    /// <remarks>Set this value to null to have no transform applied.</remarks>302    public ICryptoTransform CryptoTransform303    {304      set { - 107305        cryptoTransform = value; - 107306         if ( cryptoTransform != null ) { - 27307           if ( rawData == clearText ) { - 27308             if ( internalClearText == null ) { - 26309              internalClearText = new byte[rawData.Length];310            } - 27311            clearText = internalClearText;312          } - 27313          clearTextLength = rawLength; - 27314           if ( available > 0 ) { - 27315            cryptoTransform.TransformBlock(rawData, rawLength - available, available, clearText, rawLength - available);316          } - 27317        } else { - 80318          clearText = rawData; - 80319          clearTextLength = rawLength;320        } - 80321      }322    }323#endif324325    #region Instance Fields326    int rawLength;327    byte[] rawData;328329    int clearTextLength;330    byte[] clearText;331#if !NETCF_1_0332    byte[] internalClearText;333#endif334335    int available;336337#if !NETCF_1_0338    ICryptoTransform cryptoTransform;339#endif340    Stream inputStream;341    #endregion342  }343344  /// <summary>345  /// This filter stream is used to decompress data compressed using the "deflate"346  /// format. The "deflate" format is described in RFC 1951.347  ///348  /// This stream may form the basis for other decompression filters, such349  /// as the <see cref="ICSharpCode.SharpZipLib.GZip.GZipInputStream">GZipInputStream</see>.350  ///351  /// Author of the original java version : John Leuner.352  /// </summary>353  public class InflaterInputStream : Stream354  {355    #region Constructors356    /// <summary>357    /// Create an InflaterInputStream with the default decompressor358    /// and a default buffer size of 4KB.359    /// </summary>360    /// <param name = "baseInputStream">361    /// The InputStream to read bytes from362    /// </param>363    public InflaterInputStream(Stream baseInputStream)364      : this(baseInputStream, new Inflater(), 4096)365    {366    }367368    /// <summary>369    /// Create an InflaterInputStream with the specified decompressor370    /// and a default buffer size of 4KB.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    }165166    /// <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    }198199    /// <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    }215216    /// <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    }224225    /// <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    }233234    /// <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    }242243    /// <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    }267268    #region Instance Fields269    int rawLength;270    byte[] rawData;271272    int clearTextLength;273    byte[] clearText;274    byte[] internalClearText;275276    int available;277278    ICryptoTransform cryptoTransform;279    Stream inputStream;280    #endregion281  }282283  /// <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, such288  /// 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 : Stream293  {294    #region Constructors295    /// <summary>296    /// Create an InflaterInputStream with the default decompressor297    /// and a default buffer size of 4KB.298    /// </summary>299    /// <param name = "baseInputStream">300    /// The InputStream to read bytes from301    /// </param>302    public InflaterInputStream(Stream baseInputStream)303      : this(baseInputStream, new Inflater(), 4096)304    {305    }306307    /// <summary>308    /// Create an InflaterInputStream with the specified decompressor309    /// and a default buffer size of 4KB.310    /// </summary>311    /// <param name = "baseInputStream">312    /// The source of input data313    /// </param>314    /// <param name = "inf">315    /// The decompressor used to decompress data read from baseInputStream316    /// </param>317    public InflaterInputStream(Stream baseInputStream, Inflater inf)318      : this(baseInputStream, inf, 4096)319    {320    }321322    /// <summary>323    /// Create an InflaterInputStream with the specified decompressor324    /// and the specified buffer size.325    /// </summary>326    /// <param name = "baseInputStream">327    /// The InputStream to read bytes from328    /// </param>329    /// <param name = "inflater">330    /// The decompressor to use331    /// </param>332    /// <param name = "bufferSize">333    /// Size of the buffer to use334    /// </param>335    public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize)336    {337      if (baseInputStream == null) {338        throw new ArgumentNullException(nameof(baseInputStream));339      }340341      if (inflater == null) {342        throw new ArgumentNullException(nameof(inflater));343      }344345      if (bufferSize <= 0) {346        throw new ArgumentOutOfRangeException(nameof(bufferSize));347      }348349      this.baseInputStream = baseInputStream;350      this.inf = inflater;351352      inputBuffer = new InflaterInputBuffer(baseInputStream, bufferSize);353    }354355    #endregion356357    /// <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    }368369    /// <summary>370    /// Skip specified number of bytes of uncompressed data  371    /// </summary>372    /// <param name = "baseInputStream">373    /// The source of input data372    /// <param name ="count">373    /// Number of bytes to skip  374    /// </param>375    /// <param name = "inf">376    /// The decompressor used to decompress data read from baseInputStream377    /// </param>378    public InflaterInputStream(Stream baseInputStream, Inflater inf)379      : this(baseInputStream, inf, 4096)380    {381    }382383    /// <summary>384    /// Create an InflaterInputStream with the specified decompressor385    /// and the specified buffer size.386    /// </summary>387    /// <param name = "baseInputStream">388    /// The InputStream to read bytes from389    /// </param>390    /// <param name = "inflater">391    /// The decompressor to use392    /// </param>393    /// <param name = "bufferSize">394    /// Size of the buffer to use395    /// </param>396    public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize)397    {398      if (baseInputStream == null) {399        throw new ArgumentNullException(nameof(baseInputStream));400      }375    /// <returns>376    /// The number of bytes skipped, zero if the end of377    /// stream has been reached378    /// </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      }387388      // 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        }397398        byte[] tmp = new byte[length];399        int readCount = 1;400        long toSkip = count;  401402      if (inflater == null) {403        throw new ArgumentNullException(nameof(inflater));404      }405406      if (bufferSize <= 0) {407        throw new ArgumentOutOfRangeException(nameof(bufferSize));408      }409410      this.baseInputStream = baseInputStream;411      this.inf = inflater;412413      inputBuffer = new InflaterInputBuffer(baseInputStream, bufferSize);414    }415416    #endregion417418    /// <summary>419    /// Get/set flag indicating ownership of underlying stream.420    /// When the flag is true <see cref="Close"/> will close the underlying stream also.421    /// </summary>422    /// <remarks>423    /// The default value is true.424    /// </remarks>425    public bool IsStreamOwner426    {427      get { return isStreamOwner; }428      set { isStreamOwner = value; }429    }430431    /// <summary>432    /// Skip specified number of bytes of uncompressed data433    /// </summary>434    /// <param name ="count">435    /// Number of bytes to skip436    /// </param>437    /// <returns>438    /// The number of bytes skipped, zero if the end of439    /// stream has been reached440    /// </returns>441    /// <exception cref="ArgumentOutOfRangeException">442    /// <paramref name="count">The number of bytes</paramref> to skip is less than or equal to zero.443    /// </exception>444    public long Skip(long count)445    {446      if (count <= 0) {447        throw new ArgumentOutOfRangeException(nameof(count));448      }449450      // v0.80 Skip by seeking if underlying stream supports it...451      if (baseInputStream.CanSeek) {452        baseInputStream.Seek(count, SeekOrigin.Current);453        return count;454      }455      else {456        int length = 2048;457        if (count < length) {458          length = (int) count;459        }402        while ((toSkip > 0) && (readCount > 0)) {403          if (toSkip < length) {404            length = (int)toSkip;405          }406407          readCount = baseInputStream.Read(tmp, 0, length);408          toSkip -= readCount;409        }410411        return count - toSkip;412      }413    }414415    /// <summary>416    /// Clear any cryptographic state.417    /// </summary>418    protected void StopDecrypting()419    {420      inputBuffer.CryptoTransform = null;421    }422423    /// <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    }432433    /// <summary>434    /// Fills the buffer with more data to decompress.435    /// </summary>436    /// <exception cref="SharpZipBaseException">437    /// Stream ends early438    /// </exception>439    protected void Fill()440    {441      // Protect against redundant calls442      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    }450451    #region Stream Overrides452    /// <summary>453    /// Gets a value indicating whether the current stream supports reading454    /// </summary>455    public override bool CanRead {456      get {457        return baseInputStream.CanRead;458      }459    }  460461        byte[] tmp = new byte[length];462        int readCount = 1;463        long toSkip = count;464465        while ((toSkip > 0) && (readCount > 0) ) {466          if (toSkip < length) {467            length = (int)toSkip;468          }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    }  469470          readCount = baseInputStream.Read(tmp, 0, length);471          toSkip -= readCount;472        }473474        return count - toSkip;475      }476    }477478    /// <summary>479    /// Clear any cryptographic state.480    /// </summary>481    protected void StopDecrypting()482    {483#if !NETCF_1_0484      inputBuffer.CryptoTransform = null;485#endif470    /// <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    }478479    /// <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    /// Returns 0 once the end of the stream (EOF) has been reached.490    /// Otherwise returns 1.489    /// The current position within the stream.490    /// Throws a NotSupportedException when attempting to set the position  491    /// </summary>492    public virtual int Available493    {492    /// <exception cref="NotSupportedException">Attempting to set the position</exception>493    public override long Position {  494      get {495        return inf.IsFinished ? 0 : 1;495        return baseInputStream.Position;  496      }497    }498499    /// <summary>500    /// Fills the buffer with more data to decompress.501    /// </summary>502    /// <exception cref="SharpZipBaseException">503    /// Stream ends early504    /// </exception>505    protected void Fill()497      set {498        throw new NotSupportedException("InflaterInputStream Position not supported");499      }500    }501502    /// <summary>503    /// Flushes the baseInputStream504    /// </summary>505    public override void Flush()  506    {507      // Protect against redundant calls508      if (inputBuffer.Available <= 0) {509        inputBuffer.Fill();510        if (inputBuffer.Available <= 0) {511          throw new SharpZipBaseException("Unexpected EOF");512        }513      }514      inputBuffer.SetInflaterInput(inf);515    }516517    #region Stream Overrides518    /// <summary>519    /// Gets a value indicating whether the current stream supports reading520    /// </summary>521    public override bool CanRead522    {523      get {524        return baseInputStream.CanRead;525      }526    }527528    /// <summary>529    /// Gets a value of false indicating seeking is not supported for this stream.530    /// </summary>531    public override bool CanSeek {532      get {533        return false;534      }535    }536537    /// <summary>538    /// Gets a value of false indicating that this stream is not writeable.539    /// </summary>540    public override bool CanWrite {541      get {542        return false;543      }544    }545546    /// <summary>547    /// A value representing the length of the stream in bytes.548    /// </summary>549    public override long Length {550      get {551        return inputBuffer.RawLength;552      }553    }554555    /// <summary>556    /// The current position within the stream.557    /// Throws a NotSupportedException when attempting to set the position558    /// </summary>559    /// <exception cref="NotSupportedException">Attempting to set the position</exception>560    public override long Position {561      get {562        return baseInputStream.Position;563      }564      set {565        throw new NotSupportedException("InflaterInputStream Position not supported");566      }567    }568569    /// <summary>570    /// Flushes the baseInputStream571    /// </summary>572    public override void Flush()573    {574      baseInputStream.Flush();575    }576577    /// <summary>578    /// Sets the position within the current stream579    /// Always throws a NotSupportedException580    /// </summary>581    /// <param name="offset">The relative offset to seek to.</param>582    /// <param name="origin">The <see cref="SeekOrigin"/> defining where to seek from.</param>583    /// <returns>The new position in the stream.</returns>584    /// <exception cref="NotSupportedException">Any access</exception>585    public override long Seek(long offset, SeekOrigin origin)586    {587      throw new NotSupportedException("Seek not supported");588    }589590    /// <summary>591    /// Set the length of the current stream592    /// Always throws a NotSupportedException593    /// </summary>594    /// <param name="value">The new length value for the stream.</param>595    /// <exception cref="NotSupportedException">Any access</exception>596    public override void SetLength(long value)597    {598      throw new NotSupportedException("InflaterInputStream SetLength not supported");599    }600601    /// <summary>602    /// Writes a sequence of bytes to stream and advances the current position603    /// This method always throws a NotSupportedException604    /// </summary>605    /// <param name="buffer">Thew buffer containing data to write.</param>606    /// <param name="offset">The offset of the first byte to write.</param>607    /// <param name="count">The number of bytes to write.</param>608    /// <exception cref="NotSupportedException">Any access</exception>609    public override void Write(byte[] buffer, int offset, int count)610    {611      throw new NotSupportedException("InflaterInputStream Write not supported");612    }613614    /// <summary>615    /// Writes one byte to the current stream and advances the current position616    /// Always throws a NotSupportedException617    /// </summary>618    /// <param name="value">The byte to write.</param>619    /// <exception cref="NotSupportedException">Any access</exception>620    public override void WriteByte(byte value)621    {622      throw new NotSupportedException("InflaterInputStream WriteByte not supported");623    }624625    /// <summary>626    /// Entry point to begin an asynchronous write.  Always throws a NotSupportedException.627    /// </summary>628    /// <param name="buffer">The buffer to write data from</param>629    /// <param name="offset">Offset of first byte to write</param>630    /// <param name="count">The maximum number of bytes to write</param>631    /// <param name="callback">The method to be called when the asynchronous write operation is completed</param>632    /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from ot633    /// <returns>An <see cref="System.IAsyncResult">IAsyncResult</see> that references the asynchronous write</returns>634    /// <exception cref="NotSupportedException">Any access</exception>635    public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)636    {637      throw new NotSupportedException("InflaterInputStream BeginWrite not supported");638    }507      baseInputStream.Flush();508    }509510    /// <summary>511    /// Sets the position within the current stream512    /// Always throws a NotSupportedException513    /// </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    }522523    /// <summary>524    /// Set the length of the current stream525    /// Always throws a NotSupportedException526    /// </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    }533534    /// <summary>535    /// Writes a sequence of bytes to stream and advances the current position536    /// This method always throws a NotSupportedException537    /// </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    }546547    /// <summary>548    /// Writes one byte to the current stream and advances the current position549    /// Always throws a NotSupportedException550    /// </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    }557558    /// <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 ot566    /// <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    }572573    /// <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    }586587    /// <summary>588    /// Reads decompressed data into the provided buffer byte array589    /// </summary>590    /// <param name ="buffer">591    /// The array to read and decompress data into592    /// </param>593    /// <param name ="offset">594    /// The offset indicating where the data should be placed595    /// </param>596    /// <param name ="count">597    /// The number of bytes to decompress598    /// </param>599    /// <returns>The number of bytes read.  Zero signals the end of stream</returns>600    /// <exception cref="SharpZipBaseException">601    /// Inflater needs a dictionary602    /// </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      }608609      int remainingBytes = count;610      while (true) {611        int bytesRead = inf.Inflate(buffer, offset, remainingBytes);612        offset += bytesRead;613        remainingBytes -= bytesRead;614615        if (remainingBytes == 0 || inf.IsFinished) {616          break;617        }618619        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    #endregion628629    #region Instance Fields630    /// <summary>631    /// Decompressor for this stream632    /// </summary>633    protected Inflater inf;634635    /// <summary>636    /// <see cref="InflaterInputBuffer">Input buffer</see> for this stream.637    /// </summary>638    protected InflaterInputBuffer inputBuffer;  639  640    /// <summary>641    /// Closes the input stream.  When <see cref="IsStreamOwner"></see>642    /// is true the underlying stream is also closed.643    /// </summary>644    public override void Close()645    {646      if ( !isClosed ) {647        isClosed = true;648        if ( isStreamOwner ) {649          baseInputStream.Close();650        }651      }652    }653654    /// <summary>655    /// Reads decompressed data into the provided buffer byte array656    /// </summary>657    /// <param name ="buffer">658    /// The array to read and decompress data into659    /// </param>660    /// <param name ="offset">661    /// The offset indicating where the data should be placed662    /// </param>663    /// <param name ="count">664    /// The number of bytes to decompress665    /// </param>666    /// <returns>The number of bytes read.  Zero signals the end of stream</returns>667    /// <exception cref="SharpZipBaseException">668    /// Inflater needs a dictionary669    /// </exception>670    public override int Read(byte[] buffer, int offset, int count)671    {672      if (inf.IsNeedingDictionary)673      {674        throw new SharpZipBaseException("Need a dictionary");675      }676677      int remainingBytes = count;678      while (true) {679        int bytesRead = inf.Inflate(buffer, offset, remainingBytes);680        offset += bytesRead;681        remainingBytes -= bytesRead;682683        if (remainingBytes == 0 || inf.IsFinished) {684          break;685        }686687        if ( inf.IsNeedingInput ) {688          Fill();689        }690        else if ( bytesRead == 0 ) {691          throw new ZipException("Dont know what to do");692        }693      }694      return count - remainingBytes;695    }696    #endregion697698    #region Instance Fields699    /// <summary>700    /// Decompressor for this stream701    /// </summary>702    protected Inflater inf;703704    /// <summary>705    /// <see cref="InflaterInputBuffer">Input buffer</see> for this stream.706    /// </summary>707    protected InflaterInputBuffer inputBuffer;708709    /// <summary>710    /// Base stream the inflater reads from.711    /// </summary>712    private Stream baseInputStream;713714    /// <summary>715    /// The compressed size716    /// </summary>717    protected long csize;718719    /// <summary>720    /// Flag indicating wether this instance has been closed or not.721    /// </summary>722    bool isClosed;723724    /// <summary>725    /// Flag indicating wether this instance is designated the stream owner.726    /// When closing if this flag is true the underlying stream is closed.727    /// </summary>728    bool isStreamOwner = true;729    #endregion730  }731}641    /// Base stream the inflater reads from.642    /// </summary>643    private Stream baseInputStream;644645    /// <summary>646    /// The compressed size647    /// </summary>648    protected long csize;649650    /// <summary>651    /// Flag indicating wether this instance has been closed or not.652    /// </summary>653    bool isClosed;654655    /// <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    #endregion661  }662} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterInputStream.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterInputStream.htm index 86550a7c1..6570d574b 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterInputStream.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_InflaterInputStream.htm @@ -16,11 +16,11 @@

Summary

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:37 -Coverable lines:75 -Total lines:731 -Line coverage:50.6% -Branch coverage:42.1% +Uncovered lines:36 +Coverable lines:74 +Total lines:662 +Line coverage:51.3% +Branch coverage:39.4%

Metrics

@@ -32,7 +32,7 @@

Metrics

.ctor(...)47557.14 Skip(...)700 StopDecrypting()1100100 -Fill()383.3380 +Fill()383.3360 Flush()100 Seek(...)100 SetLength(...)100 @@ -48,739 +48,670 @@

#LineLine coverage - 1// InflaterInputStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  11-08-2009  GeoffHart  T9121  Added Multi-member gzip support4142using System;43using System.IO;4445#if !NETCF_1_046using System.Security.Cryptography;47#endif4849namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams50{5152  /// <summary>53  /// An input buffer customised for use by <see cref="InflaterInputStream"/>54  /// </summary>55  /// <remarks>56  /// The buffer supports decryption of incoming data.57  /// </remarks>58  public class InflaterInputBuffer59  {60    #region Constructors61    /// <summary>62    /// Initialise a new instance of <see cref="InflaterInputBuffer"/> with a default buffer size63    /// </summary>64    /// <param name="stream">The stream to buffer.</param>65    public InflaterInputBuffer(Stream stream) : this(stream , 4096)66    {1using System;2using System.IO;3using System.Security.Cryptography;45namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams6{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 InflaterInputBuffer14  {15    #region Constructors16    /// <summary>17    /// Initialise a new instance of <see cref="InflaterInputBuffer"/> with a default buffer size18    /// </summary>19    /// <param name="stream">The stream to buffer.</param>20    public InflaterInputBuffer(Stream stream) : this(stream, 4096)21    {22    }2324    /// <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    #endregion4041    /// <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    }4950    /// <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    }5960    /// <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    /// Initialise a new instance of <see cref="InflaterInputBuffer"/>70    /// Get the contents of the clear text buffer.  71    /// </summary>72    /// <param name="stream">The stream to buffer.</param>73    /// <param name="bufferSize">The size to use for the buffer</param>74    /// <remarks>A minimum buffer size of 1KB is permitted.  Lower sizes are treated as 1KB.</remarks>75    public InflaterInputBuffer(Stream stream, int bufferSize)76    {77      inputStream = stream;78      if ( bufferSize < 1024 ) {79        bufferSize = 1024;80      }81      rawData = new byte[bufferSize];82      clearText = rawData;83    }84    #endregion72    public byte[] ClearText {73      get {74        return clearText;75      }76    }7778    /// <summary>79    /// Get/set the number of bytes available80    /// </summary>81    public int Available {82      get { return available; }83      set { available = value; }84    }  85  86    /// <summary>87    /// Get the length of bytes bytes in the <see cref="RawData"/>87    /// Call <see cref="Inflater.SetInput(byte[], int, int)"/> passing the current clear text buffer contents.  88    /// </summary>89    public int RawLength90    {91      get {92        return rawLength;93      }94    }9596    /// <summary>97    /// Get the contents of the raw data buffer.98    /// </summary>99    /// <remarks>This may contain encrypted data.</remarks>100    public byte[] RawData101    {102      get {103        return rawData;104      }105    }106107    /// <summary>108    /// Get the number of useable bytes in <see cref="ClearText"/>109    /// </summary>110    public int ClearTextLength111    {112      get {113        return clearTextLength;114      }115    }116117    /// <summary>118    /// Get the contents of the clear text buffer.119    /// </summary>120    public byte[] ClearText121    {122      get {123        return clearText;124      }125    }126127    /// <summary>128    /// Get/set the number of bytes available129    /// </summary>130    public int Available131    {132      get { return available; }133      set { available = value; }134    }135136    /// <summary>137    /// Call <see cref="Inflater.SetInput(byte[], int, int)"/> passing the current clear text buffer contents.138    /// </summary>139    /// <param name="inflater">The inflater to set input for.</param>140    public void SetInflaterInput(Inflater inflater)141    {142      if ( available > 0 ) {143        inflater.SetInput(clearText, clearTextLength - available, available);144        available = 0;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    }9798    /// <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;105106      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      }114115      if (cryptoTransform != null) {116        clearTextLength = cryptoTransform.TransformBlock(rawData, 0, rawLength, clearText, 0);117      } else {118        clearTextLength = rawLength;119      }120121      available = clearTextLength;122    }123124    /// <summary>125    /// Read a buffer directly from the input stream126    /// </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    }133134    /// <summary>135    /// Read a buffer directly from the input stream136    /// </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    }147148    /// <summary>149    /// Fill the buffer from the underlying input stream.150    /// </summary>151    public void Fill()152    {153      rawLength = 0;154      int toRead = rawData.Length;155156      while (toRead > 0) {157        int count = inputStream.Read(rawData, rawLength, toRead);158        if ( count <= 0 ) {159          break;160        }161        rawLength += count;162        toRead -= count;163      }164165#if !NETCF_1_0166      if ( cryptoTransform != null ) {167        clearTextLength = cryptoTransform.TransformBlock(rawData, 0, rawLength, clearText, 0);168      }169      else170#endif171      {172        clearTextLength = rawLength;173      }174175      available = clearTextLength;176    }177178    /// <summary>179    /// Read a buffer directly from the input stream180    /// </summary>181    /// <param name="buffer">The buffer to fill</param>182    /// <returns>Returns the number of bytes read.</returns>183    public int ReadRawBuffer(byte[] buffer)184    {185      return ReadRawBuffer(buffer, 0, buffer.Length);186    }187188    /// <summary>189    /// Read a buffer directly from the input stream190    /// </summary>191    /// <param name="outBuffer">The buffer to read into</param>192    /// <param name="offset">The offset to start reading data into.</param>193    /// <param name="length">The number of bytes to read.</param>194    /// <returns>Returns the number of bytes read.</returns>195    public int ReadRawBuffer(byte[] outBuffer, int offset, int length)196    {197      if ( length < 0 ) {198        throw new ArgumentOutOfRangeException(nameof(length));199      }200201      int currentOffset = offset;202      int currentLength = length;203204      while ( currentLength > 0 ) {205        if ( available <= 0 ) {206          Fill();207          if (available <= 0) {208            return 0;209          }210        }211        int toCopy = Math.Min(currentLength, available);212        System.Array.Copy(rawData, rawLength - (int)available, outBuffer, currentOffset, toCopy);213        currentOffset += toCopy;214        currentLength -= toCopy;215        available -= toCopy;216      }217      return length;218    }219220    /// <summary>221    /// Read clear text data from the input stream.222    /// </summary>223    /// <param name="outBuffer">The buffer to add data to.</param>224    /// <param name="offset">The offset to start adding data at.</param>225    /// <param name="length">The number of bytes to read.</param>226    /// <returns>Returns the number of bytes actually read.</returns>227    public int ReadClearTextBuffer(byte[] outBuffer, int offset, int length)228    {229      if ( length < 0 ) {230        throw new ArgumentOutOfRangeException(nameof(length));231      }232233      int currentOffset = offset;234      int currentLength = length;235236      while ( currentLength > 0 ) {237        if ( available <= 0 ) {238          Fill();239          if (available <= 0) {240            return 0;241          }242        }243244        int toCopy = Math.Min(currentLength, available);245        Array.Copy(clearText, clearTextLength - (int)available, outBuffer, currentOffset, toCopy);246        currentOffset += toCopy;247        currentLength -= toCopy;248        available -= toCopy;249      }250      return length;251    }252253    /// <summary>254    /// Read a <see cref="byte"/> from the input stream.255    /// </summary>256    /// <returns>Returns the byte read.</returns>257    public int ReadLeByte()258    {259      if (available <= 0) {260        Fill();261        if (available <= 0) {262          throw new ZipException("EOF in header");263        }264      }265      byte result = rawData[rawLength - available];266      available -= 1;267      return result;268    }269270    /// <summary>271    /// Read an <see cref="short"/> in little endian byte order.272    /// </summary>273    /// <returns>The short value read case to an int.</returns>274    public int ReadLeShort()275    {276      return ReadLeByte() | (ReadLeByte() << 8);277    }278279    /// <summary>280    /// Read an <see cref="int"/> in little endian byte order.281    /// </summary>282    /// <returns>The int value read.</returns>283    public int ReadLeInt()284    {285      return ReadLeShort() | (ReadLeShort() << 16);286    }287288    /// <summary>289    /// Read a <see cref="long"/> in little endian byte order.290    /// </summary>291    /// <returns>The long value read.</returns>292    public long ReadLeLong()293    {294      return (uint)ReadLeInt() | ((long)ReadLeInt() << 32);295    }296297#if !NETCF_1_0298    /// <summary>299    /// Get/set the <see cref="ICryptoTransform"/> to apply to any data.300    /// </summary>301    /// <remarks>Set this value to null to have no transform applied.</remarks>302    public ICryptoTransform CryptoTransform303    {304      set {305        cryptoTransform = value;306        if ( cryptoTransform != null ) {307          if ( rawData == clearText ) {308            if ( internalClearText == null ) {309              internalClearText = new byte[rawData.Length];310            }311            clearText = internalClearText;312          }313          clearTextLength = rawLength;314          if ( available > 0 ) {315            cryptoTransform.TransformBlock(rawData, rawLength - available, available, clearText, rawLength - available);316          }317        } else {318          clearText = rawData;319          clearTextLength = rawLength;320        }321      }322    }323#endif324325    #region Instance Fields326    int rawLength;327    byte[] rawData;328329    int clearTextLength;330    byte[] clearText;331#if !NETCF_1_0332    byte[] internalClearText;333#endif334335    int available;336337#if !NETCF_1_0338    ICryptoTransform cryptoTransform;339#endif340    Stream inputStream;341    #endregion342  }343344  /// <summary>345  /// This filter stream is used to decompress data compressed using the "deflate"346  /// format. The "deflate" format is described in RFC 1951.347  ///348  /// This stream may form the basis for other decompression filters, such349  /// as the <see cref="ICSharpCode.SharpZipLib.GZip.GZipInputStream">GZipInputStream</see>.350  ///351  /// Author of the original java version : John Leuner.352  /// </summary>353  public class InflaterInputStream : Stream354  {355    #region Constructors356    /// <summary>357    /// Create an InflaterInputStream with the default decompressor358    /// and a default buffer size of 4KB.359    /// </summary>360    /// <param name = "baseInputStream">361    /// The InputStream to read bytes from362    /// </param>363    public InflaterInputStream(Stream baseInputStream) - 3364      : this(baseInputStream, new Inflater(), 4096)365    { - 3366    }367368    /// <summary>369    /// Create an InflaterInputStream with the specified decompressor370    /// and a default buffer size of 4KB.146147      int currentOffset = offset;148      int currentLength = length;149150      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    }165166    /// <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      }178179      int currentOffset = offset;180      int currentLength = length;181182      while (currentLength > 0) {183        if (available <= 0) {184          Fill();185          if (available <= 0) {186            return 0;187          }188        }189190        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    }198199    /// <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    }215216    /// <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    }224225    /// <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    }233234    /// <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    }242243    /// <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    }267268    #region Instance Fields269    int rawLength;270    byte[] rawData;271272    int clearTextLength;273    byte[] clearText;274    byte[] internalClearText;275276    int available;277278    ICryptoTransform cryptoTransform;279    Stream inputStream;280    #endregion281  }282283  /// <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, such288  /// 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 : Stream293  {294    #region Constructors295    /// <summary>296    /// Create an InflaterInputStream with the default decompressor297    /// and a default buffer size of 4KB.298    /// </summary>299    /// <param name = "baseInputStream">300    /// The InputStream to read bytes from301    /// </param>302    public InflaterInputStream(Stream baseInputStream) + 3303      : this(baseInputStream, new Inflater(), 4096)304    { + 3305    }306307    /// <summary>308    /// Create an InflaterInputStream with the specified decompressor309    /// and a default buffer size of 4KB.310    /// </summary>311    /// <param name = "baseInputStream">312    /// The source of input data313    /// </param>314    /// <param name = "inf">315    /// The decompressor used to decompress data read from baseInputStream316    /// </param>317    public InflaterInputStream(Stream baseInputStream, Inflater inf) + 430318      : this(baseInputStream, inf, 4096)319    { + 430320    }321322    /// <summary>323    /// Create an InflaterInputStream with the specified decompressor324    /// and the specified buffer size.325    /// </summary>326    /// <param name = "baseInputStream">327    /// The InputStream to read bytes from328    /// </param>329    /// <param name = "inflater">330    /// The decompressor to use331    /// </param>332    /// <param name = "bufferSize">333    /// Size of the buffer to use334    /// </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    }354355    #endregion356357    /// <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    }368369    /// <summary>370    /// Skip specified number of bytes of uncompressed data  371    /// </summary>372    /// <param name = "baseInputStream">373    /// The source of input data372    /// <param name ="count">373    /// Number of bytes to skip  374    /// </param>375    /// <param name = "inf">376    /// The decompressor used to decompress data read from baseInputStream377    /// </param>378    public InflaterInputStream(Stream baseInputStream, Inflater inf) - 434379      : this(baseInputStream, inf, 4096)380    { - 434381    }382383    /// <summary>384    /// Create an InflaterInputStream with the specified decompressor385    /// and the specified buffer size.386    /// </summary>387    /// <param name = "baseInputStream">388    /// The InputStream to read bytes from389    /// </param>390    /// <param name = "inflater">391    /// The decompressor to use392    /// </param>393    /// <param name = "bufferSize">394    /// Size of the buffer to use395    /// </param> - 441396    public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize)397    { - 441398       if (baseInputStream == null) { - 0399        throw new ArgumentNullException(nameof(baseInputStream));400      }375    /// <returns>376    /// The number of bytes skipped, zero if the end of377    /// stream has been reached378    /// </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      }387388      // 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 - 441402       if (inflater == null) { - 0403        throw new ArgumentNullException(nameof(inflater));404      }405 - 441406       if (bufferSize <= 0) { - 0407        throw new ArgumentOutOfRangeException(nameof(bufferSize));408      }409 - 441410      this.baseInputStream = baseInputStream; - 441411      this.inf = inflater;412 - 441413      inputBuffer = new InflaterInputBuffer(baseInputStream, bufferSize); - 441414    }415416    #endregion417418    /// <summary>419    /// Get/set flag indicating ownership of underlying stream.420    /// When the flag is true <see cref="Close"/> will close the underlying stream also.421    /// </summary>422    /// <remarks>423    /// The default value is true.424    /// </remarks>425    public bool IsStreamOwner426    { - 0427      get { return isStreamOwner; } - 4428      set { isStreamOwner = value; }429    }430431    /// <summary>432    /// Skip specified number of bytes of uncompressed data433    /// </summary>434    /// <param name ="count">435    /// Number of bytes to skip436    /// </param>437    /// <returns>438    /// The number of bytes skipped, zero if the end of439    /// stream has been reached440    /// </returns>441    /// <exception cref="ArgumentOutOfRangeException">442    /// <paramref name="count">The number of bytes</paramref> to skip is less than or equal to zero.443    /// </exception>444    public long Skip(long count)445    { - 0446       if (count <= 0) { - 0447        throw new ArgumentOutOfRangeException(nameof(count));448      }449450      // v0.80 Skip by seeking if underlying stream supports it... - 0451       if (baseInputStream.CanSeek) { - 0452        baseInputStream.Seek(count, SeekOrigin.Current); - 0453        return count;454      }455      else { - 0456        int length = 2048; - 0457         if (count < length) { - 0458          length = (int) count;459        } + 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    }414415    /// <summary>416    /// Clear any cryptographic state.417    /// </summary>418    protected void StopDecrypting()419    { + 32420      inputBuffer.CryptoTransform = null; + 32421    }422423    /// <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    }432433    /// <summary>434    /// Fills the buffer with more data to decompress.435    /// </summary>436    /// <exception cref="SharpZipBaseException">437    /// Stream ends early438    /// </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    }450451    #region Stream Overrides452    /// <summary>453    /// Gets a value indicating whether the current stream supports reading454    /// </summary>455    public override bool CanRead {456      get { + 8457        return baseInputStream.CanRead;458      }459    }  460 - 0461        byte[] tmp = new byte[length]; - 0462        int readCount = 1; - 0463        long toSkip = count;464 - 0465         while ((toSkip > 0) && (readCount > 0) ) { - 0466           if (toSkip < length) { - 0467            length = (int)toSkip;468          }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 - 0470          readCount = baseInputStream.Read(tmp, 0, length); - 0471          toSkip -= readCount;472        }473 - 0474        return count - toSkip;475      }476    }477478    /// <summary>479    /// Clear any cryptographic state.480    /// </summary>481    protected void StopDecrypting()482    {483#if !NETCF_1_0 - 33484      inputBuffer.CryptoTransform = null;485#endif - 33486    }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    }478479    /// <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    /// Returns 0 once the end of the stream (EOF) has been reached.490    /// Otherwise returns 1.489    /// The current position within the stream.490    /// Throws a NotSupportedException when attempting to set the position  491    /// </summary>492    public virtual int Available493    {492    /// <exception cref="NotSupportedException">Attempting to set the position</exception>493    public override long Position {  494      get { - 0495         return inf.IsFinished ? 0 : 1; + 0495        return baseInputStream.Position;  496      }497    }498499    /// <summary>500    /// Fills the buffer with more data to decompress.501    /// </summary>502    /// <exception cref="SharpZipBaseException">503    /// Stream ends early504    /// </exception>505    protected void Fill()497      set { + 0498        throw new NotSupportedException("InflaterInputStream Position not supported");499      }500    }501502    /// <summary>503    /// Flushes the baseInputStream504    /// </summary>505    public override void Flush()  506    {507      // Protect against redundant calls - 1392508       if (inputBuffer.Available <= 0) { - 1391509        inputBuffer.Fill(); - 1391510         if (inputBuffer.Available <= 0) { - 0511          throw new SharpZipBaseException("Unexpected EOF");512        }513      } - 1392514      inputBuffer.SetInflaterInput(inf); - 1392515    }516517    #region Stream Overrides518    /// <summary>519    /// Gets a value indicating whether the current stream supports reading520    /// </summary>521    public override bool CanRead522    {523      get { - 9524        return baseInputStream.CanRead;525      }526    }527528    /// <summary>529    /// Gets a value of false indicating seeking is not supported for this stream.530    /// </summary>531    public override bool CanSeek {532      get { - 3533        return false;534      }535    }536537    /// <summary>538    /// Gets a value of false indicating that this stream is not writeable.539    /// </summary>540    public override bool CanWrite {541      get { - 0542        return false;543      }544    }545546    /// <summary>547    /// A value representing the length of the stream in bytes.548    /// </summary>549    public override long Length {550      get { - 0551        return inputBuffer.RawLength;552      }553    }554555    /// <summary>556    /// The current position within the stream.557    /// Throws a NotSupportedException when attempting to set the position558    /// </summary>559    /// <exception cref="NotSupportedException">Attempting to set the position</exception>560    public override long Position {561      get { - 0562        return baseInputStream.Position;563      }564      set { - 0565        throw new NotSupportedException("InflaterInputStream Position not supported");566      }567    }568569    /// <summary>570    /// Flushes the baseInputStream571    /// </summary>572    public override void Flush()573    { - 0574      baseInputStream.Flush(); - 0575    }576577    /// <summary>578    /// Sets the position within the current stream579    /// Always throws a NotSupportedException580    /// </summary>581    /// <param name="offset">The relative offset to seek to.</param>582    /// <param name="origin">The <see cref="SeekOrigin"/> defining where to seek from.</param>583    /// <returns>The new position in the stream.</returns>584    /// <exception cref="NotSupportedException">Any access</exception>585    public override long Seek(long offset, SeekOrigin origin)586    { - 0587      throw new NotSupportedException("Seek not supported");588    }589590    /// <summary>591    /// Set the length of the current stream592    /// Always throws a NotSupportedException593    /// </summary>594    /// <param name="value">The new length value for the stream.</param>595    /// <exception cref="NotSupportedException">Any access</exception>596    public override void SetLength(long value)597    { - 0598      throw new NotSupportedException("InflaterInputStream SetLength not supported");599    }600601    /// <summary>602    /// Writes a sequence of bytes to stream and advances the current position603    /// This method always throws a NotSupportedException604    /// </summary>605    /// <param name="buffer">Thew buffer containing data to write.</param>606    /// <param name="offset">The offset of the first byte to write.</param>607    /// <param name="count">The number of bytes to write.</param>608    /// <exception cref="NotSupportedException">Any access</exception>609    public override void Write(byte[] buffer, int offset, int count)610    { - 0611      throw new NotSupportedException("InflaterInputStream Write not supported");612    }613614    /// <summary>615    /// Writes one byte to the current stream and advances the current position616    /// Always throws a NotSupportedException617    /// </summary>618    /// <param name="value">The byte to write.</param>619    /// <exception cref="NotSupportedException">Any access</exception>620    public override void WriteByte(byte value)621    { - 0622      throw new NotSupportedException("InflaterInputStream WriteByte not supported");623    }624625    /// <summary>626    /// Entry point to begin an asynchronous write.  Always throws a NotSupportedException.627    /// </summary>628    /// <param name="buffer">The buffer to write data from</param>629    /// <param name="offset">Offset of first byte to write</param>630    /// <param name="count">The maximum number of bytes to write</param>631    /// <param name="callback">The method to be called when the asynchronous write operation is completed</param>632    /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from ot633    /// <returns>An <see cref="System.IAsyncResult">IAsyncResult</see> that references the asynchronous write</returns>634    /// <exception cref="NotSupportedException">Any access</exception>635    public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)636    { - 0637      throw new NotSupportedException("InflaterInputStream BeginWrite not supported");638    } + 0507      baseInputStream.Flush(); + 0508    }509510    /// <summary>511    /// Sets the position within the current stream512    /// Always throws a NotSupportedException513    /// </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    }522523    /// <summary>524    /// Set the length of the current stream525    /// Always throws a NotSupportedException526    /// </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    }533534    /// <summary>535    /// Writes a sequence of bytes to stream and advances the current position536    /// This method always throws a NotSupportedException537    /// </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    }546547    /// <summary>548    /// Writes one byte to the current stream and advances the current position549    /// Always throws a NotSupportedException550    /// </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    }557558    /// <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 ot566    /// <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    }572573    /// <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    }586587    /// <summary>588    /// Reads decompressed data into the provided buffer byte array589    /// </summary>590    /// <param name ="buffer">591    /// The array to read and decompress data into592    /// </param>593    /// <param name ="offset">594    /// The offset indicating where the data should be placed595    /// </param>596    /// <param name ="count">597    /// The number of bytes to decompress598    /// </param>599    /// <returns>The number of bytes read.  Zero signals the end of stream</returns>600    /// <exception cref="SharpZipBaseException">601    /// Inflater needs a dictionary602    /// </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    #endregion628629    #region Instance Fields630    /// <summary>631    /// Decompressor for this stream632    /// </summary>633    protected Inflater inf;634635    /// <summary>636    /// <see cref="InflaterInputBuffer">Input buffer</see> for this stream.637    /// </summary>638    protected InflaterInputBuffer inputBuffer;  639  640    /// <summary>641    /// Closes the input stream.  When <see cref="IsStreamOwner"></see>642    /// is true the underlying stream is also closed.643    /// </summary>644    public override void Close()645    { - 395646       if ( !isClosed ) { - 385647        isClosed = true; - 385648         if ( isStreamOwner ) { - 383649          baseInputStream.Close();650        }651      } - 395652    }653654    /// <summary>655    /// Reads decompressed data into the provided buffer byte array656    /// </summary>657    /// <param name ="buffer">658    /// The array to read and decompress data into659    /// </param>660    /// <param name ="offset">661    /// The offset indicating where the data should be placed662    /// </param>663    /// <param name ="count">664    /// The number of bytes to decompress665    /// </param>666    /// <returns>The number of bytes read.  Zero signals the end of stream</returns>667    /// <exception cref="SharpZipBaseException">668    /// Inflater needs a dictionary669    /// </exception>670    public override int Read(byte[] buffer, int offset, int count)671    { - 855672       if (inf.IsNeedingDictionary)673      { - 0674        throw new SharpZipBaseException("Need a dictionary");675      }676 - 855677      int remainingBytes = count;678      while (true) { - 2247679        int bytesRead = inf.Inflate(buffer, offset, remainingBytes); - 2247680        offset += bytesRead; - 2247681        remainingBytes -= bytesRead;682 - 2247683         if (remainingBytes == 0 || inf.IsFinished) {684          break;685        }686 - 1392687         if ( inf.IsNeedingInput ) { - 1392688          Fill(); - 1392689        } - 0690         else if ( bytesRead == 0 ) { - 0691          throw new ZipException("Dont know what to do");692        }693      } - 855694      return count - remainingBytes;695    }696    #endregion697698    #region Instance Fields699    /// <summary>700    /// Decompressor for this stream701    /// </summary>702    protected Inflater inf;703704    /// <summary>705    /// <see cref="InflaterInputBuffer">Input buffer</see> for this stream.706    /// </summary>707    protected InflaterInputBuffer inputBuffer;708709    /// <summary>710    /// Base stream the inflater reads from.711    /// </summary>712    private Stream baseInputStream;713714    /// <summary>715    /// The compressed size716    /// </summary>717    protected long csize;718719    /// <summary>720    /// Flag indicating wether this instance has been closed or not.721    /// </summary>722    bool isClosed;723724    /// <summary>725    /// Flag indicating wether this instance is designated the stream owner.726    /// When closing if this flag is true the underlying stream is closed.727    /// </summary> - 441728    bool isStreamOwner = true;729    #endregion730  }731}641    /// Base stream the inflater reads from.642    /// </summary>643    private Stream baseInputStream;644645    /// <summary>646    /// The compressed size647    /// </summary>648    protected long csize;649650    /// <summary>651    /// Flag indicating wether this instance has been closed or not.652    /// </summary>653    bool isClosed;654655    /// <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    #endregion661  }662} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_InvalidHeaderException.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_InvalidHeaderException.htm index 47252f573..6ff28f669 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_InvalidHeaderException.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_InvalidHeaderException.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:8 Coverable lines:8 -Total lines:109 +Total lines:51 Line coverage:0% @@ -37,117 +37,59 @@

#LineLine coverage - 1// InvalidHeaderException.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;3738#if !NETCF_1_0 && !NETCF_2_039using System.Runtime.Serialization;40#endif4142namespace ICSharpCode.SharpZipLib.Tar {4344  /// <summary>45  /// This exception is used to indicate that there is a problem46  /// with a TAR archive header.47  /// </summary>48#if !NETCF_1_0 && !NETCF_2_049  [Serializable]50#endif51  public class InvalidHeaderException : TarException52  {5354#if !NETCF_1_0 && !NETCF_2_055    /// <summary>56    /// Deserialization constructor57    /// </summary>58    /// <param name="information"><see cref="SerializationInfo"/> for this constructor</param>59    /// <param name="context"><see cref="StreamingContext"/> for this constructor</param>60    protected InvalidHeaderException(SerializationInfo information, StreamingContext context) - 061      : base(information, context)6263    { - 064    }65#endif6667    /// <summary>68    /// Initialise a new instance of the InvalidHeaderException class.69    /// </summary> - 070    public InvalidHeaderException()71    { - 072    }7374    /// <summary>75    /// Initialises a new instance of the InvalidHeaderException class with a specified message.76    /// </summary>77    /// <param name="message">Message describing the exception cause.</param>78    public InvalidHeaderException(string message) - 079      : base(message)80    { - 081    }8283    /// <summary>84    /// Initialise a new instance of InvalidHeaderException85    /// </summary>86    /// <param name="message">Message describing the problem.</param>87    /// <param name="exception">The exception that is the cause of the current exception.</param>88    public InvalidHeaderException(string message, Exception exception) - 089      : base(message, exception)90    { - 091    }92  }93}9495/* The original Java file had this header:96** Authored by Timothy Gerard Endres97** <mailto:time@gjt.org>  <http://www.trustice.com>98**99** This work has been placed into the public domain.100** You may use this work in any way and for any purpose you wish.101**102** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,103** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR104** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY105** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR106** REDISTRIBUTION OF THIS SOFTWARE.107**108*/1091using System;2using System.Runtime.Serialization;34namespace ICSharpCode.SharpZipLib.Tar5{6  /// <summary>7  /// This exception is used to indicate that there is a problem8  /// with a TAR archive header.9  /// </summary>10  [Serializable]11  public class InvalidHeaderException : TarException12  {1314    /// <summary>15    /// Deserialization constructor16    /// </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)2122    { + 023    }2425    /// <summary>26    /// Initialise a new instance of the InvalidHeaderException class.27    /// </summary> + 028    public InvalidHeaderException()29    { + 030    }3132    /// <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    }4041    /// <summary>42    /// Initialise a new instance of InvalidHeaderException43    /// </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/Documentation/opencover/ICSharpCode.SharpZipLib_KeysRequiredEventArgs.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_KeysRequiredEventArgs.htm index fae085340..89a27dd01 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_KeysRequiredEventArgs.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_KeysRequiredEventArgs.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:10 Coverable lines:10 -Total lines:4476 +Total lines:4263 Line coverage:0% @@ -35,4484 +35,4271 @@

#LineLine coverage - 1// ZipFile.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  2009-12-22  Z-1649  Added AES support41//  2010-03-02  Z-1650  Fixed updating ODT archives in memory. Exposed exceptions in updating.42//  2010-05-25  Z-1663  Fixed exception when testing local header compressed size of -143//  2012-11-29  Z-1684  Fixed ZipFile.Add(string fileName, string entryName) losing the file TimeStamp4445using System;46using System.Collections;47using System.IO;48using System.Text;49using System.Globalization;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;1213namespace ICSharpCode.SharpZipLib.Zip14{15  #region Keys Required Event Args16  /// <summary>17  /// Arguments used with KeysRequiredEvent18  /// </summary>19  public class KeysRequiredEventArgs : EventArgs20  {21    #region Constructors22    /// <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    }3031    /// <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    }4142    #endregion43    #region Properties44    /// <summary>45    /// Gets the name of the file for which keys are required.46    /// </summary>47    public string FileName { + 048      get { return fileName; }49    }  5051#if !NETCF_1_052using System.Security.Cryptography;53using ICSharpCode.SharpZipLib.Encryption;54#endif5556using ICSharpCode.SharpZipLib.Core;57using ICSharpCode.SharpZipLib.Checksums;58using ICSharpCode.SharpZipLib.Zip.Compression.Streams;59using ICSharpCode.SharpZipLib.Zip.Compression;6061namespace ICSharpCode.SharpZipLib.Zip62{63  #region Keys Required Event Args64  /// <summary>65  /// Arguments used with KeysRequiredEvent66  /// </summary>67  public class KeysRequiredEventArgs : EventArgs68  {69    #region Constructors70    /// <summary>71    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>72    /// </summary>73    /// <param name="name">The name of the file for which keys are required.</param> - 074    public KeysRequiredEventArgs(string name)75    { - 076      fileName = name; - 077    }7879    /// <summary>80    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>81    /// </summary>82    /// <param name="name">The name of the file for which keys are required.</param>83    /// <param name="keyValue">The current key value.</param> - 084    public KeysRequiredEventArgs(string name, byte[] keyValue)85    { - 086      fileName = name; - 087      key = keyValue; - 088    }8990    #endregion91    #region Properties92    /// <summary>93    /// Gets the name of the file for which keys are required.94    /// </summary>95    public string FileName96    { - 097      get { return fileName; }98    }99100    /// <summary>101    /// Gets or sets the key value102    /// </summary>103    public byte[] Key104    { - 0105      get { return key; } - 0106      set { key = value; }107    }108    #endregion109110    #region Instance Fields111    string fileName;112    byte[] key;113    #endregion114  }115  #endregion116117  #region Test Definitions118  /// <summary>119  /// The strategy to apply to testing.120  /// </summary>121  public enum TestStrategy122  {123    /// <summary>124    /// Find the first error only.125    /// </summary>126    FindFirstError,51    /// <summary>52    /// Gets or sets the key value53    /// </summary>54    public byte[] Key { + 055      get { return key; } + 056      set { key = value; }57    }58    #endregion5960    #region Instance Fields61    string fileName;62    byte[] key;63    #endregion64  }65  #endregion6667  #region Test Definitions68  /// <summary>69  /// The strategy to apply to testing.70  /// </summary>71  public enum TestStrategy72  {73    /// <summary>74    /// Find the first error only.75    /// </summary>76    FindFirstError,77    /// <summary>78    /// Find all possible errors.79    /// </summary>80    FindAllErrors,81  }8283  /// <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 TestOperation88  {89    /// <summary>90    /// Setting up testing.91    /// </summary>92    Initialising,9394    /// <summary>95    /// Testing an individual entries header96    /// </summary>97    EntryHeader,9899    /// <summary>100    /// Testing an individual entries data101    /// </summary>102    EntryData,103104    /// <summary>105    /// Testing an individual entry has completed.106    /// </summary>107    EntryComplete,108109    /// <summary>110    /// Running miscellaneous tests111    /// </summary>112    MiscellaneousTests,113114    /// <summary>115    /// Testing is complete116    /// </summary>117    Complete,118  }119120  /// <summary>121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.122  /// </summary>123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>124  public class TestStatus125  {126    #region Constructors  127    /// <summary>128    /// Find all possible errors.128    /// Initialise a new instance of <see cref="TestStatus"/>  129    /// </summary>130    FindAllErrors,131  }132133  /// <summary>134  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.135  /// </summary>136  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>137  public enum TestOperation138  {130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>131    public TestStatus(ZipFile file)132    {133      file_ = file;134    }135    #endregion136137    #region Properties138  139    /// <summary>140    /// Setting up testing.140    /// Get the current <see cref="TestOperation"/> in progress.  141    /// </summary>142    Initialising,143144    /// <summary>145    /// Testing an individual entries header146    /// </summary>147    EntryHeader,148149    /// <summary>150    /// Testing an individual entries data151    /// </summary>152    EntryData,153154    /// <summary>155    /// Testing an individual entry has completed.156    /// </summary>157    EntryComplete,158159    /// <summary>160    /// Running miscellaneous tests161    /// </summary>162    MiscellaneousTests,163164    /// <summary>165    /// Testing is complete166    /// </summary>167    Complete,168  }169170  /// <summary>171  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.172  /// </summary>173  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>174  public class TestStatus175  {176    #region Constructors177    /// <summary>178    /// Initialise a new instance of <see cref="TestStatus"/>179    /// </summary>180    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>181    public TestStatus(ZipFile file)182    {183      file_ = file;184    }185    #endregion186187    #region Properties142    public TestOperation Operation {143      get { return operation_; }144    }145146    /// <summary>147    /// Get the <see cref="ZipFile"/> this status is applicable to.148    /// </summary>149    public ZipFile File {150      get { return file_; }151    }152153    /// <summary>154    /// Get the current/last entry tested.155    /// </summary>156    public ZipEntry Entry {157      get { return entry_; }158    }159160    /// <summary>161    /// Get the number of errors detected so far.162    /// </summary>163    public int ErrorCount {164      get { return errorCount_; }165    }166167    /// <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    }173174    /// <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    #endregion181182    #region Internal API183    internal void AddError()184    {185      errorCount_++;186      entryValid_ = false;187    }  188189    /// <summary>190    /// Get the current <see cref="TestOperation"/> in progress.191    /// </summary>192    public TestOperation Operation193    {194      get { return operation_; }195    }196197    /// <summary>198    /// Get the <see cref="ZipFile"/> this status is applicable to.199    /// </summary>200    public ZipFile File201    {202      get { return file_; }203    }204205    /// <summary>206    /// Get the current/last entry tested.207    /// </summary>208    public ZipEntry Entry209    {210      get { return entry_; }211    }212213    /// <summary>214    /// Get the number of errors detected so far.215    /// </summary>216    public int ErrorCount217    {218      get { return errorCount_; }219    }220221    /// <summary>222    /// Get the number of bytes tested so far for the current entry.223    /// </summary>224    public long BytesTested225    {226      get { return bytesTested_; }227    }228229    /// <summary>230    /// Get a value indicating wether the last entry test was valid.231    /// </summary>232    public bool EntryValid233    {234      get { return entryValid_; }235    }236    #endregion237238    #region Internal API239    internal void AddError()240    {241      errorCount_++;242      entryValid_ = false;243    }244245    internal void SetOperation(TestOperation operation)246    {247      operation_ = operation;248    }249250    internal void SetEntry(ZipEntry entry)251    {252      entry_ = entry;253      entryValid_ = true;254      bytesTested_ = 0;255    }256257    internal void SetBytesTested(long value)258    {259      bytesTested_ = value;260    }261    #endregion262263    #region Instance Fields264    ZipFile file_;265    ZipEntry entry_;266    bool entryValid_;267    int errorCount_;268    long bytesTested_;269    TestOperation operation_;270    #endregion271  }272273  /// <summary>274  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if275  /// </summary>276  /// <remarks>If the message is non-null an error has occured.  If the message is null277  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>278  public delegate void ZipTestResultHandler(TestStatus status, string message);279  #endregion280281  #region Update Definitions282  /// <summary>283  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.284  /// </summary>285  public enum FileUpdateMode286  {287    /// <summary>288    /// Perform all updates on temporary files ensuring that the original file is saved.289    /// </summary>290    Safe,291    /// <summary>292    /// Update the archive directly, which is faster but less safe.293    /// </summary>294    Direct,295  }296  #endregion189    internal void SetOperation(TestOperation operation)190    {191      operation_ = operation;192    }193194    internal void SetEntry(ZipEntry entry)195    {196      entry_ = entry;197      entryValid_ = true;198      bytesTested_ = 0;199    }200201    internal void SetBytesTested(long value)202    {203      bytesTested_ = value;204    }205    #endregion206207    #region Instance Fields208    ZipFile file_;209    ZipEntry entry_;210    bool entryValid_;211    int errorCount_;212    long bytesTested_;213    TestOperation operation_;214    #endregion215  }216217  /// <summary>218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if219  /// </summary>220  /// <remarks>If the message is non-null an error has occured.  If the message is null221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>222  public delegate void ZipTestResultHandler(TestStatus status, string message);223  #endregion224225  #region Update Definitions226  /// <summary>227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.228  /// </summary>229  public enum FileUpdateMode230  {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  #endregion241242  #region ZipFile Class243  /// <summary>244  /// This class represents a Zip archive.  You can ask for the contained245  /// entries, or get an input stream for a file entry.  The entry is246  /// 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 arbitrary251  /// entries in different threads.252  /// <br/>253  /// <br/>Author of the original java version : Jochen Hoenicke254  /// </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 MainClass265  /// {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, IDisposable287  {288    #region KeyHandling289290    /// <summary>291    /// Delegate for handling keys/password setting during compresion/decompression.292    /// </summary>293    public delegate void KeysRequiredEventHandler(294      object sender,295      KeysRequiredEventArgs e296    );  297298  #region ZipFile Class299  /// <summary>300  /// This class represents a Zip archive.  You can ask for the contained301  /// entries, or get an input stream for a file entry.  The entry is302  /// automatically decompressed.303  ///304  /// You can also update the archive adding or deleting entries.305  ///306  /// This class is thread safe for input:  You can open input streams for arbitrary307  /// entries in different threads.308  /// <br/>309  /// <br/>Author of the original java version : Jochen Hoenicke310  /// </summary>311  /// <example>312  /// <code>313  /// using System;314  /// using System.Text;315  /// using System.Collections;316  /// using System.IO;317  ///318  /// using ICSharpCode.SharpZipLib.Zip;319  ///320  /// class MainClass321  /// {322  ///   static public void Main(string[] args)323  ///   {324  ///     using (ZipFile zFile = new ZipFile(args[0])) {325  ///       Console.WriteLine("Listing of : " + zFile.Name);326  ///       Console.WriteLine("");327  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");328  ///       Console.WriteLine("--------  --------  --------  ------  ---------");329  ///       foreach (ZipEntry e in zFile) {330  ///         if ( e.IsFile ) {331  ///           DateTime d = e.DateTime;332  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,333  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),334  ///             e.Name);335  ///         }336  ///       }337  ///     }338  ///   }339  /// }340  /// </code>341  /// </example>342  public class ZipFile : IEnumerable, IDisposable343  {344    #region KeyHandling345346    /// <summary>347    /// Delegate for handling keys/password setting during compresion/decompression.348    /// </summary>349    public delegate void KeysRequiredEventHandler(350      object sender,351      KeysRequiredEventArgs e352    );353354    /// <summary>355    /// Event handler for handling encryption keys.356    /// </summary>357    public KeysRequiredEventHandler KeysRequired;358359    /// <summary>360    /// Handles getting of encryption keys when required.361    /// </summary>362    /// <param name="fileName">The file for which encryption keys are required.</param>363    void OnKeysRequired(string fileName)364    {365      if (KeysRequired != null) {366        var krea = new KeysRequiredEventArgs(fileName, key);367        KeysRequired(this, krea);368        key = krea.Key;369      }370    }371372    /// <summary>373    /// Get/set the encryption key value.374    /// </summary>375    byte[] Key376    {377      get { return key; }378      set { key = value; }379    }380381#if !NETCF_1_0382    /// <summary>383    /// Password to be used for encrypting/decrypting files.384    /// </summary>385    /// <remarks>Set to null if no password is required.</remarks>386    public string Password387    {388      set389      {390        if ( string.IsNullOrEmpty(value)) {391          key = null;392        }393        else {394          rawPassword_ = value;395          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));396        }298    /// <summary>299    /// Event handler for handling encryption keys.300    /// </summary>301    public KeysRequiredEventHandler KeysRequired;302303    /// <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    }315316    /// <summary>317    /// Get/set the encryption key value.318    /// </summary>319    byte[] Key {320      get { return key; }321      set { key = value; }322    }323324    /// <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    }338339    /// <summary>340    /// Get a value indicating wether encryption keys are currently available.341    /// </summary>342    bool HaveKeys {343      get { return key != null; }344    }345    #endregion346347    #region Constructors348    /// <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 occurs355    /// </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      }364365      name_ = name;366367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);368      isStreamOwner = true;369370      try {371        ReadEntries();372      } catch {373        DisposeInternal(true);374        throw;375      }376    }377378    /// <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      }394395      if (!file.CanSeek) {396        throw new ArgumentException("Stream is not seekable", nameof(file));  397      }398    }399#endif400401    /// <summary>402    /// Get a value indicating wether encryption keys are currently available.403    /// </summary>404    bool HaveKeys405    {406      get { return key != null; }407    }408    #endregion409410    #region Constructors398399      baseStream_ = file;400      name_ = file.Name;401      isStreamOwner = true;402403      try {404        ReadEntries();405      } catch {406        DisposeInternal(true);407        throw;408      }409    }410  411    /// <summary>412    /// Opens a Zip file with the given name for reading.412    /// Opens a Zip file reading the given <see cref="Stream"/>.  413    /// </summary>414    /// <param name="name">The name of the file to open.</param>415    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>416    /// <exception cref="IOException">417    /// An i/o error occurs418    /// </exception>419    /// <exception cref="ZipException">420    /// The file doesn't contain a valid zip archive.421    /// </exception>422    public ZipFile(string name)423    {424      if ( name == null ) {425        throw new ArgumentNullException(nameof(name));426      }427428      name_ = name;429430      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);431      isStreamOwner = true;414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>415    /// <exception cref="IOException">416    /// An i/o error occurs417    /// </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      }  432433      try {434        ReadEntries();433      if (!stream.CanSeek) {434        throw new ArgumentException("Stream is not seekable", nameof(stream));  435      }436      catch {437        DisposeInternal(true);438        throw;439      }440    }441442    /// <summary>443    /// Opens a Zip file reading the given <see cref="FileStream"/>.444    /// </summary>445    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>446    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>447    /// <exception cref="IOException">448    /// An i/o error occurs.449    /// </exception>450    /// <exception cref="ZipException">451    /// The file doesn't contain a valid zip archive.452    /// </exception>453    public ZipFile(FileStream file)454    {455      if ( file == null ) {456        throw new ArgumentNullException(nameof(file));457      }458459      if ( !file.CanSeek ) {460        throw new ArgumentException("Stream is not seekable", nameof(file));461      }462463      baseStream_  = file;464      name_ = file.Name;465      isStreamOwner = true;466467      try {468        ReadEntries();469      }470      catch {471        DisposeInternal(true);472        throw;473      }474    }475476    /// <summary>477    /// Opens a Zip file reading the given <see cref="Stream"/>.478    /// </summary>479    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>480    /// <exception cref="IOException">481    /// An i/o error occurs482    /// </exception>483    /// <exception cref="ZipException">484    /// The stream doesn't contain a valid zip archive.<br/>485    /// </exception>486    /// <exception cref="ArgumentException">487    /// The <see cref="Stream">stream</see> doesnt support seeking.488    /// </exception>489    /// <exception cref="ArgumentNullException">490    /// The <see cref="Stream">stream</see> argument is null.491    /// </exception>492    public ZipFile(Stream stream)493    {494      if ( stream == null ) {495        throw new ArgumentNullException(nameof(stream));496      }497498      if ( !stream.CanSeek ) {499        throw new ArgumentException("Stream is not seekable", nameof(stream));500      }501502      baseStream_  = stream;503      isStreamOwner = true;504505      if ( baseStream_.Length > 0 ) {506        try {507          ReadEntries();508        }509        catch {510          DisposeInternal(true);511          throw;512        }513      } else {514        entries_ = new ZipEntry[0];515        isNewArchive_ = true;516      }517    }518519    /// <summary>520    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.521    /// </summary>522    internal ZipFile()523    {524      entries_ = new ZipEntry[0];525      isNewArchive_ = true;526    }527528    #endregion529530    #region Destructors and Closing531    /// <summary>532    /// Finalize this instance.533    /// </summary>534    ~ZipFile()535    {536      Dispose(false);537    }538436437      baseStream_ = stream;438      isStreamOwner = true;439440      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    }452453    /// <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    }461462    #endregion463464    #region Destructors and Closing465    /// <summary>466    /// Finalize this instance.467    /// </summary>468    ~ZipFile()469    {470      Dispose(false);471    }472473    /// <summary>474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying475    /// 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    }485486    #endregion487488    #region Creators489    /// <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      }500501      FileStream fs = File.Create(fileName);502503      var result = new ZipFile();504      result.name_ = fileName;505      result.baseStream_ = fs;506      result.isStreamOwner = true;507      return result;508    }509510    /// <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      }522523      if (!outStream.CanWrite) {524        throw new ArgumentException("Stream is not writeable", nameof(outStream));525      }526527      if (!outStream.CanSeek) {528        throw new ArgumentException("Stream is not seekable", nameof(outStream));529      }530531      var result = new ZipFile();532      result.baseStream_ = outStream;533      return result;534    }535536    #endregion537538    #region Properties  539    /// <summary>540    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying541    /// Once closed, no further instance methods should be called.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    /// <exception cref="System.IO.IOException">544    /// An i/o error occurs.545    /// </exception>546    public void Close()547    {548      DisposeInternal(true);549      GC.SuppressFinalize(this);550    }551552    #endregion553554    #region Creators555    /// <summary>556    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.557    /// </summary>558    /// <param name="fileName">The name of the archive to create.</param>559    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>560    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>561    public static ZipFile Create(string fileName)562    {563      if ( fileName == null ) {564        throw new ArgumentNullException(nameof(fileName));565      }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    }550551    /// <summary>552    /// Get a value indicating wether553    /// this archive is embedded in another file or not.554    /// </summary>555    public bool IsEmbeddedArchive {556      // Not strictly correct in all circumstances currently557      get { return offsetOfFirstEntry > 0; }558    }559560    /// <summary>561    /// Get a value indicating that this archive is a new one.562    /// </summary>563    public bool IsNewArchive {564      get { return isNewArchive_; }565    }  566567      FileStream fs = File.Create(fileName);568569      var result = new ZipFile();570      result.name_ = fileName;571      result.baseStream_ = fs;572      result.isStreamOwner = true;573      return result;574    }575576    /// <summary>577    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.578    /// </summary>579    /// <param name="outStream">The stream providing data storage.</param>580    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>581    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>582    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>583    public static ZipFile Create(Stream outStream)584    {585      if ( outStream == null ) {586        throw new ArgumentNullException(nameof(outStream));587      }588589      if ( !outStream.CanWrite ) {590        throw new ArgumentException("Stream is not writeable", nameof(outStream));567    /// <summary>568    /// Gets the comment for the zip file.569    /// </summary>570    public string ZipFileComment {571      get { return comment_; }572    }573574    /// <summary>575    /// Gets the name of this zip file.576    /// </summary>577    public string Name {578      get { return name_; }579    }580581    /// <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      }592593      if ( !outStream.CanSeek ) {594        throw new ArgumentException("Stream is not seekable", nameof(outStream));595      }596597      var result = new ZipFile();598      result.baseStream_ = outStream;599      return result;600    }601602    #endregion603604    #region Properties605    /// <summary>606    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.607    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.608    /// </summary>609    /// <remarks>610    /// The default value is true in all cases.611    /// </remarks>612    public bool IsStreamOwner613    {614      get { return isStreamOwner; }615      set { isStreamOwner = value; }616    }617618    /// <summary>619    /// Get a value indicating wether620    /// this archive is embedded in another file or not.621    /// </summary>622    public bool IsEmbeddedArchive623    {624      // Not strictly correct in all circumstances currently625      get { return offsetOfFirstEntry > 0; }626    }627628    /// <summary>629    /// Get a value indicating that this archive is a new one.630    /// </summary>631    public bool IsNewArchive632    {633      get { return isNewArchive_; }634    }635636    /// <summary>637    /// Gets the comment for the zip file.638    /// </summary>639    public string ZipFileComment640    {641      get { return comment_; }642    }643644    /// <summary>645    /// Gets the name of this zip file.646    /// </summary>647    public string Name648    {649      get { return name_; }650    }651652    /// <summary>653    /// Gets the number of entries in this zip file.654    /// </summary>655    /// <exception cref="InvalidOperationException">656    /// The Zip file has been closed.657    /// </exception>658    [Obsolete("Use the Count property instead")]659    public int Size660    {661      get662      {663        return entries_.Length;664      }665    }666667    /// <summary>668    /// Get the number of entries contained in this <see cref="ZipFile"/>.669    /// </summary>670    public long Count671    {672      get673      {674        return entries_.Length;675      }676    }677678    /// <summary>679    /// Indexer property for ZipEntries680    /// </summary>681    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]682    public ZipEntry this[int index]683    {684      get {685        return (ZipEntry) entries_[index].Clone();686      }687    }688689    #endregion690691    #region Input Handling692    /// <summary>693    /// Gets an enumerator for the Zip entries in this Zip file.694    /// </summary>695    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>696    /// <exception cref="ObjectDisposedException">697    /// The Zip file has been closed.698    /// </exception>699    public IEnumerator GetEnumerator()700    {701      if (isDisposed_) {702        throw new ObjectDisposedException("ZipFile");703      }704705      return new ZipEntryEnumerator(entries_);706    }707708    /// <summary>709    /// Return the index of the entry with a matching name710    /// </summary>711    /// <param name="name">Entry name to find</param>712    /// <param name="ignoreCase">If true the comparison is case insensitive</param>713    /// <returns>The index position of the matching entry or -1 if not found</returns>714    /// <exception cref="ObjectDisposedException">715    /// The Zip file has been closed.716    /// </exception>717    public int FindEntry(string name, bool ignoreCase)718    {719      if (isDisposed_) {720        throw new ObjectDisposedException("ZipFile");721      }722723      // TODO: This will be slow as the next ice age for huge archives!724      for (int i = 0; i < entries_.Length; i++) {725        if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {726          return i;727        }728      }729      return -1;730    }731732    /// <summary>733    /// Searches for a zip entry in this archive with the given name.734    /// String comparisons are case insensitive735    /// </summary>736    /// <param name="name">737    /// The name to find. May contain directory components separated by slashes ('/').738    /// </param>739    /// <returns>740    /// A clone of the zip entry, or null if no entry with that name exists.741    /// </returns>742    /// <exception cref="ObjectDisposedException">743    /// The Zip file has been closed.744    /// </exception>745    public ZipEntry GetEntry(string name)746    {747      if (isDisposed_) {748        throw new ObjectDisposedException("ZipFile");749      }750751      int index = FindEntry(name, true);752      return (index >= 0) ? (ZipEntry) entries_[index].Clone() : null;753    }754755    /// <summary>756    /// Gets an input stream for reading the given zip entry data in an uncompressed form.757    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().758    /// </summary>759    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>760    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>761    /// <exception cref="ObjectDisposedException">762    /// The ZipFile has already been closed763    /// </exception>764    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">765    /// The compression method for the entry is unknown766    /// </exception>767    /// <exception cref="IndexOutOfRangeException">768    /// The entry is not found in the ZipFile769    /// </exception>770    public Stream GetInputStream(ZipEntry entry)771    {772      if ( entry == null ) {773        throw new ArgumentNullException(nameof(entry));774      }775776      if ( isDisposed_ ) {777        throw new ObjectDisposedException("ZipFile");778      }779780      long index = entry.ZipFileIndex;781      if ( (index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name) ) {782        index = FindEntry(entry.Name, true);783        if (index < 0) {784          throw new ZipException("Entry cannot be found");785        }786      }787      return GetInputStream(index);788    }789790    /// <summary>791    /// Creates an input stream reading a zip entry792    /// </summary>793    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>794    /// <returns>795    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>796    /// </returns>797    /// <exception cref="ObjectDisposedException">798    /// The ZipFile has already been closed799    /// </exception>800    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">801    /// The compression method for the entry is unknown802    /// </exception>803    /// <exception cref="IndexOutOfRangeException">804    /// The entry is not found in the ZipFile805    /// </exception>806    public Stream GetInputStream(long entryIndex)807    {808      if ( isDisposed_ ) {809        throw new ObjectDisposedException("ZipFile");810      }592    }593594    /// <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    }602603    /// <summary>604    /// Indexer property for ZipEntries605    /// </summary>606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]607    public ZipEntry this[int index] {608      get {609        return (ZipEntry)entries_[index].Clone();610      }611    }612613    #endregion614615    #region Input Handling616    /// <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      }628629      return new ZipEntryEnumerator(entries_);630    }631632    /// <summary>633    /// Return the index of the entry with a matching name634    /// </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      }646647      // 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    }655656    /// <summary>657    /// Searches for a zip entry in this archive with the given name.658    /// String comparisons are case insensitive659    /// </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      }674675      int index = FindEntry(name, true);676      return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;677    }678679    /// <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 closed687    /// </exception>688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">689    /// The compression method for the entry is unknown690    /// </exception>691    /// <exception cref="IndexOutOfRangeException">692    /// The entry is not found in the ZipFile693    /// </exception>694    public Stream GetInputStream(ZipEntry entry)695    {696      if (entry == null) {697        throw new ArgumentNullException(nameof(entry));698      }699700      if (isDisposed_) {701        throw new ObjectDisposedException("ZipFile");702      }703704      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    }713714    /// <summary>715    /// Creates an input stream reading a zip entry716    /// </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 closed723    /// </exception>724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">725    /// The compression method for the entry is unknown726    /// </exception>727    /// <exception cref="IndexOutOfRangeException">728    /// The entry is not found in the ZipFile729    /// </exception>730    public Stream GetInputStream(long entryIndex)731    {732      if (isDisposed_) {733        throw new ObjectDisposedException("ZipFile");734      }735736      long start = LocateEntry(entries_[entryIndex]);737      CompressionMethod method = entries_[entryIndex].CompressionMethod;738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);739740      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      }746747      switch (method) {748        case CompressionMethod.Stored:749          // read as is.750          break;751752        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;756757        default:758          throw new ZipException("Unsupported compression method " + method);759      }760761      return result;762    }763764    #endregion765766    #region Archive Testing767    /// <summary>768    /// Test an archive for integrity/validity769    /// </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    }777778    /// <summary>779    /// Test an archive for integrity/validity780    /// </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      }791792      var status = new TestStatus(this);793794      if (resultHandler != null) {795        resultHandler(status, null);796      }797798      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;799800      bool testing = true;801802      try {803        int entryIndex = 0;804805        while (testing && (entryIndex < Count)) {806          if (resultHandler != null) {807            status.SetEntry(this[entryIndex]);808            status.SetOperation(TestOperation.EntryHeader);809            resultHandler(status, null);810          }  811812      long start = LocateEntry(entries_[entryIndex]);813      CompressionMethod method = entries_[entryIndex].CompressionMethod;814      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);815816      if (entries_[entryIndex].IsCrypted == true) {817#if NETCF_1_0818        throw new ZipException("decryption not supported for Compact Framework 1.0");819#else820        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);821        if (result == null) {822          throw new ZipException("Unable to decrypt this entry");823        }824#endif825      }826827      switch (method) {828        case CompressionMethod.Stored:829          // read as is.830          break;831832        case CompressionMethod.Deflated:833          // No need to worry about ownership and closing as underlying stream close does nothing.834          result = new InflaterInputStream(result, new Inflater(true));835          break;836837        default:838          throw new ZipException("Unsupported compression method " + method);839      }812          try {813            TestLocalHeader(this[entryIndex], test);814          } catch (ZipException ex) {815            status.AddError();816817            if (resultHandler != null) {818              resultHandler(status,819                string.Format("Exception during test - '{0}'", ex.Message));820            }821822            testing &= strategy != TestStrategy.FindFirstError;823          }824825          if (testing && testData && this[entryIndex].IsFile) {826            if (resultHandler != null) {827              status.SetOperation(TestOperation.EntryData);828              resultHandler(status, null);829            }830831            var crc = new Crc32();832833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {834835              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);  840841      return result;842    }843844    #endregion845846    #region Archive Testing847    /// <summary>848    /// Test an archive for integrity/validity849    /// </summary>850    /// <param name="testData">Perform low level data Crc check</param>851    /// <returns>true if all tests pass, false otherwise</returns>852    /// <remarks>Testing will terminate on the first error found.</remarks>853    public bool TestArchive(bool testData)854    {855      return TestArchive(testData, TestStrategy.FindFirstError, null);856    }857858    /// <summary>859    /// Test an archive for integrity/validity860    /// </summary>861    /// <param name="testData">Perform low level data Crc check</param>862    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>863    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>864    /// <returns>true if all tests pass, false otherwise</returns>865    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>866    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)867    {868      if (isDisposed_) {869        throw new ObjectDisposedException("ZipFile");870      }871872      var status = new TestStatus(this);873874      if ( resultHandler != null ) {875        resultHandler(status, null);876      }877878      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;879880      bool testing = true;841                if (resultHandler != null) {842                  totalBytes += bytesRead;843                  status.SetBytesTested(totalBytes);844                  resultHandler(status, null);845                }846              }847            }848849            if (this[entryIndex].Crc != crc.Value) {850              status.AddError();851852              if (resultHandler != null) {853                resultHandler(status, "CRC mismatch");854              }855856              testing &= strategy != TestStrategy.FindFirstError;857            }858859            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              }866867              if (this[entryIndex].CompressedSize != data.CompressedSize) {868                status.AddError();869              }870871              if (this[entryIndex].Size != data.Size) {872                status.AddError();873              }874            }875          }876877          if (resultHandler != null) {878            status.SetOperation(TestOperation.EntryComplete);879            resultHandler(status, null);880          }  881882      try {883        int entryIndex = 0;882          entryIndex += 1;883        }  884885        while ( testing && (entryIndex < Count) ) {886          if ( resultHandler != null ) {887            status.SetEntry(this[entryIndex]);888            status.SetOperation(TestOperation.EntryHeader);889            resultHandler(status, null);890          }891892          try  {893            TestLocalHeader(this[entryIndex], test);894          }895          catch(ZipException ex) {896            status.AddError();897898            if ( resultHandler != null ) {899              resultHandler(status,900                string.Format("Exception during test - '{0}'", ex.Message));901            }902903            testing &= strategy != TestStrategy.FindFirstError;904          }885        if (resultHandler != null) {886          status.SetOperation(TestOperation.MiscellaneousTests);887          resultHandler(status, null);888        }889890        // TODO: the 'Corrina Johns' test where local headers are missing from891        // the central directory.  They are therefore invisible to many archivers.892      } catch (Exception ex) {893        status.AddError();894895        if (resultHandler != null) {896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));897        }898      }899900      if (resultHandler != null) {901        status.SetOperation(TestOperation.Complete);902        status.SetEntry(null);903        resultHandler(status, null);904      }  905906          if ( testing && testData && this[entryIndex].IsFile ) {907            if ( resultHandler != null ) {908              status.SetOperation(TestOperation.EntryData);909              resultHandler(status, null);910            }911912                        var crc = new Crc32();913914                        using (Stream entryStream = this.GetInputStream(this[entryIndex]))915                        {916917                            byte[] buffer = new byte[4096];918                            long totalBytes = 0;919                            int bytesRead;920                            while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0)921                            {922                                crc.Update(buffer, 0, bytesRead);923924                                if (resultHandler != null)925                                {926                                    totalBytes += bytesRead;927                                    status.SetBytesTested(totalBytes);928                                    resultHandler(status, null);929                                }930                            }931                        }932933            if (this[entryIndex].Crc != crc.Value) {934              status.AddError();935936              if ( resultHandler != null ) {937                resultHandler(status, "CRC mismatch");938              }939940              testing &= strategy != TestStrategy.FindFirstError;941            }942943            if (( this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0 ) {944              var helper = new ZipHelperStream(baseStream_);945              var data = new DescriptorData();946              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);947              if (this[entryIndex].Crc != data.Crc) {948                status.AddError();949              }950951              if (this[entryIndex].CompressedSize != data.CompressedSize) {952                status.AddError();953              }954955              if (this[entryIndex].Size != data.Size) {956                status.AddError();957              }958            }959          }960961          if ( resultHandler != null ) {962            status.SetOperation(TestOperation.EntryComplete);963            resultHandler(status, null);964          }965966          entryIndex += 1;967        }968969        if ( resultHandler != null ) {970          status.SetOperation(TestOperation.MiscellaneousTests);971          resultHandler(status, null);972        }973974        // TODO: the 'Corrina Johns' test where local headers are missing from975        // the central directory.  They are therefore invisible to many archivers.976      }977      catch (Exception ex) {978        status.AddError();906      return (status.ErrorCount == 0);907    }908909    [Flags]910    enum HeaderTest911    {912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted913      Header = 0x02,     // Check that this header contents are valid914    }915916    /// <summary>917    /// Test a local header against that provided from the central directory918    /// </summary>919    /// <param name="entry">920    /// The entry to test against921    /// </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;929930        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        }934935        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();945946        byte[] nameData = new byte[storedNameLength];947        StreamUtils.ReadFully(baseStream_, nameData);948949        byte[] extraData = new byte[extraDataLength];950        StreamUtils.ReadFully(baseStream_, extraData);951952        var localExtraData = new ZipExtraData(extraData);953954        // Extra data / zip64 checks955        if (localExtraData.Find(1)) {956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64957          // and size or compressedSize = MaxValue, due to rogue creators.958959          size = localExtraData.ReadLong();960          compressedSize = localExtraData.ReadLong();961962          if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {963            // These may be valid if patched later964            if ((size != -1) && (size != entry.Size)) {965              throw new ZipException("Size invalid for descriptor");966            }967968            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        }  979980        if ( resultHandler != null ) {981          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));982        }983      }984985      if ( resultHandler != null ) {986        status.SetOperation(TestOperation.Complete);987        status.SetEntry(null);988        resultHandler(status, null);989      }980        if (testData) {981          if (entry.IsFile) {982            if (!entry.IsCompressionMethodSupported()) {983              throw new ZipException("Compression method not supported");984            }985986            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})", extract989            }  990991      return (status.ErrorCount == 0);992    }993994    [Flags]995    enum HeaderTest996    {997      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted998      Header  = 0x02,     // Check that this header contents are valid999    }10001001    /// <summary>1002    /// Test a local header against that provided from the central directory1003    /// </summary>1004    /// <param name="entry">1005    /// The entry to test against1006    /// </param>1007    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>1008    /// <returns>The offset of the entries data in the file</returns>1009    long TestLocalHeader(ZipEntry entry, HeaderTest tests)1010    {1011      lock(baseStream_)1012      {1013        bool testHeader = (tests & HeaderTest.Header) != 0;1014        bool testData = (tests & HeaderTest.Extract) != 0;10151016        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);1017        if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {1018          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)1019        }10201021        var extractVersion = ( short ) (ReadLEUshort() & 0x00ff);1022        var localFlags = ( short )ReadLEUshort();1023        var compressionMethod = ( short )ReadLEUshort();1024        var fileTime = ( short )ReadLEUshort();1025        var fileDate = ( short )ReadLEUshort();1026        uint crcValue = ReadLEUint();1027        long compressedSize = ReadLEUint();1028        long size = ReadLEUint();1029        int storedNameLength = ReadLEUshort();1030        int extraDataLength = ReadLEUshort();10311032        byte[] nameData = new byte[storedNameLength];1033        StreamUtils.ReadFully(baseStream_, nameData);10341035        byte[] extraData = new byte[extraDataLength];1036        StreamUtils.ReadFully(baseStream_, extraData);991            if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance992              throw new ZipException("The library does not support the zip version required to extract this entry");993            }994          }995        }996997        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})", extractVersi1015          }10161017          // Local entry flags dont have reserved bit set on.1018          if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R1019            throw new ZipException("Reserved bit flags cannot be set.");1020          }10211022          // Encryption requires extract version >= 201023          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          }10261027          // 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            }10321033            if (extractVersion < 50) {1034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({01035            }1036          }  10371038        var localExtraData = new ZipExtraData(extraData);10391040        // Extra data / zip64 checks1041        if (localExtraData.Find(1))1042        {1043          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip641044          // and size or compressedSize = MaxValue, due to rogue creators.10451046          size = localExtraData.ReadLong();1047          compressedSize = localExtraData.ReadLong();10481049                    if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0)1050                    {1051                        // These may be valid if patched later1052                        if ( (size != -1) && (size != entry.Size)) {1053                            throw new ZipException("Size invalid for descriptor");1054                        }10551056                        if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {1057                            throw new ZipException("Compressed size invalid for descriptor");1058                        }1059                    }1060                }1061        else1062        {1063          // No zip64 extra data but entry requires it.1064          if ((extractVersion >= ZipConstants.VersionZip64) &&1065            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue)))1066          {1067            throw new ZipException("Required Zip64 extended information missing");1038          // Patched entries require extract version >= 271039          if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {1040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));1041          }10421043          // Central header flags match local entry flags.1044          if (localFlags != entry.Flags) {1045            throw new ZipException("Central header/local header flags mismatch");1046          }10471048          // Central header compression method matches local entry1049          if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {1050            throw new ZipException("Central header/local header compression method mismatch");1051          }10521053          if (entry.Version != extractVersion) {1054            throw new ZipException("Extract version mismatch");1055          }10561057          // Strong encryption and extract version match1058          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          }10631064          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        }10701071        if ( testData ) {1072          if ( entry.IsFile ) {1073            if ( !entry.IsCompressionMethodSupported() ) {1074              throw new ZipException("Compression method not supported");1075            }10761077            if ( (extractVersion > ZipConstants.VersionMadeBy)1078              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)) ) {1079              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract1080            }10811082            if ( (localFlags & ( int )(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enha1083              throw new ZipException("The library does not support the zip version required to extract this entry");1084            }1085          }1086        }10871088                if (testHeader)1089                {1090                    if ((extractVersion <= 63) &&  // Ignore later versions as we dont know about them..1091                        (extractVersion != 10) &&1092                        (extractVersion != 11) &&1093                        (extractVersion != 20) &&1094                        (extractVersion != 21) &&1095                        (extractVersion != 25) &&1096                        (extractVersion != 27) &&1097                        (extractVersion != 45) &&1098                        (extractVersion != 46) &&1099                        (extractVersion != 50) &&1100                        (extractVersion != 51) &&1101                        (extractVersion != 52) &&1102                        (extractVersion != 61) &&1103                        (extractVersion != 62) &&1104                        (extractVersion != 63)1105                        )1106                    {1107                        throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", 1108                    }11091110                    // Local entry flags dont have reserved bit set on.1111                    if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | General1112                    {1113                        throw new ZipException("Reserved bit flags cannot be set.");1114                    }11151116                    // Encryption requires extract version >= 201117                    if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20))1118                    {1119                        throw new ZipException(string.Format("Version required to extract this entry is too low for encr1120                    }11211122                    // Strong encryption requires encryption flag to be set and extract version >= 50.1123                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1124                    {1125                        if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0)1126                        {1127                            throw new ZipException("Strong encryption flag set but encryption flag is not set");1128                        }10691070          if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {1071            if (crcValue != (uint)entry.Crc) {1072              throw new ZipException("Central header/local header crc mismatch");1073            }1074          }10751076          // Crc valid for empty entry.1077          // This will also apply to streamed entries where size isnt known and the header cant be patched1078          if ((size == 0) && (compressedSize == 0)) {1079            if (crcValue != 0) {1080              throw new ZipException("Invalid CRC for empty entry");1081            }1082          }10831084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably1086          if (entry.Name.Length > storedNameLength) {1087            throw new ZipException("File name length mismatch");1088          }10891090          // Name data has already been read convert it and compare.1091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);10921093          // Central directory and local entry name match1094          if (localName != entry.Name) {1095            throw new ZipException("Central header and local header file name mismatch");1096          }10971098          // Directories have zero actual size but can have compressed size1099          if (entry.IsDirectory) {1100            if (size > 0) {1101              throw new ZipException("Directory cannot have size");1102            }11031104            // 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 bytes1112              // 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 bytes1114              throw new ZipException("Directory compressed size invalid");1115            }1116          }11171118          if (!ZipNameTransform.IsValidName(localName, true)) {1119            throw new ZipException("Name is invalid");1120          }1121        }11221123        // Tests that apply to both data and header.11241125        // 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)) {  11291130                        if (extractVersion < 50)1131                        {1132                            throw new ZipException(string.Format("Version required to extract this entry is too low for 1133                        }1134                    }11351136                    // Patched entries require extract version >= 271137                    if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27))1138                    {1139                        throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractV1140                    }11411142                    // Central header flags match local entry flags.1143                    if (localFlags != entry.Flags)1144                    {1145                        throw new ZipException("Central header/local header flags mismatch");1146                    }11471148                    // Central header compression method matches local entry1149                    if (entry.CompressionMethod != (CompressionMethod)compressionMethod)1150                    {1151                        throw new ZipException("Central header/local header compression method mismatch");1152                    }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          }11361137          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        }11441145        int extraLength = storedNameLength + extraDataLength;1146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;1147      }1148    }11491150    #endregion11511152    #region Updating  11531154                    if (entry.Version != extractVersion)1155                    {1156                        throw new ZipException("Extract version mismatch");1157                    }11581159                    // Strong encryption and extract version match1160                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1161                    {1162                        if (extractVersion < 62)1163                        {1164                            throw new ZipException("Strong encryption flag set but version not high enough");1165                        }1166                    }11671168                    if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0)1169                    {1170                        if ((fileTime != 0) || (fileDate != 0))1171                        {1172                            throw new ZipException("Header masked set but date/time values non-zero");1173                        }1174                    }11751176                    if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0)1177                    {1178                        if (crcValue != (uint)entry.Crc)1179                        {1180                            throw new ZipException("Central header/local header crc mismatch");1181                        }1182                    }11831184                    // Crc valid for empty entry.1185                    // This will also apply to streamed entries where size isnt known and the header cant be patched1186                    if ((size == 0) && (compressedSize == 0))1187                    {1188                        if (crcValue != 0)1189                        {1190                            throw new ZipException("Invalid CRC for empty entry");1191                        }1192                    }11931194                    // TODO: make test more correct...  can't compare lengths as was done originally as this can fail fo1195                    // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntr1196                    if (entry.Name.Length > storedNameLength)1197                    {1198                        throw new ZipException("File name length mismatch");1199                    }12001201                    // Name data has already been read convert it and compare.1202                    string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);12031204                    // Central directory and local entry name match1205                    if (localName != entry.Name)1206                    {1207                        throw new ZipException("Central header and local header file name mismatch");1208                    }12091210                    // Directories have zero actual size but can have compressed size1211                    if (entry.IsDirectory)1212                    {1213                        if (size > 0)1214                        {1215                            throw new ZipException("Directory cannot have size");1216                        }12171218                        // There may be other cases where the compressed size can be greater than this?1219                        // If so until details are known we will be strict.1220                        if (entry.IsCrypted)1221                        {1222                            if (compressedSize > ZipConstants.CryptoHeaderSize + 2)1223                            {1224                                throw new ZipException("Directory compressed size invalid");1225                            }1226                        }1227                        else if (compressedSize > 2)1228                        {1229                            // When not compressed the directory size can validly be 2 bytes1230                            // if the true size wasnt known when data was originally being written.1231                            // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes1232                            throw new ZipException("Directory compressed size invalid");1233                        }1234                    }12351236                    if (!ZipNameTransform.IsValidName(localName, true))1237                    {1238                        throw new ZipException("Name is invalid");1239                    }1240                }12411242        // Tests that apply to both data and header.1154    const int DefaultBufferSize = 4096;11551156    /// <summary>1157    /// The kind of update to apply.1158    /// </summary>1159    enum UpdateCommand1160    {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    }11651166    #region Properties1167    /// <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      }11741175      set {1176        updateEntryFactory_.NameTransform = value;1177      }1178    }11791180    /// <summary>1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1182    /// during updates.1183    /// </summary>1184    public IEntryFactory EntryFactory {1185      get {1186        return updateEntryFactory_;1187      }11881189      set {1190        if (value == null) {1191          updateEntryFactory_ = new ZipEntryFactory();1192        } else {1193          updateEntryFactory_ = value;1194        }1195      }1196    }11971198    /// <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        }12071208        if (bufferSize_ != value) {1209          bufferSize_ = value;1210          copyBuffer_ = null;1211        }1212      }1213    }12141215    /// <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    }12211222    /// <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    }12291230    #endregion12311232    #region Immediate updating1233    //    TBD: Direct form of updating1234    //1235    //    public void Update(IEntryMatcher deleteMatcher)1236    //    {1237    //    }1238    //1239    //    public void Update(IScanner addScanner)1240    //    {1241    //    }1242    #endregion  12431244        // Size can be verified only if it is known in the local header.1245        // it will always be known in the central header.1246        if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||1247          ((size > 0) || (compressedSize > 0))) {12481249          if (size != entry.Size) {1250            throw new ZipException(1251              string.Format("Size mismatch between central header({0}) and local header({1})",1252                entry.Size, size));1253          }12541255          if (compressedSize != entry.CompressedSize &&1256            compressedSize != 0xFFFFFFFF && compressedSize != -1) {1257            throw new ZipException(1258              string.Format("Compressed size mismatch between central header({0}) and local header({1})",1259              entry.CompressedSize, compressedSize));1260          }1261        }1244    #region Deferred Updating1245    /// <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.</p1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1250    /// <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      }12581259      if (dataSource == null) {1260        throw new ArgumentNullException(nameof(dataSource));1261      }  12621263        int extraLength = storedNameLength + extraDataLength;1264        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;1263      if (isDisposed_) {1264        throw new ObjectDisposedException("ZipFile");  1265      }1266    }12671268    #endregion12691270    #region Updating12711272    const int DefaultBufferSize = 4096;12661267      if (IsEmbeddedArchive) {1268        throw new ZipException("Cannot update embedded/SFX archives");1269      }12701271      archiveStorage_ = archiveStorage;1272      updateDataSource_ = dataSource;  12731274    /// <summary>1275    /// The kind of update to apply.1276    /// </summary>1277    enum UpdateCommand1278    {1279      Copy,       // Copy original file contents.1280      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.1281      Add,        // Add a new file to the archive.1282    }1274      // NOTE: the baseStream_ may not currently support writing or seeking.12751276      updateIndex_ = new Hashtable();12771278      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      }  12831284    #region Properties1285    /// <summary>1286    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.1287    /// </summary>1288    public INameTransform NameTransform1289    {1290      get {1291        return updateEntryFactory_.NameTransform;1292      }12931294      set {1295        updateEntryFactory_.NameTransform = value;1296      }1297    }12981299    /// <summary>1300    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1301    /// during updates.1302    /// </summary>1303    public IEntryFactory EntryFactory1304    {1305      get {1306        return updateEntryFactory_;1307      }13081309      set {1310        if (value == null) {1311          updateEntryFactory_ = new ZipEntryFactory();1312        }1313        else {1314          updateEntryFactory_ = value;1315        }1316      }1317    }13181319    /// <summary>1320    /// Get /set the buffer size to be used when updating this zip file.1321    /// </summary>1322    public int BufferSize1323    {1324      get { return bufferSize_; }1325      set {1326        if ( value < 1024 ) {1327#if NETCF_1_01328          throw new ArgumentOutOfRangeException("value");1329#else1330          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");1331#endif1332        }13331334        if ( bufferSize_ != value ) {1335          bufferSize_ = value;1336          copyBuffer_ = null;1337        }1338      }1339    }1284      // We must sort by offset before using offset's calculated sizes1285      updates_.Sort(new UpdateComparer());12861287      int idx = 0;1288      foreach (ZipUpdate update in updates_) {1289        //If last entry, there is no next entry offset to use1290        if (idx == updates_.Count - 1)1291          break;12921293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;1294        idx++;1295      }1296      updateCount_ = updates_.Count;12971298      contentsEdited_ = false;1299      commentEdited_ = false;1300      newComment_ = null;1301    }13021303    /// <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    }13111312    /// <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    }13261327    /// <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      }13381339      CheckUpdating();  13401341    /// <summary>1342    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.1343    /// </summary>1344    public bool IsUpdating1345    {1346      get { return updates_ != null; }1347    }13481349    /// <summary>1350    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.1351    /// </summary>1352    public UseZip64 UseZip641353    {1354      get { return useZip64_; }1355      set { useZip64_ = value; }1356    }13571358    #endregion13591360    #region Immediate updating1361//    TBD: Direct form of updating1362//1363//    public void Update(IEntryMatcher deleteMatcher)1364//    {1365//    }1366//1367//    public void Update(IScanner addScanner)1368//    {1369//    }1370    #endregion13711372    #region Deferred Updating1373    /// <summary>1374    /// Begin updating this <see cref="ZipFile"/> archive.1375    /// </summary>1376    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p1377    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1341      try {1342        updateIndex_.Clear();1343        updateIndex_ = null;13441345        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        }13581359      } finally {1360        PostUpdateCleanup();1361      }1362    }13631364    /// <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    }13731374    /// <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    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>1380    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1381    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)1382    {1383      if ( archiveStorage == null ) {1384        throw new ArgumentNullException(nameof(archiveStorage));1385      }1379    public void SetComment(string comment)1380    {1381      if (isDisposed_) {1382        throw new ObjectDisposedException("ZipFile");1383      }13841385      CheckUpdating();  13861387      if ( dataSource == null ) {1388        throw new ArgumentNullException(nameof(dataSource));1389      }13901391      if ( isDisposed_ ) {1392        throw new ObjectDisposedException("ZipFile");1393      }13941395      if ( IsEmbeddedArchive ) {1396        throw new ZipException ("Cannot update embedded/SFX archives");1397      }1387      newComment_ = new ZipString(comment);13881389      if (newComment_.RawLength > 0xffff) {1390        newComment_ = null;1391        throw new ZipException("Comment length exceeds maximum - 65535");1392      }13931394      // We dont take account of the original and current comment appearing to be the same1395      // as encoding may be different.1396      commentEdited_ = true;1397    }  13981399      archiveStorage_ = archiveStorage;1400      updateDataSource_ = dataSource;14011402      // NOTE: the baseStream_ may not currently support writing or seeking.14031404      updateIndex_ = new Hashtable();14051406      updates_ = new ArrayList(entries_.Length);1407      foreach(ZipEntry entry in entries_) {1408        int index = updates_.Add(new ZipUpdate(entry));1409        updateIndex_.Add(entry.Name, index);1410      }14111412      // We must sort by offset before using offset's calculated sizes1413      updates_.Sort(new UpdateComparer());14141415      int idx = 0;1416      foreach (ZipUpdate update in updates_) {1417        //If last entry, there is no next entry offset to use1418        if (idx == updates_.Count - 1)1419          break;14201421        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;1422        idx++;1423      }1424      updateCount_ = updates_.Count;14251426      contentsEdited_ = false;1427      commentEdited_ = false;1428      newComment_ = null;1429    }14301431    /// <summary>1432    /// Begin updating to this <see cref="ZipFile"/> archive.1433    /// </summary>1434    /// <param name="archiveStorage">The storage to use during the update.</param>1435    public void BeginUpdate(IArchiveStorage archiveStorage)1436    {1437      BeginUpdate(archiveStorage, new DynamicDiskDataSource());1438    }14391440    /// <summary>1441    /// Begin updating this <see cref="ZipFile"/> archive.1442    /// </summary>1443    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>1444    /// <seealso cref="CommitUpdate"></seealso>1445    /// <seealso cref="AbortUpdate"></seealso>1446    public void BeginUpdate()1447    {1448      if ( Name == null ) {1449        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());1450      }1451      else {1452        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());1453      }1399    #endregion14001401    #region Adding Entries14021403    void AddUpdate(ZipUpdate update)1404    {1405      contentsEdited_ = true;14061407      int index = FindExistingUpdate(update.Entry.Name);14081409      if (index >= 0) {1410        if (updates_[index] == null) {1411          updateCount_ += 1;1412        }14131414        // 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    }14221423    /// <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      }14371438      if (isDisposed_) {1439        throw new ObjectDisposedException("ZipFile");1440      }14411442      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1444      }14451446      CheckUpdating();1447      contentsEdited_ = true;14481449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1450      entry.IsUnicodeText = useUnicodeText;1451      entry.CompressionMethod = compressionMethod;14521453      AddUpdate(new ZipUpdate(fileName, entry));  1454    }  1455  1456    /// <summary>1457    /// Commit current updates, updating this archive.1457    /// Add a new entry to the archive.  1458    /// </summary>1459    /// <seealso cref="BeginUpdate()"></seealso>1460    /// <seealso cref="AbortUpdate"></seealso>1461    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1462    public void CommitUpdate()1463    {1464      if ( isDisposed_ ) {1465        throw new ObjectDisposedException("ZipFile");1466      }14671468      CheckUpdating();14691470      try {1471        updateIndex_.Clear();1472        updateIndex_=null;14731474        if( contentsEdited_ ) {1475          RunUpdates();1476        }1477        else if( commentEdited_ ) {1478          UpdateCommentOnly();1479        }1480        else {1481          // Create an empty archive if none existed originally.1482          if( entries_.Length==0 ) {1483            byte[] theComment=(newComment_!=null)?newComment_.RawComment:ZipConstants.ConvertToArray(comment_);1484            using( ZipHelperStream zhs=new ZipHelperStream(baseStream_) ) {1485              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);1486            }1487          }1488        }14891459    /// <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      }14681469      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1471      }14721473      CheckUpdating();1474      contentsEdited_ = true;14751476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1477      entry.CompressionMethod = compressionMethod;1478      AddUpdate(new ZipUpdate(fileName, entry));1479    }14801481    /// <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      finally {1492        PostUpdateCleanup();1493      }14911492      CheckUpdating();1493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));  1494    }  1495  1496    /// <summary>1497    /// Abort updating leaving the archive unchanged.1497    /// Add a file to the archive.  1498    /// </summary>1499    /// <seealso cref="BeginUpdate()"></seealso>1500    /// <seealso cref="CommitUpdate"></seealso>1501    public void AbortUpdate()1502    {1503      PostUpdateCleanup();1504    }15051506    /// <summary>1507    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.1508    /// </summary>1509    /// <param name="comment">The comment to record.</param>1510    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1511    public void SetComment(string comment)1512    {1513      if ( isDisposed_ ) {1514        throw new ObjectDisposedException("ZipFile");1515      }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      }15071508      if (entryName == null) {1509        throw new ArgumentNullException(nameof(entryName));1510      }15111512      CheckUpdating();1513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));1514    }1515  15161517      CheckUpdating();15181519      newComment_ = new ZipString(comment);15201521      if ( newComment_.RawLength  > 0xffff ) {1522        newComment_ = null;1523        throw new ZipException("Comment length exceeds maximum - 65535");1524      }15251526      // We dont take account of the original and current comment appearing to be the same1527      // as encoding may be different.1528      commentEdited_ = true;1529    }15301531    #endregion15321533    #region Adding Entries15341535    void AddUpdate(ZipUpdate update)1536    {1537      contentsEdited_ = true;15381539      int index = FindExistingUpdate(update.Entry.Name);15401541      if (index >= 0) {1542        if ( updates_[index] == null ) {1543          updateCount_ += 1;1544        }15451546        // Direct replacement is faster than delete and add.1547        updates_[index] = update;1548      }1549      else {1550        index = updates_.Add(update);1551        updateCount_ += 1;1552        updateIndex_.Add(update.Entry.Name, index);1553      }1554    }15551556    /// <summary>1557    /// Add a new entry to the archive.1558    /// </summary>1559    /// <param name="fileName">The name of the file to add.</param>1560    /// <param name="compressionMethod">The compression method to use.</param>1561    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>1562    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1563    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1564    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>1565    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText )1566    {1567      if (fileName == null) {1568        throw new ArgumentNullException(nameof(fileName));1569      }15701571      if ( isDisposed_ ) {1572        throw new ObjectDisposedException("ZipFile");1573      }15741575      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1576        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1577      }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      }15271528      if (entryName == null) {1529        throw new ArgumentNullException(nameof(entryName));1530      }15311532      CheckUpdating();1533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));1534    }15351536    /// <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      }15471548      if (entryName == null) {1549        throw new ArgumentNullException(nameof(entryName));1550      }15511552      CheckUpdating();15531554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1555      entry.CompressionMethod = compressionMethod;15561557      AddUpdate(new ZipUpdate(dataSource, entry));1558    }15591560    /// <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 useUnicode1568    {1569      if (dataSource == null) {1570        throw new ArgumentNullException(nameof(dataSource));1571      }15721573      if (entryName == null) {1574        throw new ArgumentNullException(nameof(entryName));1575      }15761577      CheckUpdating();  15781579      CheckUpdating();1580      contentsEdited_ = true;15811582      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1583      entry.IsUnicodeText = useUnicodeText;1584      entry.CompressionMethod = compressionMethod;1579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1580      entry.IsUnicodeText = useUnicodeText;1581      entry.CompressionMethod = compressionMethod;15821583      AddUpdate(new ZipUpdate(dataSource, entry));1584    }  15851586      AddUpdate(new ZipUpdate(fileName, entry));1587    }15881589    /// <summary>1590    /// Add a new entry to the archive.1591    /// </summary>1592    /// <param name="fileName">The name of the file to add.</param>1593    /// <param name="compressionMethod">The compression method to use.</param>1594    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>1595    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>1596    public void Add(string fileName, CompressionMethod compressionMethod)1597    {1598      if ( fileName == null ) {1599        throw new ArgumentNullException(nameof(fileName));1600      }16011602      if ( !ZipEntry.IsCompressionMethodSupported(compressionMethod) ) {1603        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1604      }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      }15961597      CheckUpdating();15981599      if ((entry.Size != 0) || (entry.CompressedSize != 0)) {1600        throw new ZipException("Entry cannot have any data");1601      }16021603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));1604    }  16051606      CheckUpdating();1607      contentsEdited_ = true;16081609      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1610      entry.CompressionMethod = compressionMethod;1611      AddUpdate(new ZipUpdate(fileName, entry));1612    }16131614    /// <summary>1615    /// Add a file to the archive.1616    /// </summary>1617    /// <param name="fileName">The name of the file to add.</param>1618    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1619    public void Add(string fileName)1620    {1621      if ( fileName == null ) {1622        throw new ArgumentNullException(nameof(fileName));1623      }16241625      CheckUpdating();1626      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));1627    }16281629    /// <summary>1630    /// Add a file to the archive.1631    /// </summary>1632    /// <param name="fileName">The name of the file to add.</param>1633    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>1634    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1635    public void Add(string fileName, string entryName)1636    {1637      if (fileName == null) {1638        throw new ArgumentNullException(nameof(fileName));1639      }16401641      if ( entryName == null ) {1642        throw new ArgumentNullException(nameof(entryName));1643      }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      }16151616      CheckUpdating();16171618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);1619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));1620    }16211622    #endregion16231624    #region Modifying Entries1625    /* 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          }16331634          if ( updated == null ) {1635            throw new ArgumentNullException("updated");1636          }16371638          CheckUpdating();1639          contentsEdited_ = true;1640          updates_.Add(new ZipUpdate(original, updated));1641        }1642    */1643    #endregion  16441645      CheckUpdating();1646      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));1647    }164816491650    /// <summary>1651    /// Add a file entry with data.1652    /// </summary>1653    /// <param name="dataSource">The source of the data for this entry.</param>1654    /// <param name="entryName">The name to give to the entry.</param>1655    public void Add(IStaticDataSource dataSource, string entryName)1656    {1657      if ( dataSource == null ) {1658        throw new ArgumentNullException(nameof(dataSource));1659      }16601661      if ( entryName == null ) {1662        throw new ArgumentNullException(nameof(entryName));1663      }16641665      CheckUpdating();1666      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));1667    }16681669    /// <summary>1670    /// Add a file entry with data.1671    /// </summary>1672    /// <param name="dataSource">The source of the data for this entry.</param>1673    /// <param name="entryName">The name to give to the entry.</param>1674    /// <param name="compressionMethod">The compression method to use.</param>1675    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)1676    {1677      if ( dataSource == null ) {1678        throw new ArgumentNullException(nameof(dataSource));1679      }16801681      if ( entryName == null ) {1682        throw new ArgumentNullException(nameof(entryName));1683      }16841685      CheckUpdating();16861687      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1688      entry.CompressionMethod = compressionMethod;16891690      AddUpdate(new ZipUpdate(dataSource, entry));1691    }16921693    /// <summary>1694    /// Add a file entry with data.1695    /// </summary>1696    /// <param name="dataSource">The source of the data for this entry.</param>1697    /// <param name="entryName">The name to give to the entry.</param>1698    /// <param name="compressionMethod">The compression method to use.</param>1699    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>1700    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode1701    {1702      if (dataSource == null) {1703        throw new ArgumentNullException(nameof(dataSource));1704      }17051706      if ( entryName == null ) {1707        throw new ArgumentNullException(nameof(entryName));1708      }17091710      CheckUpdating();17111712      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1713      entry.IsUnicodeText = useUnicodeText;1714      entry.CompressionMethod = compressionMethod;17151716      AddUpdate(new ZipUpdate(dataSource, entry));1717    }17181719    /// <summary>1720    /// Add a <see cref="ZipEntry"/> that contains no data.1721    /// </summary>1722    /// <param name="entry">The entry to add.</param>1723    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>1724    public void Add(ZipEntry entry)1725    {1726      if ( entry == null ) {1727        throw new ArgumentNullException(nameof(entry));1728      }17291730      CheckUpdating();1645    #region Deleting Entries1646    /// <summary>1647    /// Delete an entry by name1648    /// </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      }16561657      CheckUpdating();16581659      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    }16711672    /// <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      }16811682      CheckUpdating();16831684      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    }16931694    #endregion16951696    #region Update Support16971698    #region Writing Values/Headers1699    void WriteLEShort(int value)1700    {1701      baseStream_.WriteByte((byte)(value & 0xff));1702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));1703    }17041705    /// <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    }17131714    /// <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    }17221723    /// <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    }  17311732      if ( (entry.Size != 0) || (entry.CompressedSize != 0) ) {1733        throw new ZipException("Entry cannot have any data");1734      }17351736      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));1737    }17381739    /// <summary>1740    /// Add a directory entry to the archive.1741    /// </summary>1742    /// <param name="directoryName">The directory to add.</param>1743    public void AddDirectory(string directoryName)1744    {1745      if ( directoryName == null ) {1746        throw new ArgumentNullException(nameof(directoryName));1747      }17481749      CheckUpdating();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    }17401741    void WriteLEUlong(ulong value)1742    {1743      WriteLEUint((uint)(value & 0xffffffff));1744      WriteLEUint((uint)(value >> 32));1745    }17461747    void WriteLocalEntryHeader(ZipUpdate update)1748    {1749      ZipEntry entry = update.OutEntry;  17501751      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);1752      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));1753    }17541755    #endregion17561757    #region Modifying Entries1758/* Modify not yet ready for public consumption.1759   Direct modification of an entry should not overwrite original data before its read.1760   Safe mode is trivial in this sense.1761    public void Modify(ZipEntry original, ZipEntry updated)1762    {1763      if ( original == null ) {1764        throw new ArgumentNullException("original");1765      }1751      // TODO: Local offset will require adjusting for multi-disk zip files.1752      entry.Offset = baseStream_.Position;17531754      // 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        }  17661767      if ( updated == null ) {1768        throw new ArgumentNullException("updated");1769      }17701771      CheckUpdating();1772      contentsEdited_ = true;1773      updates_.Add(new ZipUpdate(original, updated));1774    }1775*/1776    #endregion17771778    #region Deleting Entries1779    /// <summary>1780    /// Delete an entry by name1781    /// </summary>1782    /// <param name="fileName">The filename to delete</param>1783    /// <returns>True if the entry was found and deleted; false otherwise.</returns>1784    public bool Delete(string fileName)1785    {1786      if ( fileName == null ) {1787        throw new ArgumentNullException(nameof(fileName));1788      }17891790      CheckUpdating();17911792      bool result = false;1793      int index = FindExistingUpdate(fileName);1794      if ( (index >= 0) && (updates_[index] != null) ) {1795        result = true;1796        contentsEdited_ = true;1797        updates_[index] = null;1798        updateCount_ -= 1;1799      }1800      else {1801        throw new ZipException("Cannot find entry to delete");1802      }1803      return result;1804    }18051806    /// <summary>1807    /// Delete a <see cref="ZipEntry"/> from the archive.1808    /// </summary>1809    /// <param name="entry">The entry to delete.</param>1810    public void Delete(ZipEntry entry)1811    {1812      if ( entry == null ) {1813        throw new ArgumentNullException(nameof(entry));1814      }18151816      CheckUpdating();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        }17751776        switch (useZip64_) {1777          case UseZip64.Dynamic:1778            if (entry.Size < 0) {1779              entry.ForceZip64();1780            }1781            break;17821783          case UseZip64.On:1784            entry.ForceZip64();1785            break;17861787          case UseZip64.Off:1788            // Do nothing.  The entry itself may be using Zip64 independantly.1789            break;1790        }1791      }17921793      // Write the local file header1794      WriteLEInt(ZipConstants.LocalHeaderSignature);17951796      WriteLEShort(entry.Version);1797      WriteLEShort(entry.Flags);17981799      WriteLEShort((byte)entry.CompressionMethod);1800      WriteLEInt((int)entry.DosTime);18011802      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      }18091810      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        }  18171818      int index = FindExistingUpdate(entry);1819      if ( index >= 0 ) {1820        contentsEdited_ = true;1821        updates_[index] = null;1822        updateCount_ -= 1;1823      }1824      else {1825        throw new ZipException("Cannot find entry to delete");1818        WriteLEInt((int)entry.CompressedSize);1819        WriteLEInt((int)entry.Size);1820      }18211822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);18231824      if (name.Length > 0xFFFF) {1825        throw new ZipException("Entry name too long.");  1826      }1827    }18281829    #endregion18301831    #region Update Support18271828      var ed = new ZipExtraData(entry.ExtraData);18291830      if (entry.LocalHeaderRequiresZip64) {1831        ed.StartNewEntry();  18321833    #region Writing Values/Headers1834    void WriteLEShort(int value)1835    {1836      baseStream_.WriteByte(( byte )(value & 0xff));1837      baseStream_.WriteByte(( byte )((value >> 8) & 0xff));1838    }18391840    /// <summary>1841    /// Write an unsigned short in little endian byte order.1842    /// </summary>1843    void WriteLEUshort(ushort value)1844    {1845      baseStream_.WriteByte(( byte )(value & 0xff));1846      baseStream_.WriteByte(( byte )(value >> 8));1847    }18481849    /// <summary>1850    /// Write an int in little endian byte order.1851    /// </summary>1852    void WriteLEInt(int value)1853    {1854      WriteLEShort(value & 0xffff);1855      WriteLEShort(value >> 16);1856    }18571858    /// <summary>1859    /// Write an unsigned int in little endian byte order.1860    /// </summary>1861    void WriteLEUint(uint value)1862    {1863      WriteLEUshort((ushort)(value & 0xffff));1864      WriteLEUshort((ushort)(value >> 16));1865    }18661867    /// <summary>1868    /// Write a long in little endian byte order.1869    /// </summary>1870    void WriteLeLong(long value)1871    {1872      WriteLEInt(( int )(value & 0xffffffff));1873      WriteLEInt(( int )(value >> 32));1874    }18751876    void WriteLEUlong(ulong value)1877    {1878      WriteLEUint(( uint )(value & 0xffffffff));1879      WriteLEUint(( uint )(value >> 32));1880    }18811882    void WriteLocalEntryHeader(ZipUpdate update)1883    {1884      ZipEntry entry = update.OutEntry;18851886      // TODO: Local offset will require adjusting for multi-disk zip files.1887      entry.Offset = baseStream_.Position;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      }18411842      entry.ExtraData = ed.GetEntryData();18431844      WriteLEShort(name.Length);1845      WriteLEShort(entry.ExtraData.Length);18461847      if (name.Length > 0) {1848        baseStream_.Write(name, 0, name.Length);1849      }18501851      if (entry.LocalHeaderRequiresZip64) {1852        if (!ed.Find(1)) {1853          throw new ZipException("Internal error cannot find extra data");1854        }18551856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1857      }18581859      if (entry.ExtraData.Length > 0) {1860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);1861      }1862    }18631864    int WriteCentralDirectoryHeader(ZipEntry entry)1865    {1866      if (entry.CompressedSize < 0) {1867        throw new ZipException("Attempt to write central directory entry with unknown csize");1868      }18691870      if (entry.Size < 0) {1871        throw new ZipException("Attempt to write central directory entry with unknown size");1872      }18731874      if (entry.Crc < 0) {1875        throw new ZipException("Attempt to write central directory entry with unknown crc");1876      }18771878      // Write the central file header1879      WriteLEInt(ZipConstants.CentralHeaderSignature);18801881      // Version made by1882      WriteLEShort(ZipConstants.VersionMadeBy);18831884      // Version required to extract1885      WriteLEShort(entry.Version);18861887      WriteLEShort(entry.Flags);  18881889      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.1890      if (update.Command != UpdateCommand.Copy) {1891        if (entry.CompressionMethod == CompressionMethod.Deflated) {1892          if (entry.Size == 0) {1893            // No need to compress - no data.1894            entry.CompressedSize = entry.Size;1895            entry.Crc = 0;1896            entry.CompressionMethod = CompressionMethod.Stored;1897          }1898        }1899        else if (entry.CompressionMethod == CompressionMethod.Stored) {1900          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;1901        }19021903        if (HaveKeys) {1904          entry.IsCrypted = true;1905          if (entry.Crc < 0) {1906            entry.Flags |= (int)GeneralBitFlags.Descriptor;1907          }1908        }1909        else {1910          entry.IsCrypted = false;1911        }1889      unchecked {1890        WriteLEShort((byte)entry.CompressionMethod);1891        WriteLEInt((int)entry.DosTime);1892        WriteLEInt((int)entry.Crc);1893      }18941895      if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {1896        WriteLEInt(-1);1897      } else {1898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));1899      }19001901      if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {1902        WriteLEInt(-1);1903      } else {1904        WriteLEInt((int)entry.Size);1905      }19061907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);19081909      if (name.Length > 0xFFFF) {1910        throw new ZipException("Entry name is too long.");1911      }  19121913        switch (useZip64_) {1914          case UseZip64.Dynamic:1915            if (entry.Size < 0) {1916              entry.ForceZip64();1917            }1918            break;19191920          case UseZip64.On:1921            entry.ForceZip64();1922            break;19231924          case UseZip64.Off:1925            // Do nothing.  The entry itself may be using Zip64 independantly.1926            break;1913      WriteLEShort(name.Length);19141915      // Central header extra data is different to local header version so regenerate.1916      var ed = new ZipExtraData(entry.ExtraData);19171918      if (entry.CentralHeaderRequiresZip64) {1919        ed.StartNewEntry();19201921        if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {1922          ed.AddLeLong(entry.Size);1923        }19241925        if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {1926          ed.AddLeLong(entry.CompressedSize);  1927        }1928      }19291930      // Write the local file header1931      WriteLEInt(ZipConstants.LocalHeaderSignature);19281929        if (entry.Offset >= 0xffffffff) {1930          ed.AddLeLong(entry.Offset);1931        }  19321933      WriteLEShort(entry.Version);1934      WriteLEShort(entry.Flags);19351936      WriteLEShort((byte)entry.CompressionMethod);1937      WriteLEInt(( int )entry.DosTime);19381939      if ( !entry.HasCrc ) {1940        // Note patch address for updating CRC later.1941        update.CrcPatchOffset = baseStream_.Position;1942        WriteLEInt(( int )0);1943      }1944      else {1945        WriteLEInt(unchecked(( int )entry.Crc));1946      }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      }19391940      byte[] centralExtraData = ed.GetEntryData();19411942      WriteLEShort(centralExtraData.Length);1943      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);19441945      WriteLEShort(0);    // disk number1946      WriteLEShort(0);    // internal file attributes  19471948      if (entry.LocalHeaderRequiresZip64) {1949        WriteLEInt(-1);1950        WriteLEInt(-1);1951      }1952      else {1953        if ( (entry.CompressedSize < 0) || (entry.Size < 0) ) {1954          update.SizePatchOffset = baseStream_.Position;1955        }19561957        WriteLEInt(( int )entry.CompressedSize);1958        WriteLEInt(( int )entry.Size);1959      }19601961      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);19621963      if ( name.Length > 0xFFFF ) {1964        throw new ZipException("Entry name too long.");1965      }19661967      var ed = new ZipExtraData(entry.ExtraData);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      }19581959      if (entry.Offset >= 0xffffffff) {1960        WriteLEUint(0xffffffff);1961      } else {1962        WriteLEUint((uint)(int)entry.Offset);1963      }19641965      if (name.Length > 0) {1966        baseStream_.Write(name, 0, name.Length);1967      }  19681969      if ( entry.LocalHeaderRequiresZip64 ) {1970        ed.StartNewEntry();19711972        // Local entry header always includes size and compressed size.1973        // NOTE the order of these fields is reversed when compared to the normal headers!1974        ed.AddLeLong(entry.Size);1975        ed.AddLeLong(entry.CompressedSize);1976        ed.AddNewEntry(1);1969      if (centralExtraData.Length > 0) {1970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);1971      }19721973      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];19741975      if (rawComment.Length > 0) {1976        baseStream_.Write(rawComment, 0, rawComment.Length);  1977      }1978      else {1979        ed.Delete(1);1980      }19811982      entry.ExtraData = ed.GetEntryData();19831984      WriteLEShort(name.Length);1985      WriteLEShort(entry.ExtraData.Length);19861987      if ( name.Length > 0 ) {1988        baseStream_.Write(name, 0, name.Length);1989      }19901991      if ( entry.LocalHeaderRequiresZip64 ) {1992        if ( !ed.Find(1) ) {1993          throw new ZipException("Internal error cannot find extra data");1994        }19951996        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1997      }19981999      if ( entry.ExtraData.Length > 0 ) {2000        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);2001      }2002    }20032004    int WriteCentralDirectoryHeader(ZipEntry entry)2005    {2006      if ( entry.CompressedSize < 0 ) {2007        throw new ZipException("Attempt to write central directory entry with unknown csize");2008      }20092010      if ( entry.Size < 0 ) {2011        throw new ZipException("Attempt to write central directory entry with unknown size");2012      }20132014      if ( entry.Crc < 0 ) {2015        throw new ZipException("Attempt to write central directory entry with unknown crc");2016      }20172018      // Write the central file header2019      WriteLEInt(ZipConstants.CentralHeaderSignature);20202021      // Version made by2022      WriteLEShort(ZipConstants.VersionMadeBy);20232024      // Version required to extract2025      WriteLEShort(entry.Version);19781979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;1980    }1981    #endregion19821983    void PostUpdateCleanup()1984    {1985      updateDataSource_ = null;1986      updates_ = null;1987      updateIndex_ = null;19881989      if (archiveStorage_ != null) {1990        archiveStorage_.Dispose();1991        archiveStorage_ = null;1992      }1993    }19941995    string GetTransformedFileName(string name)1996    {1997      INameTransform transform = NameTransform;1998      return (transform != null) ?1999        transform.TransformFile(name) :2000        name;2001    }20022003    string GetTransformedDirectoryName(string name)2004    {2005      INameTransform transform = NameTransform;2006      return (transform != null) ?2007        transform.TransformDirectory(name) :2008        name;2009    }20102011    /// <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    }20222023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2024    {2025      int bytesToCopy = GetDescriptorSize(update);  20262027      WriteLEShort(entry.Flags);20282029      unchecked {2030        WriteLEShort((byte)entry.CompressionMethod);2031        WriteLEInt((int)entry.DosTime);2032        WriteLEInt((int)entry.Crc);2033      }20342035      if ( (entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff) ) {2036        WriteLEInt(-1);2037      }2038      else {2039        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));2040      }20412042      if ( (entry.IsZip64Forced()) || (entry.Size >= 0xffffffff) ) {2043        WriteLEInt(-1);2044      }2045      else {2046        WriteLEInt((int)entry.Size);2047      }20482049      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);2027      if (bytesToCopy > 0) {2028        byte[] buffer = GetBuffer();20292030        while (bytesToCopy > 0) {2031          int readSize = Math.Min(buffer.Length, bytesToCopy);20322033          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    }20432044    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      }  20502051      if ( name.Length > 0xFFFF ) {2052        throw new ZipException("Entry name is too long.");2053      }2051      // NOTE: Compressed size is updated elsewhere.2052      var crc = new Crc32();2053      byte[] buffer = GetBuffer();  20542055      WriteLEShort(name.Length);20562057      // Central header extra data is different to local header version so regenerate.2058      var ed = new ZipExtraData(entry.ExtraData);20592060      if ( entry.CentralHeaderRequiresZip64 ) {2061        ed.StartNewEntry();20622063        if ( (entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On) )2064        {2065          ed.AddLeLong(entry.Size);2066        }20672068        if ( (entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On) )2069        {2070          ed.AddLeLong(entry.CompressedSize);2071        }20722073        if ( entry.Offset >= 0xffffffff ) {2074          ed.AddLeLong(entry.Offset);2075        }20762077        // Number of disk on which this file starts isnt supported and is never written here.2078        ed.AddNewEntry(1);2079      }2080      else {2081        // Should have already be done when local header was added.2082        ed.Delete(1);2083      }20842085      byte[] centralExtraData = ed.GetEntryData();2055      long targetBytes = bytesToCopy;2056      long totalBytesRead = 0;20572058      int bytesRead;2059      do {2060        int readSize = buffer.Length;20612062        if (bytesToCopy < readSize) {2063          readSize = (int)bytesToCopy;2064        }20652066        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));20772078      if (totalBytesRead != targetBytes) {2079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2080      }20812082      if (updateCrc) {2083        update.OutEntry.Crc = crc.Value;2084      }2085    }  20862087      WriteLEShort(centralExtraData.Length);2088      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);20892090      WriteLEShort(0);  // disk number2091      WriteLEShort(0);  // internal file attributes20922093      // External file attributes...2094      if ( entry.ExternalFileAttributes != -1 ) {2095        WriteLEInt(entry.ExternalFileAttributes);2096      }2097      else {2098        if ( entry.IsDirectory ) {2099          WriteLEUint(16);2100        }2101        else {2102          WriteLEUint(0);2103        }2104      }21052106      if ( entry.Offset >= 0xffffffff ) {2107        WriteLEUint(0xffffffff);2108      }2109      else {2110        WriteLEUint((uint)(int)entry.Offset);2111      }21122113      if ( name.Length > 0 ) {2114        baseStream_.Write(name, 0, name.Length);2115      }21162117      if ( centralExtraData.Length > 0 ) {2118        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);2119      }21202121      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];21222123      if ( rawComment.Length > 0 ) {2124        baseStream_.Write(rawComment, 0, rawComment.Length);2125      }21262127      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;2128    }2129    #endregion21302131    void PostUpdateCleanup()2132    {2133            updateDataSource_ = null;2134            updates_ = null;2135            updateIndex_ = null;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    }21032104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2105    {2106      int bytesToCopy = GetDescriptorSize(update);21072108      while (bytesToCopy > 0) {2109        var readSize = (int)bytesToCopy;2110        byte[] buffer = GetBuffer();21112112        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    }21252126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2127    {2128      long bytesToCopy = update.Entry.CompressedSize;21292130      // NOTE: Compressed size is updated elsewhere.2131      var crc = new Crc32();2132      byte[] buffer = GetBuffer();21332134      long targetBytes = bytesToCopy;2135      long totalBytesRead = 0;  21362137            if (archiveStorage_ != null)2138            {2139        archiveStorage_.Dispose();2140        archiveStorage_=null;2141      }2142    }21432144    string GetTransformedFileName(string name)2145    {2146            INameTransform transform = NameTransform;2147      return (transform != null) ?2148        transform.TransformFile(name) :2149        name;2150    }21512152    string GetTransformedDirectoryName(string name)2153    {2154            INameTransform transform = NameTransform;2155            return (transform != null) ?2156        transform.TransformDirectory(name) :2157        name;2158    }21592160    /// <summary>2161    /// Get a raw memory buffer.2162    /// </summary>2163    /// <returns>Returns a raw memory buffer.</returns>2164    byte[] GetBuffer()2165    {2166      if ( copyBuffer_ == null ) {2167        copyBuffer_ = new byte[bufferSize_];2137      int bytesRead;2138      do {2139        int readSize = buffer.Length;21402141        if (bytesToCopy < readSize) {2142          readSize = (int)bytesToCopy;2143        }21442145        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);21532154          destinationPosition += bytesRead;2155          sourcePosition += bytesRead;2156          bytesToCopy -= bytesRead;2157          totalBytesRead += bytesRead;2158        }2159      }2160      while ((bytesRead > 0) && (bytesToCopy > 0));21612162      if (totalBytesRead != targetBytes) {2163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2164      }21652166      if (updateCrc) {2167        update.OutEntry.Crc = crc.Value;  2168      }2169      return copyBuffer_;2170    }21712172    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2173    {2174      int bytesToCopy = GetDescriptorSize(update);2169    }21702171    int FindExistingUpdate(ZipEntry entry)2172    {2173      int result = -1;2174      string convertedName = GetTransformedFileName(entry.Name);  21752176      if ( bytesToCopy > 0 ) {2177        byte[] buffer = GetBuffer();21782179        while ( bytesToCopy > 0 ) {2180          int readSize = Math.Min(buffer.Length, bytesToCopy);21812182          int bytesRead = source.Read(buffer, 0, readSize);2183          if ( bytesRead > 0 ) {2184            dest.Write(buffer, 0, bytesRead);2185            bytesToCopy -= bytesRead;2186          }2187          else {2188            throw new ZipException("Unxpected end of stream");2189          }2190        }2191      }2192    }21932194    void CopyBytes(ZipUpdate update, Stream destination, Stream source,2195      long bytesToCopy, bool updateCrc)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 useful2181            // 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    }21942195    int FindExistingUpdate(string fileName)  2196    {2197      if ( destination == source ) {2198        throw new InvalidOperationException("Destination and source are the same");2199      }2197      int result = -1;21982199      string convertedName = GetTransformedFileName(fileName);  22002201      // NOTE: Compressed size is updated elsewhere.2202      var crc = new Crc32();2203      byte[] buffer = GetBuffer();2201      if (updateIndex_.ContainsKey(convertedName)) {2202        result = (int)updateIndex_[convertedName];2203      }  22042205      long targetBytes = bytesToCopy;2206      long totalBytesRead = 0;22072208      int bytesRead;2209      do {2210        int readSize = buffer.Length;22112212        if ( bytesToCopy < readSize ) {2213          readSize = (int)bytesToCopy;2214        }22152216        bytesRead = source.Read(buffer, 0, readSize);2217        if ( bytesRead > 0 ) {2218          if ( updateCrc ) {2219            crc.Update(buffer, 0, bytesRead);2220          }2221          destination.Write(buffer, 0, bytesRead);2222          bytesToCopy -= bytesRead;2223          totalBytesRead += bytesRead;2224        }2225      }2226      while ( (bytesRead > 0) && (bytesToCopy > 0) );22272228      if ( totalBytesRead != targetBytes ) {2229        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2230      }22312232      if ( updateCrc ) {2233        update.OutEntry.Crc = crc.Value;2234      }2235    }22362237    /// <summary>2238    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.2239    /// </summary>2240    /// <param name="update">The update to get the size for.</param>2241    /// <returns>The descriptor size, zero if there isnt one.</returns>2242    int GetDescriptorSize(ZipUpdate update)2243    {2244      int result = 0;2245      if ( (update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {2246        result = ZipConstants.DataDescriptorSize - 4;2247        if ( update.Entry.LocalHeaderRequiresZip64 ) {2248          result = ZipConstants.Zip64DataDescriptorSize - 4;2249        }2250      }2251      return result;2252    }2205      /*2206            // This is slow like the coming of the next ice age but takes less storage and may be useful2207            // 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       */22162217      return result;2218    }22192220    /// <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_;22282229      if (entry.IsCrypted == true) {2230        result = CreateAndInitEncryptionStream(result, entry);2231      }22322233      switch (entry.CompressionMethod) {2234        case CompressionMethod.Stored:2235          result = new UncompressedStream(result);2236          break;22372238        case CompressionMethod.Deflated:2239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));2240          dos.IsStreamOwner = false;2241          result = dos;2242          break;22432244        default:2245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2246      }2247      return result;2248    }22492250    void AddEntry(ZipFile workFile, ZipUpdate update)2251    {2252      Stream source = null;  22532254    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2255    {2256      int bytesToCopy = GetDescriptorSize(update);22572258      while ( bytesToCopy > 0 ) {2259        var readSize = (int)bytesToCopy;2260        byte[] buffer = GetBuffer();2254      if (update.Entry.IsFile) {2255        source = update.GetSource();22562257        if (source == null) {2258          source = updateDataSource_.GetSource(update.Entry, update.Filename);2259        }2260      }  22612262        stream.Position = sourcePosition;2263        int bytesRead = stream.Read(buffer, 0, readSize);2264        if ( bytesRead > 0 ) {2265          stream.Position = destinationPosition;2266          stream.Write(buffer, 0, bytesRead);2267          bytesToCopy -= bytesRead;2268          destinationPosition += bytesRead;2269          sourcePosition += bytesRead;2270        }2271        else {2272          throw new ZipException("Unxpected end of stream");2273        }2274      }2275    }22762277    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2278    {2279      long bytesToCopy = update.Entry.CompressedSize;22802281      // NOTE: Compressed size is updated elsewhere.2282      var crc = new Crc32();2283      byte[] buffer = GetBuffer();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          }22732274          workFile.WriteLocalEntryHeader(update);22752276          long dataStart = workFile.baseStream_.Position;22772278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {2279            CopyBytes(update, output, source, sourceStreamLength, true);2280          }22812282          long dataEnd = workFile.baseStream_.Position;2283          update.OutEntry.CompressedSize = dataEnd - dataStart;  22842285      long targetBytes = bytesToCopy;2286      long totalBytesRead = 0;22872288      int bytesRead;2289      do2290      {2291        int readSize = buffer.Length;22922293        if ( bytesToCopy < readSize ) {2294          readSize = (int)bytesToCopy;2295        }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      }22942295    }  22962297        stream.Position = sourcePosition;2298        bytesRead = stream.Read(buffer, 0, readSize);2299        if ( bytesRead > 0 ) {2300          if ( updateCrc ) {2301            crc.Update(buffer, 0, bytesRead);2302          }2303          stream.Position = destinationPosition;2304          stream.Write(buffer, 0, bytesRead);23052306          destinationPosition += bytesRead;2307          sourcePosition += bytesRead;2308          bytesToCopy -= bytesRead;2309          totalBytesRead += bytesRead;2310        }2311      }2312      while ( (bytesRead > 0) && (bytesToCopy > 0) );23132314      if ( totalBytesRead != targetBytes ) {2315        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2316      }23172318      if ( updateCrc ) {2319        update.OutEntry.Crc = crc.Value;2320      }2321    }23222323    int FindExistingUpdate(ZipEntry entry)2324    {2325      int result = -1;2326      string convertedName = GetTransformedFileName(entry.Name);23272328      if (updateIndex_.ContainsKey(convertedName)) {2329        result = (int)updateIndex_[convertedName];2330      }2331/*2332      // This is slow like the coming of the next ice age but takes less storage and may be useful2333      // for CF?2334      for (int index = 0; index < updates_.Count; ++index)2335      {2336        ZipUpdate zu = ( ZipUpdate )updates_[index];2337        if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&2338          (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {2339          result = index;2340          break;2341        }2342      }2343 */2344      return result;2345    }23462347    int FindExistingUpdate(string fileName)2348    {2349      int result = -1;23502351      string convertedName = GetTransformedFileName(fileName);23522353      if (updateIndex_.ContainsKey(convertedName)) {2354        result = (int)updateIndex_[convertedName];2355      }23562357/*2358      // This is slow like the coming of the next ice age but takes less storage and may be useful2359      // for CF?2360      for ( int index = 0; index < updates_.Count; ++index ) {2361        if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,2362          true, CultureInfo.InvariantCulture) == 0 ) {2363          result = index;2364          break;2365        }2366      }2367 */23682369      return result;2370    }23712372    /// <summary>2373    /// Get an output stream for the specified <see cref="ZipEntry"/>2374    /// </summary>2375    /// <param name="entry">The entry to get an output stream for.</param>2376    /// <returns>The output stream obtained for the entry.</returns>2377    Stream GetOutputStream(ZipEntry entry)2378    {2379      Stream result = baseStream_;2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)2298    {2299      workFile.WriteLocalEntryHeader(update);2300      long dataStart = workFile.baseStream_.Position;23012302      // 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      }23102311      long dataEnd = workFile.baseStream_.Position;2312      update.Entry.CompressedSize = dataEnd - dataStart;2313    }23142315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2316    {2317      bool skipOver = false || update.Entry.Offset == destinationPosition;23182319      if (!skipOver) {2320        baseStream_.Position = destinationPosition;2321        workFile.WriteLocalEntryHeader(update);2322        destinationPosition = baseStream_.Position;2323      }23242325      long sourcePosition = 0;23262327      const int NameLengthOffset = 26;23282329      // TODO: Add base for SFX friendly handling2330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;23312332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23332334      // 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();23382339      sourcePosition = baseStream_.Position + nameLength + extraLength;23402341      if (skipOver) {2342        if (update.OffsetBasedSize != -1)2343          destinationPosition += update.OffsetBasedSize;2344        else2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2346          // WinZip produces a warning on these entries:2347          // "caution: value of lrec.csize (compressed size) changed from ..."2348          destinationPosition +=2349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size2350            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    }23582359    void CopyEntry(ZipFile workFile, ZipUpdate update)2360    {2361      workFile.WriteLocalEntryHeader(update);23622363      if (update.Entry.CompressedSize > 0) {2364        const int NameLengthOffset = 26;23652366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;23672368        // TODO: This wont work for SFX files!2369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23702371        uint nameLength = ReadLEUshort();2372        uint extraLength = ReadLEUshort();23732374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);23752376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2377      }2378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);2379    }  23802381      if ( entry.IsCrypted == true ) {2382#if NETCF_1_02383        throw new ZipException("Encryption not supported for Compact Framework 1.0");2384#else2385        result = CreateAndInitEncryptionStream(result, entry);2386#endif2387      }23882389      switch ( entry.CompressionMethod ) {2390        case CompressionMethod.Stored:2391          result = new UncompressedStream(result);2392          break;23932394        case CompressionMethod.Deflated:2395          var dos = new DeflaterOutputStream(result, new Deflater(9, true));2396          dos.IsStreamOwner = false;2397          result = dos;2398          break;23992400        default:2401          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2402      }2403      return result;2404    }24052406    void AddEntry(ZipFile workFile, ZipUpdate update)2407    {2408      Stream source = null;24092410      if ( update.Entry.IsFile ) {2411        source = update.GetSource();24122413        if ( source == null ) {2414          source = updateDataSource_.GetSource(update.Entry, update.Filename);2415        }2416      }24172418      if ( source != null ) {2419        using ( source ) {2420          long sourceStreamLength = source.Length;2421          if ( update.OutEntry.Size < 0 ) {2422            update.OutEntry.Size = sourceStreamLength;2423          }2424          else {2425            // Check for errant entries.2426            if ( update.OutEntry.Size != sourceStreamLength ) {2427              throw new ZipException("Entry size/stream size mismatch");2428            }2429          }24302431          workFile.WriteLocalEntryHeader(update);24322433          long dataStart = workFile.baseStream_.Position;24342435          using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {2436            CopyBytes(update, output, source, sourceStreamLength, true);2437          }24382439          long dataEnd = workFile.baseStream_.Position;2440          update.OutEntry.CompressedSize = dataEnd - dataStart;24412442          if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor)2443          {2444            var helper = new ZipHelperStream(workFile.baseStream_);2445            helper.WriteDataDescriptor(update.OutEntry);2446          }2447        }2381    void Reopen(Stream source)2382    {2383      if (source == null) {2384        throw new ZipException("Failed to reopen archive - no source");2385      }23862387      isNewArchive_ = false;2388      baseStream_ = source;2389      ReadEntries();2390    }23912392    void Reopen()2393    {2394      if (Name == null) {2395        throw new InvalidOperationException("Name is not known cannot Reopen");2396      }23972398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));2399    }24002401    void UpdateCommentOnly()2402    {2403      long baseLength = baseStream_.Length;24042405      ZipHelperStream updateFile = null;24062407      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {2408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);2409        updateFile = new ZipHelperStream(copyStream);2410        updateFile.IsStreamOwner = true;24112412        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 doesnt2418          // 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.24212422          // 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      }24312432      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        }24392440        const int CentralHeaderCommentSizeOffset = 16;2441        updateFile.Position += CentralHeaderCommentSizeOffset;24422443        byte[] rawComment = newComment_.RawComment;24442445        updateFile.WriteLEShort(rawComment.Length);2446        updateFile.Write(rawComment, 0, rawComment.Length);2447        updateFile.SetLength(updateFile.Position);  2448      }2449      else {2450        workFile.WriteLocalEntryHeader(update);2451        update.OutEntry.CompressedSize = 0;2452      }24532454    }24552456    void ModifyEntry(ZipFile workFile, ZipUpdate update)2457    {2458      workFile.WriteLocalEntryHeader(update);2459      long dataStart = workFile.baseStream_.Position;24602461      // TODO: This is slow if the changes don't effect the data!!2462      if ( update.Entry.IsFile && (update.Filename != null) ) {2463        using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {2464          using ( Stream source = this.GetInputStream(update.Entry) ) {2465            CopyBytes(update, output, source, source.Length, true);2466          }2467        }2468      }24692470      long dataEnd = workFile.baseStream_.Position;2471      update.Entry.CompressedSize = dataEnd - dataStart;2472    }24732474    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2475    {2476      bool skipOver = false || update.Entry.Offset == destinationPosition;24492450      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {2451        Reopen(archiveStorage_.ConvertTemporaryToFinal());2452      } else {2453        ReadEntries();2454      }2455    }24562457    /// <summary>2458    /// Class used to sort updates.2459    /// </summary>2460    class UpdateComparer : IComparer2461    {2462      /// <summary>2463      /// Compares two objects and returns a value indicating whether one is2464      /// 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;24752476        int result;  24772478      if ( !skipOver ) {2479        baseStream_.Position = destinationPosition;2480        workFile.WriteLocalEntryHeader(update);2481        destinationPosition = baseStream_.Position;2482      }24832484      long sourcePosition = 0;24852486      const int NameLengthOffset = 26;24872488      // TODO: Add base for SFX friendly handling2489      long entryDataOffset = update.Entry.Offset + NameLengthOffset;24902491      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);24922493      // Clumsy way of handling retrieving the original name and extra data length for now.2494      // TODO: Stop re-reading name and data length in CopyEntryDirect.2495      uint nameLength = ReadLEUshort();2496      uint extraLength = ReadLEUshort();24972498      sourcePosition = baseStream_.Position + nameLength + extraLength;24992500      if (skipOver) {2501        if (update.OffsetBasedSize != -1)2502          destinationPosition += update.OffsetBasedSize;2503        else2504          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2505          // WinZip produces a warning on these entries:2506          // "caution: value of lrec.csize (compressed size) changed from ..."2507          destinationPosition +=2508            (sourcePosition - entryDataOffset) + NameLengthOffset +  // Header size2509            update.Entry.CompressedSize + GetDescriptorSize(update);2510      }2511      else {2512        if ( update.Entry.CompressedSize > 0 ) {2513          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition );2514        }2515        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);2516      }2517    }25182519    void CopyEntry(ZipFile workFile, ZipUpdate update)2520    {2521      workFile.WriteLocalEntryHeader(update);25222523      if ( update.Entry.CompressedSize > 0 ) {2524        const int NameLengthOffset = 26;25252526        long entryDataOffset = update.Entry.Offset + NameLengthOffset;25272528        // TODO: This wont work for SFX files!2529        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);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;24892490          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    }25052506    void RunUpdates()2507    {2508      long sizeEntries = 0;2509      long endOfStream = 0;2510      bool directUpdate = false;2511      long destinationPosition = 0; // NOT SFX friendly25122513      ZipFile workFile;25142515      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;25232524        // 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;  25302531        uint nameLength = ReadLEUshort();2532        uint extraLength = ReadLEUshort();25332534        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);2531        if (key != null) {2532          workFile.key = (byte[])key.Clone();2533        }2534      }  25352536        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2537      }2538      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);2539    }25402541    void Reopen(Stream source)2542    {2543      if ( source == null ) {2544        throw new ZipException("Failed to reopen archive - no source");2545      }25462547      isNewArchive_ = false;2548      baseStream_ = source;2549      ReadEntries();2550    }25512552    void Reopen()2553    {2554      if (Name == null) {2555        throw new InvalidOperationException("Name is not known cannot Reopen");2556      }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;25472548              case UpdateCommand.Modify:2549                // TODO: Direct modifying of an entry will take some legwork.2550                ModifyEntry(workFile, update);2551                break;25522553              case UpdateCommand.Add:2554                if (!IsNewArchive && directUpdate) {2555                  workFile.baseStream_.Position = destinationPosition;2556                }  25572558      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));2559    }25602561    void UpdateCommentOnly()2562    {2563      long baseLength = baseStream_.Length;25642565      ZipHelperStream updateFile = null;25662567      if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {2568        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);2569        updateFile = new ZipHelperStream(copyStream);2570        updateFile.IsStreamOwner = true;2558                AddEntry(workFile, update);25592560                if (directUpdate) {2561                  destinationPosition = workFile.baseStream_.Position;2562                }2563                break;2564            }2565          }2566        }25672568        if (!IsNewArchive && directUpdate) {2569          workFile.baseStream_.Position = destinationPosition;2570        }  25712572        baseStream_.Close();2573        baseStream_ = null;2574      }2575      else {2576        if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {2577          // TODO: archiveStorage wasnt originally intended for this use.2578          // Need to revisit this to tidy up handling as archive storage currently doesnt2579          // handle the original stream well.2580          // The problem is when using an existing zip archive with an in memory archive storage.2581          // The open stream wont support writing but the memory storage should open the same file not an in memory one.25822583          // Need to tidy up the archive storage interface and contract basically.2584          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);2585          updateFile = new ZipHelperStream(baseStream_);2586        }2587        else {2588          baseStream_.Close();2589          baseStream_ = null;2590          updateFile = new ZipHelperStream(Name);2591        }2592      }25932594      using ( updateFile ) {2595        long locatedCentralDirOffset =2596          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,2597                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);2598        if ( locatedCentralDirOffset < 0 ) {2599          throw new ZipException("Cannot find central directory");2600        }26012602        const int CentralHeaderCommentSizeOffset = 16;2603        updateFile.Position += CentralHeaderCommentSizeOffset;26042605        byte[] rawComment = newComment_.RawComment;26062607        updateFile.WriteLEShort(rawComment.Length);2608        updateFile.Write(rawComment, 0, rawComment.Length);2609        updateFile.SetLength(updateFile.Position);2610      }26112612      if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {2613        Reopen(archiveStorage_.ConvertTemporaryToFinal());2614      }2615      else {2616        ReadEntries();2617      }2618    }26192620    /// <summary>2621    /// Class used to sort updates.2622    /// </summary>2623    class UpdateComparer : IComparer2624    {2625      /// <summary>2626      /// Compares two objects and returns a value indicating whether one is2627      /// less than, equal to or greater than the other.2628      /// </summary>2629      /// <param name="x">First object to compare</param>2630      /// <param name="y">Second object to compare.</param>2631      /// <returns>Compare result.</returns>2632      public int Compare(2633        object x,2634        object y)2635      {2636        var zx = x as ZipUpdate;2637        var zy = y as ZipUpdate;26382639        int result;26402641        if (zx == null) {2642          if (zy == null) {2643            result = 0;2644          }2645          else {2646            result = -1;2647          }2648        }2649        else if (zy == null) {2650          result = 1;2651        }2652        else {2653          int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;2654          int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;26552656          result = xCmdValue - yCmdValue;2657          if (result == 0) {2658            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;2659            if (offsetDiff < 0) {2660              result = -1;2661            }2662            else if (offsetDiff == 0) {2663              result = 0;2664            }2665            else {2666              result = 1;2667            }2668          }2669        }2670        return result;2671      }2672    }26732674    void RunUpdates()2675    {2676      long sizeEntries = 0;2677      long endOfStream = 0;2678      bool directUpdate = false;2679      long destinationPosition = 0; // NOT SFX friendly26802681      ZipFile workFile;2572        long centralDirOffset = workFile.baseStream_.Position;25732574        foreach (ZipUpdate update in updates_) {2575          if (update != null) {2576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2577          }2578        }25792580        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        }25842585        endOfStream = workFile.baseStream_.Position;25862587        // 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            }25962597            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      }26162617      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    }26272628    void CheckUpdating()2629    {2630      if (updates_ == null) {2631        throw new InvalidOperationException("BeginUpdate has not been called");2632      }2633    }26342635    #endregion26362637    #region ZipUpdate class2638    /// <summary>2639    /// Represents a pending update to a Zip file.2640    /// </summary>2641    class ZipUpdate2642    {2643      #region Constructors2644      public ZipUpdate(string fileName, ZipEntry entry)2645      {2646        command_ = UpdateCommand.Add;2647        entry_ = entry;2648        filename_ = fileName;2649      }26502651      [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      }26592660      [Obsolete]2661      public ZipUpdate(string fileName, string entryName)2662        : this(fileName, entryName, CompressionMethod.Deflated)2663      {2664        // Do nothing.2665      }26662667      [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      }26752676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2677      {2678        command_ = UpdateCommand.Add;2679        entry_ = entry;2680        dataSource_ = dataSource;2681      }  26822683      if ( IsNewArchive ) {2684        workFile = this;2685        workFile.baseStream_.Position = 0;2686        directUpdate = true;2687      }2688      else if ( archiveStorage_.UpdateMode == FileUpdateMode.Direct ) {2689        workFile = this;2690        workFile.baseStream_.Position = 0;2691        directUpdate = true;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      }  26922693        // Sort the updates by offset within copies/modifies, then adds.2694        // This ensures that data required by copies will not be overwritten.2695        updates_.Sort(new UpdateComparer());2696      }2697      else {2698        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());2699        workFile.UseZip64 = UseZip64;27002701        if (key != null) {2702          workFile.key = (byte[])key.Clone();2703        }2704      }27052706      try {2707        foreach ( ZipUpdate update in updates_ ) {2708          if (update != null) {2709            switch (update.Command) {2710              case UpdateCommand.Copy:2711                if (directUpdate) {2712                  CopyEntryDirect(workFile, update, ref destinationPosition);2713                }2714                else {2715                  CopyEntry(workFile, update);2716                }2717                break;2693      public ZipUpdate(UpdateCommand command, ZipEntry entry)2694      {2695        command_ = command;2696        entry_ = (ZipEntry)entry.Clone();2697      }269826992700      /// <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      #endregion27102711      /// <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      }  27182719              case UpdateCommand.Modify:2720                // TODO: Direct modifying of an entry will take some legwork.2721                ModifyEntry(workFile, update);2722                break;27232724              case UpdateCommand.Add:2725                if (!IsNewArchive && directUpdate) {2726                  workFile.baseStream_.Position = destinationPosition;2727                }27282729                AddEntry(workFile, update);27302731                if (directUpdate) {2732                  destinationPosition = workFile.baseStream_.Position;2733                }2734                break;2735            }2736          }2737        }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          }27272728          return outEntry_;2729        }2730      }27312732      /// <summary>2733      /// Get the command for this update.2734      /// </summary>2735      public UpdateCommand Command {2736        get { return command_; }2737      }  27382739        if ( !IsNewArchive && directUpdate ) {2740          workFile.baseStream_.Position = destinationPosition;2741        }27422743        long centralDirOffset = workFile.baseStream_.Position;27442745        foreach ( ZipUpdate update in updates_ ) {2746          if (update != null) {2747            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2748          }2749        }27502751        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);2752        using ( ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_) ) {2753          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);2754        }27552756        endOfStream = workFile.baseStream_.Position;27572758        // And now patch entries...2759        foreach ( ZipUpdate update in updates_ ) {2760          if (update != null)2761          {2762            // If the size of the entry is zero leave the crc as 0 as well.2763            // The calculated crc will be all bits on...2764            if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {2765              workFile.baseStream_.Position = update.CrcPatchOffset;2766              workFile.WriteLEInt((int)update.OutEntry.Crc);2767            }27682769            if (update.SizePatchOffset > 0) {2770              workFile.baseStream_.Position = update.SizePatchOffset;2771              if (update.OutEntry.LocalHeaderRequiresZip64) {2772                workFile.WriteLeLong(update.OutEntry.Size);2773                workFile.WriteLeLong(update.OutEntry.CompressedSize);2774              }2775              else {2776                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);2777                workFile.WriteLEInt((int)update.OutEntry.Size);2778              }2779            }2780          }2781        }2782      }2783      catch {2784        workFile.Close();2785        if (!directUpdate && (workFile.Name != null)) {2786          File.Delete(workFile.Name);2787        }2788        throw;2789      }27902791      if (directUpdate) {2792        workFile.baseStream_.SetLength(endOfStream);2793        workFile.baseStream_.Flush();2794        isNewArchive_ = false;2795        ReadEntries();2796      }2797      else {2798        baseStream_.Close();2799        Reopen(archiveStorage_.ConvertTemporaryToFinal());2800      }2801    }28022803    void CheckUpdating()2804    {2805      if ( updates_ == null ) {2806        throw new InvalidOperationException("BeginUpdate has not been called");2807      }2808    }28092810    #endregion28112812    #region ZipUpdate class2813    /// <summary>2814    /// Represents a pending update to a Zip file.2815    /// </summary>2816    class ZipUpdate2817    {2818      #region Constructors2819      public ZipUpdate(string fileName, ZipEntry entry)2820      {2821        command_ = UpdateCommand.Add;2822        entry_ = entry;2823        filename_ = fileName;2824      }28252826      [Obsolete]2827      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)2828      {2829        command_ = UpdateCommand.Add;2830        entry_ = new ZipEntry(entryName);2831        entry_.CompressionMethod = compressionMethod;2832        filename_ = fileName;2833      }28342835      [Obsolete]2836      public ZipUpdate(string fileName, string entryName)2837        : this(fileName, entryName, CompressionMethod.Deflated)2838      {2839        // Do nothing.2840      }28412842      [Obsolete]2843      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)2844      {2845        command_ = UpdateCommand.Add;2846        entry_ = new ZipEntry(entryName);2847        entry_.CompressionMethod = compressionMethod;2848        dataSource_ = dataSource;2849      }28502851      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2852      {2853        command_ = UpdateCommand.Add;2854        entry_ = entry;2855        dataSource_ = dataSource;2856      }28572858      public ZipUpdate(ZipEntry original, ZipEntry updated)2859      {2860        throw new ZipException("Modify not currently supported");2861      /*2862        command_ = UpdateCommand.Modify;2863        entry_ = ( ZipEntry )original.Clone();2864        outEntry_ = ( ZipEntry )updated.Clone();2865      */2866      }28672868      public ZipUpdate(UpdateCommand command, ZipEntry entry)2869      {2870        command_ = command;2871        entry_ = ( ZipEntry )entry.Clone();2872      }28732739      /// <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      }27452746      /// <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      }27532754      /// <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      }27612762      /// <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      }27702771      public Stream GetSource()2772      {2773        Stream result = null;2774        if (dataSource_ != null) {2775          result = dataSource_.GetSource();2776        }27772778        return result;2779      }27802781      #region Instance Fields2782      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      #endregion2791    }27922793    #endregion2794    #endregion27952796    #region Disposing27972798    #region IDisposable Members2799    void IDisposable.Dispose()2800    {2801      Close();2802    }2803    #endregion28042805    void DisposeInternal(bool disposing)2806    {2807      if (!isDisposed_) {2808        isDisposed_ = true;2809        entries_ = new ZipEntry[0];28102811        if (IsStreamOwner && (baseStream_ != null)) {2812          lock (baseStream_) {2813            baseStream_.Close();2814          }2815        }28162817        PostUpdateCleanup();2818      }2819    }28202821    /// <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    }28302831    #endregion28322833    #region Internal routines2834    #region Reading2835    /// <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 prematurely2841    /// </exception>2842    ushort ReadLEUshort()2843    {2844      int data1 = baseStream_.ReadByte();28452846      if (data1 < 0) {2847        throw new EndOfStreamException("End of stream");2848      }28492850      int data2 = baseStream_.ReadByte();28512852      if (data2 < 0) {2853        throw new EndOfStreamException("End of stream");2854      }285528562857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));2858    }28592860    /// <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 prematurely2869    /// </exception>2870    uint ReadLEUint()2871    {2872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));2873    }  28742875      /// <summary>2876      /// Copy an existing entry.2877      /// </summary>2878      /// <param name="entry">The existing entry to copy.</param>2879      public ZipUpdate(ZipEntry entry)2880        : this(UpdateCommand.Copy, entry)2881      {2882        // Do nothing.2883      }2884      #endregion28852886      /// <summary>2887      /// Get the <see cref="ZipEntry"/> for this update.2888      /// </summary>2889      /// <remarks>This is the source or original entry.</remarks>2890      public ZipEntry Entry2891      {2892        get { return entry_; }2893      }28942895      /// <summary>2896      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.2897      /// </summary>2898      public ZipEntry OutEntry2899      {2900        get {2901          if ( outEntry_ == null ) {2902            outEntry_ = (ZipEntry)entry_.Clone();2903          }29042905          return outEntry_;2906        }2907      }2875    ulong ReadLEUlong()2876    {2877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);2878    }28792880    #endregion2881    // 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    }28882889    /// <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 found2897    /// </exception>2898    void ReadEntries()2899    {2900      // Search for the End Of Central Directory.  When a zip comment is2901      // present the directory will start earlier2902      //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 files2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then2906      // this could be invalid.2907      // Could also speed this up by reading memory in larger blocks.  29082909      /// <summary>2910      /// Get the command for this update.2911      /// </summary>2912      public UpdateCommand Command2913      {2914        get { return command_; }2915      }29162917      /// <summary>2918      /// Get the filename if any for this update.  Null if none exists.2919      /// </summary>2920      public string Filename2921      {2922        get { return filename_; }2923      }29242925      /// <summary>2926      /// Get/set the location of the size patch for this update.2927      /// </summary>2928      public long SizePatchOffset2929      {2930        get { return sizePatchOffset_; }2931        set { sizePatchOffset_ = value; }2932      }29332934      /// <summary>2935      /// Get /set the location of the crc patch for this update.2936      /// </summary>2937      public long CrcPatchOffset2938      {2939        get { return crcPatchOffset_; }2940        set { crcPatchOffset_ = value; }2941      }29422943      /// <summary>2944      /// Get/set the size calculated by offset.2945      /// Specifically, the difference between this and next entry's starting offset.2946      /// </summary>2947      public long OffsetBasedSize2948      {2949        get { return _offsetBasedSize; }2950        set { _offsetBasedSize = value; }2951      }29522953      public Stream GetSource()2954      {2955        Stream result = null;2956        if ( dataSource_ != null ) {2957          result = dataSource_.GetSource();2958        }29592960        return result;2961      }29622963      #region Instance Fields2964      ZipEntry entry_;2965      ZipEntry outEntry_;2966      UpdateCommand command_;2967      IStaticDataSource dataSource_;2968      string filename_;2969      long sizePatchOffset_ = -1;2970      long crcPatchOffset_ = -1;2971      long _offsetBasedSize = -1;2972      #endregion2973    }29742975    #endregion2976    #endregion29772978    #region Disposing29792980    #region IDisposable Members2981    void IDisposable.Dispose()2982    {2983      Close();2984    }2985    #endregion29862987    void DisposeInternal(bool disposing)2988    {2989      if ( !isDisposed_ ) {2990        isDisposed_ = true;2991        entries_ = new ZipEntry[0];29922993        if ( IsStreamOwner && (baseStream_ != null) ) {2994          lock(baseStream_) {2995            baseStream_.Close();2996          }2997        }2909      if (baseStream_.CanSeek == false) {2910        throw new ZipException("ZipFile stream must be seekable");2911      }29122913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,2914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);29152916      if (locatedEndOfCentralDir < 0) {2917        throw new ZipException("Cannot find central directory");2918      }29192920      // Read end of central directory record2921      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();29282929      if (commentSize > 0) {2930        byte[] comment = new byte[commentSize];29312932        StreamUtils.ReadFully(baseStream_, comment);2933        comment_ = ZipConstants.ConvertToString(comment);2934      } else {2935        comment_ = string.Empty;2936      }29372938      bool isZip64 = false;29392940      // 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;29482949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 2950        if (offset < 0) {2951          throw new ZipException("Cannot find Zip64 locator");2952        }29532954        // number of the disk with the start of the zip64 end of central directory 4 bytes2955        // relative offset of the zip64 end of central directory record 8 bytes2956        // total number of disks 4 bytes2957        ReadLEUint(); // startDisk64 is not currently used2958        ulong offset64 = ReadLEUlong();2959        uint totalDisks = ReadLEUint();29602961        baseStream_.Position = (long)offset64;2962        long sig64 = ReadLEUint();29632964        if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {2965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));2966        }29672968        // 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();29782979        // NOTE: zip64 extensible data sector (variable size) is ignored.2980      }29812982      entries_ = new ZipEntry[entriesForThisDisk];29832984      // SFX/embedded support, find the offset of the first entry vis the start of the stream2985      // 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 offsets2988      // 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      }29962997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);  29982999        PostUpdateCleanup();3000      }3001    }30023003    /// <summary>3004    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.3005    /// </summary>3006    /// <param name="disposing">true to release both managed and unmanaged resources;3007    /// false to release only unmanaged resources.</param>3008    protected virtual void Dispose(bool disposing)3009    {3010      DisposeInternal(disposing);3011    }30123013    #endregion30143015    #region Internal routines3016    #region Reading3017    /// <summary>3018    /// Read an unsigned short in little endian byte order.3019    /// </summary>3020    /// <returns>Returns the value read.</returns>3021    /// <exception cref="EndOfStreamException">3022    /// The stream ends prematurely3023    /// </exception>3024    ushort ReadLEUshort()3025    {3026      int data1 = baseStream_.ReadByte();30273028      if ( data1 < 0 ) {3029        throw new EndOfStreamException("End of stream");3030      }30313032      int data2 = baseStream_.ReadByte();30333034      if ( data2 < 0 ) {3035        throw new EndOfStreamException("End of stream");3036      }303730383039      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));3040    }30413042    /// <summary>3043    /// Read a uint in little endian byte order.3044    /// </summary>3045    /// <returns>Returns the value read.</returns>3046    /// <exception cref="IOException">3047    /// An i/o error occurs.3048    /// </exception>3049    /// <exception cref="System.IO.EndOfStreamException">3050    /// The file ends prematurely3051    /// </exception>3052    uint ReadLEUint()3053    {3054      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));3055    }30563057    ulong ReadLEUlong()3058    {3059      return ReadLEUint() | ((ulong)ReadLEUint() << 32);3060    }30613062    #endregion3063    // NOTE this returns the offset of the first byte after the signature.3064    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)3065    {3066      using ( ZipHelperStream les = new ZipHelperStream(baseStream_) ) {3067        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);3068      }3069    }30703071    /// <summary>3072    /// Search for and read the central directory of a zip file filling the entries array.3073    /// </summary>3074    /// <exception cref="System.IO.IOException">3075    /// An i/o error occurs.3076    /// </exception>3077    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3078    /// The central directory is malformed or cannot be found3079    /// </exception>3080    void ReadEntries()3081    {3082      // Search for the End Of Central Directory.  When a zip comment is3083      // present the directory will start earlier3084      //3085      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.3086      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files3087      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then3088      // this could be invalid.3089      // Could also speed this up by reading memory in larger blocks.2999      for (ulong i = 0; i < entriesForThisDisk; i++) {3000        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {3001          throw new ZipException("Wrong Central Directory signature");3002        }30033004        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();30153016        int diskStartNo = ReadLEUshort();  // Not currently used3017        int internalAttributes = ReadLEUshort();  // Not currently used30183019        uint externalAttributes = ReadLEUint();3020        long offset = ReadLEUint();30213022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];30233024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);3025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);30263027        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;30363037        if ((bitFlags & 8) == 0) {3038          entry.CryptoCheckValue = (byte)(crc >> 24);3039        } else {3040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3041        }30423043        if (extraLen > 0) {3044          byte[] extra = new byte[extraLen];3045          StreamUtils.ReadFully(baseStream_, extra);3046          entry.ExtraData = extra;3047        }30483049        entry.ProcessExtraData(false);30503051        if (commentLen > 0) {3052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);3053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3054        }30553056        entries_[i] = entry;3057      }3058    }30593060    /// <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 prematurely3068    /// </exception>3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3070    /// The local header signature is invalid, the entry and central header file name lengths are different3071    /// or the local and entry compression methods dont match3072    /// </exception>3073    long LocateEntry(ZipEntry entry)3074    {3075      return TestLocalHeader(entry, HeaderTest.Extract);3076    }30773078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3079    {3080      CryptoStream result = null;30813082      if ((entry.Version < ZipConstants.VersionStrongEncryption)3083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3084        var classicManaged = new PkzipClassicManaged();30853086        OnKeysRequired(entry.Name);3087        if (HaveKeys == false) {3088          throw new ZipException("No password available for encrypted stream");3089        }  30903091      if (baseStream_.CanSeek == false) {3092        throw new ZipException("ZipFile stream must be seekable");3093      }30943095      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,3096        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);30973098      if (locatedEndOfCentralDir < 0) {3099        throw new ZipException("Cannot find central directory");3100      }31013102      // Read end of central directory record3103      ushort thisDiskNumber           = ReadLEUshort();3104      ushort startCentralDirDisk      = ReadLEUshort();3105      ulong entriesForThisDisk        = ReadLEUshort();3106      ulong entriesForWholeCentralDir = ReadLEUshort();3107      ulong centralDirSize            = ReadLEUint();3108      long offsetOfCentralDir         = ReadLEUint();3109      uint commentSize                = ReadLEUshort();31103111      if ( commentSize > 0 ) {3112        byte[] comment = new byte[commentSize];31133114        StreamUtils.ReadFully(baseStream_, comment);3115        comment_ = ZipConstants.ConvertToString(comment);3116      }3117      else {3118        comment_ = string.Empty;3119      }31203121      bool isZip64 = false;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 bytes31093110          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      }31193120      return result;3121    }  31223123      // Check if zip64 header information is required.3124      if ( (thisDiskNumber == 0xffff) ||3125        (startCentralDirDisk == 0xffff) ||3126        (entriesForThisDisk == 0xffff) ||3127        (entriesForWholeCentralDir == 0xffff) ||3128        (centralDirSize == 0xffffffff) ||3129        (offsetOfCentralDir == 0xffffffff) ) {3130        isZip64 = true;31313132        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 3133        if ( offset < 0 ) {3134          throw new ZipException("Cannot find Zip64 locator");3135        }31363137        // number of the disk with the start of the zip64 end of central directory 4 bytes3138        // relative offset of the zip64 end of central directory record 8 bytes3139        // total number of disks 4 bytes3140        ReadLEUint(); // startDisk64 is not currently used3141        ulong offset64 = ReadLEUlong();3142        uint totalDisks = ReadLEUint();31433144        baseStream_.Position = (long)offset64;3145        long sig64 = ReadLEUint();31463147        if ( sig64 != ZipConstants.Zip64CentralFileHeaderSignature ) {3148          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));3149        }31503151        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.3152        ulong recordSize = ReadLEUlong();3153        int versionMadeBy = ReadLEUshort();3154        int versionToExtract = ReadLEUshort();3155        uint thisDisk = ReadLEUint();3156        uint centralDirDisk = ReadLEUint();3157        entriesForThisDisk = ReadLEUlong();3158        entriesForWholeCentralDir = ReadLEUlong();3159        centralDirSize = ReadLEUlong();3160        offsetOfCentralDir = (long)ReadLEUlong();31613162        // NOTE: zip64 extensible data sector (variable size) is ignored.3163      }31643165      entries_ = new ZipEntry[entriesForThisDisk];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();31293130        OnKeysRequired(entry.Name);3131        if (HaveKeys == false) {3132          throw new ZipException("No password available for encrypted stream");3133        }31343135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3136        // which doesnt do this.3137        result = new CryptoStream(new UncompressedStream(baseStream),3138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);31393140        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    }31483149    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    }31573158    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    }  31663167      // SFX/embedded support, find the offset of the first entry vis the start of the stream3168      // This applies to Zip files that are appended to the end of an SFX stub.3169      // Or are appended as a resource to an executable.3170      // Zip files created by some archivers have the offsets altered to reflect the true offsets3171      // and so dont require any adjustment here...3172      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?3173      if ( !isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize)) ) {3174        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);3175        if (offsetOfFirstEntry <= 0) {3176          throw new ZipException("Invalid embedded zip archive");3177        }3178      }31793180      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);31813182      for (ulong i = 0; i < entriesForThisDisk; i++) {3183        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {3184          throw new ZipException("Wrong Central Directory signature");3185        }3167    #endregion31683169    #region Instance Fields3170    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_;31803181    // Default is dynamic which is not backwards compatible and can cause problems3182    // 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;  31863187        int versionMadeBy      = ReadLEUshort();3188        int versionToExtract   = ReadLEUshort();3189        int bitFlags           = ReadLEUshort();3190        int method             = ReadLEUshort();3191        uint dostime           = ReadLEUint();3192        uint crc               = ReadLEUint();3193        var csize             = (long)ReadLEUint();3194        var size              = (long)ReadLEUint();3195        int nameLen            = ReadLEUshort();3196        int extraLen           = ReadLEUshort();3197        int commentLen         = ReadLEUshort();31983199        int diskStartNo        = ReadLEUshort();  // Not currently used3200        int internalAttributes = ReadLEUshort();  // Not currently used3187    #region Zip Update Instance Fields3188    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    #endregion3200    #endregion  32013202        uint externalAttributes = ReadLEUint();3203        long offset             = ReadLEUint();32043205        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];32063207        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);3208        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);32093210        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);3211        entry.Crc = crc & 0xffffffffL;3212        entry.Size = size & 0xffffffffL;3213        entry.CompressedSize = csize & 0xffffffffL;3214        entry.Flags = bitFlags;3215        entry.DosTime = (uint)dostime;3216        entry.ZipFileIndex = (long)i;3217        entry.Offset = offset;3218        entry.ExternalFileAttributes = (int)externalAttributes;32193220        if ((bitFlags & 8) == 0) {3221          entry.CryptoCheckValue = (byte)(crc >> 24);3222        }3223        else {3224          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3225        }32263227        if (extraLen > 0) {3228          byte[] extra = new byte[extraLen];3229          StreamUtils.ReadFully(baseStream_, extra);3230          entry.ExtraData = extra;3231        }32323233        entry.ProcessExtraData(false);32343235        if (commentLen > 0) {3236          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);3237          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3238        }32393240        entries_[i] = entry;3241      }3242    }32433244    /// <summary>3245    /// Locate the data for a given entry.3246    /// </summary>3247    /// <returns>3248    /// The start offset of the data.3249    /// </returns>3250    /// <exception cref="System.IO.EndOfStreamException">3251    /// The stream ends prematurely3252    /// </exception>3253    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3254    /// The local header signature is invalid, the entry and central header file name lengths are different3255    /// or the local and entry compression methods dont match3256    /// </exception>3257    long LocateEntry(ZipEntry entry)3258    {3259      return TestLocalHeader(entry, HeaderTest.Extract);3260    }32613262#if !NETCF_1_03263    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3264    {3265      CryptoStream result = null;32663267      if ( (entry.Version < ZipConstants.VersionStrongEncryption)3268        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3269        var classicManaged = new PkzipClassicManaged();32703271        OnKeysRequired(entry.Name);3272        if (HaveKeys == false) {3273          throw new ZipException("No password available for encrypted stream");3274        }3202    #region Support Classes3203    /// <summary>3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3205    /// </summary>3206    class ZipString3207    {3208      #region Constructors3209      /// <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      }32183219      /// <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      #endregion32283229      /// <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      }32363237      /// <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      }32463247      /// <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      }32563257      /// <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      }32683269      void MakeTextAvailable()3270      {3271        if (comment_ == null) {3272          comment_ = ZipConstants.ConvertToString(rawComment_);3273        }3274      }  32753276        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);3277        CheckClassicPassword(result, entry);3278      }3279      else {3280#if !NET_1_1 && !NETCF_2_03281        if (entry.Version == ZipConstants.VERSION_AES) {3282          //3283          OnKeysRequired(entry.Name);3284          if (HaveKeys == false) {3285            throw new ZipException("No password available for AES encrypted stream");3286          }3287          int saltLen = entry.AESSaltLen;3288          byte[] saltBytes = new byte[saltLen];3289          int saltIn = baseStream.Read(saltBytes, 0, saltLen);3290          if (saltIn != saltLen)3291            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);3292          //3293          byte[] pwdVerifyRead = new byte[2];3294          baseStream.Read(pwdVerifyRead, 0, 2);3295          int blockSize = entry.AESKeySize / 8;  // bits to bytes32963297          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);3298          byte[] pwdVerifyCalc = decryptor.PwdVerifier;3299          if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])3300            throw new Exception("Invalid password for AES");3301          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);3302        }3303        else3304#endif3305        {3306          throw new ZipException("Decryption method not supported");3307        }3308      }33093310      return result;3311    }33123313    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)3314    {3315      CryptoStream result = null;3316      if ( (entry.Version < ZipConstants.VersionStrongEncryption)3317        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3318        var classicManaged = new PkzipClassicManaged();3276      void MakeBytesAvailable()3277      {3278        if (rawComment_ == null) {3279          rawComment_ = ZipConstants.ConvertToArray(comment_);3280        }3281      }32823283      /// <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      }32933294      #region Instance Fields3295      string comment_;3296      byte[] rawComment_;3297      bool isSourceString_;3298      #endregion3299    }33003301    /// <summary>3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3303    /// </summary>3304    class ZipEntryEnumerator : IEnumerator3305    {3306      #region Constructors3307      public ZipEntryEnumerator(ZipEntry[] entries)3308      {3309        array = entries;3310      }33113312      #endregion3313      #region IEnumerator Members3314      public object Current {3315        get {3316          return array[index];3317        }3318      }  33193320        OnKeysRequired(entry.Name);3321        if (HaveKeys == false) {3322          throw new ZipException("No password available for encrypted stream");3323        }3320      public void Reset()3321      {3322        index = -1;3323      }  33243325        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3326        // which doesnt do this.3327        result = new CryptoStream(new UncompressedStream(baseStream),3328          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);33293330        if ( (entry.Crc < 0) || (entry.Flags & 8) != 0) {3331          WriteEncryptionHeader(result, entry.DosTime << 16);3332        }3333        else {3334          WriteEncryptionHeader(result, entry.Crc);3335        }3336      }3337      return result;3338    }33393340    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)3325      public bool MoveNext()3326      {3327        return (++index < array.Length);3328      }3329      #endregion3330      #region Instance Fields3331      ZipEntry[] array;3332      int index = -1;3333      #endregion3334    }33353336    /// <summary>3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3338    /// to and flush, but cannot read, seek or do anything else to.3339    /// </summary>3340    class UncompressedStream : Stream  3341    {3342      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];3343      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);3344      if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {3345        throw new ZipException("Invalid password");3342      #region Constructors3343      public UncompressedStream(Stream baseStream)3344      {3345        baseStream_ = baseStream;  3346      }3347    }3348#endif33473348      #endregion  33493350    static void WriteEncryptionHeader(Stream stream, long crcValue)3351    {3352      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];3353      var rnd = new Random();3354      rnd.NextBytes(cryptBuffer);3355      cryptBuffer[11] = (byte)(crcValue >> 24);3356      stream.Write(cryptBuffer, 0, cryptBuffer.Length);3357    }33583359    #endregion33603361    #region Instance Fields3362    bool       isDisposed_;3363    string     name_;3364    string     comment_;3365    string     rawPassword_;3366    Stream     baseStream_;3367    bool       isStreamOwner;3368    long       offsetOfFirstEntry;3369    ZipEntry[] entries_;3370    byte[] key;3371    bool isNewArchive_;33723373    // Default is dynamic which is not backwards compatible and can cause problems3374    // with XP's built in compression which cant read Zip64 archives.3375    // However it does avoid the situation were a large file is added and cannot be completed correctly.3376    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.3377    UseZip64 useZip64_ = UseZip64.Dynamic ;33783379    #region Zip Update Instance Fields3380    ArrayList updates_;3381    long updateCount_; // Count is managed manually as updates_ can contain nulls!3382    Hashtable updateIndex_;3383    IArchiveStorage archiveStorage_;3384    IDynamicDataSource updateDataSource_;3385    bool contentsEdited_;3386    int bufferSize_ = DefaultBufferSize;3387    byte[] copyBuffer_;3388    ZipString newComment_;3389    bool commentEdited_;3390    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();3391    #endregion3392    #endregion33933394    #region Support Classes3395    /// <summary>3396    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3397    /// </summary>3398    class ZipString3399    {3400      #region Constructors3401      /// <summary>3402      /// Initialise a <see cref="ZipString"/> with a string.3403      /// </summary>3404      /// <param name="comment">The textual string form.</param>3405      public ZipString(string comment)3406      {3407        comment_ = comment;3408        isSourceString_ = true;3409      }34103411      /// <summary>3412      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.3413      /// </summary>3414      /// <param name="rawString"></param>3415      public ZipString(byte[] rawString)3416      {3417        rawComment_ = rawString;3418      }3419      #endregion34203421      /// <summary>3422      /// Get a value indicating the original source of data for this instance.3423      /// True if the source was a string; false if the source was binary data.3424      /// </summary>3425      public bool IsSourceString3426      {3427        get { return isSourceString_; }3428      }34293430      /// <summary>3431      /// Get the length of the comment when represented as raw bytes.3432      /// </summary>3433      public int RawLength3434      {3435        get {3436          MakeBytesAvailable();3437          return rawComment_.Length;3438        }3439      }34403441      /// <summary>3442      /// Get the comment in its 'raw' form as plain bytes.3443      /// </summary>3444      public byte[] RawComment3445      {3446        get {3447          MakeBytesAvailable();3448          return (byte[])rawComment_.Clone();3449        }3450      }34513452      /// <summary>3453      /// Reset the comment to its initial state.3454      /// </summary>3455      public void Reset()3456      {3457        if ( isSourceString_ ) {3458          rawComment_ = null;3459        }3460        else {3461          comment_ = null;3462        }3463      }34643465      void MakeTextAvailable()3466      {3467        if ( comment_ == null ) {3468          comment_ = ZipConstants.ConvertToString(rawComment_);3469        }3470      }34713472      void MakeBytesAvailable()3473      {3474        if ( rawComment_ == null ) {3475          rawComment_ = ZipConstants.ConvertToArray(comment_);3476        }3477      }34783479      /// <summary>3480      /// Implicit conversion of comment to a string.3481      /// </summary>3482      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>3483      /// <returns>The textual equivalent for the input value.</returns>3484      static public implicit operator string(ZipString zipString)3485      {3486        zipString.MakeTextAvailable();3487        return zipString.comment_;3488      }34893490      #region Instance Fields3491      string comment_;3492      byte[] rawComment_;3493      bool isSourceString_;3494      #endregion3495    }34963497    /// <summary>3498    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3499    /// </summary>3500    class ZipEntryEnumerator : IEnumerator3501    {3502      #region Constructors3503      public ZipEntryEnumerator(ZipEntry[] entries)3504      {3505        array = entries;3506      }35073508      #endregion3509      #region IEnumerator Members3510      public object Current3511      {3512        get {3513          return array[index];3514        }3515      }35163517      public void Reset()3518      {3519        index = -1;3520      }35213522      public bool MoveNext()3523      {3524        return (++index < array.Length);3525      }3526      #endregion3527      #region Instance Fields3528      ZipEntry[] array;3529      int index = -1;3530      #endregion3531    }35323533    /// <summary>3534    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3535    /// to and flush, but cannot read, seek or do anything else to.3536    /// </summary>3537    class UncompressedStream : Stream3538    {3539      #region Constructors3540      public UncompressedStream(Stream baseStream)3541      {3542        baseStream_ = baseStream;3543      }35443545      #endregion35463547      /// <summary>3548      /// Close this stream instance.3549      /// </summary>3550      public override void Close()3551      {3552        // Do nothing3553      }35543555      /// <summary>3556      /// Gets a value indicating whether the current stream supports reading.3557      /// </summary>3558      public override bool CanRead3559      {3560        get {3561          return false;3562        }3563      }35643565      /// <summary>3566      /// Write any buffered data to underlying storage.3567      /// </summary>3568      public override void Flush()3569      {3570        baseStream_.Flush();3571      }35723573      /// <summary>3574      /// Gets a value indicating whether the current stream supports writing.3575      /// </summary>3576      public override bool CanWrite3577      {3578        get {3579          return baseStream_.CanWrite;3580        }3581      }35823583      /// <summary>3584      /// Gets a value indicating whether the current stream supports seeking.3585      /// </summary>3586      public override bool CanSeek3587      {3588        get {3589          return false;3590        }3591      }35923593      /// <summary>3594      /// Get the length in bytes of the stream.3595      /// </summary>3596      public override long Length3597      {3598        get {3599          return 0;3600        }3601      }36023603      /// <summary>3604      /// Gets or sets the position within the current stream.3605      /// </summary>3606      public override long Position3607      {3608        get  {3609          return baseStream_.Position;3610        }3611                set {3612                    throw new NotImplementedException();3613                }3614            }36153616            /// <summary>3617            /// Reads a sequence of bytes from the current stream and advances the position within the stream by the num3618            /// </summary>3619            /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte3620            /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from t3621            /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3622            /// <returns>3623            /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if t3624            /// </returns>3625            /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer lengt3626            /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </ex3627            /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3628            /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3629            /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3630            /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3631            public override int Read(byte[] buffer, int offset, int count)3632      {3633        return 0;3634      }36353636      /// <summary>3637      /// Sets the position within the current stream.3638      /// </summary>3639      /// <param name="offset">A byte offset relative to the origin parameter.</param>3640      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3641      /// <returns>3642      /// The new position within the current stream.3643      /// </returns>3644      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3645      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3646      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3647      public override long Seek(long offset, SeekOrigin origin)3648      {3649        return 0;3650      }36513652      /// <summary>3653      /// Sets the length of the current stream.3654      /// </summary>3655      /// <param name="value">The desired length of the current stream in bytes.</param>3656      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3350      /// <summary>3351      /// Close this stream instance.3352      /// </summary>3353      public override void Close()3354      {3355        // Do nothing3356      }33573358      /// <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      }33663367      /// <summary>3368      /// Write any buffered data to underlying storage.3369      /// </summary>3370      public override void Flush()3371      {3372        baseStream_.Flush();3373      }33743375      /// <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      }33833384      /// <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      }33923393      /// <summary>3394      /// Get the length in bytes of the stream.3395      /// </summary>3396      public override long Length {3397        get {3398          return 0;3399        }3400      }34013402      /// <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      }34133414      /// <summary>3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3416      /// </summary>3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3419      /// <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 ma3422      /// </returns>3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3425      /// <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      }34333434      /// <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 is3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3445      public override long Seek(long offset, SeekOrigin origin)3446      {3447        return 0;3448      }34493450      /// <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 as3455      /// <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. </exceptio3457      public override void SetLength(long value)3458      {3459      }34603461      /// <summary>3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3463      /// </summary>3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3466      /// <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. </exceptio3470      /// <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      }34773478      readonly34793480      #region Instance Fields3481      Stream baseStream_;3482      #endregion3483    }34843485    /// <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 : Stream3490    {3491      #region Constructors3492      /// <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;35023503        // Although this is the only time the zipfile is used3504        // keeping a reference here prevents premature closure of3505        // this zip file and thus the baseStream_.35063507        // Code like this will cause apparently random failures depending3508        // 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      #endregion35193520      /// <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        }35303531        lock (baseStream_) {3532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);3533          return baseStream_.ReadByte();3534        }3535      }35363537      /// <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      }35473548      /// <summary>3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3550      /// </summary>3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3553      /// <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 ma3556      /// </returns>3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3559      /// <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 Seek3573          // (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      }35843585      /// <summary>3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3587      /// </summary>3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3590      /// <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. </exceptio3594      /// <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      }36013602      /// <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 as3607      /// <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. </exceptio3609      public override void SetLength(long value)3610      {3611        throw new NotSupportedException();3612      }36133614      /// <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 is3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3625      public override long Seek(long offset, SeekOrigin origin)3626      {3627        long newPos = readPos_;36283629        switch (origin) {3630          case SeekOrigin.Begin:3631            newPos = start_ + offset;3632            break;36333634          case SeekOrigin.Current:3635            newPos = readPos_ + offset;3636            break;36373638          case SeekOrigin.End:3639            newPos = end_ + offset;3640            break;3641        }36423643        if (newPos < start_) {3644          throw new ArgumentException("Negative position is invalid");3645        }36463647        if (newPos >= end_) {3648          throw new IOException("Cannot seek past end");3649        }3650        readPos_ = newPos;3651        return readPos_;3652      }36533654      /// <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      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3659      public override void SetLength(long value)3660      {3658      public override void Flush()3659      {3660        // Nothing to do.  3661      }  3662  3663      /// <summary>3664      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3664      /// Gets or sets the position within the current stream.  3665      /// </summary>3666      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3667      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3668      /// <param name="count">The number of bytes to be written to the current stream.</param>3669      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3670      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3671      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3672      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3673      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3674      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3675      public override void Write(byte[] buffer, int offset, int count)3676      {3677        baseStream_.Write(buffer, offset, count);3678      }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. </exceptio3671      public override long Position {3672        get { return readPos_ - start_; }3673        set {3674          long newPos = start_ + value;36753676          if (newPos < start_) {3677            throw new ArgumentException("Negative position is invalid");3678          }  36793680      readonly36813682      #region Instance Fields3683      Stream baseStream_;3684      #endregion3685    }3680          if (newPos >= end_) {3681            throw new InvalidOperationException("Cannot seek past end");3682          }3683          readPos_ = newPos;3684        }3685      }  36863687    /// <summary>3688    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>3689    /// whose data is only a part or subsection of a file.3690    /// </summary>3691    class PartialInputStream : Stream3692    {3693      #region Constructors3694      /// <summary>3695      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.3696      /// </summary>3697      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>3698      /// <param name="start">The start of the partial data.</param>3699      /// <param name="length">The length of the partial data.</param>3700      public PartialInputStream(ZipFile zipFile, long start, long length)3701      {3702        start_ = start;3703        length_ = length;37043705        // Although this is the only time the zipfile is used3706        // keeping a reference here prevents premature closure of3707        // this zip file and thus the baseStream_.37083709        // Code like this will cause apparently random failures depending3710        // on the size of the files and when garbage is collected.3711        //3712        // ZipFile z = new ZipFile (stream);3713        // Stream reader = z.GetInputStream(0);3714        // uses reader here....3715        zipFile_ = zipFile;3716        baseStream_ = zipFile_.baseStream_;3717        readPos_ = start;3718        end_ = start + length;3719      }3720      #endregion37213722      /// <summary>3723      /// Read a byte from this stream.3724      /// </summary>3725      /// <returns>Returns the byte read or -1 on end of stream.</returns>3726      public override int ReadByte()3727      {3728        if (readPos_ >= end_) {3729           // -1 is the correct value at end of stream.3730          return -1;3731        }37323733        lock( baseStream_ ) {3734          baseStream_.Seek(readPos_++, SeekOrigin.Begin);3735          return baseStream_.ReadByte();3736        }3737      }37383739      /// <summary>3740      /// Close this <see cref="PartialInputStream">partial input stream</see>.3741      /// </summary>3742      /// <remarks>3743      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.3744      /// </remarks>3745      public override void Close()3746      {3747        // Do nothing at all!3748      }37493750      /// <summary>3751      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3752      /// </summary>3753      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3754      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3755      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3756      /// <returns>3757      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma3758      /// </returns>3759      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3760      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3761      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3762      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3763      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3764      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3765      public override int Read(byte[] buffer, int offset, int count)3766      {3767        lock(baseStream_) {3768          if (count > end_ - readPos_) {3769            count = (int) (end_ - readPos_);3770            if (count == 0) {3771              return 0;3772            }3773          }37743775          baseStream_.Seek(readPos_, SeekOrigin.Begin);3776          int readCount = baseStream_.Read(buffer, offset, count);3777          if (readCount > 0) {3778            readPos_ += readCount;3779          }3780          return readCount;3781        }3782      }37833784      /// <summary>3785      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3786      /// </summary>3787      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3788      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3789      /// <param name="count">The number of bytes to be written to the current stream.</param>3790      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3791      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3792      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3793      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3794      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3795      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3796      public override void Write(byte[] buffer, int offset, int count)3797      {3798        throw new NotSupportedException();3799      }38003801      /// <summary>3802      /// When overridden in a derived class, sets the length of the current stream.3803      /// </summary>3804      /// <param name="value">The desired length of the current stream in bytes.</param>3805      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3806      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3807      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3808      public override void SetLength(long value)3809      {3810        throw new NotSupportedException();3811      }38123813      /// <summary>3814      /// When overridden in a derived class, sets the position within the current stream.3815      /// </summary>3816      /// <param name="offset">A byte offset relative to the origin parameter.</param>3817      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3818      /// <returns>3819      /// The new position within the current stream.3820      /// </returns>3821      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3822      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3823      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3824      public override long Seek(long offset, SeekOrigin origin)3825      {3826        long newPos = readPos_;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. </excep3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3694      public override long Length {3695        get { return length_; }3696      }36973698      /// <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      }37063707      /// <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      }37153716      /// <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      }37243725      /// <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 Fields3734      ZipFile zipFile_;3735      Stream baseStream_;3736      long start_;3737      long length_;3738      long readPos_;3739      long end_;3740      #endregion3741    }3742    #endregion3743  }37443745  #endregion37463747  #region DataSources3748  /// <summary>3749  /// Provides a static way to obtain a source of data for an entry.3750  /// </summary>3751  public interface IStaticDataSource3752  {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  }37603761  /// <summary>3762  /// Represents a source of data that can dynamically provide3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3764  /// </summary>3765  public interface IDynamicDataSource3766  {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  }37763777  /// <summary>3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3779  /// </summary>3780  public class StaticDiskDataSource : IStaticDataSource3781  {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    }37903791    #region IDataSource Members37923793    /// <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    }38013802    readonly38033804    #endregion3805    #region Instance Fields3806    string fileName_;3807    #endregion3808  }380938103811  /// <summary>3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.3813  /// </summary>3814  public class DynamicDiskDataSource : IDynamicDataSource3815  {38163817    #region IDataSource Members3818    /// <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;  38273828        switch ( origin )3829        {3830          case SeekOrigin.Begin:3831            newPos = start_ + offset;3832            break;38333834          case SeekOrigin.Current:3835            newPos = readPos_ + offset;3836            break;3828      if (name != null) {3829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);3830      }38313832      return result;3833    }38343835    #endregion3836  }  38373838          case SeekOrigin.End:3839            newPos = end_ + offset;3840            break;3841        }38423843        if ( newPos < start_ ) {3844          throw new ArgumentException("Negative position is invalid");3845        }38463847        if ( newPos >= end_ ) {3848          throw new IOException("Cannot seek past end");3849        }3850        readPos_ = newPos;3851        return readPos_;3852      }38533854      /// <summary>3855      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.3856      /// </summary>3857      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3858      public override void Flush()3859      {3860        // Nothing to do.3861      }38623863      /// <summary>3864      /// Gets or sets the position within the current stream.3865      /// </summary>3866      /// <value></value>3867      /// <returns>The current position within the stream.</returns>3868      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3869      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>3870      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3871      public override long Position {3872        get { return readPos_ - start_; }3873        set {3874          long newPos = start_ + value;38753876          if ( newPos < start_ ) {3877            throw new ArgumentException("Negative position is invalid");3878          }3838  #endregion38393840  #region Archive Storage3841  /// <summary>3842  /// Defines facilities for data storage when updating Zip Archives.3843  /// </summary>3844  public interface IArchiveStorage3845  {3846    /// <summary>3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.3848    /// </summary>3849    FileUpdateMode UpdateMode { get; }38503851    /// <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();38573858    /// <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();38643865    /// <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);38713872    /// <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);  38793880          if ( newPos >= end_ ) {3881            throw new InvalidOperationException("Cannot seek past end");3882          }3883          readPos_ = newPos;3884        }3885      }38863887      /// <summary>3888      /// Gets the length in bytes of the stream.3889      /// </summary>3890      /// <value></value>3891      /// <returns>A long value representing the length of the stream in bytes.</returns>3892      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep3893      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3894      public override long Length {3895        get { return length_; }3896      }38973898      /// <summary>3899      /// Gets a value indicating whether the current stream supports writing.3900      /// </summary>3901      /// <value>false</value>3902      /// <returns>true if the stream supports writing; otherwise, false.</returns>3903      public override bool CanWrite {3904        get { return false; }3905      }39063907      /// <summary>3908      /// Gets a value indicating whether the current stream supports seeking.3909      /// </summary>3910      /// <value>true</value>3911      /// <returns>true if the stream supports seeking; otherwise, false.</returns>3912      public override bool CanSeek {3913        get { return true; }3914      }39153916      /// <summary>3917      /// Gets a value indicating whether the current stream supports reading.3918      /// </summary>3919      /// <value>true.</value>3920      /// <returns>true if the stream supports reading; otherwise, false.</returns>3921      public override bool CanRead {3922        get { return true; }3923      }39243925#if !NET_1_0 && !NET_1_1 && !NETCF_1_03926      /// <summary>3927      /// Gets a value that determines whether the current stream can time out.3928      /// </summary>3929      /// <value></value>3930      /// <returns>A value that determines whether the current stream can time out.</returns>3931      public override bool CanTimeout {3932        get { return baseStream_.CanTimeout; }3933      }3934#endif3935      #region Instance Fields3936      ZipFile zipFile_;3937      Stream baseStream_;3938      long start_;3939      long length_;3940      long readPos_;3941      long end_;3942      #endregion3943    }3944    #endregion3945  }39463947  #endregion39483949  #region DataSources3950  /// <summary>3951  /// Provides a static way to obtain a source of data for an entry.3952  /// </summary>3953  public interface IStaticDataSource3954  {3955    /// <summary>3956    /// Get a source of data by creating a new stream.3957    /// </summary>3958    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3959    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3960    Stream GetSource();3961  }39623963  /// <summary>3964  /// Represents a source of data that can dynamically provide3965  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3966  /// </summary>3967  public interface IDynamicDataSource3968  {3969    /// <summary>3970    /// Get a data source.3971    /// </summary>3972    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>3973    /// <param name="name">The name for data if known.</param>3974    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3975    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3976    Stream GetSource(ZipEntry entry, string name);3977  }39783979  /// <summary>3980  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3981  /// </summary>3982  public class StaticDiskDataSource : IStaticDataSource3983  {3984    /// <summary>3985    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>3986    /// </summary>3987    /// <param name="fileName">The name of the file to obtain data from.</param>3988    public StaticDiskDataSource(string fileName)3989    {3990      fileName_ = fileName;3991    }39923993    #region IDataSource Members39943995    /// <summary>3996    /// Get a <see cref="Stream"/> providing data.3997    /// </summary>3998    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>3999    public Stream GetSource()4000    {4001      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4002    }3880    /// <summary>3881    /// Dispose of this instance.3882    /// </summary>3883    void Dispose();3884  }38853886  /// <summary>3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.3888  /// </summary>3889  abstract public class BaseArchiveStorage : IArchiveStorage3890  {3891    #region Constructors3892    /// <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    #endregion39013902    #region IArchiveStorage Members39033904    /// <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();39103911    /// <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 read3915    /// the final storage for the archive.</returns>3916    /// <seealso cref="GetTemporaryOutput"/>3917    public abstract Stream ConvertTemporaryToFinal();39183919    /// <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);39253926    /// <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);39323933    /// <summary>3934    /// Disposes this instance.3935    /// </summary>3936    public abstract void Dispose();39373938    /// <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    }39473948    #endregion39493950    #region Instance Fields3951    FileUpdateMode updateMode_;3952    #endregion3953  }39543955  /// <summary>3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.3957  /// </summary>3958  public class DiskArchiveStorage : BaseArchiveStorage3959  {3960    #region Constructors3961    /// <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      }39723973      fileName_ = file.Name;3974    }39753976    /// <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    #endregion39853986    #region IArchiveStorage Members39873988    /// <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      }  40034004    readonly40054006    #endregion4007    #region Instance Fields4008    string fileName_;4009    #endregion4010  }401140124013  /// <summary>4014  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.4015  /// </summary>4016  public class DynamicDiskDataSource : IDynamicDataSource4017  {40184019    #region IDataSource Members4020    /// <summary>4021    /// Get a <see cref="Stream"/> providing data for an entry.4022    /// </summary>4023    /// <param name="entry">The entry to provide data for.</param>4024    /// <param name="name">The file name for data if known.</param>4025    /// <returns>Returns a stream providing data; or null if not available</returns>4026    public Stream GetSource(ZipEntry entry, string name)4027    {4028      Stream result = null;4004      return temporaryStream_;4005    }40064007    /// <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 read4011    /// 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      }40174018      Stream result = null;40194020      string moveTempName = GetTempFileName(fileName_, false);4021      bool newFileCreated = false;40224023      try {4024        temporaryStream_.Close();4025        File.Move(fileName_, moveTempName);4026        File.Move(temporaryName_, fileName_);4027        newFileCreated = true;4028        File.Delete(moveTempName);  40294030      if ( name != null ) {4031        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);4032      }4030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4031      } catch (Exception) {4032        result = null;  40334034      return result;4035    }40364037    #endregion4038  }4034        // Try to roll back changes...4035        if (!newFileCreated) {4036          File.Move(moveTempName, fileName_);4037          File.Delete(temporaryName_);4038        }  40394040  #endregion40414042  #region Archive Storage4043  /// <summary>4044  /// Defines facilities for data storage when updating Zip Archives.4045  /// </summary>4046  public interface IArchiveStorage4047  {4048    /// <summary>4049    /// Get the <see cref="FileUpdateMode"/> to apply during updates.4050    /// </summary>4051    FileUpdateMode UpdateMode { get; }40524053    /// <summary>4054    /// Get an empty <see cref="Stream"/> that can be used for temporary output.4055    /// </summary>4056    /// <returns>Returns a temporary output <see cref="Stream"/></returns>4057    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4058    Stream GetTemporaryOutput();40594060    /// <summary>4061    /// Convert a temporary output stream to a final stream.4062    /// </summary>4063    /// <returns>The resulting final <see cref="Stream"/></returns>4064    /// <seealso cref="GetTemporaryOutput"/>4065    Stream ConvertTemporaryToFinal();40664067    /// <summary>4068    /// Make a temporary copy of the original stream.4069    /// </summary>4070    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4071    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4072    Stream MakeTemporaryCopy(Stream stream);40734074    /// <summary>4075    /// Return a stream suitable for performing direct updates on the original source.4076    /// </summary>4077    /// <param name="stream">The current stream.</param>4078    /// <returns>Returns a stream suitable for direct updating.</returns>4079    /// <remarks>This may be the current stream passed.</remarks>4080    Stream OpenForDirectUpdate(Stream stream);40814082    /// <summary>4083    /// Dispose of this instance.4084    /// </summary>4085    void Dispose();4086  }4040        throw;4041      }40424043      return result;4044    }40454046    /// <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();40544055      temporaryName_ = GetTempFileName(fileName_, true);4056      File.Copy(fileName_, temporaryName_, true);40574058      temporaryStream_ = new FileStream(temporaryName_,4059        FileMode.Open,4060        FileAccess.ReadWrite);4061      return temporaryStream_;4062    }40634064    /// <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        }40774078        result = new FileStream(fileName_,4079            FileMode.Open,4080            FileAccess.ReadWrite);4081      } else {4082        result = stream;4083      }40844085      return result;4086    }  40874088  /// <summary>4089  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.4090  /// </summary>4091  abstract public class BaseArchiveStorage : IArchiveStorage4092  {4093    #region Constructors4094    /// <summary>4095    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.4096    /// </summary>4097    /// <param name="updateMode">The update mode.</param>4098    protected BaseArchiveStorage(FileUpdateMode updateMode)4099    {4100      updateMode_ = updateMode;4101    }4102    #endregion41034104    #region IArchiveStorage Members41054106    /// <summary>4107    /// Gets a temporary output <see cref="Stream"/>4108    /// </summary>4109    /// <returns>Returns the temporary output stream.</returns>4110    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4111    public abstract Stream GetTemporaryOutput();41124113    /// <summary>4114    /// Converts the temporary <see cref="Stream"/> to its final form.4115    /// </summary>4116    /// <returns>Returns a <see cref="Stream"/> that can be used to read4117    /// the final storage for the archive.</returns>4118    /// <seealso cref="GetTemporaryOutput"/>4119    public abstract Stream ConvertTemporaryToFinal();41204121    /// <summary>4122    /// Make a temporary copy of a <see cref="Stream"/>.4123    /// </summary>4124    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>4125    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4126    public abstract Stream MakeTemporaryCopy(Stream stream);41274128    /// <summary>4129    /// Return a stream suitable for performing direct updates on the original source.4130    /// </summary>4131    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>4132    /// <returns>Returns a stream suitable for direct updating.</returns>4133    public abstract Stream OpenForDirectUpdate(Stream stream);41344135    /// <summary>4136    /// Disposes this instance.4137    /// </summary>4138    public abstract void Dispose();41394140    /// <summary>4141    /// Gets the update mode applicable.4142    /// </summary>4143    /// <value>The update mode.</value>4144    public FileUpdateMode UpdateMode4145    {4146      get {4147        return updateMode_;4148      }4149    }41504151    #endregion41524153    #region Instance Fields4154    FileUpdateMode updateMode_;4155    #endregion4156  }41574158  /// <summary>4159  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.4160  /// </summary>4161  public class DiskArchiveStorage : BaseArchiveStorage4162  {4163    #region Constructors4164    /// <summary>4165    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4166    /// </summary>4167    /// <param name="file">The file.</param>4168    /// <param name="updateMode">The update mode.</param>4169    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)4170      : base(updateMode)4171    {4172      if ( file.Name == null ) {4173        throw new ZipException("Cant handle non file archives");4174      }41754176      fileName_ = file.Name;4177    }4088    /// <summary>4089    /// Disposes this instance.4090    /// </summary>4091    public override void Dispose()4092    {4093      if (temporaryStream_ != null) {4094        temporaryStream_.Close();4095      }4096    }40974098    #endregion40994100    #region Internal routines4101    static string GetTempFileName(string original, bool makeTempFile)4102    {4103      string result = null;41044105      if (original == null) {4106        result = Path.GetTempFileName();4107      } else {4108        int counter = 0;4109        int suffixSeed = DateTime.Now.Second;41104111        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    #endregion41334134    #region Instance Fields4135    Stream temporaryStream_;4136    string fileName_;4137    string temporaryName_;4138    #endregion4139  }41404141  /// <summary>4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4143  /// </summary>4144  public class MemoryArchiveStorage : BaseArchiveStorage4145  {4146    #region Constructors4147    /// <summary>4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4149    /// </summary>4150    public MemoryArchiveStorage()4151      : base(FileUpdateMode.Direct)4152    {4153    }41544155    /// <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    }41644165    #endregion41664167    #region Properties4168    /// <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    }41744175    #endregion41764177    #region IArchiveStorage Members  4178  4179    /// <summary>4180    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4180    /// Gets the temporary output <see cref="Stream"/>  4181    /// </summary>4182    /// <param name="file">The file.</param>4183    public DiskArchiveStorage(ZipFile file)4184      : this(file, FileUpdateMode.Safe)4185    {4186    }4187    #endregion4182    /// <returns>Returns the temporary output stream.</returns>4183    public override Stream GetTemporaryOutput()4184    {4185      temporaryStream_ = new MemoryStream();4186      return temporaryStream_;4187    }  41884189    #region IArchiveStorage Members41904191    /// <summary>4192    /// Gets a temporary output <see cref="Stream"/> for performing updates on.4193    /// </summary>4194    /// <returns>Returns the temporary output stream.</returns>4195    public override Stream GetTemporaryOutput()4196    {4197      if ( temporaryName_ != null ) {4198        temporaryName_ = GetTempFileName(temporaryName_, true);4199        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4200      }4201      else {4202        // Determine where to place files based on internal strategy.4203        // Currently this is always done in system temp directory.4204        temporaryName_ = Path.GetTempFileName();4205        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4206      }42074208      return temporaryStream_;4209    }42104211    /// <summary>4212    /// Converts a temporary <see cref="Stream"/> to its final form.4213    /// </summary>4214    /// <returns>Returns a <see cref="Stream"/> that can be used to read4215    /// the final storage for the archive.</returns>4216    public override Stream ConvertTemporaryToFinal()4217    {4218      if ( temporaryStream_ == null ) {4219        throw new ZipException("No temporary stream has been created");4220      }42214222      Stream result = null;42234224      string moveTempName = GetTempFileName(fileName_, false);4225      bool newFileCreated = false;42264227      try  {4228        temporaryStream_.Close();4229        File.Move(fileName_, moveTempName);4230        File.Move(temporaryName_, fileName_);4231        newFileCreated = true;4232        File.Delete(moveTempName);42334234        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4235      }4236      catch(Exception) {4237        result  = null;42384239        // Try to roll back changes...4240        if ( !newFileCreated ) {4241          File.Move(moveTempName, fileName_);4242          File.Delete(temporaryName_);4243        }42444245        throw;4246      }42474248      return result;4249    }42504251    /// <summary>4252    /// Make a temporary copy of a stream.4253    /// </summary>4254    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4255    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4256    public override Stream MakeTemporaryCopy(Stream stream)4257    {4258      stream.Close();42594260      temporaryName_ = GetTempFileName(fileName_, true);4261      File.Copy(fileName_, temporaryName_, true);42624263      temporaryStream_ = new FileStream(temporaryName_,4264        FileMode.Open,4265        FileAccess.ReadWrite);4266      return temporaryStream_;4267    }42684269    /// <summary>4270    /// Return a stream suitable for performing direct updates on the original source.4271    /// </summary>4272    /// <param name="stream">The current stream.</param>4273    /// <returns>Returns a stream suitable for direct updating.</returns>4274    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>4275    public override Stream OpenForDirectUpdate(Stream stream)4276    {4277      Stream result;4278      if ((stream == null) || !stream.CanWrite)4279      {4280        if (stream != null) {4281          stream.Close();4282        }42834284        result = new FileStream(fileName_,4285            FileMode.Open,4286            FileAccess.ReadWrite);4287      }4288      else4289      {4290        result = stream;4291      }42924293      return result;4294    }42954296    /// <summary>4297    /// Disposes this instance.4298    /// </summary>4299    public override void Dispose()4300    {4301      if ( temporaryStream_ != null ) {4302        temporaryStream_.Close();4303      }4304    }43054306    #endregion43074308    #region Internal routines4309    static string GetTempFileName(string original, bool makeTempFile)4310    {4311      string result = null;43124313      if ( original == null ) {4314        result = Path.GetTempFileName();4315      }4316      else {4317        int counter = 0;4318        int suffixSeed = DateTime.Now.Second;43194320        while ( result == null ) {4321          counter += 1;4322          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);4323          if ( !File.Exists(newName) ) {4324            if ( makeTempFile) {4325              try  {4326                // Try and create the file.4327                using ( FileStream stream = File.Create(newName) ) {4328                }4329                result = newName;4330              }4331              catch {4332                suffixSeed = DateTime.Now.Second;4333              }4334            }4335            else {4336              result = newName;4337            }4338          }4339        }4340      }4341      return result;4342    }4343    #endregion43444345    #region Instance Fields4346    Stream temporaryStream_;4347    string fileName_;4348    string temporaryName_;4349    #endregion4350  }43514352  /// <summary>4353  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4354  /// </summary>4355  public class MemoryArchiveStorage : BaseArchiveStorage4356  {4357    #region Constructors4358    /// <summary>4359    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4360    /// </summary>4361    public MemoryArchiveStorage()4362      : base(FileUpdateMode.Direct)4363    {4364    }43654366    /// <summary>4367    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4368    /// </summary>4369    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>4370    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>4371    public MemoryArchiveStorage(FileUpdateMode updateMode)4372      : base(updateMode)4373    {4374    }43754376    #endregion43774378    #region Properties4379    /// <summary>4380    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.4381    /// </summary>4382    public MemoryStream FinalStream4383    {4384      get { return finalStream_; }4385    }43864387    #endregion43884389    #region IArchiveStorage Members43904391    /// <summary>4392    /// Gets the temporary output <see cref="Stream"/>4393    /// </summary>4394    /// <returns>Returns the temporary output stream.</returns>4395    public override Stream GetTemporaryOutput()4396    {4397      temporaryStream_ = new MemoryStream();4398      return temporaryStream_;4399    }44004401    /// <summary>4402    /// Converts the temporary <see cref="Stream"/> to its final form.4403    /// </summary>4404    /// <returns>Returns a <see cref="Stream"/> that can be used to read4405    /// the final storage for the archive.</returns>4406    public override Stream ConvertTemporaryToFinal()4407    {4408      if ( temporaryStream_ == null ) {4409        throw new ZipException("No temporary stream has been created");4410      }44114412      finalStream_ = new MemoryStream(temporaryStream_.ToArray());4413      return finalStream_;4414    }44154416    /// <summary>4417    /// Make a temporary copy of the original stream.4418    /// </summary>4419    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4420    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4421    public override Stream MakeTemporaryCopy(Stream stream)4422    {4423      temporaryStream_ = new MemoryStream();4424      stream.Position = 0;4425      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);4426      return temporaryStream_;4427    }44284429    /// <summary>4430    /// Return a stream suitable for performing direct updates on the original source.4431    /// </summary>4432    /// <param name="stream">The original source stream</param>4433    /// <returns>Returns a stream suitable for direct updating.</returns>4434    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;4435    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>4436    public override Stream OpenForDirectUpdate(Stream stream)4437    {4438      Stream result;4439      if ((stream == null) || !stream.CanWrite) {44404441        result = new MemoryStream();44424443        if (stream != null) {4444          stream.Position = 0;4445          StreamUtils.Copy(stream, result, new byte[4096]);44464447          stream.Close();4448        }4449      }4450      else {4451        result = stream;4452      }44534454      return result;4455    }44564457    /// <summary>4458    /// Disposes this instance.4459    /// </summary>4460    public override void Dispose()4461    {4462      if ( temporaryStream_ != null ) {4463        temporaryStream_.Close();4464      }4465    }44664467    #endregion44684469    #region Instance Fields4470    MemoryStream temporaryStream_;4471    MemoryStream finalStream_;4472    #endregion4473  }44744475  #endregion4476}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 read4193    /// 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      }41994200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());4201      return finalStream_;4202    }42034204    /// <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    }42164217    /// <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) {42284229        result = new MemoryStream();42304231        if (stream != null) {4232          stream.Position = 0;4233          StreamUtils.Copy(stream, result, new byte[4096]);42344235          stream.Close();4236        }4237      } else {4238        result = stream;4239      }42404241      return result;4242    }42434244    /// <summary>4245    /// Disposes this instance.4246    /// </summary>4247    public override void Dispose()4248    {4249      if (temporaryStream_ != null) {4250        temporaryStream_.Close();4251      }4252    }42534254    #endregion42554256    #region Instance Fields4257    MemoryStream temporaryStream_;4258    MemoryStream finalStream_;4259    #endregion4260  }42614262  #endregion4263} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_LzwConstants.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_LzwConstants.htm index 50b5f8764..264d8f86b 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_LzwConstants.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_LzwConstants.htm @@ -2,7 +2,7 @@ -ICSharpCode.SharpZipLib.LZW.LzwConstants - Coverage Report +ICSharpCode.SharpZipLib.Lzw.LzwConstants - Coverage Report

Summary

@@ -12,13 +12,13 @@

Summary

-Class:ICSharpCode.SharpZipLib.LZW.LzwConstants +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:94 +Total lines:61 Line coverage:0% @@ -26,7 +26,7 @@

Metrics

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

File(s)

@@ -34,102 +34,69 @@

#LineLine coverage - 1// LzwConstants.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.1namespace ICSharpCode.SharpZipLib.Lzw2{3  /// <summary>4  /// This class contains constants used for LZW5  /// </summary>6  sealed public class LzwConstants7  {8    /// <summary>9    /// Magic number found at start of LZW header: 0x1f 0x9d10    /// </summary>11    public const int MAGIC = 0x1f9d;1213    /// <summary>14    /// Maximum number of bits per code15    /// </summary>16    public const int MAX_BITS = 16;1718    /* 3rd header byte:19         * bit 0..4 Number of compression bits20         * bit 5    Extended header21         * bit 6    Free22         * bit 7    Block mode23         */2425    /// <summary>26    /// Mask for 'number of compression bits'27    /// </summary>28    public const int BIT_MASK = 0x1f;2930    /// <summary>31    /// Indicates the presence of a fourth header byte32    /// </summary>33    public const int EXTENDED_MASK = 0x20;34    //public const int FREE_MASK      = 0x40;  3536namespace ICSharpCode.SharpZipLib.LZW {3738    /// <summary>39    /// This class contains constants used for LZW40    /// </summary>41    sealed public class LzwConstants {42        /// <summary>43        /// Magic number found at start of LZW header: 0x1f 0x9d44        /// </summary>45        public const int MAGIC = 0x1f9d;36    /// <summary>37    /// Reserved bits38    /// </summary>39    public const int RESERVED_MASK = 0x60;4041    /// <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;  4647        /// <summary>48        /// Maximum number of bits per code49        /// </summary>50        public const int MAX_BITS = 16;47    /// <summary>48    /// LZW file header size (in bytes)49    /// </summary>50    public const int HDR_SIZE = 3;  5152        /* 3rd header byte:53         * bit 0..4 Number of compression bits54         * bit 5    Extended header55         * bit 6    Free56         * bit 7    Block mode57         */5859        /// <summary>60        /// Mask for 'number of compression bits'61        /// </summary>62        public const int BIT_MASK       = 0x1f;6364        /// <summary>65        /// Indicates the presence of a fourth header byte66        /// </summary>67        public const int EXTENDED_MASK  = 0x20;68        //public const int FREE_MASK      = 0x40;6970        /// <summary>71        /// Reserved bits72        /// </summary>73        public const int RESERVED_MASK  = 0x60;7475        /// <summary>76        /// Block compression: if table is full and compression rate is dropping,77        /// clear the dictionary.78        /// </summary>79        public const int BLOCK_MODE_MASK = 0x80;8081        /// <summary>82        /// LZW file header size (in bytes)83        /// </summary>84        public const int HDR_SIZE = 3;8586        /// <summary>87        /// Initial number of bits per code88        /// </summary>89        public const int INIT_BITS = 9;90 - 091        LzwConstants() { - 092        }93    }94}52    /// <summary>53    /// Initial number of bits per code54    /// </summary>55    public const int INIT_BITS = 9;56 + 057    LzwConstants()58    { + 059    }60  }61} -

+ \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_LzwException.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_LzwException.htm index 5676f3d75..c8bd1e8a0 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_LzwException.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_LzwException.htm @@ -2,7 +2,7 @@ -ICSharpCode.SharpZipLib.LZW.LzwException - Coverage Report +ICSharpCode.SharpZipLib.Lzw.LzwException - Coverage Report

Summary

@@ -12,24 +12,24 @@

Summary

-Class:ICSharpCode.SharpZipLib.LZW.LzwException +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:2 -Uncovered lines:6 +Covered lines:0 +Uncovered lines:8 Coverable lines:8 -Total lines:88 -Line coverage:25% +Total lines:48 +Line coverage:0%

Metrics

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

File(s)

@@ -37,96 +37,56 @@

#LineLine coverage - 1// LzwException.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;1using System;2using System.Runtime.Serialization;34namespace ICSharpCode.SharpZipLib.Lzw5{6  /// <summary>7  /// LzwException represents exceptions specific to LZW classes and code.8  /// </summary>9  [Serializable]10  public class LzwException : SharpZipBaseException11  {12    /// <summary>13    /// Deserialization constructor14    /// </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    }2122    /// <summary>23    /// Initialise a new instance of <see cref="LzwException" />.24    /// </summary> + 025    public LzwException()26    { + 027    }2829    /// <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    }  3738#if !NETCF_1_0 && !NETCF_2_039using System.Runtime.Serialization;40#endif4142namespace ICSharpCode.SharpZipLib.LZW43{4445    /// <summary>46    /// LzwException represents a LZW specific exception47    /// </summary>48#if !NETCF_1_0 && !NETCF_2_049    [Serializable]50#endif51    public class LzwException : SharpZipBaseException52    {5354#if !NETCF_1_0 && !NETCF_2_055        /// <summary>56        /// Deserialization constructor57        /// </summary>58        /// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>59        /// <param name="context"><see cref="StreamingContext"/> for this constructor</param>60        protected LzwException(SerializationInfo info, StreamingContext context) - 061            : base(info, context) { - 062        }63#endif6465        /// <summary>66        /// Initialise a new instance of LzwException67        /// </summary> - 068        public LzwException() { - 069        }7071        /// <summary>72        /// Initialise a new instance of LzwException with its message string.73        /// </summary>74        /// <param name="message">A <see cref="string"/> that describes the error.</param>75        public LzwException(string message) - 176            : base(message) { - 177        }7879        /// <summary>80        /// Initialise a new instance of <see cref="LzwException"></see>.81        /// </summary>82        /// <param name="message">A <see cref="string"/> that describes the error.</param>83        /// <param name="innerException">The <see cref="Exception"/> that caused this exception.</param>84        public LzwException(string message, Exception innerException) - 085            : base(message, innerException) { - 086        }87    }88}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/Documentation/opencover/ICSharpCode.SharpZipLib_LzwInputStream.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_LzwInputStream.htm index cab6e9522..3645793e8 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_LzwInputStream.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_LzwInputStream.htm @@ -2,7 +2,7 @@ -ICSharpCode.SharpZipLib.LZW.LzwInputStream - Coverage Report +ICSharpCode.SharpZipLib.Lzw.LzwInputStream - Coverage Report

Summary

@@ -12,34 +12,34 @@

Summary

-Class:ICSharpCode.SharpZipLib.LZW.LzwInputStream +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:23 -Uncovered lines:168 -Coverable lines:191 -Total lines:599 -Line coverage:12% -Branch coverage:11.2% +Covered lines:0 +Uncovered lines:194 +Coverable lines:194 +Total lines:559 +Line coverage:0% +Branch coverage:0%

Metrics

- - - - - - - - - - - - - + + + + + + + + + + + + +
MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
ReadByte()22533.33
Read(...)251.714.88
ResetBuf(...)100
Fill()200
ParseHeader()920.6926.67
Flush()100
Seek(...)100
SetLength(...)100
Write(...)100
WriteByte(...)100
BeginWrite(...)100
Close()310080
.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)

@@ -47,607 +47,567 @@

#LineLine coverage - 1// LzwInputStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;37using System.IO;3839namespace ICSharpCode.SharpZipLib.LZW40{4142    /// <summary>43    /// This filter stream is used to decompress a LZW format stream.44    /// Specifically, a stream that uses the LZC compression method.45    /// This file format is usually associated with the .Z file extension.46    ///47    /// See http://en.wikipedia.org/wiki/Compress48    /// See http://wiki.wxwidgets.org/Development:_Z_File_Format49    ///50    /// The file header consists of 3 (or optionally 4) bytes. The first two bytes51    /// contain the magic marker "0x1f 0x9d", followed by a byte of flags.52    ///53    /// Based on Java code by Ronald Tschalar, which in turn was based on the unlzw.c54    /// code in the gzip package.55    /// </summary>56    /// <example> This sample shows how to unzip a compressed file57    /// <code>58    /// using System;59    /// using System.IO;60    ///61    /// using ICSharpCode.SharpZipLib.Core;62    /// using ICSharpCode.SharpZipLib.LZW;63    ///64    /// class MainClass65    /// {66    ///   public static void Main(string[] args)67    ///   {68    ///      using (Stream inStream = new LzwInputStream(File.OpenRead(args[0])))69    ///      using (FileStream outStream = File.Create(Path.GetFileNameWithoutExtension(args[0]))) {70    ///        byte[] buffer = new byte[4096];71    ///        StreamUtils.Copy(inStream, outStream, buffer);72    ///                         // OR73    ///                         inStream.Read(buffer, 0, buffer.Length);74    ///                         // now do something with the buffer75    ///     }76    ///   }77    /// }78    /// </code>79    /// </example>80    public class LzwInputStream : Stream81    {82        /// <summary>83        /// Get/set flag indicating ownership of underlying stream.84        /// When the flag is true <see cref="Close"/> will close the underlying stream also.85        /// </summary>86        /// <remarks>87        /// The default value is true.88        /// </remarks>89        public bool IsStreamOwner90        { - 091            get { return isStreamOwner; } - 292            set { isStreamOwner = value; }93        }9495        /// <summary>96        /// Creates a LzwInputStream97        /// </summary>98        /// <param name="baseInputStream">99        /// The stream to read compressed data from (baseInputStream LZW format)100        /// </param> - 3101        public LzwInputStream(Stream baseInputStream) { - 3102            this.baseInputStream = baseInputStream; - 3103        }104105        /// <summary>106        /// See <see cref="System.IO.Stream.ReadByte"/>107        /// </summary>108        /// <returns></returns>109        public override int ReadByte() { - 1110            int b = Read(one, 0, 1); - 0111             if (b == 1) - 0112                return (one[0] & 0xff); - 0113            return -1;114        }115116        /// <summary>117        /// Reads decompressed data into the provided buffer byte array118        /// </summary>119        /// <param name ="buffer">120        /// The array to read and decompress data into121        /// </param>122        /// <param name ="offset">123        /// The offset indicating where the data should be placed124        /// </param>125        /// <param name ="count">126        /// The number of bytes to decompress127        /// </param>128        /// <returns>The number of bytes read. Zero signals the end of stream</returns>129        public override int Read(byte[] buffer, int offset, int count) { - 2130             if (!headerParsed) ParseHeader();1using System;2using System.IO;34namespace ICSharpCode.SharpZipLib.Lzw5{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/Compress12  /// See http://wiki.wxwidgets.org/Development:_Z_File_Format13  ///14  /// The file header consists of 3 (or optionally 4) bytes. The first two bytes15  /// 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.c18  /// code in the gzip package.19  /// </summary>20  /// <example> This sample shows how to unzip a compressed file21  /// <code>22  /// using System;23  /// using System.IO;24  ///25  /// using ICSharpCode.SharpZipLib.Core;26  /// using ICSharpCode.SharpZipLib.LZW;27  ///28  /// class MainClass29  /// {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  ///                         // OR37  ///                         inStream.Read(buffer, 0, buffer.Length);38  ///                         // now do something with the buffer39  ///     }40  ///   }41  /// }42  /// </code>43  /// </example>44  public class LzwInputStream : Stream45  {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    }5758    /// <summary>59    /// Creates a LzwInputStream60    /// </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    }6869    /// <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    }8081    /// <summary>82    /// Reads decompressed data into the provided buffer byte array83    /// </summary>84    /// <param name ="buffer">85    /// The array to read and decompress data into86    /// </param>87    /// <param name ="offset">88    /// The offset indicating where the data should be placed89    /// </param>90    /// <param name ="count">91    /// The number of bytes to decompress92    /// </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;103104      /* Using local copies of various variables speeds things up by as105           * 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;120121122      // 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 (eof) return 0;133 - 0134            int start = offset;135136            /* Using local copies of various variables speeds things up by as137           * much as 30% in Java! Performance not tested in C#.138           */ - 0139            int[] lTabPrefix = tabPrefix; - 0140            byte[] lTabSuffix = tabSuffix; - 0141            byte[] lStack = stack; - 0142            int lNBits = nBits; - 0143            int lMaxCode = maxCode; - 0144            int lMaxMaxCode = maxMaxCode; - 0145            int lBitMask = bitMask; - 0146            int lOldCode = oldCode; - 0147            byte lFinChar = finChar; - 0148            int lStackP = stackP; - 0149            int lFreeEnt = freeEnt; - 0150            byte[] lData = data; - 0151            int lBitPos = bitPos;152153154            // empty stack if stuff still left - 0155            int sSize = lStack.Length - lStackP; - 0156             if (sSize > 0) { - 0157                 int num = (sSize >= count) ? count : sSize; - 0158                Array.Copy(lStack, lStackP, buffer, offset, num); - 0159                offset += num; - 0160                count -= num; - 0161                lStackP += num;162            }163 - 0164             if (count == 0) { - 0165                stackP = lStackP; - 0166                return offset - start;167            }168169170            // loop, filling local buffer until enough data has been decompressed171            MainLoop: do { - 0172                 if (end < EXTRA) { - 0173                    Fill();174                }175 - 0176                int bitIn = (got > 0) ? (end - end % lNBits) << 3 : - 0177                                        (end << 3) - (lNBits - 1);178 - 0179                 while (lBitPos < bitIn) {180                    #region A181                    // handle 1-byte reads correctly - 0182                     if (count == 0) { - 0183                        nBits = lNBits; - 0184                        maxCode = lMaxCode; - 0185                        maxMaxCode = lMaxMaxCode; - 0186                        bitMask = lBitMask; - 0187                        oldCode = lOldCode; - 0188                        finChar = lFinChar; - 0189                        stackP = lStackP; - 0190                        freeEnt = lFreeEnt; - 0191                        bitPos = lBitPos;192 - 0193                        return offset - start;194                    } + 0132       if (count == 0) { + 0133        stackP = lStackP; + 0134        return offset - start;135      }136137138      // loop, filling local buffer until enough data has been decompressed139      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 A150          // 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          }164165          // 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          #endregion180181          #region B182          // 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;190191          // handle first iteration + 0192           if (lOldCode == -1) { + 0193             if (code >= 256) + 0194              throw new LzwException("corrupt input: " + code + " > 255");  195196                    // check for code-width expansion - 0197                     if (lFreeEnt > lMaxCode) { - 0198                        int nBytes = lNBits << 3; - 0199                        lBitPos = (lBitPos - 1) + - 0200                        nBytes - (lBitPos - 1 + nBytes) % nBytes; + 0196            lFinChar = (byte)(lOldCode = code); + 0197            buffer[offset++] = lFinChar; + 0198            count--; + 0199            continue;200          }  201 - 0202                        lNBits++; - 0203                        lMaxCode = (lNBits == maxBits) ? lMaxMaxCode : - 0204                                                        (1 << lNBits) - 1;205 - 0206                        lBitMask = (1 << lNBits) - 1; - 0207                        lBitPos = ResetBuf(lBitPos); - 0208                        goto MainLoop;209                    }210                    #endregion211212                    #region B213                    // read next code - 0214                    int pos = lBitPos >> 3; - 0215                    int code = (((lData[pos] & 0xFF) | - 0216                        ((lData[pos + 1] & 0xFF) << 8) | - 0217                        ((lData[pos + 2] & 0xFF) << 16)) >> - 0218                        (lBitPos & 0x7)) & lBitMask;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;212213            // Code tables reset214 + 0215            lBitPos = ResetBuf(lBitPos); + 0216            goto MainLoop;217          }218          #endregion  219 - 0220                        lBitPos += lNBits;221222                    // handle first iteration - 0223                     if (lOldCode == -1) { - 0224                         if (code >= 256) throw new LzwException("corrupt input: " + code + " > 255");225 - 0226                        lFinChar = (byte) (lOldCode = code); - 0227                        buffer[offset++] = lFinChar; - 0228                        count--; - 0229                        continue;230                    }220          #region C221          // setup + 0222          int inCode = code; + 0223          lStackP = lStack.Length;224225          // Handle KwK case + 0226           if (code >= lFreeEnt) { + 0227             if (code > lFreeEnt) { + 0228              throw new LzwException("corrupt input: code=" + code + + 0229                ", freeEnt=" + lFreeEnt);230            }  231232                    // handle CLEAR code - 0233                     if (code == TBL_CLEAR && blockMode) { - 0234                        Array.Copy(zeros, 0, lTabPrefix, 0, zeros.Length); - 0235                        lFreeEnt = TBL_FIRST - 1;236 - 0237                        int nBytes = lNBits << 3; - 0238                        lBitPos = (lBitPos - 1) + nBytes - (lBitPos - 1 + nBytes) % nBytes; - 0239                        lNBits = LzwConstants.INIT_BITS; - 0240                        lMaxCode = (1 << lNBits) - 1; - 0241                        lBitMask = lMaxCode;242243                        // Code tables reset244 - 0245                        lBitPos = ResetBuf(lBitPos); - 0246                        goto MainLoop;247                    }248                    #endregion249250                    #region C251                    // setup - 0252                    int inCode = code; - 0253                    lStackP = lStack.Length; + 0232            lStack[--lStackP] = lFinChar; + 0233            code = lOldCode;234          }235236          // 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--;245246          // 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  254255                    // Handle KwK case - 0256                     if (code >= lFreeEnt) { - 0257                         if (code > lFreeEnt) { - 0258                            throw new LzwException("corrupt input: code=" + code + - 0259                                ", freeEnt=" + lFreeEnt);260                        }261 - 0262                        lStack[--lStackP] = lFinChar; - 0263                        code = lOldCode;264                    }255          #region D256          // generate new entry in table + 0257           if (lFreeEnt < lMaxMaxCode) { + 0258            lTabPrefix[lFreeEnt] = lOldCode; + 0259            lTabSuffix[lFreeEnt] = lFinChar; + 0260            lFreeEnt++;261          }262263          // Remember previous code + 0264          lOldCode = inCode;  265266                    // Generate output characters in reverse order - 0267                     while (code >= 256) { - 0268                        lStack[--lStackP] = lTabSuffix[code]; - 0269                        code = lTabPrefix[code];270                    }271 - 0272                    lFinChar = lTabSuffix[code]; - 0273                    buffer[offset++] = lFinChar; - 0274                    count--;275276                    // And put them out in forward order - 0277                    sSize = lStack.Length - lStackP; - 0278                     int num = (sSize >= count) ? count : sSize; - 0279                    Array.Copy(lStack, lStackP, buffer, offset, num); - 0280                    offset += num; - 0281                    count -= num; - 0282                    lStackP += num;283                    #endregion284285                    #region D286                    // generate new entry in table - 0287                     if (lFreeEnt < lMaxMaxCode) { - 0288                        lTabPrefix[lFreeEnt] = lOldCode; - 0289                        lTabSuffix[lFreeEnt] = lFinChar; - 0290                        lFreeEnt++;291                    }292293                    // Remember previous code - 0294                    lOldCode = inCode;295296                    // if output buffer full, then return - 0297                     if (count == 0) { - 0298                        nBits = lNBits; - 0299                        maxCode = lMaxCode; - 0300                        bitMask = lBitMask; - 0301                        oldCode = lOldCode; - 0302                        finChar = lFinChar; - 0303                        stackP = lStackP; - 0304                        freeEnt = lFreeEnt; - 0305                        bitPos = lBitPos;306 - 0307                        return offset - start;308                    }309                    #endregion310                }   // while311 - 0312                lBitPos = ResetBuf(lBitPos);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          #endregion280        }   // while281 + 0282        lBitPos = ResetBuf(lBitPos);283 + 0284       } while (got > 0);  // do..while285 + 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    }298299    /// <summary>300    /// Moves the unread data in the buffer to the beginning and resets301    /// 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 - 0314             } while (got > 0);  // do..while315 - 0316            nBits = lNBits; - 0317            maxCode = lMaxCode; - 0318            bitMask = lBitMask; - 0319            oldCode = lOldCode; - 0320            finChar = lFinChar; - 0321            stackP = lStackP; - 0322            freeEnt = lFreeEnt; - 0323            bitPos = lBitPos;324 - 0325            eof = true; - 0326            return offset - start;327        }314    private void Fill()315    { + 0316      got = baseInputStream.Read(data, end, data.Length - 1 - end); + 0317       if (got > 0) { + 0318        end += got;319      } + 0320    }321322323    private void ParseHeader()324    { + 0325      headerParsed = true;326 + 0327      byte[] hdr = new byte[LzwConstants.HDR_SIZE];  328329        /// <summary>330        /// Moves the unread data in the buffer to the beginning and resets331        /// the pointers.332        /// </summary>333        /// <param name="bitPosition"></param>334        /// <returns></returns>335        private int ResetBuf(int bitPosition) { - 0336            int pos = bitPosition >> 3; - 0337            Array.Copy(data, pos, data, 0, end - pos); - 0338            end -= pos; - 0339            return 0;340        }341342343        private void Fill() { - 0344            got = baseInputStream.Read(data, end, data.Length - 1 - end); - 0345             if (got > 0) { - 0346                end += got;347            } - 0348        }349 + 0329      int result = baseInputStream.Read(hdr, 0, hdr.Length);330331      // 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      }340341      // 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      }  350351        private void ParseHeader() { - 1352            headerParsed = true;353 - 1354            byte[] hdr = new byte[LzwConstants.HDR_SIZE];355 - 1356            int result = baseInputStream.Read(hdr, 0, hdr.Length);357358            // Check the magic marker - 1359             if (result < 0) - 0360                throw new LzwException("Failed to read LZW header");361 - 1362             if (hdr[0] != (LzwConstants.MAGIC >> 8) || hdr[1] != (LzwConstants.MAGIC & 0xff)) { - 1363                throw new LzwException(String.Format( - 1364                    "Wrong LZW header. Magic bytes don't match. 0x{0:x2} 0x{1:x2}", - 1365                    hdr[0], hdr[1]));366            }367368            // Check the 3rd header byte - 0369            blockMode = (hdr[2] & LzwConstants.BLOCK_MODE_MASK) > 0; - 0370            maxBits = hdr[2] & LzwConstants.BIT_MASK;371 - 0372             if (maxBits > LzwConstants.MAX_BITS) { - 0373                throw new LzwException("Stream compressed with " + maxBits + - 0374                    " bits, but decompression can only handle " + - 0375                    LzwConstants.MAX_BITS + " bits.");376            }377 - 0378             if ((hdr[2] & LzwConstants.RESERVED_MASK) > 0) { - 0379                throw new LzwException("Unsupported bits set in the header.");380            }381382            // Initialize variables - 0383            maxMaxCode = 1 << maxBits; - 0384            nBits = LzwConstants.INIT_BITS; - 0385            maxCode = (1 << nBits) - 1; - 0386            bitMask = maxCode; - 0387            oldCode = -1; - 0388            finChar = 0; - 0389             freeEnt = blockMode ? TBL_FIRST : 256;390 - 0391            tabPrefix = new int[1 << maxBits]; - 0392            tabSuffix = new byte[1 << maxBits]; - 0393            stack = new byte[1 << maxBits]; - 0394            stackP = stack.Length;395 - 0396             for (int idx = 255; idx >= 0; idx--) - 0397                tabSuffix[idx] = (byte)idx; - 0398        }399400        #region Stream Overrides401        /// <summary>402        /// Gets a value indicating whether the current stream supports reading403        /// </summary>404        public override bool CanRead405        {406            get407            { - 0408                return baseInputStream.CanRead;409            }410        }411412        /// <summary>413        /// Gets a value of false indicating seeking is not supported for this stream.414        /// </summary>415        public override bool CanSeek416        {417            get418            { - 0419                return false;420            }421        }422423        /// <summary>424        /// Gets a value of false indicating that this stream is not writeable.425        /// </summary>426        public override bool CanWrite427        {428            get429            { - 0430                return false;431            }432        }433434        /// <summary>435        /// A value representing the length of the stream in bytes.436        /// </summary>437        public override long Length438        {439            get440            { - 0441                return got;442            }443        } + 0351       if ((hdr[2] & LzwConstants.RESERVED_MASK) > 0) { + 0352        throw new LzwException("Unsupported bits set in the header.");353      }354355      // 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    }372373    #region Stream Overrides374    /// <summary>375    /// Gets a value indicating whether the current stream supports reading376    /// </summary>377    public override bool CanRead {378      get { + 0379        return baseInputStream.CanRead;380      }381    }382383    /// <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    }391392    /// <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    }400401    /// <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    }409410    /// <summary>411    /// The current position within the stream.412    /// Throws a NotSupportedException when attempting to set the position413    /// </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    }423424    /// <summary>425    /// Flushes the baseInputStream426    /// </summary>427    public override void Flush()428    { + 0429      baseInputStream.Flush(); + 0430    }431432    /// <summary>433    /// Sets the position within the current stream434    /// Always throws a NotSupportedException435    /// </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    }  444445        /// <summary>446        /// The current position within the stream.447        /// Throws a NotSupportedException when attempting to set the position448        /// </summary>449        /// <exception cref="NotSupportedException">Attempting to set the position</exception>450        public override long Position451        {452            get453            { - 0454                return baseInputStream.Position;455            }456            set457            { - 0458                throw new NotSupportedException("InflaterInputStream Position not supported");459            }460        }461462        /// <summary>463        /// Flushes the baseInputStream464        /// </summary>465        public override void Flush()466        { - 0467            baseInputStream.Flush(); - 0468        }469470        /// <summary>471        /// Sets the position within the current stream472        /// Always throws a NotSupportedException473        /// </summary>474        /// <param name="offset">The relative offset to seek to.</param>475        /// <param name="origin">The <see cref="SeekOrigin"/> defining where to seek from.</param>476        /// <returns>The new position in the stream.</returns>477        /// <exception cref="NotSupportedException">Any access</exception>478        public override long Seek(long offset, SeekOrigin origin)479        { - 0480            throw new NotSupportedException("Seek not supported");481        }482483        /// <summary>484        /// Set the length of the current stream485        /// Always throws a NotSupportedException486        /// </summary>487        /// <param name="value">The new length value for the stream.</param>488        /// <exception cref="NotSupportedException">Any access</exception>489        public override void SetLength(long value)490        { - 0491            throw new NotSupportedException("InflaterInputStream SetLength not supported");492        }493494        /// <summary>495        /// Writes a sequence of bytes to stream and advances the current position496        /// This method always throws a NotSupportedException497        /// </summary>498        /// <param name="buffer">Thew buffer containing data to write.</param>499        /// <param name="offset">The offset of the first byte to write.</param>500        /// <param name="count">The number of bytes to write.</param>501        /// <exception cref="NotSupportedException">Any access</exception>502        public override void Write(byte[] buffer, int offset, int count)503        { - 0504            throw new NotSupportedException("InflaterInputStream Write not supported");445    /// <summary>446    /// Set the length of the current stream447    /// Always throws a NotSupportedException448    /// </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    }455456    /// <summary>457    /// Writes a sequence of bytes to stream and advances the current position458    /// This method always throws a NotSupportedException459    /// </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    }468469    /// <summary>470    /// Writes one byte to the current stream and advances the current position471    /// Always throws a NotSupportedException472    /// </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    }479480    /// <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 ot488    /// <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    }494495    /// <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        }506507        /// <summary>508        /// Writes one byte to the current stream and advances the current position509        /// Always throws a NotSupportedException510        /// </summary>511        /// <param name="value">The byte to write.</param>512        /// <exception cref="NotSupportedException">Any access</exception>513        public override void WriteByte(byte value)514        { - 0515            throw new NotSupportedException("InflaterInputStream WriteByte not supported");516        }517518        /// <summary>519        /// Entry point to begin an asynchronous write.  Always throws a NotSupportedException.520        /// </summary>521        /// <param name="buffer">The buffer to write data from</param>522        /// <param name="offset">Offset of first byte to write</param>523        /// <param name="count">The maximum number of bytes to write</param>524        /// <param name="callback">The method to be called when the asynchronous write operation is completed</param>525        /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request fro526        /// <returns>An <see cref="System.IAsyncResult">IAsyncResult</see> that references the asynchronous write</retur527        /// <exception cref="NotSupportedException">Any access</exception>528        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object sta529        { - 0530            throw new NotSupportedException("InflaterInputStream BeginWrite not supported");531        }506      } + 0507    }508509    #endregion510511    #region Instance Fields512513    Stream baseInputStream;514515    /// <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;520521    /// <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;528529    // string table stuff530    private const int TBL_CLEAR = 0x100;531    private const int TBL_FIRST = TBL_CLEAR + 1;  532533        /// <summary>534        /// Closes the input stream.  When <see cref="IsStreamOwner"></see>535        /// is true the underlying stream is also closed.536        /// </summary>537        public override void Close()538        { - 2539             if (!isClosed)540            { - 2541                isClosed = true; - 2542                 if (isStreamOwner)543                { - 1544                    baseInputStream.Close();545                }546            } - 2547        }548549        #endregion550551        #region Instance Fields552553        Stream baseInputStream;554555        /// <summary>556        /// Flag indicating wether this instance is designated the stream owner.557        /// When closing if this flag is true the underlying stream is closed.558        /// </summary> - 3559        bool isStreamOwner = true;560561        /// <summary>562        /// Flag indicating wether this instance has been closed or not.563        /// </summary>564        bool isClosed;565 - 3566        readonly byte[] one = new byte[1];567        bool headerParsed;568569        // string table stuff570        private const int TBL_CLEAR = 0x100;571        private const int TBL_FIRST = TBL_CLEAR + 1;572573        private int[] tabPrefix;574        private byte[] tabSuffix; - 3575        private readonly int[] zeros = new int[256];576        private byte[] stack;577578        // various state579        private bool blockMode;580        private int nBits;581        private int maxBits;582        private int maxMaxCode;583        private int maxCode;584        private int bitMask;585        private int oldCode;586        private byte finChar;587        private int stackP;588        private int freeEnt;589590        // input buffer - 3591        private readonly byte[] data = new byte[1024 * 8];592        private int bitPos;593        private int end;594        int got;595        private bool eof;596        private const int EXTRA = 64;597        #endregion598    }599}533    private int[] tabPrefix;534    private byte[] tabSuffix; + 0535    private readonly int[] zeros = new int[256];536    private byte[] stack;537538    // various state539    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;549550    // 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    #endregion558  }559} -

+ \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_MemoryArchiveStorage.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_MemoryArchiveStorage.htm index 61b4efc4a..575c23086 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_MemoryArchiveStorage.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_MemoryArchiveStorage.htm @@ -18,7 +18,7 @@

Summary

Covered lines:15 Uncovered lines:12 Coverable lines:27 -Total lines:4476 +Total lines:4263 Line coverage:55.5% Branch coverage:50% @@ -41,4484 +41,4271 @@

#LineLine coverage - 1// ZipFile.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  2009-12-22  Z-1649  Added AES support41//  2010-03-02  Z-1650  Fixed updating ODT archives in memory. Exposed exceptions in updating.42//  2010-05-25  Z-1663  Fixed exception when testing local header compressed size of -143//  2012-11-29  Z-1684  Fixed ZipFile.Add(string fileName, string entryName) losing the file TimeStamp4445using System;46using System.Collections;47using System.IO;48using System.Text;49using System.Globalization;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;1213namespace ICSharpCode.SharpZipLib.Zip14{15  #region Keys Required Event Args16  /// <summary>17  /// Arguments used with KeysRequiredEvent18  /// </summary>19  public class KeysRequiredEventArgs : EventArgs20  {21    #region Constructors22    /// <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    }3031    /// <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    }4142    #endregion43    #region Properties44    /// <summary>45    /// Gets the name of the file for which keys are required.46    /// </summary>47    public string FileName {48      get { return fileName; }49    }  5051#if !NETCF_1_052using System.Security.Cryptography;53using ICSharpCode.SharpZipLib.Encryption;54#endif5556using ICSharpCode.SharpZipLib.Core;57using ICSharpCode.SharpZipLib.Checksums;58using ICSharpCode.SharpZipLib.Zip.Compression.Streams;59using ICSharpCode.SharpZipLib.Zip.Compression;6061namespace ICSharpCode.SharpZipLib.Zip62{63  #region Keys Required Event Args64  /// <summary>65  /// Arguments used with KeysRequiredEvent66  /// </summary>67  public class KeysRequiredEventArgs : EventArgs68  {69    #region Constructors70    /// <summary>71    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>72    /// </summary>73    /// <param name="name">The name of the file for which keys are required.</param>74    public KeysRequiredEventArgs(string name)75    {76      fileName = name;77    }7879    /// <summary>80    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>81    /// </summary>82    /// <param name="name">The name of the file for which keys are required.</param>83    /// <param name="keyValue">The current key value.</param>84    public KeysRequiredEventArgs(string name, byte[] keyValue)85    {86      fileName = name;87      key = keyValue;88    }8990    #endregion91    #region Properties92    /// <summary>93    /// Gets the name of the file for which keys are required.94    /// </summary>95    public string FileName96    {97      get { return fileName; }98    }99100    /// <summary>101    /// Gets or sets the key value102    /// </summary>103    public byte[] Key104    {105      get { return key; }106      set { key = value; }107    }108    #endregion109110    #region Instance Fields111    string fileName;112    byte[] key;113    #endregion114  }115  #endregion116117  #region Test Definitions118  /// <summary>119  /// The strategy to apply to testing.120  /// </summary>121  public enum TestStrategy122  {123    /// <summary>124    /// Find the first error only.125    /// </summary>126    FindFirstError,51    /// <summary>52    /// Gets or sets the key value53    /// </summary>54    public byte[] Key {55      get { return key; }56      set { key = value; }57    }58    #endregion5960    #region Instance Fields61    string fileName;62    byte[] key;63    #endregion64  }65  #endregion6667  #region Test Definitions68  /// <summary>69  /// The strategy to apply to testing.70  /// </summary>71  public enum TestStrategy72  {73    /// <summary>74    /// Find the first error only.75    /// </summary>76    FindFirstError,77    /// <summary>78    /// Find all possible errors.79    /// </summary>80    FindAllErrors,81  }8283  /// <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 TestOperation88  {89    /// <summary>90    /// Setting up testing.91    /// </summary>92    Initialising,9394    /// <summary>95    /// Testing an individual entries header96    /// </summary>97    EntryHeader,9899    /// <summary>100    /// Testing an individual entries data101    /// </summary>102    EntryData,103104    /// <summary>105    /// Testing an individual entry has completed.106    /// </summary>107    EntryComplete,108109    /// <summary>110    /// Running miscellaneous tests111    /// </summary>112    MiscellaneousTests,113114    /// <summary>115    /// Testing is complete116    /// </summary>117    Complete,118  }119120  /// <summary>121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.122  /// </summary>123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>124  public class TestStatus125  {126    #region Constructors  127    /// <summary>128    /// Find all possible errors.128    /// Initialise a new instance of <see cref="TestStatus"/>  129    /// </summary>130    FindAllErrors,131  }132133  /// <summary>134  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.135  /// </summary>136  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>137  public enum TestOperation138  {130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>131    public TestStatus(ZipFile file)132    {133      file_ = file;134    }135    #endregion136137    #region Properties138  139    /// <summary>140    /// Setting up testing.140    /// Get the current <see cref="TestOperation"/> in progress.  141    /// </summary>142    Initialising,143144    /// <summary>145    /// Testing an individual entries header146    /// </summary>147    EntryHeader,148149    /// <summary>150    /// Testing an individual entries data151    /// </summary>152    EntryData,153154    /// <summary>155    /// Testing an individual entry has completed.156    /// </summary>157    EntryComplete,158159    /// <summary>160    /// Running miscellaneous tests161    /// </summary>162    MiscellaneousTests,163164    /// <summary>165    /// Testing is complete166    /// </summary>167    Complete,168  }169170  /// <summary>171  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.172  /// </summary>173  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>174  public class TestStatus175  {176    #region Constructors177    /// <summary>178    /// Initialise a new instance of <see cref="TestStatus"/>179    /// </summary>180    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>181    public TestStatus(ZipFile file)182    {183      file_ = file;184    }185    #endregion186187    #region Properties142    public TestOperation Operation {143      get { return operation_; }144    }145146    /// <summary>147    /// Get the <see cref="ZipFile"/> this status is applicable to.148    /// </summary>149    public ZipFile File {150      get { return file_; }151    }152153    /// <summary>154    /// Get the current/last entry tested.155    /// </summary>156    public ZipEntry Entry {157      get { return entry_; }158    }159160    /// <summary>161    /// Get the number of errors detected so far.162    /// </summary>163    public int ErrorCount {164      get { return errorCount_; }165    }166167    /// <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    }173174    /// <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    #endregion181182    #region Internal API183    internal void AddError()184    {185      errorCount_++;186      entryValid_ = false;187    }  188189    /// <summary>190    /// Get the current <see cref="TestOperation"/> in progress.191    /// </summary>192    public TestOperation Operation193    {194      get { return operation_; }195    }196197    /// <summary>198    /// Get the <see cref="ZipFile"/> this status is applicable to.199    /// </summary>200    public ZipFile File201    {202      get { return file_; }203    }204205    /// <summary>206    /// Get the current/last entry tested.207    /// </summary>208    public ZipEntry Entry209    {210      get { return entry_; }211    }212213    /// <summary>214    /// Get the number of errors detected so far.215    /// </summary>216    public int ErrorCount217    {218      get { return errorCount_; }219    }220221    /// <summary>222    /// Get the number of bytes tested so far for the current entry.223    /// </summary>224    public long BytesTested225    {226      get { return bytesTested_; }227    }228229    /// <summary>230    /// Get a value indicating wether the last entry test was valid.231    /// </summary>232    public bool EntryValid233    {234      get { return entryValid_; }235    }236    #endregion237238    #region Internal API239    internal void AddError()240    {241      errorCount_++;242      entryValid_ = false;243    }244245    internal void SetOperation(TestOperation operation)246    {247      operation_ = operation;248    }249250    internal void SetEntry(ZipEntry entry)251    {252      entry_ = entry;253      entryValid_ = true;254      bytesTested_ = 0;255    }256257    internal void SetBytesTested(long value)258    {259      bytesTested_ = value;260    }261    #endregion262263    #region Instance Fields264    ZipFile file_;265    ZipEntry entry_;266    bool entryValid_;267    int errorCount_;268    long bytesTested_;269    TestOperation operation_;270    #endregion271  }272273  /// <summary>274  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if275  /// </summary>276  /// <remarks>If the message is non-null an error has occured.  If the message is null277  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>278  public delegate void ZipTestResultHandler(TestStatus status, string message);279  #endregion280281  #region Update Definitions282  /// <summary>283  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.284  /// </summary>285  public enum FileUpdateMode286  {287    /// <summary>288    /// Perform all updates on temporary files ensuring that the original file is saved.289    /// </summary>290    Safe,291    /// <summary>292    /// Update the archive directly, which is faster but less safe.293    /// </summary>294    Direct,295  }296  #endregion189    internal void SetOperation(TestOperation operation)190    {191      operation_ = operation;192    }193194    internal void SetEntry(ZipEntry entry)195    {196      entry_ = entry;197      entryValid_ = true;198      bytesTested_ = 0;199    }200201    internal void SetBytesTested(long value)202    {203      bytesTested_ = value;204    }205    #endregion206207    #region Instance Fields208    ZipFile file_;209    ZipEntry entry_;210    bool entryValid_;211    int errorCount_;212    long bytesTested_;213    TestOperation operation_;214    #endregion215  }216217  /// <summary>218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if219  /// </summary>220  /// <remarks>If the message is non-null an error has occured.  If the message is null221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>222  public delegate void ZipTestResultHandler(TestStatus status, string message);223  #endregion224225  #region Update Definitions226  /// <summary>227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.228  /// </summary>229  public enum FileUpdateMode230  {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  #endregion241242  #region ZipFile Class243  /// <summary>244  /// This class represents a Zip archive.  You can ask for the contained245  /// entries, or get an input stream for a file entry.  The entry is246  /// 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 arbitrary251  /// entries in different threads.252  /// <br/>253  /// <br/>Author of the original java version : Jochen Hoenicke254  /// </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 MainClass265  /// {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, IDisposable287  {288    #region KeyHandling289290    /// <summary>291    /// Delegate for handling keys/password setting during compresion/decompression.292    /// </summary>293    public delegate void KeysRequiredEventHandler(294      object sender,295      KeysRequiredEventArgs e296    );  297298  #region ZipFile Class299  /// <summary>300  /// This class represents a Zip archive.  You can ask for the contained301  /// entries, or get an input stream for a file entry.  The entry is302  /// automatically decompressed.303  ///304  /// You can also update the archive adding or deleting entries.305  ///306  /// This class is thread safe for input:  You can open input streams for arbitrary307  /// entries in different threads.308  /// <br/>309  /// <br/>Author of the original java version : Jochen Hoenicke310  /// </summary>311  /// <example>312  /// <code>313  /// using System;314  /// using System.Text;315  /// using System.Collections;316  /// using System.IO;317  ///318  /// using ICSharpCode.SharpZipLib.Zip;319  ///320  /// class MainClass321  /// {322  ///   static public void Main(string[] args)323  ///   {324  ///     using (ZipFile zFile = new ZipFile(args[0])) {325  ///       Console.WriteLine("Listing of : " + zFile.Name);326  ///       Console.WriteLine("");327  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");328  ///       Console.WriteLine("--------  --------  --------  ------  ---------");329  ///       foreach (ZipEntry e in zFile) {330  ///         if ( e.IsFile ) {331  ///           DateTime d = e.DateTime;332  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,333  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),334  ///             e.Name);335  ///         }336  ///       }337  ///     }338  ///   }339  /// }340  /// </code>341  /// </example>342  public class ZipFile : IEnumerable, IDisposable343  {344    #region KeyHandling345346    /// <summary>347    /// Delegate for handling keys/password setting during compresion/decompression.348    /// </summary>349    public delegate void KeysRequiredEventHandler(350      object sender,351      KeysRequiredEventArgs e352    );353354    /// <summary>355    /// Event handler for handling encryption keys.356    /// </summary>357    public KeysRequiredEventHandler KeysRequired;358359    /// <summary>360    /// Handles getting of encryption keys when required.361    /// </summary>362    /// <param name="fileName">The file for which encryption keys are required.</param>363    void OnKeysRequired(string fileName)364    {365      if (KeysRequired != null) {366        var krea = new KeysRequiredEventArgs(fileName, key);367        KeysRequired(this, krea);368        key = krea.Key;369      }370    }371372    /// <summary>373    /// Get/set the encryption key value.374    /// </summary>375    byte[] Key376    {377      get { return key; }378      set { key = value; }379    }380381#if !NETCF_1_0382    /// <summary>383    /// Password to be used for encrypting/decrypting files.384    /// </summary>385    /// <remarks>Set to null if no password is required.</remarks>386    public string Password387    {388      set389      {390        if ( string.IsNullOrEmpty(value)) {391          key = null;392        }393        else {394          rawPassword_ = value;395          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));396        }298    /// <summary>299    /// Event handler for handling encryption keys.300    /// </summary>301    public KeysRequiredEventHandler KeysRequired;302303    /// <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    }315316    /// <summary>317    /// Get/set the encryption key value.318    /// </summary>319    byte[] Key {320      get { return key; }321      set { key = value; }322    }323324    /// <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    }338339    /// <summary>340    /// Get a value indicating wether encryption keys are currently available.341    /// </summary>342    bool HaveKeys {343      get { return key != null; }344    }345    #endregion346347    #region Constructors348    /// <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 occurs355    /// </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      }364365      name_ = name;366367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);368      isStreamOwner = true;369370      try {371        ReadEntries();372      } catch {373        DisposeInternal(true);374        throw;375      }376    }377378    /// <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      }394395      if (!file.CanSeek) {396        throw new ArgumentException("Stream is not seekable", nameof(file));  397      }398    }399#endif400401    /// <summary>402    /// Get a value indicating wether encryption keys are currently available.403    /// </summary>404    bool HaveKeys405    {406      get { return key != null; }407    }408    #endregion409410    #region Constructors398399      baseStream_ = file;400      name_ = file.Name;401      isStreamOwner = true;402403      try {404        ReadEntries();405      } catch {406        DisposeInternal(true);407        throw;408      }409    }410  411    /// <summary>412    /// Opens a Zip file with the given name for reading.412    /// Opens a Zip file reading the given <see cref="Stream"/>.  413    /// </summary>414    /// <param name="name">The name of the file to open.</param>415    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>416    /// <exception cref="IOException">417    /// An i/o error occurs418    /// </exception>419    /// <exception cref="ZipException">420    /// The file doesn't contain a valid zip archive.421    /// </exception>422    public ZipFile(string name)423    {424      if ( name == null ) {425        throw new ArgumentNullException(nameof(name));426      }427428      name_ = name;429430      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);431      isStreamOwner = true;414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>415    /// <exception cref="IOException">416    /// An i/o error occurs417    /// </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      }  432433      try {434        ReadEntries();433      if (!stream.CanSeek) {434        throw new ArgumentException("Stream is not seekable", nameof(stream));  435      }436      catch {437        DisposeInternal(true);438        throw;439      }440    }441442    /// <summary>443    /// Opens a Zip file reading the given <see cref="FileStream"/>.444    /// </summary>445    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>446    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>447    /// <exception cref="IOException">448    /// An i/o error occurs.449    /// </exception>450    /// <exception cref="ZipException">451    /// The file doesn't contain a valid zip archive.452    /// </exception>453    public ZipFile(FileStream file)454    {455      if ( file == null ) {456        throw new ArgumentNullException(nameof(file));457      }458459      if ( !file.CanSeek ) {460        throw new ArgumentException("Stream is not seekable", nameof(file));461      }462463      baseStream_  = file;464      name_ = file.Name;465      isStreamOwner = true;466467      try {468        ReadEntries();469      }470      catch {471        DisposeInternal(true);472        throw;473      }474    }475476    /// <summary>477    /// Opens a Zip file reading the given <see cref="Stream"/>.478    /// </summary>479    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>480    /// <exception cref="IOException">481    /// An i/o error occurs482    /// </exception>483    /// <exception cref="ZipException">484    /// The stream doesn't contain a valid zip archive.<br/>485    /// </exception>486    /// <exception cref="ArgumentException">487    /// The <see cref="Stream">stream</see> doesnt support seeking.488    /// </exception>489    /// <exception cref="ArgumentNullException">490    /// The <see cref="Stream">stream</see> argument is null.491    /// </exception>492    public ZipFile(Stream stream)493    {494      if ( stream == null ) {495        throw new ArgumentNullException(nameof(stream));496      }497498      if ( !stream.CanSeek ) {499        throw new ArgumentException("Stream is not seekable", nameof(stream));500      }501502      baseStream_  = stream;503      isStreamOwner = true;504505      if ( baseStream_.Length > 0 ) {506        try {507          ReadEntries();508        }509        catch {510          DisposeInternal(true);511          throw;512        }513      } else {514        entries_ = new ZipEntry[0];515        isNewArchive_ = true;516      }517    }518519    /// <summary>520    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.521    /// </summary>522    internal ZipFile()523    {524      entries_ = new ZipEntry[0];525      isNewArchive_ = true;526    }527528    #endregion529530    #region Destructors and Closing531    /// <summary>532    /// Finalize this instance.533    /// </summary>534    ~ZipFile()535    {536      Dispose(false);537    }538436437      baseStream_ = stream;438      isStreamOwner = true;439440      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    }452453    /// <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    }461462    #endregion463464    #region Destructors and Closing465    /// <summary>466    /// Finalize this instance.467    /// </summary>468    ~ZipFile()469    {470      Dispose(false);471    }472473    /// <summary>474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying475    /// 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    }485486    #endregion487488    #region Creators489    /// <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      }500501      FileStream fs = File.Create(fileName);502503      var result = new ZipFile();504      result.name_ = fileName;505      result.baseStream_ = fs;506      result.isStreamOwner = true;507      return result;508    }509510    /// <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      }522523      if (!outStream.CanWrite) {524        throw new ArgumentException("Stream is not writeable", nameof(outStream));525      }526527      if (!outStream.CanSeek) {528        throw new ArgumentException("Stream is not seekable", nameof(outStream));529      }530531      var result = new ZipFile();532      result.baseStream_ = outStream;533      return result;534    }535536    #endregion537538    #region Properties  539    /// <summary>540    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying541    /// Once closed, no further instance methods should be called.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    /// <exception cref="System.IO.IOException">544    /// An i/o error occurs.545    /// </exception>546    public void Close()547    {548      DisposeInternal(true);549      GC.SuppressFinalize(this);550    }551552    #endregion553554    #region Creators555    /// <summary>556    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.557    /// </summary>558    /// <param name="fileName">The name of the archive to create.</param>559    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>560    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>561    public static ZipFile Create(string fileName)562    {563      if ( fileName == null ) {564        throw new ArgumentNullException(nameof(fileName));565      }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    }550551    /// <summary>552    /// Get a value indicating wether553    /// this archive is embedded in another file or not.554    /// </summary>555    public bool IsEmbeddedArchive {556      // Not strictly correct in all circumstances currently557      get { return offsetOfFirstEntry > 0; }558    }559560    /// <summary>561    /// Get a value indicating that this archive is a new one.562    /// </summary>563    public bool IsNewArchive {564      get { return isNewArchive_; }565    }  566567      FileStream fs = File.Create(fileName);568569      var result = new ZipFile();570      result.name_ = fileName;571      result.baseStream_ = fs;572      result.isStreamOwner = true;573      return result;574    }575576    /// <summary>577    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.578    /// </summary>579    /// <param name="outStream">The stream providing data storage.</param>580    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>581    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>582    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>583    public static ZipFile Create(Stream outStream)584    {585      if ( outStream == null ) {586        throw new ArgumentNullException(nameof(outStream));587      }588589      if ( !outStream.CanWrite ) {590        throw new ArgumentException("Stream is not writeable", nameof(outStream));567    /// <summary>568    /// Gets the comment for the zip file.569    /// </summary>570    public string ZipFileComment {571      get { return comment_; }572    }573574    /// <summary>575    /// Gets the name of this zip file.576    /// </summary>577    public string Name {578      get { return name_; }579    }580581    /// <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      }592593      if ( !outStream.CanSeek ) {594        throw new ArgumentException("Stream is not seekable", nameof(outStream));595      }596597      var result = new ZipFile();598      result.baseStream_ = outStream;599      return result;600    }601602    #endregion603604    #region Properties605    /// <summary>606    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.607    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.608    /// </summary>609    /// <remarks>610    /// The default value is true in all cases.611    /// </remarks>612    public bool IsStreamOwner613    {614      get { return isStreamOwner; }615      set { isStreamOwner = value; }616    }617618    /// <summary>619    /// Get a value indicating wether620    /// this archive is embedded in another file or not.621    /// </summary>622    public bool IsEmbeddedArchive623    {624      // Not strictly correct in all circumstances currently625      get { return offsetOfFirstEntry > 0; }626    }627628    /// <summary>629    /// Get a value indicating that this archive is a new one.630    /// </summary>631    public bool IsNewArchive632    {633      get { return isNewArchive_; }634    }635636    /// <summary>637    /// Gets the comment for the zip file.638    /// </summary>639    public string ZipFileComment640    {641      get { return comment_; }642    }643644    /// <summary>645    /// Gets the name of this zip file.646    /// </summary>647    public string Name648    {649      get { return name_; }650    }651652    /// <summary>653    /// Gets the number of entries in this zip file.654    /// </summary>655    /// <exception cref="InvalidOperationException">656    /// The Zip file has been closed.657    /// </exception>658    [Obsolete("Use the Count property instead")]659    public int Size660    {661      get662      {663        return entries_.Length;664      }665    }666667    /// <summary>668    /// Get the number of entries contained in this <see cref="ZipFile"/>.669    /// </summary>670    public long Count671    {672      get673      {674        return entries_.Length;675      }676    }677678    /// <summary>679    /// Indexer property for ZipEntries680    /// </summary>681    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]682    public ZipEntry this[int index]683    {684      get {685        return (ZipEntry) entries_[index].Clone();686      }687    }688689    #endregion690691    #region Input Handling692    /// <summary>693    /// Gets an enumerator for the Zip entries in this Zip file.694    /// </summary>695    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>696    /// <exception cref="ObjectDisposedException">697    /// The Zip file has been closed.698    /// </exception>699    public IEnumerator GetEnumerator()700    {701      if (isDisposed_) {702        throw new ObjectDisposedException("ZipFile");703      }704705      return new ZipEntryEnumerator(entries_);706    }707708    /// <summary>709    /// Return the index of the entry with a matching name710    /// </summary>711    /// <param name="name">Entry name to find</param>712    /// <param name="ignoreCase">If true the comparison is case insensitive</param>713    /// <returns>The index position of the matching entry or -1 if not found</returns>714    /// <exception cref="ObjectDisposedException">715    /// The Zip file has been closed.716    /// </exception>717    public int FindEntry(string name, bool ignoreCase)718    {719      if (isDisposed_) {720        throw new ObjectDisposedException("ZipFile");721      }722723      // TODO: This will be slow as the next ice age for huge archives!724      for (int i = 0; i < entries_.Length; i++) {725        if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {726          return i;727        }728      }729      return -1;730    }731732    /// <summary>733    /// Searches for a zip entry in this archive with the given name.734    /// String comparisons are case insensitive735    /// </summary>736    /// <param name="name">737    /// The name to find. May contain directory components separated by slashes ('/').738    /// </param>739    /// <returns>740    /// A clone of the zip entry, or null if no entry with that name exists.741    /// </returns>742    /// <exception cref="ObjectDisposedException">743    /// The Zip file has been closed.744    /// </exception>745    public ZipEntry GetEntry(string name)746    {747      if (isDisposed_) {748        throw new ObjectDisposedException("ZipFile");749      }750751      int index = FindEntry(name, true);752      return (index >= 0) ? (ZipEntry) entries_[index].Clone() : null;753    }754755    /// <summary>756    /// Gets an input stream for reading the given zip entry data in an uncompressed form.757    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().758    /// </summary>759    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>760    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>761    /// <exception cref="ObjectDisposedException">762    /// The ZipFile has already been closed763    /// </exception>764    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">765    /// The compression method for the entry is unknown766    /// </exception>767    /// <exception cref="IndexOutOfRangeException">768    /// The entry is not found in the ZipFile769    /// </exception>770    public Stream GetInputStream(ZipEntry entry)771    {772      if ( entry == null ) {773        throw new ArgumentNullException(nameof(entry));774      }775776      if ( isDisposed_ ) {777        throw new ObjectDisposedException("ZipFile");778      }779780      long index = entry.ZipFileIndex;781      if ( (index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name) ) {782        index = FindEntry(entry.Name, true);783        if (index < 0) {784          throw new ZipException("Entry cannot be found");785        }786      }787      return GetInputStream(index);788    }789790    /// <summary>791    /// Creates an input stream reading a zip entry792    /// </summary>793    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>794    /// <returns>795    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>796    /// </returns>797    /// <exception cref="ObjectDisposedException">798    /// The ZipFile has already been closed799    /// </exception>800    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">801    /// The compression method for the entry is unknown802    /// </exception>803    /// <exception cref="IndexOutOfRangeException">804    /// The entry is not found in the ZipFile805    /// </exception>806    public Stream GetInputStream(long entryIndex)807    {808      if ( isDisposed_ ) {809        throw new ObjectDisposedException("ZipFile");810      }592    }593594    /// <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    }602603    /// <summary>604    /// Indexer property for ZipEntries605    /// </summary>606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]607    public ZipEntry this[int index] {608      get {609        return (ZipEntry)entries_[index].Clone();610      }611    }612613    #endregion614615    #region Input Handling616    /// <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      }628629      return new ZipEntryEnumerator(entries_);630    }631632    /// <summary>633    /// Return the index of the entry with a matching name634    /// </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      }646647      // 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    }655656    /// <summary>657    /// Searches for a zip entry in this archive with the given name.658    /// String comparisons are case insensitive659    /// </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      }674675      int index = FindEntry(name, true);676      return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;677    }678679    /// <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 closed687    /// </exception>688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">689    /// The compression method for the entry is unknown690    /// </exception>691    /// <exception cref="IndexOutOfRangeException">692    /// The entry is not found in the ZipFile693    /// </exception>694    public Stream GetInputStream(ZipEntry entry)695    {696      if (entry == null) {697        throw new ArgumentNullException(nameof(entry));698      }699700      if (isDisposed_) {701        throw new ObjectDisposedException("ZipFile");702      }703704      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    }713714    /// <summary>715    /// Creates an input stream reading a zip entry716    /// </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 closed723    /// </exception>724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">725    /// The compression method for the entry is unknown726    /// </exception>727    /// <exception cref="IndexOutOfRangeException">728    /// The entry is not found in the ZipFile729    /// </exception>730    public Stream GetInputStream(long entryIndex)731    {732      if (isDisposed_) {733        throw new ObjectDisposedException("ZipFile");734      }735736      long start = LocateEntry(entries_[entryIndex]);737      CompressionMethod method = entries_[entryIndex].CompressionMethod;738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);739740      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      }746747      switch (method) {748        case CompressionMethod.Stored:749          // read as is.750          break;751752        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;756757        default:758          throw new ZipException("Unsupported compression method " + method);759      }760761      return result;762    }763764    #endregion765766    #region Archive Testing767    /// <summary>768    /// Test an archive for integrity/validity769    /// </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    }777778    /// <summary>779    /// Test an archive for integrity/validity780    /// </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      }791792      var status = new TestStatus(this);793794      if (resultHandler != null) {795        resultHandler(status, null);796      }797798      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;799800      bool testing = true;801802      try {803        int entryIndex = 0;804805        while (testing && (entryIndex < Count)) {806          if (resultHandler != null) {807            status.SetEntry(this[entryIndex]);808            status.SetOperation(TestOperation.EntryHeader);809            resultHandler(status, null);810          }  811812      long start = LocateEntry(entries_[entryIndex]);813      CompressionMethod method = entries_[entryIndex].CompressionMethod;814      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);815816      if (entries_[entryIndex].IsCrypted == true) {817#if NETCF_1_0818        throw new ZipException("decryption not supported for Compact Framework 1.0");819#else820        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);821        if (result == null) {822          throw new ZipException("Unable to decrypt this entry");823        }824#endif825      }826827      switch (method) {828        case CompressionMethod.Stored:829          // read as is.830          break;831832        case CompressionMethod.Deflated:833          // No need to worry about ownership and closing as underlying stream close does nothing.834          result = new InflaterInputStream(result, new Inflater(true));835          break;836837        default:838          throw new ZipException("Unsupported compression method " + method);839      }812          try {813            TestLocalHeader(this[entryIndex], test);814          } catch (ZipException ex) {815            status.AddError();816817            if (resultHandler != null) {818              resultHandler(status,819                string.Format("Exception during test - '{0}'", ex.Message));820            }821822            testing &= strategy != TestStrategy.FindFirstError;823          }824825          if (testing && testData && this[entryIndex].IsFile) {826            if (resultHandler != null) {827              status.SetOperation(TestOperation.EntryData);828              resultHandler(status, null);829            }830831            var crc = new Crc32();832833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {834835              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);  840841      return result;842    }843844    #endregion845846    #region Archive Testing847    /// <summary>848    /// Test an archive for integrity/validity849    /// </summary>850    /// <param name="testData">Perform low level data Crc check</param>851    /// <returns>true if all tests pass, false otherwise</returns>852    /// <remarks>Testing will terminate on the first error found.</remarks>853    public bool TestArchive(bool testData)854    {855      return TestArchive(testData, TestStrategy.FindFirstError, null);856    }857858    /// <summary>859    /// Test an archive for integrity/validity860    /// </summary>861    /// <param name="testData">Perform low level data Crc check</param>862    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>863    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>864    /// <returns>true if all tests pass, false otherwise</returns>865    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>866    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)867    {868      if (isDisposed_) {869        throw new ObjectDisposedException("ZipFile");870      }871872      var status = new TestStatus(this);873874      if ( resultHandler != null ) {875        resultHandler(status, null);876      }877878      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;879880      bool testing = true;841                if (resultHandler != null) {842                  totalBytes += bytesRead;843                  status.SetBytesTested(totalBytes);844                  resultHandler(status, null);845                }846              }847            }848849            if (this[entryIndex].Crc != crc.Value) {850              status.AddError();851852              if (resultHandler != null) {853                resultHandler(status, "CRC mismatch");854              }855856              testing &= strategy != TestStrategy.FindFirstError;857            }858859            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              }866867              if (this[entryIndex].CompressedSize != data.CompressedSize) {868                status.AddError();869              }870871              if (this[entryIndex].Size != data.Size) {872                status.AddError();873              }874            }875          }876877          if (resultHandler != null) {878            status.SetOperation(TestOperation.EntryComplete);879            resultHandler(status, null);880          }  881882      try {883        int entryIndex = 0;882          entryIndex += 1;883        }  884885        while ( testing && (entryIndex < Count) ) {886          if ( resultHandler != null ) {887            status.SetEntry(this[entryIndex]);888            status.SetOperation(TestOperation.EntryHeader);889            resultHandler(status, null);890          }891892          try  {893            TestLocalHeader(this[entryIndex], test);894          }895          catch(ZipException ex) {896            status.AddError();897898            if ( resultHandler != null ) {899              resultHandler(status,900                string.Format("Exception during test - '{0}'", ex.Message));901            }902903            testing &= strategy != TestStrategy.FindFirstError;904          }885        if (resultHandler != null) {886          status.SetOperation(TestOperation.MiscellaneousTests);887          resultHandler(status, null);888        }889890        // TODO: the 'Corrina Johns' test where local headers are missing from891        // the central directory.  They are therefore invisible to many archivers.892      } catch (Exception ex) {893        status.AddError();894895        if (resultHandler != null) {896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));897        }898      }899900      if (resultHandler != null) {901        status.SetOperation(TestOperation.Complete);902        status.SetEntry(null);903        resultHandler(status, null);904      }  905906          if ( testing && testData && this[entryIndex].IsFile ) {907            if ( resultHandler != null ) {908              status.SetOperation(TestOperation.EntryData);909              resultHandler(status, null);910            }911912                        var crc = new Crc32();913914                        using (Stream entryStream = this.GetInputStream(this[entryIndex]))915                        {916917                            byte[] buffer = new byte[4096];918                            long totalBytes = 0;919                            int bytesRead;920                            while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0)921                            {922                                crc.Update(buffer, 0, bytesRead);923924                                if (resultHandler != null)925                                {926                                    totalBytes += bytesRead;927                                    status.SetBytesTested(totalBytes);928                                    resultHandler(status, null);929                                }930                            }931                        }932933            if (this[entryIndex].Crc != crc.Value) {934              status.AddError();935936              if ( resultHandler != null ) {937                resultHandler(status, "CRC mismatch");938              }939940              testing &= strategy != TestStrategy.FindFirstError;941            }942943            if (( this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0 ) {944              var helper = new ZipHelperStream(baseStream_);945              var data = new DescriptorData();946              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);947              if (this[entryIndex].Crc != data.Crc) {948                status.AddError();949              }950951              if (this[entryIndex].CompressedSize != data.CompressedSize) {952                status.AddError();953              }954955              if (this[entryIndex].Size != data.Size) {956                status.AddError();957              }958            }959          }960961          if ( resultHandler != null ) {962            status.SetOperation(TestOperation.EntryComplete);963            resultHandler(status, null);964          }965966          entryIndex += 1;967        }968969        if ( resultHandler != null ) {970          status.SetOperation(TestOperation.MiscellaneousTests);971          resultHandler(status, null);972        }973974        // TODO: the 'Corrina Johns' test where local headers are missing from975        // the central directory.  They are therefore invisible to many archivers.976      }977      catch (Exception ex) {978        status.AddError();906      return (status.ErrorCount == 0);907    }908909    [Flags]910    enum HeaderTest911    {912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted913      Header = 0x02,     // Check that this header contents are valid914    }915916    /// <summary>917    /// Test a local header against that provided from the central directory918    /// </summary>919    /// <param name="entry">920    /// The entry to test against921    /// </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;929930        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        }934935        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();945946        byte[] nameData = new byte[storedNameLength];947        StreamUtils.ReadFully(baseStream_, nameData);948949        byte[] extraData = new byte[extraDataLength];950        StreamUtils.ReadFully(baseStream_, extraData);951952        var localExtraData = new ZipExtraData(extraData);953954        // Extra data / zip64 checks955        if (localExtraData.Find(1)) {956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64957          // and size or compressedSize = MaxValue, due to rogue creators.958959          size = localExtraData.ReadLong();960          compressedSize = localExtraData.ReadLong();961962          if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {963            // These may be valid if patched later964            if ((size != -1) && (size != entry.Size)) {965              throw new ZipException("Size invalid for descriptor");966            }967968            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        }  979980        if ( resultHandler != null ) {981          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));982        }983      }984985      if ( resultHandler != null ) {986        status.SetOperation(TestOperation.Complete);987        status.SetEntry(null);988        resultHandler(status, null);989      }980        if (testData) {981          if (entry.IsFile) {982            if (!entry.IsCompressionMethodSupported()) {983              throw new ZipException("Compression method not supported");984            }985986            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})", extract989            }  990991      return (status.ErrorCount == 0);992    }993994    [Flags]995    enum HeaderTest996    {997      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted998      Header  = 0x02,     // Check that this header contents are valid999    }10001001    /// <summary>1002    /// Test a local header against that provided from the central directory1003    /// </summary>1004    /// <param name="entry">1005    /// The entry to test against1006    /// </param>1007    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>1008    /// <returns>The offset of the entries data in the file</returns>1009    long TestLocalHeader(ZipEntry entry, HeaderTest tests)1010    {1011      lock(baseStream_)1012      {1013        bool testHeader = (tests & HeaderTest.Header) != 0;1014        bool testData = (tests & HeaderTest.Extract) != 0;10151016        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);1017        if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {1018          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)1019        }10201021        var extractVersion = ( short ) (ReadLEUshort() & 0x00ff);1022        var localFlags = ( short )ReadLEUshort();1023        var compressionMethod = ( short )ReadLEUshort();1024        var fileTime = ( short )ReadLEUshort();1025        var fileDate = ( short )ReadLEUshort();1026        uint crcValue = ReadLEUint();1027        long compressedSize = ReadLEUint();1028        long size = ReadLEUint();1029        int storedNameLength = ReadLEUshort();1030        int extraDataLength = ReadLEUshort();10311032        byte[] nameData = new byte[storedNameLength];1033        StreamUtils.ReadFully(baseStream_, nameData);10341035        byte[] extraData = new byte[extraDataLength];1036        StreamUtils.ReadFully(baseStream_, extraData);991            if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance992              throw new ZipException("The library does not support the zip version required to extract this entry");993            }994          }995        }996997        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})", extractVersi1015          }10161017          // Local entry flags dont have reserved bit set on.1018          if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R1019            throw new ZipException("Reserved bit flags cannot be set.");1020          }10211022          // Encryption requires extract version >= 201023          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          }10261027          // 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            }10321033            if (extractVersion < 50) {1034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({01035            }1036          }  10371038        var localExtraData = new ZipExtraData(extraData);10391040        // Extra data / zip64 checks1041        if (localExtraData.Find(1))1042        {1043          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip641044          // and size or compressedSize = MaxValue, due to rogue creators.10451046          size = localExtraData.ReadLong();1047          compressedSize = localExtraData.ReadLong();10481049                    if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0)1050                    {1051                        // These may be valid if patched later1052                        if ( (size != -1) && (size != entry.Size)) {1053                            throw new ZipException("Size invalid for descriptor");1054                        }10551056                        if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {1057                            throw new ZipException("Compressed size invalid for descriptor");1058                        }1059                    }1060                }1061        else1062        {1063          // No zip64 extra data but entry requires it.1064          if ((extractVersion >= ZipConstants.VersionZip64) &&1065            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue)))1066          {1067            throw new ZipException("Required Zip64 extended information missing");1038          // Patched entries require extract version >= 271039          if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {1040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));1041          }10421043          // Central header flags match local entry flags.1044          if (localFlags != entry.Flags) {1045            throw new ZipException("Central header/local header flags mismatch");1046          }10471048          // Central header compression method matches local entry1049          if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {1050            throw new ZipException("Central header/local header compression method mismatch");1051          }10521053          if (entry.Version != extractVersion) {1054            throw new ZipException("Extract version mismatch");1055          }10561057          // Strong encryption and extract version match1058          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          }10631064          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        }10701071        if ( testData ) {1072          if ( entry.IsFile ) {1073            if ( !entry.IsCompressionMethodSupported() ) {1074              throw new ZipException("Compression method not supported");1075            }10761077            if ( (extractVersion > ZipConstants.VersionMadeBy)1078              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)) ) {1079              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract1080            }10811082            if ( (localFlags & ( int )(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enha1083              throw new ZipException("The library does not support the zip version required to extract this entry");1084            }1085          }1086        }10871088                if (testHeader)1089                {1090                    if ((extractVersion <= 63) &&  // Ignore later versions as we dont know about them..1091                        (extractVersion != 10) &&1092                        (extractVersion != 11) &&1093                        (extractVersion != 20) &&1094                        (extractVersion != 21) &&1095                        (extractVersion != 25) &&1096                        (extractVersion != 27) &&1097                        (extractVersion != 45) &&1098                        (extractVersion != 46) &&1099                        (extractVersion != 50) &&1100                        (extractVersion != 51) &&1101                        (extractVersion != 52) &&1102                        (extractVersion != 61) &&1103                        (extractVersion != 62) &&1104                        (extractVersion != 63)1105                        )1106                    {1107                        throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", 1108                    }11091110                    // Local entry flags dont have reserved bit set on.1111                    if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | General1112                    {1113                        throw new ZipException("Reserved bit flags cannot be set.");1114                    }11151116                    // Encryption requires extract version >= 201117                    if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20))1118                    {1119                        throw new ZipException(string.Format("Version required to extract this entry is too low for encr1120                    }11211122                    // Strong encryption requires encryption flag to be set and extract version >= 50.1123                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1124                    {1125                        if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0)1126                        {1127                            throw new ZipException("Strong encryption flag set but encryption flag is not set");1128                        }10691070          if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {1071            if (crcValue != (uint)entry.Crc) {1072              throw new ZipException("Central header/local header crc mismatch");1073            }1074          }10751076          // Crc valid for empty entry.1077          // This will also apply to streamed entries where size isnt known and the header cant be patched1078          if ((size == 0) && (compressedSize == 0)) {1079            if (crcValue != 0) {1080              throw new ZipException("Invalid CRC for empty entry");1081            }1082          }10831084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably1086          if (entry.Name.Length > storedNameLength) {1087            throw new ZipException("File name length mismatch");1088          }10891090          // Name data has already been read convert it and compare.1091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);10921093          // Central directory and local entry name match1094          if (localName != entry.Name) {1095            throw new ZipException("Central header and local header file name mismatch");1096          }10971098          // Directories have zero actual size but can have compressed size1099          if (entry.IsDirectory) {1100            if (size > 0) {1101              throw new ZipException("Directory cannot have size");1102            }11031104            // 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 bytes1112              // 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 bytes1114              throw new ZipException("Directory compressed size invalid");1115            }1116          }11171118          if (!ZipNameTransform.IsValidName(localName, true)) {1119            throw new ZipException("Name is invalid");1120          }1121        }11221123        // Tests that apply to both data and header.11241125        // 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)) {  11291130                        if (extractVersion < 50)1131                        {1132                            throw new ZipException(string.Format("Version required to extract this entry is too low for 1133                        }1134                    }11351136                    // Patched entries require extract version >= 271137                    if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27))1138                    {1139                        throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractV1140                    }11411142                    // Central header flags match local entry flags.1143                    if (localFlags != entry.Flags)1144                    {1145                        throw new ZipException("Central header/local header flags mismatch");1146                    }11471148                    // Central header compression method matches local entry1149                    if (entry.CompressionMethod != (CompressionMethod)compressionMethod)1150                    {1151                        throw new ZipException("Central header/local header compression method mismatch");1152                    }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          }11361137          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        }11441145        int extraLength = storedNameLength + extraDataLength;1146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;1147      }1148    }11491150    #endregion11511152    #region Updating  11531154                    if (entry.Version != extractVersion)1155                    {1156                        throw new ZipException("Extract version mismatch");1157                    }11581159                    // Strong encryption and extract version match1160                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1161                    {1162                        if (extractVersion < 62)1163                        {1164                            throw new ZipException("Strong encryption flag set but version not high enough");1165                        }1166                    }11671168                    if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0)1169                    {1170                        if ((fileTime != 0) || (fileDate != 0))1171                        {1172                            throw new ZipException("Header masked set but date/time values non-zero");1173                        }1174                    }11751176                    if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0)1177                    {1178                        if (crcValue != (uint)entry.Crc)1179                        {1180                            throw new ZipException("Central header/local header crc mismatch");1181                        }1182                    }11831184                    // Crc valid for empty entry.1185                    // This will also apply to streamed entries where size isnt known and the header cant be patched1186                    if ((size == 0) && (compressedSize == 0))1187                    {1188                        if (crcValue != 0)1189                        {1190                            throw new ZipException("Invalid CRC for empty entry");1191                        }1192                    }11931194                    // TODO: make test more correct...  can't compare lengths as was done originally as this can fail fo1195                    // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntr1196                    if (entry.Name.Length > storedNameLength)1197                    {1198                        throw new ZipException("File name length mismatch");1199                    }12001201                    // Name data has already been read convert it and compare.1202                    string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);12031204                    // Central directory and local entry name match1205                    if (localName != entry.Name)1206                    {1207                        throw new ZipException("Central header and local header file name mismatch");1208                    }12091210                    // Directories have zero actual size but can have compressed size1211                    if (entry.IsDirectory)1212                    {1213                        if (size > 0)1214                        {1215                            throw new ZipException("Directory cannot have size");1216                        }12171218                        // There may be other cases where the compressed size can be greater than this?1219                        // If so until details are known we will be strict.1220                        if (entry.IsCrypted)1221                        {1222                            if (compressedSize > ZipConstants.CryptoHeaderSize + 2)1223                            {1224                                throw new ZipException("Directory compressed size invalid");1225                            }1226                        }1227                        else if (compressedSize > 2)1228                        {1229                            // When not compressed the directory size can validly be 2 bytes1230                            // if the true size wasnt known when data was originally being written.1231                            // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes1232                            throw new ZipException("Directory compressed size invalid");1233                        }1234                    }12351236                    if (!ZipNameTransform.IsValidName(localName, true))1237                    {1238                        throw new ZipException("Name is invalid");1239                    }1240                }12411242        // Tests that apply to both data and header.1154    const int DefaultBufferSize = 4096;11551156    /// <summary>1157    /// The kind of update to apply.1158    /// </summary>1159    enum UpdateCommand1160    {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    }11651166    #region Properties1167    /// <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      }11741175      set {1176        updateEntryFactory_.NameTransform = value;1177      }1178    }11791180    /// <summary>1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1182    /// during updates.1183    /// </summary>1184    public IEntryFactory EntryFactory {1185      get {1186        return updateEntryFactory_;1187      }11881189      set {1190        if (value == null) {1191          updateEntryFactory_ = new ZipEntryFactory();1192        } else {1193          updateEntryFactory_ = value;1194        }1195      }1196    }11971198    /// <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        }12071208        if (bufferSize_ != value) {1209          bufferSize_ = value;1210          copyBuffer_ = null;1211        }1212      }1213    }12141215    /// <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    }12211222    /// <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    }12291230    #endregion12311232    #region Immediate updating1233    //    TBD: Direct form of updating1234    //1235    //    public void Update(IEntryMatcher deleteMatcher)1236    //    {1237    //    }1238    //1239    //    public void Update(IScanner addScanner)1240    //    {1241    //    }1242    #endregion  12431244        // Size can be verified only if it is known in the local header.1245        // it will always be known in the central header.1246        if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||1247          ((size > 0) || (compressedSize > 0))) {12481249          if (size != entry.Size) {1250            throw new ZipException(1251              string.Format("Size mismatch between central header({0}) and local header({1})",1252                entry.Size, size));1253          }12541255          if (compressedSize != entry.CompressedSize &&1256            compressedSize != 0xFFFFFFFF && compressedSize != -1) {1257            throw new ZipException(1258              string.Format("Compressed size mismatch between central header({0}) and local header({1})",1259              entry.CompressedSize, compressedSize));1260          }1261        }1244    #region Deferred Updating1245    /// <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.</p1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1250    /// <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      }12581259      if (dataSource == null) {1260        throw new ArgumentNullException(nameof(dataSource));1261      }  12621263        int extraLength = storedNameLength + extraDataLength;1264        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;1263      if (isDisposed_) {1264        throw new ObjectDisposedException("ZipFile");  1265      }1266    }12671268    #endregion12691270    #region Updating12711272    const int DefaultBufferSize = 4096;12661267      if (IsEmbeddedArchive) {1268        throw new ZipException("Cannot update embedded/SFX archives");1269      }12701271      archiveStorage_ = archiveStorage;1272      updateDataSource_ = dataSource;  12731274    /// <summary>1275    /// The kind of update to apply.1276    /// </summary>1277    enum UpdateCommand1278    {1279      Copy,       // Copy original file contents.1280      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.1281      Add,        // Add a new file to the archive.1282    }1274      // NOTE: the baseStream_ may not currently support writing or seeking.12751276      updateIndex_ = new Hashtable();12771278      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      }  12831284    #region Properties1285    /// <summary>1286    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.1287    /// </summary>1288    public INameTransform NameTransform1289    {1290      get {1291        return updateEntryFactory_.NameTransform;1292      }12931294      set {1295        updateEntryFactory_.NameTransform = value;1296      }1297    }12981299    /// <summary>1300    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1301    /// during updates.1302    /// </summary>1303    public IEntryFactory EntryFactory1304    {1305      get {1306        return updateEntryFactory_;1307      }13081309      set {1310        if (value == null) {1311          updateEntryFactory_ = new ZipEntryFactory();1312        }1313        else {1314          updateEntryFactory_ = value;1315        }1316      }1317    }13181319    /// <summary>1320    /// Get /set the buffer size to be used when updating this zip file.1321    /// </summary>1322    public int BufferSize1323    {1324      get { return bufferSize_; }1325      set {1326        if ( value < 1024 ) {1327#if NETCF_1_01328          throw new ArgumentOutOfRangeException("value");1329#else1330          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");1331#endif1332        }13331334        if ( bufferSize_ != value ) {1335          bufferSize_ = value;1336          copyBuffer_ = null;1337        }1338      }1339    }1284      // We must sort by offset before using offset's calculated sizes1285      updates_.Sort(new UpdateComparer());12861287      int idx = 0;1288      foreach (ZipUpdate update in updates_) {1289        //If last entry, there is no next entry offset to use1290        if (idx == updates_.Count - 1)1291          break;12921293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;1294        idx++;1295      }1296      updateCount_ = updates_.Count;12971298      contentsEdited_ = false;1299      commentEdited_ = false;1300      newComment_ = null;1301    }13021303    /// <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    }13111312    /// <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    }13261327    /// <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      }13381339      CheckUpdating();  13401341    /// <summary>1342    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.1343    /// </summary>1344    public bool IsUpdating1345    {1346      get { return updates_ != null; }1347    }13481349    /// <summary>1350    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.1351    /// </summary>1352    public UseZip64 UseZip641353    {1354      get { return useZip64_; }1355      set { useZip64_ = value; }1356    }13571358    #endregion13591360    #region Immediate updating1361//    TBD: Direct form of updating1362//1363//    public void Update(IEntryMatcher deleteMatcher)1364//    {1365//    }1366//1367//    public void Update(IScanner addScanner)1368//    {1369//    }1370    #endregion13711372    #region Deferred Updating1373    /// <summary>1374    /// Begin updating this <see cref="ZipFile"/> archive.1375    /// </summary>1376    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p1377    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1341      try {1342        updateIndex_.Clear();1343        updateIndex_ = null;13441345        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        }13581359      } finally {1360        PostUpdateCleanup();1361      }1362    }13631364    /// <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    }13731374    /// <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    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>1380    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1381    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)1382    {1383      if ( archiveStorage == null ) {1384        throw new ArgumentNullException(nameof(archiveStorage));1385      }1379    public void SetComment(string comment)1380    {1381      if (isDisposed_) {1382        throw new ObjectDisposedException("ZipFile");1383      }13841385      CheckUpdating();  13861387      if ( dataSource == null ) {1388        throw new ArgumentNullException(nameof(dataSource));1389      }13901391      if ( isDisposed_ ) {1392        throw new ObjectDisposedException("ZipFile");1393      }13941395      if ( IsEmbeddedArchive ) {1396        throw new ZipException ("Cannot update embedded/SFX archives");1397      }1387      newComment_ = new ZipString(comment);13881389      if (newComment_.RawLength > 0xffff) {1390        newComment_ = null;1391        throw new ZipException("Comment length exceeds maximum - 65535");1392      }13931394      // We dont take account of the original and current comment appearing to be the same1395      // as encoding may be different.1396      commentEdited_ = true;1397    }  13981399      archiveStorage_ = archiveStorage;1400      updateDataSource_ = dataSource;14011402      // NOTE: the baseStream_ may not currently support writing or seeking.14031404      updateIndex_ = new Hashtable();14051406      updates_ = new ArrayList(entries_.Length);1407      foreach(ZipEntry entry in entries_) {1408        int index = updates_.Add(new ZipUpdate(entry));1409        updateIndex_.Add(entry.Name, index);1410      }14111412      // We must sort by offset before using offset's calculated sizes1413      updates_.Sort(new UpdateComparer());14141415      int idx = 0;1416      foreach (ZipUpdate update in updates_) {1417        //If last entry, there is no next entry offset to use1418        if (idx == updates_.Count - 1)1419          break;14201421        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;1422        idx++;1423      }1424      updateCount_ = updates_.Count;14251426      contentsEdited_ = false;1427      commentEdited_ = false;1428      newComment_ = null;1429    }14301431    /// <summary>1432    /// Begin updating to this <see cref="ZipFile"/> archive.1433    /// </summary>1434    /// <param name="archiveStorage">The storage to use during the update.</param>1435    public void BeginUpdate(IArchiveStorage archiveStorage)1436    {1437      BeginUpdate(archiveStorage, new DynamicDiskDataSource());1438    }14391440    /// <summary>1441    /// Begin updating this <see cref="ZipFile"/> archive.1442    /// </summary>1443    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>1444    /// <seealso cref="CommitUpdate"></seealso>1445    /// <seealso cref="AbortUpdate"></seealso>1446    public void BeginUpdate()1447    {1448      if ( Name == null ) {1449        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());1450      }1451      else {1452        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());1453      }1399    #endregion14001401    #region Adding Entries14021403    void AddUpdate(ZipUpdate update)1404    {1405      contentsEdited_ = true;14061407      int index = FindExistingUpdate(update.Entry.Name);14081409      if (index >= 0) {1410        if (updates_[index] == null) {1411          updateCount_ += 1;1412        }14131414        // 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    }14221423    /// <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      }14371438      if (isDisposed_) {1439        throw new ObjectDisposedException("ZipFile");1440      }14411442      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1444      }14451446      CheckUpdating();1447      contentsEdited_ = true;14481449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1450      entry.IsUnicodeText = useUnicodeText;1451      entry.CompressionMethod = compressionMethod;14521453      AddUpdate(new ZipUpdate(fileName, entry));  1454    }  1455  1456    /// <summary>1457    /// Commit current updates, updating this archive.1457    /// Add a new entry to the archive.  1458    /// </summary>1459    /// <seealso cref="BeginUpdate()"></seealso>1460    /// <seealso cref="AbortUpdate"></seealso>1461    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1462    public void CommitUpdate()1463    {1464      if ( isDisposed_ ) {1465        throw new ObjectDisposedException("ZipFile");1466      }14671468      CheckUpdating();14691470      try {1471        updateIndex_.Clear();1472        updateIndex_=null;14731474        if( contentsEdited_ ) {1475          RunUpdates();1476        }1477        else if( commentEdited_ ) {1478          UpdateCommentOnly();1479        }1480        else {1481          // Create an empty archive if none existed originally.1482          if( entries_.Length==0 ) {1483            byte[] theComment=(newComment_!=null)?newComment_.RawComment:ZipConstants.ConvertToArray(comment_);1484            using( ZipHelperStream zhs=new ZipHelperStream(baseStream_) ) {1485              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);1486            }1487          }1488        }14891459    /// <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      }14681469      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1471      }14721473      CheckUpdating();1474      contentsEdited_ = true;14751476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1477      entry.CompressionMethod = compressionMethod;1478      AddUpdate(new ZipUpdate(fileName, entry));1479    }14801481    /// <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      finally {1492        PostUpdateCleanup();1493      }14911492      CheckUpdating();1493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));  1494    }  1495  1496    /// <summary>1497    /// Abort updating leaving the archive unchanged.1497    /// Add a file to the archive.  1498    /// </summary>1499    /// <seealso cref="BeginUpdate()"></seealso>1500    /// <seealso cref="CommitUpdate"></seealso>1501    public void AbortUpdate()1502    {1503      PostUpdateCleanup();1504    }15051506    /// <summary>1507    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.1508    /// </summary>1509    /// <param name="comment">The comment to record.</param>1510    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1511    public void SetComment(string comment)1512    {1513      if ( isDisposed_ ) {1514        throw new ObjectDisposedException("ZipFile");1515      }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      }15071508      if (entryName == null) {1509        throw new ArgumentNullException(nameof(entryName));1510      }15111512      CheckUpdating();1513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));1514    }1515  15161517      CheckUpdating();15181519      newComment_ = new ZipString(comment);15201521      if ( newComment_.RawLength  > 0xffff ) {1522        newComment_ = null;1523        throw new ZipException("Comment length exceeds maximum - 65535");1524      }15251526      // We dont take account of the original and current comment appearing to be the same1527      // as encoding may be different.1528      commentEdited_ = true;1529    }15301531    #endregion15321533    #region Adding Entries15341535    void AddUpdate(ZipUpdate update)1536    {1537      contentsEdited_ = true;15381539      int index = FindExistingUpdate(update.Entry.Name);15401541      if (index >= 0) {1542        if ( updates_[index] == null ) {1543          updateCount_ += 1;1544        }15451546        // Direct replacement is faster than delete and add.1547        updates_[index] = update;1548      }1549      else {1550        index = updates_.Add(update);1551        updateCount_ += 1;1552        updateIndex_.Add(update.Entry.Name, index);1553      }1554    }15551556    /// <summary>1557    /// Add a new entry to the archive.1558    /// </summary>1559    /// <param name="fileName">The name of the file to add.</param>1560    /// <param name="compressionMethod">The compression method to use.</param>1561    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>1562    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1563    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1564    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>1565    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText )1566    {1567      if (fileName == null) {1568        throw new ArgumentNullException(nameof(fileName));1569      }15701571      if ( isDisposed_ ) {1572        throw new ObjectDisposedException("ZipFile");1573      }15741575      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1576        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1577      }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      }15271528      if (entryName == null) {1529        throw new ArgumentNullException(nameof(entryName));1530      }15311532      CheckUpdating();1533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));1534    }15351536    /// <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      }15471548      if (entryName == null) {1549        throw new ArgumentNullException(nameof(entryName));1550      }15511552      CheckUpdating();15531554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1555      entry.CompressionMethod = compressionMethod;15561557      AddUpdate(new ZipUpdate(dataSource, entry));1558    }15591560    /// <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 useUnicode1568    {1569      if (dataSource == null) {1570        throw new ArgumentNullException(nameof(dataSource));1571      }15721573      if (entryName == null) {1574        throw new ArgumentNullException(nameof(entryName));1575      }15761577      CheckUpdating();  15781579      CheckUpdating();1580      contentsEdited_ = true;15811582      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1583      entry.IsUnicodeText = useUnicodeText;1584      entry.CompressionMethod = compressionMethod;1579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1580      entry.IsUnicodeText = useUnicodeText;1581      entry.CompressionMethod = compressionMethod;15821583      AddUpdate(new ZipUpdate(dataSource, entry));1584    }  15851586      AddUpdate(new ZipUpdate(fileName, entry));1587    }15881589    /// <summary>1590    /// Add a new entry to the archive.1591    /// </summary>1592    /// <param name="fileName">The name of the file to add.</param>1593    /// <param name="compressionMethod">The compression method to use.</param>1594    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>1595    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>1596    public void Add(string fileName, CompressionMethod compressionMethod)1597    {1598      if ( fileName == null ) {1599        throw new ArgumentNullException(nameof(fileName));1600      }16011602      if ( !ZipEntry.IsCompressionMethodSupported(compressionMethod) ) {1603        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1604      }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      }15961597      CheckUpdating();15981599      if ((entry.Size != 0) || (entry.CompressedSize != 0)) {1600        throw new ZipException("Entry cannot have any data");1601      }16021603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));1604    }  16051606      CheckUpdating();1607      contentsEdited_ = true;16081609      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1610      entry.CompressionMethod = compressionMethod;1611      AddUpdate(new ZipUpdate(fileName, entry));1612    }16131614    /// <summary>1615    /// Add a file to the archive.1616    /// </summary>1617    /// <param name="fileName">The name of the file to add.</param>1618    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1619    public void Add(string fileName)1620    {1621      if ( fileName == null ) {1622        throw new ArgumentNullException(nameof(fileName));1623      }16241625      CheckUpdating();1626      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));1627    }16281629    /// <summary>1630    /// Add a file to the archive.1631    /// </summary>1632    /// <param name="fileName">The name of the file to add.</param>1633    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>1634    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1635    public void Add(string fileName, string entryName)1636    {1637      if (fileName == null) {1638        throw new ArgumentNullException(nameof(fileName));1639      }16401641      if ( entryName == null ) {1642        throw new ArgumentNullException(nameof(entryName));1643      }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      }16151616      CheckUpdating();16171618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);1619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));1620    }16211622    #endregion16231624    #region Modifying Entries1625    /* 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          }16331634          if ( updated == null ) {1635            throw new ArgumentNullException("updated");1636          }16371638          CheckUpdating();1639          contentsEdited_ = true;1640          updates_.Add(new ZipUpdate(original, updated));1641        }1642    */1643    #endregion  16441645      CheckUpdating();1646      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));1647    }164816491650    /// <summary>1651    /// Add a file entry with data.1652    /// </summary>1653    /// <param name="dataSource">The source of the data for this entry.</param>1654    /// <param name="entryName">The name to give to the entry.</param>1655    public void Add(IStaticDataSource dataSource, string entryName)1656    {1657      if ( dataSource == null ) {1658        throw new ArgumentNullException(nameof(dataSource));1659      }16601661      if ( entryName == null ) {1662        throw new ArgumentNullException(nameof(entryName));1663      }16641665      CheckUpdating();1666      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));1667    }16681669    /// <summary>1670    /// Add a file entry with data.1671    /// </summary>1672    /// <param name="dataSource">The source of the data for this entry.</param>1673    /// <param name="entryName">The name to give to the entry.</param>1674    /// <param name="compressionMethod">The compression method to use.</param>1675    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)1676    {1677      if ( dataSource == null ) {1678        throw new ArgumentNullException(nameof(dataSource));1679      }16801681      if ( entryName == null ) {1682        throw new ArgumentNullException(nameof(entryName));1683      }16841685      CheckUpdating();16861687      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1688      entry.CompressionMethod = compressionMethod;16891690      AddUpdate(new ZipUpdate(dataSource, entry));1691    }16921693    /// <summary>1694    /// Add a file entry with data.1695    /// </summary>1696    /// <param name="dataSource">The source of the data for this entry.</param>1697    /// <param name="entryName">The name to give to the entry.</param>1698    /// <param name="compressionMethod">The compression method to use.</param>1699    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>1700    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode1701    {1702      if (dataSource == null) {1703        throw new ArgumentNullException(nameof(dataSource));1704      }17051706      if ( entryName == null ) {1707        throw new ArgumentNullException(nameof(entryName));1708      }17091710      CheckUpdating();17111712      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1713      entry.IsUnicodeText = useUnicodeText;1714      entry.CompressionMethod = compressionMethod;17151716      AddUpdate(new ZipUpdate(dataSource, entry));1717    }17181719    /// <summary>1720    /// Add a <see cref="ZipEntry"/> that contains no data.1721    /// </summary>1722    /// <param name="entry">The entry to add.</param>1723    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>1724    public void Add(ZipEntry entry)1725    {1726      if ( entry == null ) {1727        throw new ArgumentNullException(nameof(entry));1728      }17291730      CheckUpdating();1645    #region Deleting Entries1646    /// <summary>1647    /// Delete an entry by name1648    /// </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      }16561657      CheckUpdating();16581659      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    }16711672    /// <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      }16811682      CheckUpdating();16831684      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    }16931694    #endregion16951696    #region Update Support16971698    #region Writing Values/Headers1699    void WriteLEShort(int value)1700    {1701      baseStream_.WriteByte((byte)(value & 0xff));1702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));1703    }17041705    /// <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    }17131714    /// <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    }17221723    /// <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    }  17311732      if ( (entry.Size != 0) || (entry.CompressedSize != 0) ) {1733        throw new ZipException("Entry cannot have any data");1734      }17351736      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));1737    }17381739    /// <summary>1740    /// Add a directory entry to the archive.1741    /// </summary>1742    /// <param name="directoryName">The directory to add.</param>1743    public void AddDirectory(string directoryName)1744    {1745      if ( directoryName == null ) {1746        throw new ArgumentNullException(nameof(directoryName));1747      }17481749      CheckUpdating();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    }17401741    void WriteLEUlong(ulong value)1742    {1743      WriteLEUint((uint)(value & 0xffffffff));1744      WriteLEUint((uint)(value >> 32));1745    }17461747    void WriteLocalEntryHeader(ZipUpdate update)1748    {1749      ZipEntry entry = update.OutEntry;  17501751      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);1752      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));1753    }17541755    #endregion17561757    #region Modifying Entries1758/* Modify not yet ready for public consumption.1759   Direct modification of an entry should not overwrite original data before its read.1760   Safe mode is trivial in this sense.1761    public void Modify(ZipEntry original, ZipEntry updated)1762    {1763      if ( original == null ) {1764        throw new ArgumentNullException("original");1765      }1751      // TODO: Local offset will require adjusting for multi-disk zip files.1752      entry.Offset = baseStream_.Position;17531754      // 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        }  17661767      if ( updated == null ) {1768        throw new ArgumentNullException("updated");1769      }17701771      CheckUpdating();1772      contentsEdited_ = true;1773      updates_.Add(new ZipUpdate(original, updated));1774    }1775*/1776    #endregion17771778    #region Deleting Entries1779    /// <summary>1780    /// Delete an entry by name1781    /// </summary>1782    /// <param name="fileName">The filename to delete</param>1783    /// <returns>True if the entry was found and deleted; false otherwise.</returns>1784    public bool Delete(string fileName)1785    {1786      if ( fileName == null ) {1787        throw new ArgumentNullException(nameof(fileName));1788      }17891790      CheckUpdating();17911792      bool result = false;1793      int index = FindExistingUpdate(fileName);1794      if ( (index >= 0) && (updates_[index] != null) ) {1795        result = true;1796        contentsEdited_ = true;1797        updates_[index] = null;1798        updateCount_ -= 1;1799      }1800      else {1801        throw new ZipException("Cannot find entry to delete");1802      }1803      return result;1804    }18051806    /// <summary>1807    /// Delete a <see cref="ZipEntry"/> from the archive.1808    /// </summary>1809    /// <param name="entry">The entry to delete.</param>1810    public void Delete(ZipEntry entry)1811    {1812      if ( entry == null ) {1813        throw new ArgumentNullException(nameof(entry));1814      }18151816      CheckUpdating();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        }17751776        switch (useZip64_) {1777          case UseZip64.Dynamic:1778            if (entry.Size < 0) {1779              entry.ForceZip64();1780            }1781            break;17821783          case UseZip64.On:1784            entry.ForceZip64();1785            break;17861787          case UseZip64.Off:1788            // Do nothing.  The entry itself may be using Zip64 independantly.1789            break;1790        }1791      }17921793      // Write the local file header1794      WriteLEInt(ZipConstants.LocalHeaderSignature);17951796      WriteLEShort(entry.Version);1797      WriteLEShort(entry.Flags);17981799      WriteLEShort((byte)entry.CompressionMethod);1800      WriteLEInt((int)entry.DosTime);18011802      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      }18091810      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        }  18171818      int index = FindExistingUpdate(entry);1819      if ( index >= 0 ) {1820        contentsEdited_ = true;1821        updates_[index] = null;1822        updateCount_ -= 1;1823      }1824      else {1825        throw new ZipException("Cannot find entry to delete");1818        WriteLEInt((int)entry.CompressedSize);1819        WriteLEInt((int)entry.Size);1820      }18211822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);18231824      if (name.Length > 0xFFFF) {1825        throw new ZipException("Entry name too long.");  1826      }1827    }18281829    #endregion18301831    #region Update Support18271828      var ed = new ZipExtraData(entry.ExtraData);18291830      if (entry.LocalHeaderRequiresZip64) {1831        ed.StartNewEntry();  18321833    #region Writing Values/Headers1834    void WriteLEShort(int value)1835    {1836      baseStream_.WriteByte(( byte )(value & 0xff));1837      baseStream_.WriteByte(( byte )((value >> 8) & 0xff));1838    }18391840    /// <summary>1841    /// Write an unsigned short in little endian byte order.1842    /// </summary>1843    void WriteLEUshort(ushort value)1844    {1845      baseStream_.WriteByte(( byte )(value & 0xff));1846      baseStream_.WriteByte(( byte )(value >> 8));1847    }18481849    /// <summary>1850    /// Write an int in little endian byte order.1851    /// </summary>1852    void WriteLEInt(int value)1853    {1854      WriteLEShort(value & 0xffff);1855      WriteLEShort(value >> 16);1856    }18571858    /// <summary>1859    /// Write an unsigned int in little endian byte order.1860    /// </summary>1861    void WriteLEUint(uint value)1862    {1863      WriteLEUshort((ushort)(value & 0xffff));1864      WriteLEUshort((ushort)(value >> 16));1865    }18661867    /// <summary>1868    /// Write a long in little endian byte order.1869    /// </summary>1870    void WriteLeLong(long value)1871    {1872      WriteLEInt(( int )(value & 0xffffffff));1873      WriteLEInt(( int )(value >> 32));1874    }18751876    void WriteLEUlong(ulong value)1877    {1878      WriteLEUint(( uint )(value & 0xffffffff));1879      WriteLEUint(( uint )(value >> 32));1880    }18811882    void WriteLocalEntryHeader(ZipUpdate update)1883    {1884      ZipEntry entry = update.OutEntry;18851886      // TODO: Local offset will require adjusting for multi-disk zip files.1887      entry.Offset = baseStream_.Position;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      }18411842      entry.ExtraData = ed.GetEntryData();18431844      WriteLEShort(name.Length);1845      WriteLEShort(entry.ExtraData.Length);18461847      if (name.Length > 0) {1848        baseStream_.Write(name, 0, name.Length);1849      }18501851      if (entry.LocalHeaderRequiresZip64) {1852        if (!ed.Find(1)) {1853          throw new ZipException("Internal error cannot find extra data");1854        }18551856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1857      }18581859      if (entry.ExtraData.Length > 0) {1860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);1861      }1862    }18631864    int WriteCentralDirectoryHeader(ZipEntry entry)1865    {1866      if (entry.CompressedSize < 0) {1867        throw new ZipException("Attempt to write central directory entry with unknown csize");1868      }18691870      if (entry.Size < 0) {1871        throw new ZipException("Attempt to write central directory entry with unknown size");1872      }18731874      if (entry.Crc < 0) {1875        throw new ZipException("Attempt to write central directory entry with unknown crc");1876      }18771878      // Write the central file header1879      WriteLEInt(ZipConstants.CentralHeaderSignature);18801881      // Version made by1882      WriteLEShort(ZipConstants.VersionMadeBy);18831884      // Version required to extract1885      WriteLEShort(entry.Version);18861887      WriteLEShort(entry.Flags);  18881889      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.1890      if (update.Command != UpdateCommand.Copy) {1891        if (entry.CompressionMethod == CompressionMethod.Deflated) {1892          if (entry.Size == 0) {1893            // No need to compress - no data.1894            entry.CompressedSize = entry.Size;1895            entry.Crc = 0;1896            entry.CompressionMethod = CompressionMethod.Stored;1897          }1898        }1899        else if (entry.CompressionMethod == CompressionMethod.Stored) {1900          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;1901        }19021903        if (HaveKeys) {1904          entry.IsCrypted = true;1905          if (entry.Crc < 0) {1906            entry.Flags |= (int)GeneralBitFlags.Descriptor;1907          }1908        }1909        else {1910          entry.IsCrypted = false;1911        }1889      unchecked {1890        WriteLEShort((byte)entry.CompressionMethod);1891        WriteLEInt((int)entry.DosTime);1892        WriteLEInt((int)entry.Crc);1893      }18941895      if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {1896        WriteLEInt(-1);1897      } else {1898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));1899      }19001901      if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {1902        WriteLEInt(-1);1903      } else {1904        WriteLEInt((int)entry.Size);1905      }19061907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);19081909      if (name.Length > 0xFFFF) {1910        throw new ZipException("Entry name is too long.");1911      }  19121913        switch (useZip64_) {1914          case UseZip64.Dynamic:1915            if (entry.Size < 0) {1916              entry.ForceZip64();1917            }1918            break;19191920          case UseZip64.On:1921            entry.ForceZip64();1922            break;19231924          case UseZip64.Off:1925            // Do nothing.  The entry itself may be using Zip64 independantly.1926            break;1913      WriteLEShort(name.Length);19141915      // Central header extra data is different to local header version so regenerate.1916      var ed = new ZipExtraData(entry.ExtraData);19171918      if (entry.CentralHeaderRequiresZip64) {1919        ed.StartNewEntry();19201921        if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {1922          ed.AddLeLong(entry.Size);1923        }19241925        if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {1926          ed.AddLeLong(entry.CompressedSize);  1927        }1928      }19291930      // Write the local file header1931      WriteLEInt(ZipConstants.LocalHeaderSignature);19281929        if (entry.Offset >= 0xffffffff) {1930          ed.AddLeLong(entry.Offset);1931        }  19321933      WriteLEShort(entry.Version);1934      WriteLEShort(entry.Flags);19351936      WriteLEShort((byte)entry.CompressionMethod);1937      WriteLEInt(( int )entry.DosTime);19381939      if ( !entry.HasCrc ) {1940        // Note patch address for updating CRC later.1941        update.CrcPatchOffset = baseStream_.Position;1942        WriteLEInt(( int )0);1943      }1944      else {1945        WriteLEInt(unchecked(( int )entry.Crc));1946      }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      }19391940      byte[] centralExtraData = ed.GetEntryData();19411942      WriteLEShort(centralExtraData.Length);1943      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);19441945      WriteLEShort(0);    // disk number1946      WriteLEShort(0);    // internal file attributes  19471948      if (entry.LocalHeaderRequiresZip64) {1949        WriteLEInt(-1);1950        WriteLEInt(-1);1951      }1952      else {1953        if ( (entry.CompressedSize < 0) || (entry.Size < 0) ) {1954          update.SizePatchOffset = baseStream_.Position;1955        }19561957        WriteLEInt(( int )entry.CompressedSize);1958        WriteLEInt(( int )entry.Size);1959      }19601961      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);19621963      if ( name.Length > 0xFFFF ) {1964        throw new ZipException("Entry name too long.");1965      }19661967      var ed = new ZipExtraData(entry.ExtraData);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      }19581959      if (entry.Offset >= 0xffffffff) {1960        WriteLEUint(0xffffffff);1961      } else {1962        WriteLEUint((uint)(int)entry.Offset);1963      }19641965      if (name.Length > 0) {1966        baseStream_.Write(name, 0, name.Length);1967      }  19681969      if ( entry.LocalHeaderRequiresZip64 ) {1970        ed.StartNewEntry();19711972        // Local entry header always includes size and compressed size.1973        // NOTE the order of these fields is reversed when compared to the normal headers!1974        ed.AddLeLong(entry.Size);1975        ed.AddLeLong(entry.CompressedSize);1976        ed.AddNewEntry(1);1969      if (centralExtraData.Length > 0) {1970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);1971      }19721973      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];19741975      if (rawComment.Length > 0) {1976        baseStream_.Write(rawComment, 0, rawComment.Length);  1977      }1978      else {1979        ed.Delete(1);1980      }19811982      entry.ExtraData = ed.GetEntryData();19831984      WriteLEShort(name.Length);1985      WriteLEShort(entry.ExtraData.Length);19861987      if ( name.Length > 0 ) {1988        baseStream_.Write(name, 0, name.Length);1989      }19901991      if ( entry.LocalHeaderRequiresZip64 ) {1992        if ( !ed.Find(1) ) {1993          throw new ZipException("Internal error cannot find extra data");1994        }19951996        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1997      }19981999      if ( entry.ExtraData.Length > 0 ) {2000        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);2001      }2002    }20032004    int WriteCentralDirectoryHeader(ZipEntry entry)2005    {2006      if ( entry.CompressedSize < 0 ) {2007        throw new ZipException("Attempt to write central directory entry with unknown csize");2008      }20092010      if ( entry.Size < 0 ) {2011        throw new ZipException("Attempt to write central directory entry with unknown size");2012      }20132014      if ( entry.Crc < 0 ) {2015        throw new ZipException("Attempt to write central directory entry with unknown crc");2016      }20172018      // Write the central file header2019      WriteLEInt(ZipConstants.CentralHeaderSignature);20202021      // Version made by2022      WriteLEShort(ZipConstants.VersionMadeBy);20232024      // Version required to extract2025      WriteLEShort(entry.Version);19781979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;1980    }1981    #endregion19821983    void PostUpdateCleanup()1984    {1985      updateDataSource_ = null;1986      updates_ = null;1987      updateIndex_ = null;19881989      if (archiveStorage_ != null) {1990        archiveStorage_.Dispose();1991        archiveStorage_ = null;1992      }1993    }19941995    string GetTransformedFileName(string name)1996    {1997      INameTransform transform = NameTransform;1998      return (transform != null) ?1999        transform.TransformFile(name) :2000        name;2001    }20022003    string GetTransformedDirectoryName(string name)2004    {2005      INameTransform transform = NameTransform;2006      return (transform != null) ?2007        transform.TransformDirectory(name) :2008        name;2009    }20102011    /// <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    }20222023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2024    {2025      int bytesToCopy = GetDescriptorSize(update);  20262027      WriteLEShort(entry.Flags);20282029      unchecked {2030        WriteLEShort((byte)entry.CompressionMethod);2031        WriteLEInt((int)entry.DosTime);2032        WriteLEInt((int)entry.Crc);2033      }20342035      if ( (entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff) ) {2036        WriteLEInt(-1);2037      }2038      else {2039        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));2040      }20412042      if ( (entry.IsZip64Forced()) || (entry.Size >= 0xffffffff) ) {2043        WriteLEInt(-1);2044      }2045      else {2046        WriteLEInt((int)entry.Size);2047      }20482049      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);2027      if (bytesToCopy > 0) {2028        byte[] buffer = GetBuffer();20292030        while (bytesToCopy > 0) {2031          int readSize = Math.Min(buffer.Length, bytesToCopy);20322033          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    }20432044    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      }  20502051      if ( name.Length > 0xFFFF ) {2052        throw new ZipException("Entry name is too long.");2053      }2051      // NOTE: Compressed size is updated elsewhere.2052      var crc = new Crc32();2053      byte[] buffer = GetBuffer();  20542055      WriteLEShort(name.Length);20562057      // Central header extra data is different to local header version so regenerate.2058      var ed = new ZipExtraData(entry.ExtraData);20592060      if ( entry.CentralHeaderRequiresZip64 ) {2061        ed.StartNewEntry();20622063        if ( (entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On) )2064        {2065          ed.AddLeLong(entry.Size);2066        }20672068        if ( (entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On) )2069        {2070          ed.AddLeLong(entry.CompressedSize);2071        }20722073        if ( entry.Offset >= 0xffffffff ) {2074          ed.AddLeLong(entry.Offset);2075        }20762077        // Number of disk on which this file starts isnt supported and is never written here.2078        ed.AddNewEntry(1);2079      }2080      else {2081        // Should have already be done when local header was added.2082        ed.Delete(1);2083      }20842085      byte[] centralExtraData = ed.GetEntryData();2055      long targetBytes = bytesToCopy;2056      long totalBytesRead = 0;20572058      int bytesRead;2059      do {2060        int readSize = buffer.Length;20612062        if (bytesToCopy < readSize) {2063          readSize = (int)bytesToCopy;2064        }20652066        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));20772078      if (totalBytesRead != targetBytes) {2079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2080      }20812082      if (updateCrc) {2083        update.OutEntry.Crc = crc.Value;2084      }2085    }  20862087      WriteLEShort(centralExtraData.Length);2088      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);20892090      WriteLEShort(0);  // disk number2091      WriteLEShort(0);  // internal file attributes20922093      // External file attributes...2094      if ( entry.ExternalFileAttributes != -1 ) {2095        WriteLEInt(entry.ExternalFileAttributes);2096      }2097      else {2098        if ( entry.IsDirectory ) {2099          WriteLEUint(16);2100        }2101        else {2102          WriteLEUint(0);2103        }2104      }21052106      if ( entry.Offset >= 0xffffffff ) {2107        WriteLEUint(0xffffffff);2108      }2109      else {2110        WriteLEUint((uint)(int)entry.Offset);2111      }21122113      if ( name.Length > 0 ) {2114        baseStream_.Write(name, 0, name.Length);2115      }21162117      if ( centralExtraData.Length > 0 ) {2118        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);2119      }21202121      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];21222123      if ( rawComment.Length > 0 ) {2124        baseStream_.Write(rawComment, 0, rawComment.Length);2125      }21262127      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;2128    }2129    #endregion21302131    void PostUpdateCleanup()2132    {2133            updateDataSource_ = null;2134            updates_ = null;2135            updateIndex_ = null;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    }21032104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2105    {2106      int bytesToCopy = GetDescriptorSize(update);21072108      while (bytesToCopy > 0) {2109        var readSize = (int)bytesToCopy;2110        byte[] buffer = GetBuffer();21112112        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    }21252126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2127    {2128      long bytesToCopy = update.Entry.CompressedSize;21292130      // NOTE: Compressed size is updated elsewhere.2131      var crc = new Crc32();2132      byte[] buffer = GetBuffer();21332134      long targetBytes = bytesToCopy;2135      long totalBytesRead = 0;  21362137            if (archiveStorage_ != null)2138            {2139        archiveStorage_.Dispose();2140        archiveStorage_=null;2141      }2142    }21432144    string GetTransformedFileName(string name)2145    {2146            INameTransform transform = NameTransform;2147      return (transform != null) ?2148        transform.TransformFile(name) :2149        name;2150    }21512152    string GetTransformedDirectoryName(string name)2153    {2154            INameTransform transform = NameTransform;2155            return (transform != null) ?2156        transform.TransformDirectory(name) :2157        name;2158    }21592160    /// <summary>2161    /// Get a raw memory buffer.2162    /// </summary>2163    /// <returns>Returns a raw memory buffer.</returns>2164    byte[] GetBuffer()2165    {2166      if ( copyBuffer_ == null ) {2167        copyBuffer_ = new byte[bufferSize_];2137      int bytesRead;2138      do {2139        int readSize = buffer.Length;21402141        if (bytesToCopy < readSize) {2142          readSize = (int)bytesToCopy;2143        }21442145        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);21532154          destinationPosition += bytesRead;2155          sourcePosition += bytesRead;2156          bytesToCopy -= bytesRead;2157          totalBytesRead += bytesRead;2158        }2159      }2160      while ((bytesRead > 0) && (bytesToCopy > 0));21612162      if (totalBytesRead != targetBytes) {2163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2164      }21652166      if (updateCrc) {2167        update.OutEntry.Crc = crc.Value;  2168      }2169      return copyBuffer_;2170    }21712172    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2173    {2174      int bytesToCopy = GetDescriptorSize(update);2169    }21702171    int FindExistingUpdate(ZipEntry entry)2172    {2173      int result = -1;2174      string convertedName = GetTransformedFileName(entry.Name);  21752176      if ( bytesToCopy > 0 ) {2177        byte[] buffer = GetBuffer();21782179        while ( bytesToCopy > 0 ) {2180          int readSize = Math.Min(buffer.Length, bytesToCopy);21812182          int bytesRead = source.Read(buffer, 0, readSize);2183          if ( bytesRead > 0 ) {2184            dest.Write(buffer, 0, bytesRead);2185            bytesToCopy -= bytesRead;2186          }2187          else {2188            throw new ZipException("Unxpected end of stream");2189          }2190        }2191      }2192    }21932194    void CopyBytes(ZipUpdate update, Stream destination, Stream source,2195      long bytesToCopy, bool updateCrc)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 useful2181            // 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    }21942195    int FindExistingUpdate(string fileName)  2196    {2197      if ( destination == source ) {2198        throw new InvalidOperationException("Destination and source are the same");2199      }2197      int result = -1;21982199      string convertedName = GetTransformedFileName(fileName);  22002201      // NOTE: Compressed size is updated elsewhere.2202      var crc = new Crc32();2203      byte[] buffer = GetBuffer();2201      if (updateIndex_.ContainsKey(convertedName)) {2202        result = (int)updateIndex_[convertedName];2203      }  22042205      long targetBytes = bytesToCopy;2206      long totalBytesRead = 0;22072208      int bytesRead;2209      do {2210        int readSize = buffer.Length;22112212        if ( bytesToCopy < readSize ) {2213          readSize = (int)bytesToCopy;2214        }22152216        bytesRead = source.Read(buffer, 0, readSize);2217        if ( bytesRead > 0 ) {2218          if ( updateCrc ) {2219            crc.Update(buffer, 0, bytesRead);2220          }2221          destination.Write(buffer, 0, bytesRead);2222          bytesToCopy -= bytesRead;2223          totalBytesRead += bytesRead;2224        }2225      }2226      while ( (bytesRead > 0) && (bytesToCopy > 0) );22272228      if ( totalBytesRead != targetBytes ) {2229        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2230      }22312232      if ( updateCrc ) {2233        update.OutEntry.Crc = crc.Value;2234      }2235    }22362237    /// <summary>2238    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.2239    /// </summary>2240    /// <param name="update">The update to get the size for.</param>2241    /// <returns>The descriptor size, zero if there isnt one.</returns>2242    int GetDescriptorSize(ZipUpdate update)2243    {2244      int result = 0;2245      if ( (update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {2246        result = ZipConstants.DataDescriptorSize - 4;2247        if ( update.Entry.LocalHeaderRequiresZip64 ) {2248          result = ZipConstants.Zip64DataDescriptorSize - 4;2249        }2250      }2251      return result;2252    }2205      /*2206            // This is slow like the coming of the next ice age but takes less storage and may be useful2207            // 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       */22162217      return result;2218    }22192220    /// <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_;22282229      if (entry.IsCrypted == true) {2230        result = CreateAndInitEncryptionStream(result, entry);2231      }22322233      switch (entry.CompressionMethod) {2234        case CompressionMethod.Stored:2235          result = new UncompressedStream(result);2236          break;22372238        case CompressionMethod.Deflated:2239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));2240          dos.IsStreamOwner = false;2241          result = dos;2242          break;22432244        default:2245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2246      }2247      return result;2248    }22492250    void AddEntry(ZipFile workFile, ZipUpdate update)2251    {2252      Stream source = null;  22532254    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2255    {2256      int bytesToCopy = GetDescriptorSize(update);22572258      while ( bytesToCopy > 0 ) {2259        var readSize = (int)bytesToCopy;2260        byte[] buffer = GetBuffer();2254      if (update.Entry.IsFile) {2255        source = update.GetSource();22562257        if (source == null) {2258          source = updateDataSource_.GetSource(update.Entry, update.Filename);2259        }2260      }  22612262        stream.Position = sourcePosition;2263        int bytesRead = stream.Read(buffer, 0, readSize);2264        if ( bytesRead > 0 ) {2265          stream.Position = destinationPosition;2266          stream.Write(buffer, 0, bytesRead);2267          bytesToCopy -= bytesRead;2268          destinationPosition += bytesRead;2269          sourcePosition += bytesRead;2270        }2271        else {2272          throw new ZipException("Unxpected end of stream");2273        }2274      }2275    }22762277    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2278    {2279      long bytesToCopy = update.Entry.CompressedSize;22802281      // NOTE: Compressed size is updated elsewhere.2282      var crc = new Crc32();2283      byte[] buffer = GetBuffer();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          }22732274          workFile.WriteLocalEntryHeader(update);22752276          long dataStart = workFile.baseStream_.Position;22772278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {2279            CopyBytes(update, output, source, sourceStreamLength, true);2280          }22812282          long dataEnd = workFile.baseStream_.Position;2283          update.OutEntry.CompressedSize = dataEnd - dataStart;  22842285      long targetBytes = bytesToCopy;2286      long totalBytesRead = 0;22872288      int bytesRead;2289      do2290      {2291        int readSize = buffer.Length;22922293        if ( bytesToCopy < readSize ) {2294          readSize = (int)bytesToCopy;2295        }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      }22942295    }  22962297        stream.Position = sourcePosition;2298        bytesRead = stream.Read(buffer, 0, readSize);2299        if ( bytesRead > 0 ) {2300          if ( updateCrc ) {2301            crc.Update(buffer, 0, bytesRead);2302          }2303          stream.Position = destinationPosition;2304          stream.Write(buffer, 0, bytesRead);23052306          destinationPosition += bytesRead;2307          sourcePosition += bytesRead;2308          bytesToCopy -= bytesRead;2309          totalBytesRead += bytesRead;2310        }2311      }2312      while ( (bytesRead > 0) && (bytesToCopy > 0) );23132314      if ( totalBytesRead != targetBytes ) {2315        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2316      }23172318      if ( updateCrc ) {2319        update.OutEntry.Crc = crc.Value;2320      }2321    }23222323    int FindExistingUpdate(ZipEntry entry)2324    {2325      int result = -1;2326      string convertedName = GetTransformedFileName(entry.Name);23272328      if (updateIndex_.ContainsKey(convertedName)) {2329        result = (int)updateIndex_[convertedName];2330      }2331/*2332      // This is slow like the coming of the next ice age but takes less storage and may be useful2333      // for CF?2334      for (int index = 0; index < updates_.Count; ++index)2335      {2336        ZipUpdate zu = ( ZipUpdate )updates_[index];2337        if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&2338          (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {2339          result = index;2340          break;2341        }2342      }2343 */2344      return result;2345    }23462347    int FindExistingUpdate(string fileName)2348    {2349      int result = -1;23502351      string convertedName = GetTransformedFileName(fileName);23522353      if (updateIndex_.ContainsKey(convertedName)) {2354        result = (int)updateIndex_[convertedName];2355      }23562357/*2358      // This is slow like the coming of the next ice age but takes less storage and may be useful2359      // for CF?2360      for ( int index = 0; index < updates_.Count; ++index ) {2361        if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,2362          true, CultureInfo.InvariantCulture) == 0 ) {2363          result = index;2364          break;2365        }2366      }2367 */23682369      return result;2370    }23712372    /// <summary>2373    /// Get an output stream for the specified <see cref="ZipEntry"/>2374    /// </summary>2375    /// <param name="entry">The entry to get an output stream for.</param>2376    /// <returns>The output stream obtained for the entry.</returns>2377    Stream GetOutputStream(ZipEntry entry)2378    {2379      Stream result = baseStream_;2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)2298    {2299      workFile.WriteLocalEntryHeader(update);2300      long dataStart = workFile.baseStream_.Position;23012302      // 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      }23102311      long dataEnd = workFile.baseStream_.Position;2312      update.Entry.CompressedSize = dataEnd - dataStart;2313    }23142315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2316    {2317      bool skipOver = false || update.Entry.Offset == destinationPosition;23182319      if (!skipOver) {2320        baseStream_.Position = destinationPosition;2321        workFile.WriteLocalEntryHeader(update);2322        destinationPosition = baseStream_.Position;2323      }23242325      long sourcePosition = 0;23262327      const int NameLengthOffset = 26;23282329      // TODO: Add base for SFX friendly handling2330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;23312332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23332334      // 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();23382339      sourcePosition = baseStream_.Position + nameLength + extraLength;23402341      if (skipOver) {2342        if (update.OffsetBasedSize != -1)2343          destinationPosition += update.OffsetBasedSize;2344        else2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2346          // WinZip produces a warning on these entries:2347          // "caution: value of lrec.csize (compressed size) changed from ..."2348          destinationPosition +=2349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size2350            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    }23582359    void CopyEntry(ZipFile workFile, ZipUpdate update)2360    {2361      workFile.WriteLocalEntryHeader(update);23622363      if (update.Entry.CompressedSize > 0) {2364        const int NameLengthOffset = 26;23652366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;23672368        // TODO: This wont work for SFX files!2369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23702371        uint nameLength = ReadLEUshort();2372        uint extraLength = ReadLEUshort();23732374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);23752376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2377      }2378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);2379    }  23802381      if ( entry.IsCrypted == true ) {2382#if NETCF_1_02383        throw new ZipException("Encryption not supported for Compact Framework 1.0");2384#else2385        result = CreateAndInitEncryptionStream(result, entry);2386#endif2387      }23882389      switch ( entry.CompressionMethod ) {2390        case CompressionMethod.Stored:2391          result = new UncompressedStream(result);2392          break;23932394        case CompressionMethod.Deflated:2395          var dos = new DeflaterOutputStream(result, new Deflater(9, true));2396          dos.IsStreamOwner = false;2397          result = dos;2398          break;23992400        default:2401          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2402      }2403      return result;2404    }24052406    void AddEntry(ZipFile workFile, ZipUpdate update)2407    {2408      Stream source = null;24092410      if ( update.Entry.IsFile ) {2411        source = update.GetSource();24122413        if ( source == null ) {2414          source = updateDataSource_.GetSource(update.Entry, update.Filename);2415        }2416      }24172418      if ( source != null ) {2419        using ( source ) {2420          long sourceStreamLength = source.Length;2421          if ( update.OutEntry.Size < 0 ) {2422            update.OutEntry.Size = sourceStreamLength;2423          }2424          else {2425            // Check for errant entries.2426            if ( update.OutEntry.Size != sourceStreamLength ) {2427              throw new ZipException("Entry size/stream size mismatch");2428            }2429          }24302431          workFile.WriteLocalEntryHeader(update);24322433          long dataStart = workFile.baseStream_.Position;24342435          using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {2436            CopyBytes(update, output, source, sourceStreamLength, true);2437          }24382439          long dataEnd = workFile.baseStream_.Position;2440          update.OutEntry.CompressedSize = dataEnd - dataStart;24412442          if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor)2443          {2444            var helper = new ZipHelperStream(workFile.baseStream_);2445            helper.WriteDataDescriptor(update.OutEntry);2446          }2447        }2381    void Reopen(Stream source)2382    {2383      if (source == null) {2384        throw new ZipException("Failed to reopen archive - no source");2385      }23862387      isNewArchive_ = false;2388      baseStream_ = source;2389      ReadEntries();2390    }23912392    void Reopen()2393    {2394      if (Name == null) {2395        throw new InvalidOperationException("Name is not known cannot Reopen");2396      }23972398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));2399    }24002401    void UpdateCommentOnly()2402    {2403      long baseLength = baseStream_.Length;24042405      ZipHelperStream updateFile = null;24062407      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {2408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);2409        updateFile = new ZipHelperStream(copyStream);2410        updateFile.IsStreamOwner = true;24112412        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 doesnt2418          // 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.24212422          // 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      }24312432      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        }24392440        const int CentralHeaderCommentSizeOffset = 16;2441        updateFile.Position += CentralHeaderCommentSizeOffset;24422443        byte[] rawComment = newComment_.RawComment;24442445        updateFile.WriteLEShort(rawComment.Length);2446        updateFile.Write(rawComment, 0, rawComment.Length);2447        updateFile.SetLength(updateFile.Position);  2448      }2449      else {2450        workFile.WriteLocalEntryHeader(update);2451        update.OutEntry.CompressedSize = 0;2452      }24532454    }24552456    void ModifyEntry(ZipFile workFile, ZipUpdate update)2457    {2458      workFile.WriteLocalEntryHeader(update);2459      long dataStart = workFile.baseStream_.Position;24602461      // TODO: This is slow if the changes don't effect the data!!2462      if ( update.Entry.IsFile && (update.Filename != null) ) {2463        using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {2464          using ( Stream source = this.GetInputStream(update.Entry) ) {2465            CopyBytes(update, output, source, source.Length, true);2466          }2467        }2468      }24692470      long dataEnd = workFile.baseStream_.Position;2471      update.Entry.CompressedSize = dataEnd - dataStart;2472    }24732474    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2475    {2476      bool skipOver = false || update.Entry.Offset == destinationPosition;24492450      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {2451        Reopen(archiveStorage_.ConvertTemporaryToFinal());2452      } else {2453        ReadEntries();2454      }2455    }24562457    /// <summary>2458    /// Class used to sort updates.2459    /// </summary>2460    class UpdateComparer : IComparer2461    {2462      /// <summary>2463      /// Compares two objects and returns a value indicating whether one is2464      /// 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;24752476        int result;  24772478      if ( !skipOver ) {2479        baseStream_.Position = destinationPosition;2480        workFile.WriteLocalEntryHeader(update);2481        destinationPosition = baseStream_.Position;2482      }24832484      long sourcePosition = 0;24852486      const int NameLengthOffset = 26;24872488      // TODO: Add base for SFX friendly handling2489      long entryDataOffset = update.Entry.Offset + NameLengthOffset;24902491      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);24922493      // Clumsy way of handling retrieving the original name and extra data length for now.2494      // TODO: Stop re-reading name and data length in CopyEntryDirect.2495      uint nameLength = ReadLEUshort();2496      uint extraLength = ReadLEUshort();24972498      sourcePosition = baseStream_.Position + nameLength + extraLength;24992500      if (skipOver) {2501        if (update.OffsetBasedSize != -1)2502          destinationPosition += update.OffsetBasedSize;2503        else2504          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2505          // WinZip produces a warning on these entries:2506          // "caution: value of lrec.csize (compressed size) changed from ..."2507          destinationPosition +=2508            (sourcePosition - entryDataOffset) + NameLengthOffset +  // Header size2509            update.Entry.CompressedSize + GetDescriptorSize(update);2510      }2511      else {2512        if ( update.Entry.CompressedSize > 0 ) {2513          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition );2514        }2515        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);2516      }2517    }25182519    void CopyEntry(ZipFile workFile, ZipUpdate update)2520    {2521      workFile.WriteLocalEntryHeader(update);25222523      if ( update.Entry.CompressedSize > 0 ) {2524        const int NameLengthOffset = 26;25252526        long entryDataOffset = update.Entry.Offset + NameLengthOffset;25272528        // TODO: This wont work for SFX files!2529        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);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;24892490          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    }25052506    void RunUpdates()2507    {2508      long sizeEntries = 0;2509      long endOfStream = 0;2510      bool directUpdate = false;2511      long destinationPosition = 0; // NOT SFX friendly25122513      ZipFile workFile;25142515      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;25232524        // 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;  25302531        uint nameLength = ReadLEUshort();2532        uint extraLength = ReadLEUshort();25332534        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);2531        if (key != null) {2532          workFile.key = (byte[])key.Clone();2533        }2534      }  25352536        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2537      }2538      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);2539    }25402541    void Reopen(Stream source)2542    {2543      if ( source == null ) {2544        throw new ZipException("Failed to reopen archive - no source");2545      }25462547      isNewArchive_ = false;2548      baseStream_ = source;2549      ReadEntries();2550    }25512552    void Reopen()2553    {2554      if (Name == null) {2555        throw new InvalidOperationException("Name is not known cannot Reopen");2556      }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;25472548              case UpdateCommand.Modify:2549                // TODO: Direct modifying of an entry will take some legwork.2550                ModifyEntry(workFile, update);2551                break;25522553              case UpdateCommand.Add:2554                if (!IsNewArchive && directUpdate) {2555                  workFile.baseStream_.Position = destinationPosition;2556                }  25572558      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));2559    }25602561    void UpdateCommentOnly()2562    {2563      long baseLength = baseStream_.Length;25642565      ZipHelperStream updateFile = null;25662567      if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {2568        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);2569        updateFile = new ZipHelperStream(copyStream);2570        updateFile.IsStreamOwner = true;2558                AddEntry(workFile, update);25592560                if (directUpdate) {2561                  destinationPosition = workFile.baseStream_.Position;2562                }2563                break;2564            }2565          }2566        }25672568        if (!IsNewArchive && directUpdate) {2569          workFile.baseStream_.Position = destinationPosition;2570        }  25712572        baseStream_.Close();2573        baseStream_ = null;2574      }2575      else {2576        if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {2577          // TODO: archiveStorage wasnt originally intended for this use.2578          // Need to revisit this to tidy up handling as archive storage currently doesnt2579          // handle the original stream well.2580          // The problem is when using an existing zip archive with an in memory archive storage.2581          // The open stream wont support writing but the memory storage should open the same file not an in memory one.25822583          // Need to tidy up the archive storage interface and contract basically.2584          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);2585          updateFile = new ZipHelperStream(baseStream_);2586        }2587        else {2588          baseStream_.Close();2589          baseStream_ = null;2590          updateFile = new ZipHelperStream(Name);2591        }2592      }25932594      using ( updateFile ) {2595        long locatedCentralDirOffset =2596          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,2597                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);2598        if ( locatedCentralDirOffset < 0 ) {2599          throw new ZipException("Cannot find central directory");2600        }26012602        const int CentralHeaderCommentSizeOffset = 16;2603        updateFile.Position += CentralHeaderCommentSizeOffset;26042605        byte[] rawComment = newComment_.RawComment;26062607        updateFile.WriteLEShort(rawComment.Length);2608        updateFile.Write(rawComment, 0, rawComment.Length);2609        updateFile.SetLength(updateFile.Position);2610      }26112612      if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {2613        Reopen(archiveStorage_.ConvertTemporaryToFinal());2614      }2615      else {2616        ReadEntries();2617      }2618    }26192620    /// <summary>2621    /// Class used to sort updates.2622    /// </summary>2623    class UpdateComparer : IComparer2624    {2625      /// <summary>2626      /// Compares two objects and returns a value indicating whether one is2627      /// less than, equal to or greater than the other.2628      /// </summary>2629      /// <param name="x">First object to compare</param>2630      /// <param name="y">Second object to compare.</param>2631      /// <returns>Compare result.</returns>2632      public int Compare(2633        object x,2634        object y)2635      {2636        var zx = x as ZipUpdate;2637        var zy = y as ZipUpdate;26382639        int result;26402641        if (zx == null) {2642          if (zy == null) {2643            result = 0;2644          }2645          else {2646            result = -1;2647          }2648        }2649        else if (zy == null) {2650          result = 1;2651        }2652        else {2653          int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;2654          int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;26552656          result = xCmdValue - yCmdValue;2657          if (result == 0) {2658            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;2659            if (offsetDiff < 0) {2660              result = -1;2661            }2662            else if (offsetDiff == 0) {2663              result = 0;2664            }2665            else {2666              result = 1;2667            }2668          }2669        }2670        return result;2671      }2672    }26732674    void RunUpdates()2675    {2676      long sizeEntries = 0;2677      long endOfStream = 0;2678      bool directUpdate = false;2679      long destinationPosition = 0; // NOT SFX friendly26802681      ZipFile workFile;2572        long centralDirOffset = workFile.baseStream_.Position;25732574        foreach (ZipUpdate update in updates_) {2575          if (update != null) {2576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2577          }2578        }25792580        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        }25842585        endOfStream = workFile.baseStream_.Position;25862587        // 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            }25962597            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      }26162617      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    }26272628    void CheckUpdating()2629    {2630      if (updates_ == null) {2631        throw new InvalidOperationException("BeginUpdate has not been called");2632      }2633    }26342635    #endregion26362637    #region ZipUpdate class2638    /// <summary>2639    /// Represents a pending update to a Zip file.2640    /// </summary>2641    class ZipUpdate2642    {2643      #region Constructors2644      public ZipUpdate(string fileName, ZipEntry entry)2645      {2646        command_ = UpdateCommand.Add;2647        entry_ = entry;2648        filename_ = fileName;2649      }26502651      [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      }26592660      [Obsolete]2661      public ZipUpdate(string fileName, string entryName)2662        : this(fileName, entryName, CompressionMethod.Deflated)2663      {2664        // Do nothing.2665      }26662667      [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      }26752676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2677      {2678        command_ = UpdateCommand.Add;2679        entry_ = entry;2680        dataSource_ = dataSource;2681      }  26822683      if ( IsNewArchive ) {2684        workFile = this;2685        workFile.baseStream_.Position = 0;2686        directUpdate = true;2687      }2688      else if ( archiveStorage_.UpdateMode == FileUpdateMode.Direct ) {2689        workFile = this;2690        workFile.baseStream_.Position = 0;2691        directUpdate = true;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      }  26922693        // Sort the updates by offset within copies/modifies, then adds.2694        // This ensures that data required by copies will not be overwritten.2695        updates_.Sort(new UpdateComparer());2696      }2697      else {2698        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());2699        workFile.UseZip64 = UseZip64;27002701        if (key != null) {2702          workFile.key = (byte[])key.Clone();2703        }2704      }27052706      try {2707        foreach ( ZipUpdate update in updates_ ) {2708          if (update != null) {2709            switch (update.Command) {2710              case UpdateCommand.Copy:2711                if (directUpdate) {2712                  CopyEntryDirect(workFile, update, ref destinationPosition);2713                }2714                else {2715                  CopyEntry(workFile, update);2716                }2717                break;2693      public ZipUpdate(UpdateCommand command, ZipEntry entry)2694      {2695        command_ = command;2696        entry_ = (ZipEntry)entry.Clone();2697      }269826992700      /// <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      #endregion27102711      /// <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      }  27182719              case UpdateCommand.Modify:2720                // TODO: Direct modifying of an entry will take some legwork.2721                ModifyEntry(workFile, update);2722                break;27232724              case UpdateCommand.Add:2725                if (!IsNewArchive && directUpdate) {2726                  workFile.baseStream_.Position = destinationPosition;2727                }27282729                AddEntry(workFile, update);27302731                if (directUpdate) {2732                  destinationPosition = workFile.baseStream_.Position;2733                }2734                break;2735            }2736          }2737        }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          }27272728          return outEntry_;2729        }2730      }27312732      /// <summary>2733      /// Get the command for this update.2734      /// </summary>2735      public UpdateCommand Command {2736        get { return command_; }2737      }  27382739        if ( !IsNewArchive && directUpdate ) {2740          workFile.baseStream_.Position = destinationPosition;2741        }27422743        long centralDirOffset = workFile.baseStream_.Position;27442745        foreach ( ZipUpdate update in updates_ ) {2746          if (update != null) {2747            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2748          }2749        }27502751        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);2752        using ( ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_) ) {2753          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);2754        }27552756        endOfStream = workFile.baseStream_.Position;27572758        // And now patch entries...2759        foreach ( ZipUpdate update in updates_ ) {2760          if (update != null)2761          {2762            // If the size of the entry is zero leave the crc as 0 as well.2763            // The calculated crc will be all bits on...2764            if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {2765              workFile.baseStream_.Position = update.CrcPatchOffset;2766              workFile.WriteLEInt((int)update.OutEntry.Crc);2767            }27682769            if (update.SizePatchOffset > 0) {2770              workFile.baseStream_.Position = update.SizePatchOffset;2771              if (update.OutEntry.LocalHeaderRequiresZip64) {2772                workFile.WriteLeLong(update.OutEntry.Size);2773                workFile.WriteLeLong(update.OutEntry.CompressedSize);2774              }2775              else {2776                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);2777                workFile.WriteLEInt((int)update.OutEntry.Size);2778              }2779            }2780          }2781        }2782      }2783      catch {2784        workFile.Close();2785        if (!directUpdate && (workFile.Name != null)) {2786          File.Delete(workFile.Name);2787        }2788        throw;2789      }27902791      if (directUpdate) {2792        workFile.baseStream_.SetLength(endOfStream);2793        workFile.baseStream_.Flush();2794        isNewArchive_ = false;2795        ReadEntries();2796      }2797      else {2798        baseStream_.Close();2799        Reopen(archiveStorage_.ConvertTemporaryToFinal());2800      }2801    }28022803    void CheckUpdating()2804    {2805      if ( updates_ == null ) {2806        throw new InvalidOperationException("BeginUpdate has not been called");2807      }2808    }28092810    #endregion28112812    #region ZipUpdate class2813    /// <summary>2814    /// Represents a pending update to a Zip file.2815    /// </summary>2816    class ZipUpdate2817    {2818      #region Constructors2819      public ZipUpdate(string fileName, ZipEntry entry)2820      {2821        command_ = UpdateCommand.Add;2822        entry_ = entry;2823        filename_ = fileName;2824      }28252826      [Obsolete]2827      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)2828      {2829        command_ = UpdateCommand.Add;2830        entry_ = new ZipEntry(entryName);2831        entry_.CompressionMethod = compressionMethod;2832        filename_ = fileName;2833      }28342835      [Obsolete]2836      public ZipUpdate(string fileName, string entryName)2837        : this(fileName, entryName, CompressionMethod.Deflated)2838      {2839        // Do nothing.2840      }28412842      [Obsolete]2843      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)2844      {2845        command_ = UpdateCommand.Add;2846        entry_ = new ZipEntry(entryName);2847        entry_.CompressionMethod = compressionMethod;2848        dataSource_ = dataSource;2849      }28502851      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2852      {2853        command_ = UpdateCommand.Add;2854        entry_ = entry;2855        dataSource_ = dataSource;2856      }28572858      public ZipUpdate(ZipEntry original, ZipEntry updated)2859      {2860        throw new ZipException("Modify not currently supported");2861      /*2862        command_ = UpdateCommand.Modify;2863        entry_ = ( ZipEntry )original.Clone();2864        outEntry_ = ( ZipEntry )updated.Clone();2865      */2866      }28672868      public ZipUpdate(UpdateCommand command, ZipEntry entry)2869      {2870        command_ = command;2871        entry_ = ( ZipEntry )entry.Clone();2872      }28732739      /// <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      }27452746      /// <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      }27532754      /// <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      }27612762      /// <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      }27702771      public Stream GetSource()2772      {2773        Stream result = null;2774        if (dataSource_ != null) {2775          result = dataSource_.GetSource();2776        }27772778        return result;2779      }27802781      #region Instance Fields2782      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      #endregion2791    }27922793    #endregion2794    #endregion27952796    #region Disposing27972798    #region IDisposable Members2799    void IDisposable.Dispose()2800    {2801      Close();2802    }2803    #endregion28042805    void DisposeInternal(bool disposing)2806    {2807      if (!isDisposed_) {2808        isDisposed_ = true;2809        entries_ = new ZipEntry[0];28102811        if (IsStreamOwner && (baseStream_ != null)) {2812          lock (baseStream_) {2813            baseStream_.Close();2814          }2815        }28162817        PostUpdateCleanup();2818      }2819    }28202821    /// <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    }28302831    #endregion28322833    #region Internal routines2834    #region Reading2835    /// <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 prematurely2841    /// </exception>2842    ushort ReadLEUshort()2843    {2844      int data1 = baseStream_.ReadByte();28452846      if (data1 < 0) {2847        throw new EndOfStreamException("End of stream");2848      }28492850      int data2 = baseStream_.ReadByte();28512852      if (data2 < 0) {2853        throw new EndOfStreamException("End of stream");2854      }285528562857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));2858    }28592860    /// <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 prematurely2869    /// </exception>2870    uint ReadLEUint()2871    {2872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));2873    }  28742875      /// <summary>2876      /// Copy an existing entry.2877      /// </summary>2878      /// <param name="entry">The existing entry to copy.</param>2879      public ZipUpdate(ZipEntry entry)2880        : this(UpdateCommand.Copy, entry)2881      {2882        // Do nothing.2883      }2884      #endregion28852886      /// <summary>2887      /// Get the <see cref="ZipEntry"/> for this update.2888      /// </summary>2889      /// <remarks>This is the source or original entry.</remarks>2890      public ZipEntry Entry2891      {2892        get { return entry_; }2893      }28942895      /// <summary>2896      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.2897      /// </summary>2898      public ZipEntry OutEntry2899      {2900        get {2901          if ( outEntry_ == null ) {2902            outEntry_ = (ZipEntry)entry_.Clone();2903          }29042905          return outEntry_;2906        }2907      }2875    ulong ReadLEUlong()2876    {2877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);2878    }28792880    #endregion2881    // 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    }28882889    /// <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 found2897    /// </exception>2898    void ReadEntries()2899    {2900      // Search for the End Of Central Directory.  When a zip comment is2901      // present the directory will start earlier2902      //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 files2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then2906      // this could be invalid.2907      // Could also speed this up by reading memory in larger blocks.  29082909      /// <summary>2910      /// Get the command for this update.2911      /// </summary>2912      public UpdateCommand Command2913      {2914        get { return command_; }2915      }29162917      /// <summary>2918      /// Get the filename if any for this update.  Null if none exists.2919      /// </summary>2920      public string Filename2921      {2922        get { return filename_; }2923      }29242925      /// <summary>2926      /// Get/set the location of the size patch for this update.2927      /// </summary>2928      public long SizePatchOffset2929      {2930        get { return sizePatchOffset_; }2931        set { sizePatchOffset_ = value; }2932      }29332934      /// <summary>2935      /// Get /set the location of the crc patch for this update.2936      /// </summary>2937      public long CrcPatchOffset2938      {2939        get { return crcPatchOffset_; }2940        set { crcPatchOffset_ = value; }2941      }29422943      /// <summary>2944      /// Get/set the size calculated by offset.2945      /// Specifically, the difference between this and next entry's starting offset.2946      /// </summary>2947      public long OffsetBasedSize2948      {2949        get { return _offsetBasedSize; }2950        set { _offsetBasedSize = value; }2951      }29522953      public Stream GetSource()2954      {2955        Stream result = null;2956        if ( dataSource_ != null ) {2957          result = dataSource_.GetSource();2958        }29592960        return result;2961      }29622963      #region Instance Fields2964      ZipEntry entry_;2965      ZipEntry outEntry_;2966      UpdateCommand command_;2967      IStaticDataSource dataSource_;2968      string filename_;2969      long sizePatchOffset_ = -1;2970      long crcPatchOffset_ = -1;2971      long _offsetBasedSize = -1;2972      #endregion2973    }29742975    #endregion2976    #endregion29772978    #region Disposing29792980    #region IDisposable Members2981    void IDisposable.Dispose()2982    {2983      Close();2984    }2985    #endregion29862987    void DisposeInternal(bool disposing)2988    {2989      if ( !isDisposed_ ) {2990        isDisposed_ = true;2991        entries_ = new ZipEntry[0];29922993        if ( IsStreamOwner && (baseStream_ != null) ) {2994          lock(baseStream_) {2995            baseStream_.Close();2996          }2997        }2909      if (baseStream_.CanSeek == false) {2910        throw new ZipException("ZipFile stream must be seekable");2911      }29122913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,2914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);29152916      if (locatedEndOfCentralDir < 0) {2917        throw new ZipException("Cannot find central directory");2918      }29192920      // Read end of central directory record2921      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();29282929      if (commentSize > 0) {2930        byte[] comment = new byte[commentSize];29312932        StreamUtils.ReadFully(baseStream_, comment);2933        comment_ = ZipConstants.ConvertToString(comment);2934      } else {2935        comment_ = string.Empty;2936      }29372938      bool isZip64 = false;29392940      // 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;29482949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 2950        if (offset < 0) {2951          throw new ZipException("Cannot find Zip64 locator");2952        }29532954        // number of the disk with the start of the zip64 end of central directory 4 bytes2955        // relative offset of the zip64 end of central directory record 8 bytes2956        // total number of disks 4 bytes2957        ReadLEUint(); // startDisk64 is not currently used2958        ulong offset64 = ReadLEUlong();2959        uint totalDisks = ReadLEUint();29602961        baseStream_.Position = (long)offset64;2962        long sig64 = ReadLEUint();29632964        if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {2965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));2966        }29672968        // 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();29782979        // NOTE: zip64 extensible data sector (variable size) is ignored.2980      }29812982      entries_ = new ZipEntry[entriesForThisDisk];29832984      // SFX/embedded support, find the offset of the first entry vis the start of the stream2985      // 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 offsets2988      // 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      }29962997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);  29982999        PostUpdateCleanup();3000      }3001    }30023003    /// <summary>3004    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.3005    /// </summary>3006    /// <param name="disposing">true to release both managed and unmanaged resources;3007    /// false to release only unmanaged resources.</param>3008    protected virtual void Dispose(bool disposing)3009    {3010      DisposeInternal(disposing);3011    }30123013    #endregion30143015    #region Internal routines3016    #region Reading3017    /// <summary>3018    /// Read an unsigned short in little endian byte order.3019    /// </summary>3020    /// <returns>Returns the value read.</returns>3021    /// <exception cref="EndOfStreamException">3022    /// The stream ends prematurely3023    /// </exception>3024    ushort ReadLEUshort()3025    {3026      int data1 = baseStream_.ReadByte();30273028      if ( data1 < 0 ) {3029        throw new EndOfStreamException("End of stream");3030      }30313032      int data2 = baseStream_.ReadByte();30333034      if ( data2 < 0 ) {3035        throw new EndOfStreamException("End of stream");3036      }303730383039      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));3040    }30413042    /// <summary>3043    /// Read a uint in little endian byte order.3044    /// </summary>3045    /// <returns>Returns the value read.</returns>3046    /// <exception cref="IOException">3047    /// An i/o error occurs.3048    /// </exception>3049    /// <exception cref="System.IO.EndOfStreamException">3050    /// The file ends prematurely3051    /// </exception>3052    uint ReadLEUint()3053    {3054      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));3055    }30563057    ulong ReadLEUlong()3058    {3059      return ReadLEUint() | ((ulong)ReadLEUint() << 32);3060    }30613062    #endregion3063    // NOTE this returns the offset of the first byte after the signature.3064    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)3065    {3066      using ( ZipHelperStream les = new ZipHelperStream(baseStream_) ) {3067        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);3068      }3069    }30703071    /// <summary>3072    /// Search for and read the central directory of a zip file filling the entries array.3073    /// </summary>3074    /// <exception cref="System.IO.IOException">3075    /// An i/o error occurs.3076    /// </exception>3077    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3078    /// The central directory is malformed or cannot be found3079    /// </exception>3080    void ReadEntries()3081    {3082      // Search for the End Of Central Directory.  When a zip comment is3083      // present the directory will start earlier3084      //3085      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.3086      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files3087      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then3088      // this could be invalid.3089      // Could also speed this up by reading memory in larger blocks.2999      for (ulong i = 0; i < entriesForThisDisk; i++) {3000        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {3001          throw new ZipException("Wrong Central Directory signature");3002        }30033004        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();30153016        int diskStartNo = ReadLEUshort();  // Not currently used3017        int internalAttributes = ReadLEUshort();  // Not currently used30183019        uint externalAttributes = ReadLEUint();3020        long offset = ReadLEUint();30213022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];30233024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);3025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);30263027        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;30363037        if ((bitFlags & 8) == 0) {3038          entry.CryptoCheckValue = (byte)(crc >> 24);3039        } else {3040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3041        }30423043        if (extraLen > 0) {3044          byte[] extra = new byte[extraLen];3045          StreamUtils.ReadFully(baseStream_, extra);3046          entry.ExtraData = extra;3047        }30483049        entry.ProcessExtraData(false);30503051        if (commentLen > 0) {3052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);3053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3054        }30553056        entries_[i] = entry;3057      }3058    }30593060    /// <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 prematurely3068    /// </exception>3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3070    /// The local header signature is invalid, the entry and central header file name lengths are different3071    /// or the local and entry compression methods dont match3072    /// </exception>3073    long LocateEntry(ZipEntry entry)3074    {3075      return TestLocalHeader(entry, HeaderTest.Extract);3076    }30773078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3079    {3080      CryptoStream result = null;30813082      if ((entry.Version < ZipConstants.VersionStrongEncryption)3083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3084        var classicManaged = new PkzipClassicManaged();30853086        OnKeysRequired(entry.Name);3087        if (HaveKeys == false) {3088          throw new ZipException("No password available for encrypted stream");3089        }  30903091      if (baseStream_.CanSeek == false) {3092        throw new ZipException("ZipFile stream must be seekable");3093      }30943095      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,3096        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);30973098      if (locatedEndOfCentralDir < 0) {3099        throw new ZipException("Cannot find central directory");3100      }31013102      // Read end of central directory record3103      ushort thisDiskNumber           = ReadLEUshort();3104      ushort startCentralDirDisk      = ReadLEUshort();3105      ulong entriesForThisDisk        = ReadLEUshort();3106      ulong entriesForWholeCentralDir = ReadLEUshort();3107      ulong centralDirSize            = ReadLEUint();3108      long offsetOfCentralDir         = ReadLEUint();3109      uint commentSize                = ReadLEUshort();31103111      if ( commentSize > 0 ) {3112        byte[] comment = new byte[commentSize];31133114        StreamUtils.ReadFully(baseStream_, comment);3115        comment_ = ZipConstants.ConvertToString(comment);3116      }3117      else {3118        comment_ = string.Empty;3119      }31203121      bool isZip64 = false;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 bytes31093110          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      }31193120      return result;3121    }  31223123      // Check if zip64 header information is required.3124      if ( (thisDiskNumber == 0xffff) ||3125        (startCentralDirDisk == 0xffff) ||3126        (entriesForThisDisk == 0xffff) ||3127        (entriesForWholeCentralDir == 0xffff) ||3128        (centralDirSize == 0xffffffff) ||3129        (offsetOfCentralDir == 0xffffffff) ) {3130        isZip64 = true;31313132        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 3133        if ( offset < 0 ) {3134          throw new ZipException("Cannot find Zip64 locator");3135        }31363137        // number of the disk with the start of the zip64 end of central directory 4 bytes3138        // relative offset of the zip64 end of central directory record 8 bytes3139        // total number of disks 4 bytes3140        ReadLEUint(); // startDisk64 is not currently used3141        ulong offset64 = ReadLEUlong();3142        uint totalDisks = ReadLEUint();31433144        baseStream_.Position = (long)offset64;3145        long sig64 = ReadLEUint();31463147        if ( sig64 != ZipConstants.Zip64CentralFileHeaderSignature ) {3148          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));3149        }31503151        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.3152        ulong recordSize = ReadLEUlong();3153        int versionMadeBy = ReadLEUshort();3154        int versionToExtract = ReadLEUshort();3155        uint thisDisk = ReadLEUint();3156        uint centralDirDisk = ReadLEUint();3157        entriesForThisDisk = ReadLEUlong();3158        entriesForWholeCentralDir = ReadLEUlong();3159        centralDirSize = ReadLEUlong();3160        offsetOfCentralDir = (long)ReadLEUlong();31613162        // NOTE: zip64 extensible data sector (variable size) is ignored.3163      }31643165      entries_ = new ZipEntry[entriesForThisDisk];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();31293130        OnKeysRequired(entry.Name);3131        if (HaveKeys == false) {3132          throw new ZipException("No password available for encrypted stream");3133        }31343135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3136        // which doesnt do this.3137        result = new CryptoStream(new UncompressedStream(baseStream),3138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);31393140        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    }31483149    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    }31573158    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    }  31663167      // SFX/embedded support, find the offset of the first entry vis the start of the stream3168      // This applies to Zip files that are appended to the end of an SFX stub.3169      // Or are appended as a resource to an executable.3170      // Zip files created by some archivers have the offsets altered to reflect the true offsets3171      // and so dont require any adjustment here...3172      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?3173      if ( !isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize)) ) {3174        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);3175        if (offsetOfFirstEntry <= 0) {3176          throw new ZipException("Invalid embedded zip archive");3177        }3178      }31793180      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);31813182      for (ulong i = 0; i < entriesForThisDisk; i++) {3183        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {3184          throw new ZipException("Wrong Central Directory signature");3185        }3167    #endregion31683169    #region Instance Fields3170    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_;31803181    // Default is dynamic which is not backwards compatible and can cause problems3182    // 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;  31863187        int versionMadeBy      = ReadLEUshort();3188        int versionToExtract   = ReadLEUshort();3189        int bitFlags           = ReadLEUshort();3190        int method             = ReadLEUshort();3191        uint dostime           = ReadLEUint();3192        uint crc               = ReadLEUint();3193        var csize             = (long)ReadLEUint();3194        var size              = (long)ReadLEUint();3195        int nameLen            = ReadLEUshort();3196        int extraLen           = ReadLEUshort();3197        int commentLen         = ReadLEUshort();31983199        int diskStartNo        = ReadLEUshort();  // Not currently used3200        int internalAttributes = ReadLEUshort();  // Not currently used3187    #region Zip Update Instance Fields3188    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    #endregion3200    #endregion  32013202        uint externalAttributes = ReadLEUint();3203        long offset             = ReadLEUint();32043205        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];32063207        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);3208        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);32093210        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);3211        entry.Crc = crc & 0xffffffffL;3212        entry.Size = size & 0xffffffffL;3213        entry.CompressedSize = csize & 0xffffffffL;3214        entry.Flags = bitFlags;3215        entry.DosTime = (uint)dostime;3216        entry.ZipFileIndex = (long)i;3217        entry.Offset = offset;3218        entry.ExternalFileAttributes = (int)externalAttributes;32193220        if ((bitFlags & 8) == 0) {3221          entry.CryptoCheckValue = (byte)(crc >> 24);3222        }3223        else {3224          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3225        }32263227        if (extraLen > 0) {3228          byte[] extra = new byte[extraLen];3229          StreamUtils.ReadFully(baseStream_, extra);3230          entry.ExtraData = extra;3231        }32323233        entry.ProcessExtraData(false);32343235        if (commentLen > 0) {3236          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);3237          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3238        }32393240        entries_[i] = entry;3241      }3242    }32433244    /// <summary>3245    /// Locate the data for a given entry.3246    /// </summary>3247    /// <returns>3248    /// The start offset of the data.3249    /// </returns>3250    /// <exception cref="System.IO.EndOfStreamException">3251    /// The stream ends prematurely3252    /// </exception>3253    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3254    /// The local header signature is invalid, the entry and central header file name lengths are different3255    /// or the local and entry compression methods dont match3256    /// </exception>3257    long LocateEntry(ZipEntry entry)3258    {3259      return TestLocalHeader(entry, HeaderTest.Extract);3260    }32613262#if !NETCF_1_03263    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3264    {3265      CryptoStream result = null;32663267      if ( (entry.Version < ZipConstants.VersionStrongEncryption)3268        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3269        var classicManaged = new PkzipClassicManaged();32703271        OnKeysRequired(entry.Name);3272        if (HaveKeys == false) {3273          throw new ZipException("No password available for encrypted stream");3274        }3202    #region Support Classes3203    /// <summary>3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3205    /// </summary>3206    class ZipString3207    {3208      #region Constructors3209      /// <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      }32183219      /// <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      #endregion32283229      /// <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      }32363237      /// <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      }32463247      /// <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      }32563257      /// <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      }32683269      void MakeTextAvailable()3270      {3271        if (comment_ == null) {3272          comment_ = ZipConstants.ConvertToString(rawComment_);3273        }3274      }  32753276        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);3277        CheckClassicPassword(result, entry);3278      }3279      else {3280#if !NET_1_1 && !NETCF_2_03281        if (entry.Version == ZipConstants.VERSION_AES) {3282          //3283          OnKeysRequired(entry.Name);3284          if (HaveKeys == false) {3285            throw new ZipException("No password available for AES encrypted stream");3286          }3287          int saltLen = entry.AESSaltLen;3288          byte[] saltBytes = new byte[saltLen];3289          int saltIn = baseStream.Read(saltBytes, 0, saltLen);3290          if (saltIn != saltLen)3291            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);3292          //3293          byte[] pwdVerifyRead = new byte[2];3294          baseStream.Read(pwdVerifyRead, 0, 2);3295          int blockSize = entry.AESKeySize / 8;  // bits to bytes32963297          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);3298          byte[] pwdVerifyCalc = decryptor.PwdVerifier;3299          if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])3300            throw new Exception("Invalid password for AES");3301          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);3302        }3303        else3304#endif3305        {3306          throw new ZipException("Decryption method not supported");3307        }3308      }33093310      return result;3311    }33123313    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)3314    {3315      CryptoStream result = null;3316      if ( (entry.Version < ZipConstants.VersionStrongEncryption)3317        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3318        var classicManaged = new PkzipClassicManaged();3276      void MakeBytesAvailable()3277      {3278        if (rawComment_ == null) {3279          rawComment_ = ZipConstants.ConvertToArray(comment_);3280        }3281      }32823283      /// <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      }32933294      #region Instance Fields3295      string comment_;3296      byte[] rawComment_;3297      bool isSourceString_;3298      #endregion3299    }33003301    /// <summary>3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3303    /// </summary>3304    class ZipEntryEnumerator : IEnumerator3305    {3306      #region Constructors3307      public ZipEntryEnumerator(ZipEntry[] entries)3308      {3309        array = entries;3310      }33113312      #endregion3313      #region IEnumerator Members3314      public object Current {3315        get {3316          return array[index];3317        }3318      }  33193320        OnKeysRequired(entry.Name);3321        if (HaveKeys == false) {3322          throw new ZipException("No password available for encrypted stream");3323        }3320      public void Reset()3321      {3322        index = -1;3323      }  33243325        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3326        // which doesnt do this.3327        result = new CryptoStream(new UncompressedStream(baseStream),3328          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);33293330        if ( (entry.Crc < 0) || (entry.Flags & 8) != 0) {3331          WriteEncryptionHeader(result, entry.DosTime << 16);3332        }3333        else {3334          WriteEncryptionHeader(result, entry.Crc);3335        }3336      }3337      return result;3338    }33393340    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)3325      public bool MoveNext()3326      {3327        return (++index < array.Length);3328      }3329      #endregion3330      #region Instance Fields3331      ZipEntry[] array;3332      int index = -1;3333      #endregion3334    }33353336    /// <summary>3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3338    /// to and flush, but cannot read, seek or do anything else to.3339    /// </summary>3340    class UncompressedStream : Stream  3341    {3342      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];3343      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);3344      if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {3345        throw new ZipException("Invalid password");3342      #region Constructors3343      public UncompressedStream(Stream baseStream)3344      {3345        baseStream_ = baseStream;  3346      }3347    }3348#endif33473348      #endregion  33493350    static void WriteEncryptionHeader(Stream stream, long crcValue)3351    {3352      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];3353      var rnd = new Random();3354      rnd.NextBytes(cryptBuffer);3355      cryptBuffer[11] = (byte)(crcValue >> 24);3356      stream.Write(cryptBuffer, 0, cryptBuffer.Length);3357    }33583359    #endregion33603361    #region Instance Fields3362    bool       isDisposed_;3363    string     name_;3364    string     comment_;3365    string     rawPassword_;3366    Stream     baseStream_;3367    bool       isStreamOwner;3368    long       offsetOfFirstEntry;3369    ZipEntry[] entries_;3370    byte[] key;3371    bool isNewArchive_;33723373    // Default is dynamic which is not backwards compatible and can cause problems3374    // with XP's built in compression which cant read Zip64 archives.3375    // However it does avoid the situation were a large file is added and cannot be completed correctly.3376    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.3377    UseZip64 useZip64_ = UseZip64.Dynamic ;33783379    #region Zip Update Instance Fields3380    ArrayList updates_;3381    long updateCount_; // Count is managed manually as updates_ can contain nulls!3382    Hashtable updateIndex_;3383    IArchiveStorage archiveStorage_;3384    IDynamicDataSource updateDataSource_;3385    bool contentsEdited_;3386    int bufferSize_ = DefaultBufferSize;3387    byte[] copyBuffer_;3388    ZipString newComment_;3389    bool commentEdited_;3390    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();3391    #endregion3392    #endregion33933394    #region Support Classes3395    /// <summary>3396    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3397    /// </summary>3398    class ZipString3399    {3400      #region Constructors3401      /// <summary>3402      /// Initialise a <see cref="ZipString"/> with a string.3403      /// </summary>3404      /// <param name="comment">The textual string form.</param>3405      public ZipString(string comment)3406      {3407        comment_ = comment;3408        isSourceString_ = true;3409      }34103411      /// <summary>3412      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.3413      /// </summary>3414      /// <param name="rawString"></param>3415      public ZipString(byte[] rawString)3416      {3417        rawComment_ = rawString;3418      }3419      #endregion34203421      /// <summary>3422      /// Get a value indicating the original source of data for this instance.3423      /// True if the source was a string; false if the source was binary data.3424      /// </summary>3425      public bool IsSourceString3426      {3427        get { return isSourceString_; }3428      }34293430      /// <summary>3431      /// Get the length of the comment when represented as raw bytes.3432      /// </summary>3433      public int RawLength3434      {3435        get {3436          MakeBytesAvailable();3437          return rawComment_.Length;3438        }3439      }34403441      /// <summary>3442      /// Get the comment in its 'raw' form as plain bytes.3443      /// </summary>3444      public byte[] RawComment3445      {3446        get {3447          MakeBytesAvailable();3448          return (byte[])rawComment_.Clone();3449        }3450      }34513452      /// <summary>3453      /// Reset the comment to its initial state.3454      /// </summary>3455      public void Reset()3456      {3457        if ( isSourceString_ ) {3458          rawComment_ = null;3459        }3460        else {3461          comment_ = null;3462        }3463      }34643465      void MakeTextAvailable()3466      {3467        if ( comment_ == null ) {3468          comment_ = ZipConstants.ConvertToString(rawComment_);3469        }3470      }34713472      void MakeBytesAvailable()3473      {3474        if ( rawComment_ == null ) {3475          rawComment_ = ZipConstants.ConvertToArray(comment_);3476        }3477      }34783479      /// <summary>3480      /// Implicit conversion of comment to a string.3481      /// </summary>3482      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>3483      /// <returns>The textual equivalent for the input value.</returns>3484      static public implicit operator string(ZipString zipString)3485      {3486        zipString.MakeTextAvailable();3487        return zipString.comment_;3488      }34893490      #region Instance Fields3491      string comment_;3492      byte[] rawComment_;3493      bool isSourceString_;3494      #endregion3495    }34963497    /// <summary>3498    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3499    /// </summary>3500    class ZipEntryEnumerator : IEnumerator3501    {3502      #region Constructors3503      public ZipEntryEnumerator(ZipEntry[] entries)3504      {3505        array = entries;3506      }35073508      #endregion3509      #region IEnumerator Members3510      public object Current3511      {3512        get {3513          return array[index];3514        }3515      }35163517      public void Reset()3518      {3519        index = -1;3520      }35213522      public bool MoveNext()3523      {3524        return (++index < array.Length);3525      }3526      #endregion3527      #region Instance Fields3528      ZipEntry[] array;3529      int index = -1;3530      #endregion3531    }35323533    /// <summary>3534    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3535    /// to and flush, but cannot read, seek or do anything else to.3536    /// </summary>3537    class UncompressedStream : Stream3538    {3539      #region Constructors3540      public UncompressedStream(Stream baseStream)3541      {3542        baseStream_ = baseStream;3543      }35443545      #endregion35463547      /// <summary>3548      /// Close this stream instance.3549      /// </summary>3550      public override void Close()3551      {3552        // Do nothing3553      }35543555      /// <summary>3556      /// Gets a value indicating whether the current stream supports reading.3557      /// </summary>3558      public override bool CanRead3559      {3560        get {3561          return false;3562        }3563      }35643565      /// <summary>3566      /// Write any buffered data to underlying storage.3567      /// </summary>3568      public override void Flush()3569      {3570        baseStream_.Flush();3571      }35723573      /// <summary>3574      /// Gets a value indicating whether the current stream supports writing.3575      /// </summary>3576      public override bool CanWrite3577      {3578        get {3579          return baseStream_.CanWrite;3580        }3581      }35823583      /// <summary>3584      /// Gets a value indicating whether the current stream supports seeking.3585      /// </summary>3586      public override bool CanSeek3587      {3588        get {3589          return false;3590        }3591      }35923593      /// <summary>3594      /// Get the length in bytes of the stream.3595      /// </summary>3596      public override long Length3597      {3598        get {3599          return 0;3600        }3601      }36023603      /// <summary>3604      /// Gets or sets the position within the current stream.3605      /// </summary>3606      public override long Position3607      {3608        get  {3609          return baseStream_.Position;3610        }3611                set {3612                    throw new NotImplementedException();3613                }3614            }36153616            /// <summary>3617            /// Reads a sequence of bytes from the current stream and advances the position within the stream by the num3618            /// </summary>3619            /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte3620            /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from t3621            /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3622            /// <returns>3623            /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if t3624            /// </returns>3625            /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer lengt3626            /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </ex3627            /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3628            /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3629            /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3630            /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3631            public override int Read(byte[] buffer, int offset, int count)3632      {3633        return 0;3634      }36353636      /// <summary>3637      /// Sets the position within the current stream.3638      /// </summary>3639      /// <param name="offset">A byte offset relative to the origin parameter.</param>3640      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3641      /// <returns>3642      /// The new position within the current stream.3643      /// </returns>3644      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3645      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3646      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3647      public override long Seek(long offset, SeekOrigin origin)3648      {3649        return 0;3650      }36513652      /// <summary>3653      /// Sets the length of the current stream.3654      /// </summary>3655      /// <param name="value">The desired length of the current stream in bytes.</param>3656      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3350      /// <summary>3351      /// Close this stream instance.3352      /// </summary>3353      public override void Close()3354      {3355        // Do nothing3356      }33573358      /// <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      }33663367      /// <summary>3368      /// Write any buffered data to underlying storage.3369      /// </summary>3370      public override void Flush()3371      {3372        baseStream_.Flush();3373      }33743375      /// <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      }33833384      /// <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      }33923393      /// <summary>3394      /// Get the length in bytes of the stream.3395      /// </summary>3396      public override long Length {3397        get {3398          return 0;3399        }3400      }34013402      /// <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      }34133414      /// <summary>3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3416      /// </summary>3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3419      /// <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 ma3422      /// </returns>3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3425      /// <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      }34333434      /// <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 is3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3445      public override long Seek(long offset, SeekOrigin origin)3446      {3447        return 0;3448      }34493450      /// <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 as3455      /// <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. </exceptio3457      public override void SetLength(long value)3458      {3459      }34603461      /// <summary>3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3463      /// </summary>3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3466      /// <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. </exceptio3470      /// <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      }34773478      readonly34793480      #region Instance Fields3481      Stream baseStream_;3482      #endregion3483    }34843485    /// <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 : Stream3490    {3491      #region Constructors3492      /// <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;35023503        // Although this is the only time the zipfile is used3504        // keeping a reference here prevents premature closure of3505        // this zip file and thus the baseStream_.35063507        // Code like this will cause apparently random failures depending3508        // 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      #endregion35193520      /// <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        }35303531        lock (baseStream_) {3532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);3533          return baseStream_.ReadByte();3534        }3535      }35363537      /// <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      }35473548      /// <summary>3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3550      /// </summary>3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3553      /// <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 ma3556      /// </returns>3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3559      /// <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 Seek3573          // (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      }35843585      /// <summary>3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3587      /// </summary>3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3590      /// <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. </exceptio3594      /// <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      }36013602      /// <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 as3607      /// <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. </exceptio3609      public override void SetLength(long value)3610      {3611        throw new NotSupportedException();3612      }36133614      /// <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 is3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3625      public override long Seek(long offset, SeekOrigin origin)3626      {3627        long newPos = readPos_;36283629        switch (origin) {3630          case SeekOrigin.Begin:3631            newPos = start_ + offset;3632            break;36333634          case SeekOrigin.Current:3635            newPos = readPos_ + offset;3636            break;36373638          case SeekOrigin.End:3639            newPos = end_ + offset;3640            break;3641        }36423643        if (newPos < start_) {3644          throw new ArgumentException("Negative position is invalid");3645        }36463647        if (newPos >= end_) {3648          throw new IOException("Cannot seek past end");3649        }3650        readPos_ = newPos;3651        return readPos_;3652      }36533654      /// <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      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3659      public override void SetLength(long value)3660      {3658      public override void Flush()3659      {3660        // Nothing to do.  3661      }  3662  3663      /// <summary>3664      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3664      /// Gets or sets the position within the current stream.  3665      /// </summary>3666      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3667      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3668      /// <param name="count">The number of bytes to be written to the current stream.</param>3669      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3670      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3671      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3672      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3673      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3674      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3675      public override void Write(byte[] buffer, int offset, int count)3676      {3677        baseStream_.Write(buffer, offset, count);3678      }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. </exceptio3671      public override long Position {3672        get { return readPos_ - start_; }3673        set {3674          long newPos = start_ + value;36753676          if (newPos < start_) {3677            throw new ArgumentException("Negative position is invalid");3678          }  36793680      readonly36813682      #region Instance Fields3683      Stream baseStream_;3684      #endregion3685    }3680          if (newPos >= end_) {3681            throw new InvalidOperationException("Cannot seek past end");3682          }3683          readPos_ = newPos;3684        }3685      }  36863687    /// <summary>3688    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>3689    /// whose data is only a part or subsection of a file.3690    /// </summary>3691    class PartialInputStream : Stream3692    {3693      #region Constructors3694      /// <summary>3695      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.3696      /// </summary>3697      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>3698      /// <param name="start">The start of the partial data.</param>3699      /// <param name="length">The length of the partial data.</param>3700      public PartialInputStream(ZipFile zipFile, long start, long length)3701      {3702        start_ = start;3703        length_ = length;37043705        // Although this is the only time the zipfile is used3706        // keeping a reference here prevents premature closure of3707        // this zip file and thus the baseStream_.37083709        // Code like this will cause apparently random failures depending3710        // on the size of the files and when garbage is collected.3711        //3712        // ZipFile z = new ZipFile (stream);3713        // Stream reader = z.GetInputStream(0);3714        // uses reader here....3715        zipFile_ = zipFile;3716        baseStream_ = zipFile_.baseStream_;3717        readPos_ = start;3718        end_ = start + length;3719      }3720      #endregion37213722      /// <summary>3723      /// Read a byte from this stream.3724      /// </summary>3725      /// <returns>Returns the byte read or -1 on end of stream.</returns>3726      public override int ReadByte()3727      {3728        if (readPos_ >= end_) {3729           // -1 is the correct value at end of stream.3730          return -1;3731        }37323733        lock( baseStream_ ) {3734          baseStream_.Seek(readPos_++, SeekOrigin.Begin);3735          return baseStream_.ReadByte();3736        }3737      }37383739      /// <summary>3740      /// Close this <see cref="PartialInputStream">partial input stream</see>.3741      /// </summary>3742      /// <remarks>3743      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.3744      /// </remarks>3745      public override void Close()3746      {3747        // Do nothing at all!3748      }37493750      /// <summary>3751      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3752      /// </summary>3753      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3754      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3755      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3756      /// <returns>3757      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma3758      /// </returns>3759      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3760      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3761      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3762      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3763      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3764      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3765      public override int Read(byte[] buffer, int offset, int count)3766      {3767        lock(baseStream_) {3768          if (count > end_ - readPos_) {3769            count = (int) (end_ - readPos_);3770            if (count == 0) {3771              return 0;3772            }3773          }37743775          baseStream_.Seek(readPos_, SeekOrigin.Begin);3776          int readCount = baseStream_.Read(buffer, offset, count);3777          if (readCount > 0) {3778            readPos_ += readCount;3779          }3780          return readCount;3781        }3782      }37833784      /// <summary>3785      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3786      /// </summary>3787      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3788      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3789      /// <param name="count">The number of bytes to be written to the current stream.</param>3790      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3791      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3792      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3793      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3794      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3795      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3796      public override void Write(byte[] buffer, int offset, int count)3797      {3798        throw new NotSupportedException();3799      }38003801      /// <summary>3802      /// When overridden in a derived class, sets the length of the current stream.3803      /// </summary>3804      /// <param name="value">The desired length of the current stream in bytes.</param>3805      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3806      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3807      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3808      public override void SetLength(long value)3809      {3810        throw new NotSupportedException();3811      }38123813      /// <summary>3814      /// When overridden in a derived class, sets the position within the current stream.3815      /// </summary>3816      /// <param name="offset">A byte offset relative to the origin parameter.</param>3817      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3818      /// <returns>3819      /// The new position within the current stream.3820      /// </returns>3821      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3822      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3823      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3824      public override long Seek(long offset, SeekOrigin origin)3825      {3826        long newPos = readPos_;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. </excep3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3694      public override long Length {3695        get { return length_; }3696      }36973698      /// <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      }37063707      /// <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      }37153716      /// <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      }37243725      /// <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 Fields3734      ZipFile zipFile_;3735      Stream baseStream_;3736      long start_;3737      long length_;3738      long readPos_;3739      long end_;3740      #endregion3741    }3742    #endregion3743  }37443745  #endregion37463747  #region DataSources3748  /// <summary>3749  /// Provides a static way to obtain a source of data for an entry.3750  /// </summary>3751  public interface IStaticDataSource3752  {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  }37603761  /// <summary>3762  /// Represents a source of data that can dynamically provide3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3764  /// </summary>3765  public interface IDynamicDataSource3766  {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  }37763777  /// <summary>3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3779  /// </summary>3780  public class StaticDiskDataSource : IStaticDataSource3781  {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    }37903791    #region IDataSource Members37923793    /// <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    }38013802    readonly38033804    #endregion3805    #region Instance Fields3806    string fileName_;3807    #endregion3808  }380938103811  /// <summary>3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.3813  /// </summary>3814  public class DynamicDiskDataSource : IDynamicDataSource3815  {38163817    #region IDataSource Members3818    /// <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;  38273828        switch ( origin )3829        {3830          case SeekOrigin.Begin:3831            newPos = start_ + offset;3832            break;38333834          case SeekOrigin.Current:3835            newPos = readPos_ + offset;3836            break;3828      if (name != null) {3829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);3830      }38313832      return result;3833    }38343835    #endregion3836  }  38373838          case SeekOrigin.End:3839            newPos = end_ + offset;3840            break;3841        }38423843        if ( newPos < start_ ) {3844          throw new ArgumentException("Negative position is invalid");3845        }38463847        if ( newPos >= end_ ) {3848          throw new IOException("Cannot seek past end");3849        }3850        readPos_ = newPos;3851        return readPos_;3852      }38533854      /// <summary>3855      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.3856      /// </summary>3857      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3858      public override void Flush()3859      {3860        // Nothing to do.3861      }38623863      /// <summary>3864      /// Gets or sets the position within the current stream.3865      /// </summary>3866      /// <value></value>3867      /// <returns>The current position within the stream.</returns>3868      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3869      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>3870      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3871      public override long Position {3872        get { return readPos_ - start_; }3873        set {3874          long newPos = start_ + value;38753876          if ( newPos < start_ ) {3877            throw new ArgumentException("Negative position is invalid");3878          }3838  #endregion38393840  #region Archive Storage3841  /// <summary>3842  /// Defines facilities for data storage when updating Zip Archives.3843  /// </summary>3844  public interface IArchiveStorage3845  {3846    /// <summary>3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.3848    /// </summary>3849    FileUpdateMode UpdateMode { get; }38503851    /// <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();38573858    /// <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();38643865    /// <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);38713872    /// <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);  38793880          if ( newPos >= end_ ) {3881            throw new InvalidOperationException("Cannot seek past end");3882          }3883          readPos_ = newPos;3884        }3885      }38863887      /// <summary>3888      /// Gets the length in bytes of the stream.3889      /// </summary>3890      /// <value></value>3891      /// <returns>A long value representing the length of the stream in bytes.</returns>3892      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep3893      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3894      public override long Length {3895        get { return length_; }3896      }38973898      /// <summary>3899      /// Gets a value indicating whether the current stream supports writing.3900      /// </summary>3901      /// <value>false</value>3902      /// <returns>true if the stream supports writing; otherwise, false.</returns>3903      public override bool CanWrite {3904        get { return false; }3905      }39063907      /// <summary>3908      /// Gets a value indicating whether the current stream supports seeking.3909      /// </summary>3910      /// <value>true</value>3911      /// <returns>true if the stream supports seeking; otherwise, false.</returns>3912      public override bool CanSeek {3913        get { return true; }3914      }39153916      /// <summary>3917      /// Gets a value indicating whether the current stream supports reading.3918      /// </summary>3919      /// <value>true.</value>3920      /// <returns>true if the stream supports reading; otherwise, false.</returns>3921      public override bool CanRead {3922        get { return true; }3923      }39243925#if !NET_1_0 && !NET_1_1 && !NETCF_1_03926      /// <summary>3927      /// Gets a value that determines whether the current stream can time out.3928      /// </summary>3929      /// <value></value>3930      /// <returns>A value that determines whether the current stream can time out.</returns>3931      public override bool CanTimeout {3932        get { return baseStream_.CanTimeout; }3933      }3934#endif3935      #region Instance Fields3936      ZipFile zipFile_;3937      Stream baseStream_;3938      long start_;3939      long length_;3940      long readPos_;3941      long end_;3942      #endregion3943    }3944    #endregion3945  }39463947  #endregion39483949  #region DataSources3950  /// <summary>3951  /// Provides a static way to obtain a source of data for an entry.3952  /// </summary>3953  public interface IStaticDataSource3954  {3955    /// <summary>3956    /// Get a source of data by creating a new stream.3957    /// </summary>3958    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3959    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3960    Stream GetSource();3961  }39623963  /// <summary>3964  /// Represents a source of data that can dynamically provide3965  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3966  /// </summary>3967  public interface IDynamicDataSource3968  {3969    /// <summary>3970    /// Get a data source.3971    /// </summary>3972    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>3973    /// <param name="name">The name for data if known.</param>3974    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3975    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3976    Stream GetSource(ZipEntry entry, string name);3977  }39783979  /// <summary>3980  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3981  /// </summary>3982  public class StaticDiskDataSource : IStaticDataSource3983  {3984    /// <summary>3985    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>3986    /// </summary>3987    /// <param name="fileName">The name of the file to obtain data from.</param>3988    public StaticDiskDataSource(string fileName)3989    {3990      fileName_ = fileName;3991    }39923993    #region IDataSource Members39943995    /// <summary>3996    /// Get a <see cref="Stream"/> providing data.3997    /// </summary>3998    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>3999    public Stream GetSource()4000    {4001      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4002    }3880    /// <summary>3881    /// Dispose of this instance.3882    /// </summary>3883    void Dispose();3884  }38853886  /// <summary>3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.3888  /// </summary>3889  abstract public class BaseArchiveStorage : IArchiveStorage3890  {3891    #region Constructors3892    /// <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    #endregion39013902    #region IArchiveStorage Members39033904    /// <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();39103911    /// <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 read3915    /// the final storage for the archive.</returns>3916    /// <seealso cref="GetTemporaryOutput"/>3917    public abstract Stream ConvertTemporaryToFinal();39183919    /// <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);39253926    /// <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);39323933    /// <summary>3934    /// Disposes this instance.3935    /// </summary>3936    public abstract void Dispose();39373938    /// <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    }39473948    #endregion39493950    #region Instance Fields3951    FileUpdateMode updateMode_;3952    #endregion3953  }39543955  /// <summary>3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.3957  /// </summary>3958  public class DiskArchiveStorage : BaseArchiveStorage3959  {3960    #region Constructors3961    /// <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      }39723973      fileName_ = file.Name;3974    }39753976    /// <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    #endregion39853986    #region IArchiveStorage Members39873988    /// <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      }  40034004    readonly40054006    #endregion4007    #region Instance Fields4008    string fileName_;4009    #endregion4010  }401140124013  /// <summary>4014  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.4015  /// </summary>4016  public class DynamicDiskDataSource : IDynamicDataSource4017  {40184019    #region IDataSource Members4020    /// <summary>4021    /// Get a <see cref="Stream"/> providing data for an entry.4022    /// </summary>4023    /// <param name="entry">The entry to provide data for.</param>4024    /// <param name="name">The file name for data if known.</param>4025    /// <returns>Returns a stream providing data; or null if not available</returns>4026    public Stream GetSource(ZipEntry entry, string name)4027    {4028      Stream result = null;4004      return temporaryStream_;4005    }40064007    /// <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 read4011    /// 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      }40174018      Stream result = null;40194020      string moveTempName = GetTempFileName(fileName_, false);4021      bool newFileCreated = false;40224023      try {4024        temporaryStream_.Close();4025        File.Move(fileName_, moveTempName);4026        File.Move(temporaryName_, fileName_);4027        newFileCreated = true;4028        File.Delete(moveTempName);  40294030      if ( name != null ) {4031        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);4032      }4030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4031      } catch (Exception) {4032        result = null;  40334034      return result;4035    }40364037    #endregion4038  }4034        // Try to roll back changes...4035        if (!newFileCreated) {4036          File.Move(moveTempName, fileName_);4037          File.Delete(temporaryName_);4038        }  40394040  #endregion40414042  #region Archive Storage4043  /// <summary>4044  /// Defines facilities for data storage when updating Zip Archives.4045  /// </summary>4046  public interface IArchiveStorage4047  {4048    /// <summary>4049    /// Get the <see cref="FileUpdateMode"/> to apply during updates.4050    /// </summary>4051    FileUpdateMode UpdateMode { get; }40524053    /// <summary>4054    /// Get an empty <see cref="Stream"/> that can be used for temporary output.4055    /// </summary>4056    /// <returns>Returns a temporary output <see cref="Stream"/></returns>4057    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4058    Stream GetTemporaryOutput();40594060    /// <summary>4061    /// Convert a temporary output stream to a final stream.4062    /// </summary>4063    /// <returns>The resulting final <see cref="Stream"/></returns>4064    /// <seealso cref="GetTemporaryOutput"/>4065    Stream ConvertTemporaryToFinal();40664067    /// <summary>4068    /// Make a temporary copy of the original stream.4069    /// </summary>4070    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4071    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4072    Stream MakeTemporaryCopy(Stream stream);40734074    /// <summary>4075    /// Return a stream suitable for performing direct updates on the original source.4076    /// </summary>4077    /// <param name="stream">The current stream.</param>4078    /// <returns>Returns a stream suitable for direct updating.</returns>4079    /// <remarks>This may be the current stream passed.</remarks>4080    Stream OpenForDirectUpdate(Stream stream);40814082    /// <summary>4083    /// Dispose of this instance.4084    /// </summary>4085    void Dispose();4086  }4040        throw;4041      }40424043      return result;4044    }40454046    /// <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();40544055      temporaryName_ = GetTempFileName(fileName_, true);4056      File.Copy(fileName_, temporaryName_, true);40574058      temporaryStream_ = new FileStream(temporaryName_,4059        FileMode.Open,4060        FileAccess.ReadWrite);4061      return temporaryStream_;4062    }40634064    /// <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        }40774078        result = new FileStream(fileName_,4079            FileMode.Open,4080            FileAccess.ReadWrite);4081      } else {4082        result = stream;4083      }40844085      return result;4086    }  40874088  /// <summary>4089  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.4090  /// </summary>4091  abstract public class BaseArchiveStorage : IArchiveStorage4092  {4093    #region Constructors4094    /// <summary>4095    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.4096    /// </summary>4097    /// <param name="updateMode">The update mode.</param>4098    protected BaseArchiveStorage(FileUpdateMode updateMode)4099    {4100      updateMode_ = updateMode;4101    }4102    #endregion41034104    #region IArchiveStorage Members41054106    /// <summary>4107    /// Gets a temporary output <see cref="Stream"/>4108    /// </summary>4109    /// <returns>Returns the temporary output stream.</returns>4110    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4111    public abstract Stream GetTemporaryOutput();41124113    /// <summary>4114    /// Converts the temporary <see cref="Stream"/> to its final form.4115    /// </summary>4116    /// <returns>Returns a <see cref="Stream"/> that can be used to read4117    /// the final storage for the archive.</returns>4118    /// <seealso cref="GetTemporaryOutput"/>4119    public abstract Stream ConvertTemporaryToFinal();41204121    /// <summary>4122    /// Make a temporary copy of a <see cref="Stream"/>.4123    /// </summary>4124    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>4125    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4126    public abstract Stream MakeTemporaryCopy(Stream stream);41274128    /// <summary>4129    /// Return a stream suitable for performing direct updates on the original source.4130    /// </summary>4131    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>4132    /// <returns>Returns a stream suitable for direct updating.</returns>4133    public abstract Stream OpenForDirectUpdate(Stream stream);41344135    /// <summary>4136    /// Disposes this instance.4137    /// </summary>4138    public abstract void Dispose();41394140    /// <summary>4141    /// Gets the update mode applicable.4142    /// </summary>4143    /// <value>The update mode.</value>4144    public FileUpdateMode UpdateMode4145    {4146      get {4147        return updateMode_;4148      }4149    }41504151    #endregion41524153    #region Instance Fields4154    FileUpdateMode updateMode_;4155    #endregion4156  }41574158  /// <summary>4159  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.4160  /// </summary>4161  public class DiskArchiveStorage : BaseArchiveStorage4162  {4163    #region Constructors4164    /// <summary>4165    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4166    /// </summary>4167    /// <param name="file">The file.</param>4168    /// <param name="updateMode">The update mode.</param>4169    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)4170      : base(updateMode)4171    {4172      if ( file.Name == null ) {4173        throw new ZipException("Cant handle non file archives");4174      }41754176      fileName_ = file.Name;4177    }4088    /// <summary>4089    /// Disposes this instance.4090    /// </summary>4091    public override void Dispose()4092    {4093      if (temporaryStream_ != null) {4094        temporaryStream_.Close();4095      }4096    }40974098    #endregion40994100    #region Internal routines4101    static string GetTempFileName(string original, bool makeTempFile)4102    {4103      string result = null;41044105      if (original == null) {4106        result = Path.GetTempFileName();4107      } else {4108        int counter = 0;4109        int suffixSeed = DateTime.Now.Second;41104111        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    #endregion41334134    #region Instance Fields4135    Stream temporaryStream_;4136    string fileName_;4137    string temporaryName_;4138    #endregion4139  }41404141  /// <summary>4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4143  /// </summary>4144  public class MemoryArchiveStorage : BaseArchiveStorage4145  {4146    #region Constructors4147    /// <summary>4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4149    /// </summary>4150    public MemoryArchiveStorage() + 364151      : base(FileUpdateMode.Direct)4152    { + 364153    }41544155    /// <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    }41644165    #endregion41664167    #region Properties4168    /// <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    }41744175    #endregion41764177    #region IArchiveStorage Members  4178  4179    /// <summary>4180    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4180    /// Gets the temporary output <see cref="Stream"/>  4181    /// </summary>4182    /// <param name="file">The file.</param>4183    public DiskArchiveStorage(ZipFile file)4184      : this(file, FileUpdateMode.Safe)4185    {4186    }4187    #endregion4182    /// <returns>Returns the temporary output stream.</returns>4183    public override Stream GetTemporaryOutput()4184    { + 14185      temporaryStream_ = new MemoryStream(); + 14186      return temporaryStream_;4187    }  41884189    #region IArchiveStorage Members41904191    /// <summary>4192    /// Gets a temporary output <see cref="Stream"/> for performing updates on.4193    /// </summary>4194    /// <returns>Returns the temporary output stream.</returns>4195    public override Stream GetTemporaryOutput()4196    {4197      if ( temporaryName_ != null ) {4198        temporaryName_ = GetTempFileName(temporaryName_, true);4199        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4200      }4201      else {4202        // Determine where to place files based on internal strategy.4203        // Currently this is always done in system temp directory.4204        temporaryName_ = Path.GetTempFileName();4205        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4206      }42074208      return temporaryStream_;4209    }42104211    /// <summary>4212    /// Converts a temporary <see cref="Stream"/> to its final form.4213    /// </summary>4214    /// <returns>Returns a <see cref="Stream"/> that can be used to read4215    /// the final storage for the archive.</returns>4216    public override Stream ConvertTemporaryToFinal()4217    {4218      if ( temporaryStream_ == null ) {4219        throw new ZipException("No temporary stream has been created");4220      }42214222      Stream result = null;42234224      string moveTempName = GetTempFileName(fileName_, false);4225      bool newFileCreated = false;42264227      try  {4228        temporaryStream_.Close();4229        File.Move(fileName_, moveTempName);4230        File.Move(temporaryName_, fileName_);4231        newFileCreated = true;4232        File.Delete(moveTempName);42334234        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4235      }4236      catch(Exception) {4237        result  = null;42384239        // Try to roll back changes...4240        if ( !newFileCreated ) {4241          File.Move(moveTempName, fileName_);4242          File.Delete(temporaryName_);4243        }42444245        throw;4246      }42474248      return result;4249    }42504251    /// <summary>4252    /// Make a temporary copy of a stream.4253    /// </summary>4254    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4255    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4256    public override Stream MakeTemporaryCopy(Stream stream)4257    {4258      stream.Close();42594260      temporaryName_ = GetTempFileName(fileName_, true);4261      File.Copy(fileName_, temporaryName_, true);42624263      temporaryStream_ = new FileStream(temporaryName_,4264        FileMode.Open,4265        FileAccess.ReadWrite);4266      return temporaryStream_;4267    }42684269    /// <summary>4270    /// Return a stream suitable for performing direct updates on the original source.4271    /// </summary>4272    /// <param name="stream">The current stream.</param>4273    /// <returns>Returns a stream suitable for direct updating.</returns>4274    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>4275    public override Stream OpenForDirectUpdate(Stream stream)4276    {4277      Stream result;4278      if ((stream == null) || !stream.CanWrite)4279      {4280        if (stream != null) {4281          stream.Close();4282        }42834284        result = new FileStream(fileName_,4285            FileMode.Open,4286            FileAccess.ReadWrite);4287      }4288      else4289      {4290        result = stream;4291      }42924293      return result;4294    }42954296    /// <summary>4297    /// Disposes this instance.4298    /// </summary>4299    public override void Dispose()4300    {4301      if ( temporaryStream_ != null ) {4302        temporaryStream_.Close();4303      }4304    }43054306    #endregion43074308    #region Internal routines4309    static string GetTempFileName(string original, bool makeTempFile)4310    {4311      string result = null;43124313      if ( original == null ) {4314        result = Path.GetTempFileName();4315      }4316      else {4317        int counter = 0;4318        int suffixSeed = DateTime.Now.Second;43194320        while ( result == null ) {4321          counter += 1;4322          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);4323          if ( !File.Exists(newName) ) {4324            if ( makeTempFile) {4325              try  {4326                // Try and create the file.4327                using ( FileStream stream = File.Create(newName) ) {4328                }4329                result = newName;4330              }4331              catch {4332                suffixSeed = DateTime.Now.Second;4333              }4334            }4335            else {4336              result = newName;4337            }4338          }4339        }4340      }4341      return result;4342    }4343    #endregion43444345    #region Instance Fields4346    Stream temporaryStream_;4347    string fileName_;4348    string temporaryName_;4349    #endregion4350  }43514352  /// <summary>4353  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4354  /// </summary>4355  public class MemoryArchiveStorage : BaseArchiveStorage4356  {4357    #region Constructors4358    /// <summary>4359    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4360    /// </summary>4361    public MemoryArchiveStorage() - 364362      : base(FileUpdateMode.Direct)4363    { - 364364    }43654366    /// <summary>4367    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4368    /// </summary>4369    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>4370    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>4371    public MemoryArchiveStorage(FileUpdateMode updateMode) - 14372      : base(updateMode)4373    { - 14374    }43754376    #endregion43774378    #region Properties4379    /// <summary>4380    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.4381    /// </summary>4382    public MemoryStream FinalStream4383    { - 04384      get { return finalStream_; }4385    }43864387    #endregion43884389    #region IArchiveStorage Members43904391    /// <summary>4392    /// Gets the temporary output <see cref="Stream"/>4393    /// </summary>4394    /// <returns>Returns the temporary output stream.</returns>4395    public override Stream GetTemporaryOutput()4396    { - 14397      temporaryStream_ = new MemoryStream(); - 14398      return temporaryStream_;4399    }44004401    /// <summary>4402    /// Converts the temporary <see cref="Stream"/> to its final form.4403    /// </summary>4404    /// <returns>Returns a <see cref="Stream"/> that can be used to read4405    /// the final storage for the archive.</returns>4406    public override Stream ConvertTemporaryToFinal()4407    { - 14408       if ( temporaryStream_ == null ) { - 04409        throw new ZipException("No temporary stream has been created");4410      }4411 - 14412      finalStream_ = new MemoryStream(temporaryStream_.ToArray()); - 14413      return finalStream_;4414    }44154416    /// <summary>4417    /// Make a temporary copy of the original stream.4418    /// </summary>4419    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4420    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4421    public override Stream MakeTemporaryCopy(Stream stream)4422    { - 04423      temporaryStream_ = new MemoryStream(); - 04424      stream.Position = 0; - 04425      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]); - 04426      return temporaryStream_;4427    }44284429    /// <summary>4430    /// Return a stream suitable for performing direct updates on the original source.4431    /// </summary>4432    /// <param name="stream">The original source stream</param>4433    /// <returns>Returns a stream suitable for direct updating.</returns>4434    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;4435    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>4436    public override Stream OpenForDirectUpdate(Stream stream)4437    {4438      Stream result; - 14439       if ((stream == null) || !stream.CanWrite) {4440 - 04441        result = new MemoryStream();4442 - 04443         if (stream != null) { - 04444          stream.Position = 0; - 04445          StreamUtils.Copy(stream, result, new byte[4096]);4446 - 04447          stream.Close();4448        } - 04449      }4450      else { - 14451        result = stream;4452      }4453 - 14454      return result;4455    }44564457    /// <summary>4458    /// Disposes this instance.4459    /// </summary>4460    public override void Dispose()4461    { - 374462       if ( temporaryStream_ != null ) { - 14463        temporaryStream_.Close();4464      } - 374465    }44664467    #endregion44684469    #region Instance Fields4470    MemoryStream temporaryStream_;4471    MemoryStream finalStream_;4472    #endregion4473  }44744475  #endregion4476}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 read4193    /// 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    }42034204    /// <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    }42164217    /// <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    }42434244    /// <summary>4245    /// Disposes this instance.4246    /// </summary>4247    public override void Dispose()4248    { + 374249       if (temporaryStream_ != null) { + 14250        temporaryStream_.Close();4251      } + 374252    }42534254    #endregion42554256    #region Instance Fields4257    MemoryStream temporaryStream_;4258    MemoryStream finalStream_;4259    #endregion4260  }42614262  #endregion4263} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_NTTaggedData.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_NTTaggedData.htm index cddb0c735..4209b7bf3 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_NTTaggedData.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_NTTaggedData.htm @@ -16,10 +16,10 @@

Summary

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:10 -Coverable lines:55 -Total lines:987 -Line coverage:81.8% +Uncovered lines:9 +Coverable lines:54 +Total lines:896 +Line coverage:83.3% Branch coverage:50% @@ -38,995 +38,904 @@

#LineLine coverage - 1//2// ZipExtraData.cs3//4// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team5//6// This program is free software; you can redistribute it and/or7// modify it under the terms of the GNU General Public License8// as published by the Free Software Foundation; either version 29// of the License, or (at your option) any later version.10//11// This program is distributed in the hope that it will be useful,12// but WITHOUT ANY WARRANTY; without even the implied warranty of13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the14// GNU General Public License for more details.15//16// You should have received a copy of the GNU General Public License17// along with this program; if not, write to the Free Software18// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.19//20// Linking this library statically or dynamically with other modules is21// making a combined work based on this library.  Thus, the terms and22// conditions of the GNU General Public License cover the whole23// combination.24//25// As a special exception, the copyright holders of this library give you26// permission to link this library with independent modules to produce an27// executable, regardless of the license terms of these independent28// modules, and to copy and distribute the resulting executable under29// terms of your choice, provided that you also meet, for each linked30// independent module, the terms and conditions of the license of that31// module.  An independent module is a module which is not derived from32// or based on this library.  If you modify this library, you may extend33// this exception to your version of the library, but you are not34// obligated to do so.  If you do not wish to do so, delete this35// exception statement from your version.3637using System;38using System.IO;3940namespace ICSharpCode.SharpZipLib.Zip41{42  // TODO: Sort out wether tagged data is useful and what a good implementation might look like.43  // Its just a sketch of an idea at the moment.4445  /// <summary>46  /// ExtraData tagged value interface.47  /// </summary>48  public interface ITaggedData49  {1using System;2using System.IO;34namespace ICSharpCode.SharpZipLib.Zip5{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.89  /// <summary>10  /// ExtraData tagged value interface.11  /// </summary>12  public interface ITaggedData13  {14    /// <summary>15    /// Get the ID for this tagged data value.16    /// </summary>17    short TagID { get; }1819    /// <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);2627    /// <summary>28    /// Get the data representing this instance.29    /// </summary>30    /// <returns>Returns the data for this instance.</returns>31    byte[] GetData();32  }3334  /// <summary>35  /// A raw binary tagged value36  /// </summary>37  public class RawTaggedData : ITaggedData38  {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    }4748    #region ITaggedData Members49  50    /// <summary>  51    /// Get the ID for this tagged data value.  52    /// </summary>53    short TagID { get; }5455    /// <summary>56    /// Set the contents of this instance from the data passed.57    /// </summary>58    /// <param name="data">The data to extract contents from.</param>59    /// <param name="offset">The offset to begin extracting data from.</param>60    /// <param name="count">The number of bytes to extract.</param>61    void SetData(byte[] data, int offset, int count);6263    /// <summary>64    /// Get the data representing this instance.65    /// </summary>66    /// <returns>Returns the data for this instance.</returns>67    byte[] GetData();68  }53    public short TagID {54      get { return _tag; }55      set { _tag = value; }56    }5758    /// <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      }  6970  /// <summary>71  /// A raw binary tagged value72  /// </summary>73  public class RawTaggedData : ITaggedData74  {75    /// <summary>76    /// Initialise a new instance.77    /// </summary>78    /// <param name="tag">The tag ID.</param>79    public RawTaggedData(short tag)80    {81      _tag = tag;82    }8384    #region ITaggedData Members8586    /// <summary>87    /// Get the ID for this tagged data value.88    /// </summary>89    public short TagID90    {91      get { return _tag; }92      set { _tag = value; }93    }9470      _data = new byte[count];71      Array.Copy(data, offset, _data, 0, count);72    }7374    /// <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    }8283    #endregion8485    /// <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    }9394    #region Instance Fields  95    /// <summary>96    /// Set the data from the raw values provided.96    /// The tag ID for this instance.  97    /// </summary>98    /// <param name="data">The raw data to extract values from.</param>99    /// <param name="offset">The index to start extracting values from.</param>100    /// <param name="count">The number of bytes available.</param>101    public void SetData(byte[] data, int offset, int count)102    {103      if( data==null )104      {105        throw new ArgumentNullException(nameof(data));106      }107108      _data=new byte[count];109      Array.Copy(data, offset, _data, 0, count);110    }111112    /// <summary>113    /// Get the binary data representing this instance.114    /// </summary>115    /// <returns>The raw binary data representing this instance.</returns>116    public byte[] GetData()117    {118      return _data;119    }120121    #endregion122123    /// <summary>124    /// Get /set the binary data representing this instance.125    /// </summary>126    /// <returns>The raw binary data representing this instance.</returns>127    public byte[] Data128    {129      get { return _data; }130      set { _data=value; }131    }98    short _tag;99100    byte[] _data;101    #endregion102  }103104  /// <summary>105  /// Class representing extended unix date time values.106  /// </summary>107  public class ExtendedUnixData : ITaggedData108  {109    /// <summary>110    /// Flags indicate which values are included in this instance.111    /// </summary>112    [Flags]113    public enum Flags : byte114    {115      /// <summary>116      /// The modification time is included117      /// </summary>118      ModificationTime = 0x01,119120      /// <summary>121      /// The access time is included122      /// </summary>123      AccessTime = 0x02,124125      /// <summary>126      /// The create time is included.127      /// </summary>128      CreateTime = 0x04,129    }130131    #region ITaggedData Members  132133    #region Instance Fields134    /// <summary>135    /// The tag ID for this instance.136    /// </summary>137    short _tag;138139    byte[] _data;140    #endregion141  }142143  /// <summary>144  /// Class representing extended unix date time values.145  /// </summary>146  public class ExtendedUnixData : ITaggedData147  {148    /// <summary>149    /// Flags indicate which values are included in this instance.150    /// </summary>151    [Flags]152    public enum Flags : byte153    {154      /// <summary>155      /// The modification time is included156      /// </summary>157      ModificationTime = 0x01,133    /// <summary>134    /// Get the ID135    /// </summary>136    public short TagID {137      get { return 0x5455; }138    }139140    /// <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 present151        // bit 1           if set, access time is present152        // bit 2           if set, creation time is present153154        _flags = (Flags)helperStream.ReadByte();155        if (((_flags & Flags.ModificationTime) != 0))156        {157          int iTime = helperStream.ReadLEInt();  158159      /// <summary>160      /// The access time is included161      /// </summary>162      AccessTime = 0x02,163164      /// <summary>165      /// The create time is included.166      /// </summary>167      CreateTime = 0x04,168    }169170    #region ITaggedData Members171172    /// <summary>173    /// Get the ID174    /// </summary>175    public short TagID176    {177      get { return 0x5455; }178    }179180    /// <summary>181    /// Set the data from the raw values provided.182    /// </summary>183    /// <param name="data">The raw data to extract values from.</param>184    /// <param name="index">The index to start extracting values from.</param>185    /// <param name="count">The number of bytes available.</param>186    public void SetData(byte[] data, int index, int count)159          _modificationTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +160            new TimeSpan(0, 0, 0, iTime, 0);161162          // Central-header version is truncated after modification time163          if (count <= 5) return;164        }165166        if ((_flags & Flags.AccessTime) != 0) {167          int iTime = helperStream.ReadLEInt();168169          _lastAccessTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +170            new TimeSpan(0, 0, 0, iTime, 0);171        }172173        if ((_flags & Flags.CreateTime) != 0) {174          int iTime = helperStream.ReadLEInt();175176          _createTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +177            new TimeSpan(0, 0, 0, iTime, 0);178        }179      }180    }181182    /// <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(data, index, count, false))189      using (ZipHelperStream helperStream = new ZipHelperStream(ms))190      {191        // bit 0           if set, modification time is present192        // bit 1           if set, access time is present193        // bit 2           if set, creation time is present194195        _flags = (Flags)helperStream.ReadByte();196        if (((_flags & Flags.ModificationTime) != 0) && (count >= 5))197        {198          int iTime = helperStream.ReadLEInt();199200          _modificationTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +201            new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();202        }203204        if ((_flags & Flags.AccessTime) != 0)205        {206          int iTime = helperStream.ReadLEInt();207208          _lastAccessTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +209            new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();210        }211212        if ((_flags & Flags.CreateTime) != 0)213        {214          int iTime = helperStream.ReadLEInt();215216          _createTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +217            new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();218        }219      }220    }221222    /// <summary>223    /// Get the binary data representing this instance.224    /// </summary>225    /// <returns>The raw binary data representing this instance.</returns>226    public byte[] GetData()227    {228      using (MemoryStream ms = new MemoryStream())229      using (ZipHelperStream helperStream = new ZipHelperStream(ms))230      {231        helperStream.IsStreamOwner = false;232        helperStream.WriteByte((byte)_flags);     // Flags233        if ( (_flags & Flags.ModificationTime) != 0) {234          TimeSpan span = _modificationTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();235          var seconds = (int)span.TotalSeconds;236          helperStream.WriteLEInt(seconds);237        }238        if ( (_flags & Flags.AccessTime) != 0) {239          TimeSpan span = _lastAccessTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();240          var seconds = (int)span.TotalSeconds;241          helperStream.WriteLEInt(seconds);242        }243        if ( (_flags & Flags.CreateTime) != 0) {244          TimeSpan span = _createTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();245          var seconds = (int)span.TotalSeconds;246          helperStream.WriteLEInt(seconds);247        }248        return ms.ToArray();249      }250    }251252    #endregion253254    /// <summary>255    /// Test a <see cref="DateTime"> value to see if is valid and can be represented here.</see>256    /// </summary>257    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>258    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>259    /// <remarks>The standard Unix time is a signed integer data type, directly encoding the Unix time number,260    /// which is the number of seconds since 1970-01-01.261    /// Being 32 bits means the values here cover a range of about 136 years.262    /// The minimum representable time is 1901-12-13 20:45:52,263    /// and the maximum representable time is 2038-01-19 03:14:07.264    /// </remarks>265    public static bool IsValidValue(DateTime value)266    {267      return (( value >= new DateTime(1901, 12, 13, 20, 45, 52)) ||268          ( value <= new DateTime(2038, 1, 19, 03, 14, 07) ));269    }270271    /// <summary>272    /// Get /set the Modification Time273    /// </summary>274    /// <exception cref="ArgumentOutOfRangeException"></exception>275    /// <seealso cref="IsValidValue"></seealso>276    public DateTime ModificationTime277    {278      get { return _modificationTime; }279      set280      {281        if ( !IsValidValue(value) ) {282          throw new ArgumentOutOfRangeException(nameof(value));283        }284285        _flags |= Flags.ModificationTime;286        _modificationTime=value;287      }188      using (MemoryStream ms = new MemoryStream())189      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {190        helperStream.IsStreamOwner = false;191        helperStream.WriteByte((byte)_flags);     // Flags192        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    }210211    #endregion212213    /// <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    }229230    /// <summary>231    /// Get /set the Modification Time232    /// </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        }241242        _flags |= Flags.ModificationTime;243        _modificationTime = value;244      }245    }246247    /// <summary>248    /// Get / set the Access Time249    /// </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        }258259        _flags |= Flags.AccessTime;260        _lastAccessTime = value;261      }262    }263264    /// <summary>265    /// Get / Set the Create Time266    /// </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        }275276        _flags |= Flags.CreateTime;277        _createTime = value;278      }279    }280281    /// <summary>282    /// Get/set the <see cref="Flags">values</see> to include.283    /// </summary>284    public Flags Include285    {286      get { return _flags; }287      set { _flags = value; }  288    }  289290    /// <summary>291    /// Get / set the Access Time292    /// </summary>293    /// <exception cref="ArgumentOutOfRangeException"></exception>294    /// <seealso cref="IsValidValue"></seealso>295    public DateTime AccessTime296    {297      get { return _lastAccessTime; }298      set {299        if ( !IsValidValue(value) ) {300          throw new ArgumentOutOfRangeException(nameof(value));301        }302303        _flags |= Flags.AccessTime;304        _lastAccessTime=value;305      }306    }307308    /// <summary>309    /// Get / Set the Create Time310    /// </summary>311    /// <exception cref="ArgumentOutOfRangeException"></exception>312    /// <seealso cref="IsValidValue"></seealso>313    public DateTime CreateTime314    {315      get { return _createTime; }316      set {317        if ( !IsValidValue(value) ) {318          throw new ArgumentOutOfRangeException(nameof(value));319        }320321        _flags |= Flags.CreateTime;322        _createTime=value;323      }324    }325326    /// <summary>327    /// Get/set the <see cref="Flags">values</see> to include.328    /// </summary>329    Flags Include330    {331      get { return _flags; }332      set { _flags = value; }333    }334335    #region Instance Fields336    Flags _flags;337    DateTime _modificationTime = new DateTime(1970,1,1);338    DateTime _lastAccessTime = new DateTime(1970, 1, 1);339    DateTime _createTime = new DateTime(1970, 1, 1);340    #endregion341  }342343  /// <summary>344  /// Class handling NT date time values.345  /// </summary>346  public class NTTaggedData : ITaggedData347  {348    /// <summary>349    /// Get the ID for this tagged data value.350    /// </summary>351    public short TagID352    { - 1353      get { return 10; }354    }355356    /// <summary>357    /// Set the data from the raw values provided.358    /// </summary>359    /// <param name="data">The raw data to extract values from.</param>360    /// <param name="index">The index to start extracting values from.</param>361    /// <param name="count">The number of bytes available.</param>362    public void SetData(byte[] data, int index, int count)363    { - 1364      using (MemoryStream ms = new MemoryStream(data, index, count, false)) - 1365      using (ZipHelperStream helperStream = new ZipHelperStream(ms))366      { - 1367        helperStream.ReadLEInt(); // Reserved - 1368         while (helperStream.Position < helperStream.Length)369        { - 1370          int ntfsTag = helperStream.ReadLEShort(); - 1371          int ntfsLength = helperStream.ReadLEShort(); - 1372           if (ntfsTag == 1)373          { - 1374             if (ntfsLength >= 24)375            { - 1376              long lastModificationTicks = helperStream.ReadLELong(); - 1377              _lastModificationTime = DateTime.FromFileTime(lastModificationTicks);378 - 1379              long lastAccessTicks = helperStream.ReadLELong(); - 1380              _lastAccessTime = DateTime.FromFileTime(lastAccessTicks);381 - 1382              long createTimeTicks = helperStream.ReadLELong(); - 1383              _createTime = DateTime.FromFileTime(createTimeTicks);384            } - 1385            break;386          }387          else388          {389            // An unknown NTFS tag so simply skip it. - 0390            helperStream.Seek(ntfsLength, SeekOrigin.Current);391          }392        } - 0393      } - 1394    }395396    /// <summary>397    /// Get the binary data representing this instance.398    /// </summary>399    /// <returns>The raw binary data representing this instance.</returns>400    public byte[] GetData()401    { - 2402      using (MemoryStream ms = new MemoryStream()) - 2403      using (ZipHelperStream helperStream = new ZipHelperStream(ms))404      { - 2405        helperStream.IsStreamOwner = false; - 2406        helperStream.WriteLEInt(0);       // Reserved - 2407        helperStream.WriteLEShort(1);     // Tag - 2408        helperStream.WriteLEShort(24);    // Length = 3 x 8. - 2409        helperStream.WriteLELong(_lastModificationTime.ToFileTime()); - 2410        helperStream.WriteLELong(_lastAccessTime.ToFileTime()); - 2411        helperStream.WriteLELong(_createTime.ToFileTime()); - 2412        return ms.ToArray();413      } - 2414    }415416    /// <summary>417    /// Test a <see cref="DateTime"> valuie to see if is valid and can be represented here.</see>418    /// </summary>419    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>420    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>421    /// <remarks>422    /// NTFS filetimes are 64-bit unsigned integers, stored in Intel423    /// (least significant byte first) byte order. They determine the424    /// number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",425    /// which is "01-Jan-1601 00:00:00 UTC". 28 May 60056 is the upper limit426    /// </remarks>427    public static bool IsValidValue(DateTime value)428    { - 3429      bool result = true;430      try431      { - 3432        value.ToFileTimeUtc(); - 3433      } - 0434      catch435      { - 0436        result = false; - 0437      } - 3438      return result;439    }440441    /// <summary>442    /// Get/set the <see cref="DateTime">last modification time</see>.443    /// </summary>444    public DateTime LastModificationTime445    { - 4446      get { return _lastModificationTime; }447      set { - 1448         if (! IsValidValue(value))449        { - 0450          throw new ArgumentOutOfRangeException(nameof(value));451        } - 1452        _lastModificationTime = value; - 1453      }454    }455456    /// <summary>457    /// Get /set the <see cref="DateTime">create time</see>458    /// </summary>459    public DateTime CreateTime460    { - 0461      get { return _createTime; }462      set { - 1463         if ( !IsValidValue(value)) { - 0464          throw new ArgumentOutOfRangeException(nameof(value));465        } - 1466        _createTime = value; - 1467      }468    }469470    /// <summary>471    /// Get /set the <see cref="DateTime">last access time</see>.472    /// </summary>473    public DateTime LastAccessTime290    #region Instance Fields291    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    #endregion296  }297298  /// <summary>299  /// Class handling NT date time values.300  /// </summary>301  public class NTTaggedData : ITaggedData302  {303    /// <summary>304    /// Get the ID for this tagged data value.305    /// </summary>306    public short TagID { + 1307      get { return 10; }308    }309310    /// <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    }343344    /// <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    }362363    /// <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 Intel370    /// (least significant byte first) byte order. They determine the371    /// 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 limit373    /// </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    }384385    /// <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    }397398    /// <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    }410411    /// <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    }423424    #region Instance Fields + 1425    DateTime _lastAccessTime = DateTime.FromFileTimeUtc(0); + 1426    DateTime _lastModificationTime = DateTime.FromFileTimeUtc(0); + 1427    DateTime _createTime = DateTime.FromFileTimeUtc(0);428    #endregion429  }430431  /// <summary>432  /// A factory that creates <see cref="ITaggedData">tagged data</see> instances.433  /// </summary>434  interface ITaggedDataFactory435  {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  }446447  ///448  /// <summary>449  /// A class to handle the extra data field for Zip entries450  /// </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 but455  /// means that for extra data created by passing in data can have the values modified by the caller456  /// in some circumstances.457  /// </remarks>458  sealed public class ZipExtraData : IDisposable459  {460    #region Constructors461    /// <summary>462    /// Initialise a default instance.463    /// </summary>464    public ZipExtraData()465    {466      Clear();467    }468469    /// <summary>470    /// Initialise with known extra data.471    /// </summary>472    /// <param name="data">The extra data.</param>473    public ZipExtraData(byte[] data)  474    { - 0475      get { return _lastAccessTime; }476      set { - 1477         if (!IsValidValue(value)) { - 0478          throw new ArgumentOutOfRangeException(nameof(value));479        } - 1480        _lastAccessTime = value; - 1481      }482    }483484    #region Instance Fields - 1485    DateTime _lastAccessTime = DateTime.FromFileTime(0); - 1486    DateTime _lastModificationTime = DateTime.FromFileTime(0); - 1487    DateTime _createTime = DateTime.FromFileTime(0);488    #endregion489  }490491  /// <summary>492  /// A factory that creates <see cref="ITaggedData">tagged data</see> instances.493  /// </summary>494  interface ITaggedDataFactory495  {475      if (data == null) {476        _data = new byte[0];477      } else {478        _data = data;479      }480    }481    #endregion482483    /// <summary>484    /// Get the raw extra data value485    /// </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      }492493      return (byte[])_data.Clone();494    }495  496    /// <summary>497    /// Get data for a specific tag value.497    /// Clear the stored data.  498    /// </summary>499    /// <param name="tag">The tag ID to find.</param>500    /// <param name="data">The data to search.</param>501    /// <param name="offset">The offset to begin extracting data from.</param>502    /// <param name="count">The number of bytes to extract.</param>503    /// <returns>The located <see cref="ITaggedData">value found</see>, or null if not found.</returns>504    ITaggedData Create(short tag, byte[] data, int offset, int count);505  }506507  ///508  /// <summary>509  /// A class to handle the extra data field for Zip entries510  /// </summary>511  /// <remarks>512  /// Extra data contains 0 or more values each prefixed by a header tag and length.513  /// They contain zero or more bytes of actual data.514  /// The data is held internally using a copy on write strategy.  This is more efficient but515  /// means that for extra data created by passing in data can have the values modified by the caller516  /// in some circumstances.517  /// </remarks>518  sealed public class ZipExtraData : IDisposable519  {520    #region Constructors521    /// <summary>522    /// Initialise a default instance.523    /// </summary>524    public ZipExtraData()525    {526      Clear();527    }528529    /// <summary>530    /// Initialise with known extra data.531    /// </summary>532    /// <param name="data">The extra data.</param>533    public ZipExtraData(byte[] data)499    public void Clear()500    {501      if ((_data == null) || (_data.Length != 0)) {502        _data = new byte[0];503      }504    }505506    /// <summary>507    /// Gets the current extra data length.508    /// </summary>509    public int Length {510      get { return _data.Length; }511    }512513    /// <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    }526527    /// <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      if ( data == null )536      {537        _data = new byte[0];538      }539      else540      {541        _data = data;542      }543    }544    #endregion545546    /// <summary>547    /// Get the raw extra data value548    /// </summary>549    /// <returns>Returns the raw byte[] extra data this instance represents.</returns>550    public byte[] GetEntryData()551    {552      if ( Length > ushort.MaxValue ) {553        throw new ZipException("Data exceeds maximum length");554      }555556      return (byte[])_data.Clone();557    }558559    /// <summary>560    /// Clear the stored data.561    /// </summary>562    public void Clear()563    {564      if ( (_data == null) || (_data.Length != 0) ) {565        _data = new byte[0];566      }567    }568569    /// <summary>570    /// Gets the current extra data length.571    /// </summary>572    public int Length573    {574      get { return _data.Length; }575    }576577    /// <summary>578    /// Get a read-only <see cref="Stream"/> for the associated tag.579    /// </summary>580    /// <param name="tag">The tag to locate data for.</param>581    /// <returns>Returns a <see cref="Stream"/> containing tag data or null if no tag was found.</returns>582    public Stream GetStreamForTag(int tag)583    {584      Stream result = null;585      if ( Find(tag) ) {586        result = new MemoryStream(_data, _index, _readValueLength, false);587      }588      return result;589    }590591    /// <summary>592    /// Get the <see cref="ITaggedData">tagged data</see> for a tag.593    /// </summary>594    /// <param name="tag">The tag to search for.</param>595    /// <returns>Returns a <see cref="ITaggedData">tagged value</see> or null if none found.</returns>596    private ITaggedData GetData(short tag)597    {598      ITaggedData result = null;599      if (Find(tag))600      {601        result = Create(tag, _data, _readValueStart, _readValueLength);602      }603      return result;604    }605606    static ITaggedData Create(short tag, byte[] data, int offset, int count)607    {608      ITaggedData result = null;609      switch ( tag )610      {611        case 0x000A:612          result = new NTTaggedData();613          break;614        case 0x5455:615          result = new ExtendedUnixData();616          break;617        default:618          result = new RawTaggedData(tag);619          break;620      }621      result.SetData(data, offset, count);622      return result;623    }624625    /// <summary>626    /// Get the length of the last value found by <see cref="Find"/>627    /// </summary>628    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.</remarks>629    public int ValueLength630    {631      get { return _readValueLength; }632    }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    }543544    /// <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    }551552    /// <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 to557    /// <see cref="ReadInt"/>, <see cref="ReadShort"/> and <see cref="ReadLong"/>. </remarks>558    public int CurrentReadIndex {559      get { return _index; }560    }561562    /// <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        }571572        return _readValueStart + _readValueLength - _index;573      }574    }575576    /// <summary>577    /// Find an extra data value578    /// </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;586587      int localLength = _readValueStart;588      int localTag = headerID - 1;589590      // Trailing bytes that cant make up an entry (as there arent enough591      // 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      }599600      bool result = (localTag == headerID) && ((_index + localLength) <= _data.Length);601602      if (result) {603        _readValueStart = _index;604        _readValueLength = localLength;605      }606607      return result;608    }609610    /// <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    }621622    /// <summary>623    /// Add a new entry to extra data624    /// </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      }  633634    /// <summary>635    /// Get the index for the current read value.636    /// </summary>637    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.638    /// Initially the result will be the index of the first byte of actual data.  The value is updated after calls to639    /// <see cref="ReadInt"/>, <see cref="ReadShort"/> and <see cref="ReadLong"/>. </remarks>640    public int CurrentReadIndex641    {642      get { return _index; }643    }644645    /// <summary>646    /// Get the number of bytes remaining to be read for the current value;647    /// </summary>648    public int UnreadCount649    {650      get651      {652        if ((_readValueStart > _data.Length) ||653          (_readValueStart < 4) ) {654          throw new ZipException("Find must be called before calling a Read method");655        }656657        return _readValueStart + _readValueLength - _index;658      }659    }660661    /// <summary>662    /// Find an extra data value663    /// </summary>664    /// <param name="headerID">The identifier for the value to find.</param>665    /// <returns>Returns true if the value was found; false otherwise.</returns>666    public bool Find(int headerID)667    {668      _readValueStart = _data.Length;669      _readValueLength = 0;670      _index = 0;671672      int localLength = _readValueStart;673      int localTag = headerID - 1;634      int addLength = (fieldData == null) ? 0 : fieldData.Length;635636      if (addLength > ushort.MaxValue) {637        throw new ArgumentOutOfRangeException(nameof(fieldData), "exceeds maximum length");638      }639640      // Test for new length before adjusting data.641      int newLength = _data.Length + addLength + 4;642643      if (Find(headerID)) {644        newLength -= (ValueLength + 4);645      }646647      if (newLength > ushort.MaxValue) {648        throw new ZipException("Data exceeds maximum length");649      }650651      Delete(headerID);652653      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    }663664    /// <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 <see668    /// 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    }  674675      // Trailing bytes that cant make up an entry (as there arent enough676      // bytes for a tag and length) are ignored!677      while ( (localTag != headerID) && (_index < _data.Length - 3) ) {678        localTag = ReadShortInternal();679        localLength = ReadShortInternal();680        if ( localTag != headerID ) {681          _index += localLength;682        }683      }684685      bool result = (localTag == headerID) && ((_index + localLength) <= _data.Length);686687      if ( result ) {688        _readValueStart = _index;689        _readValueLength = localLength;690      }691692      return result;693    }694695    /// <summary>696    /// Add a new entry to extra data.697    /// </summary>698    /// <param name="taggedData">The <see cref="ITaggedData"/> value to add.</param>699    public void AddEntry(ITaggedData taggedData)700    {701      if (taggedData == null)702      {703        throw new ArgumentNullException(nameof(taggedData));704      }705      AddEntry(taggedData.TagID, taggedData.GetData());706    }707708    /// <summary>709    /// Add a new entry to extra data710    /// </summary>711    /// <param name="headerID">The ID for this entry.</param>712    /// <param name="fieldData">The data to add.</param>713    /// <remarks>If the ID already exists its contents are replaced.</remarks>714    public void AddEntry(int headerID, byte[] fieldData)715    {716      if ( (headerID > ushort.MaxValue) || (headerID < 0)) {717        throw new ArgumentOutOfRangeException(nameof(headerID));718      }719720      int addLength = (fieldData == null) ? 0 : fieldData.Length;721722      if ( addLength > ushort.MaxValue ) {723#if NETCF_1_0724        throw new ArgumentOutOfRangeException("fieldData");725#else726        throw new ArgumentOutOfRangeException(nameof(fieldData), "exceeds maximum length");727#endif728      }729730      // Test for new length before adjusting data.731      int newLength = _data.Length + addLength + 4;732733      if ( Find(headerID) )734      {735        newLength -= (ValueLength + 4);736      }737738      if ( newLength > ushort.MaxValue ) {739        throw new ZipException("Data exceeds maximum length");740      }741742      Delete(headerID);743744      byte[] newData = new byte[newLength];745      _data.CopyTo(newData, 0);746      int index = _data.Length;747      _data = newData;748      SetShort(ref index, headerID);749      SetShort(ref index, addLength);750      if ( fieldData != null ) {751        fieldData.CopyTo(newData, index);752      }753    }754755    /// <summary>756    /// Start adding a new entry.757    /// </summary>758    /// <remarks>Add data using <see cref="AddData(byte[])"/>, <see cref="AddLeShort"/>, <see cref="AddLeInt"/>, or <see759    /// The new entry is completed and actually added by calling <see cref="AddNewEntry"/></remarks>760    /// <seealso cref="AddEntry(ITaggedData)"/>761    public void StartNewEntry()762    {763      _newEntry = new MemoryStream();764    }765766    /// <summary>767    /// Add entry data added since <see cref="StartNewEntry"/> using the ID passed.768    /// </summary>769    /// <param name="headerID">The identifier to use for this entry.</param>770    public void AddNewEntry(int headerID)771    {772      byte[] newData = _newEntry.ToArray();773      _newEntry = null;774      AddEntry(headerID, newData);775    }776777    /// <summary>778    /// Add a byte of data to the pending new entry.779    /// </summary>780    /// <param name="data">The byte to add.</param>781    /// <seealso cref="StartNewEntry"/>782    public void AddData(byte data)783    {784      _newEntry.WriteByte(data);785    }786787    /// <summary>788    /// Add data to a pending new entry.789    /// </summary>790    /// <param name="data">The data to add.</param>791    /// <seealso cref="StartNewEntry"/>792    public void AddData(byte[] data)793    {794      if ( data == null ) {795        throw new ArgumentNullException(nameof(data));796      }797798      _newEntry.Write(data, 0, data.Length);799    }800801    /// <summary>802    /// Add a short value in little endian order to the pending new entry.803    /// </summary>804    /// <param name="toAdd">The data to add.</param>805    /// <seealso cref="StartNewEntry"/>806    public void AddLeShort(int toAdd)807    {808      unchecked {809        _newEntry.WriteByte(( byte )toAdd);810        _newEntry.WriteByte(( byte )(toAdd >> 8));811      }812    }813814    /// <summary>815    /// Add an integer value in little endian order to the pending new entry.816    /// </summary>817    /// <param name="toAdd">The data to add.</param>818    /// <seealso cref="StartNewEntry"/>819    public void AddLeInt(int toAdd)820    {821      unchecked {822        AddLeShort(( short )toAdd);823        AddLeShort(( short )(toAdd >> 16));824      }825    }826827    /// <summary>828    /// Add a long value in little endian order to the pending new entry.829    /// </summary>830    /// <param name="toAdd">The data to add.</param>831    /// <seealso cref="StartNewEntry"/>832    public void AddLeLong(long toAdd)833    {834      unchecked {835        AddLeInt(( int )(toAdd & 0xffffffff));836        AddLeInt(( int )(toAdd >> 32));837      }838    }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    }685686    /// <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    }695696    /// <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      }706707      _newEntry.Write(data, 0, data.Length);708    }709710    /// <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    }722723    /// <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    }735736    /// <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    }748749    /// <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;757758      if (Find(headerID)) {759        result = true;760        int trueStart = _readValueStart - 4;761762        byte[] newData = new byte[_data.Length - (ValueLength + 4)];763        Array.Copy(_data, 0, newData, 0, trueStart);764765        int trueEnd = trueStart + ValueLength + 4;766        Array.Copy(_data, trueEnd, newData, trueStart, _data.Length - trueEnd);767        _data = newData;768      }769      return result;770    }771772    #region Reading Support773    /// <summary>774    /// Read a long in little endian form from the last <see cref="Find">found</see> data value775    /// </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    }782783    /// <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);790791      int result = _data[_index] + (_data[_index + 1] << 8) +792        (_data[_index + 2] << 16) + (_data[_index + 3] << 24);793      _index += 4;794      return result;795    }796797    /// <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    }808809    /// <summary>810    /// Read a byte from an extra data811    /// </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    }822823    /// <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    }832833    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      }  839840    /// <summary>841    /// Delete an extra data field.842    /// </summary>843    /// <param name="headerID">The identifier of the field to delete.</param>844    /// <returns>Returns true if the field was found and deleted.</returns>845    public bool Delete(int headerID)846    {847      bool result = false;840      if (_index > _readValueStart + _readValueLength - length) {841        throw new ZipException("End of extra data");842      }843844      if (_index + length < 4) {845        throw new ZipException("Cannot read before start of tag");846      }847    }  848849      if ( Find(headerID) ) {850        result = true;851        int trueStart = _readValueStart - 4;852853        byte[] newData = new byte[_data.Length - (ValueLength + 4)];854        Array.Copy(_data, 0, newData, 0, trueStart);855856        int trueEnd = trueStart + ValueLength + 4;857        Array.Copy(_data, trueEnd, newData, trueStart, _data.Length - trueEnd);858        _data = newData;859      }860      return result;861    }862863    #region Reading Support864    /// <summary>865    /// Read a long in little endian form from the last <see cref="Find">found</see> data value866    /// </summary>867    /// <returns>Returns the long value read.</returns>868    public long ReadLong()869    {870      ReadCheck(8);871      return (ReadInt() & 0xffffffff) | ((( long )ReadInt()) << 32);872    }873874    /// <summary>875    /// Read an integer in little endian form from the last <see cref="Find">found</see> data value.876    /// </summary>877    /// <returns>Returns the integer read.</returns>878    public int ReadInt()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      }858859      int result = _data[_index] + (_data[_index + 1] << 8);860      _index += 2;861      return result;862    }863864    void SetShort(ref int index, int source)865    {866      _data[index] = (byte)source;867      _data[index + 1] = (byte)(source >> 8);868      index += 2;869    }870871    #endregion872873    #region IDisposable Members874875    /// <summary>876    /// Dispose of this instance.877    /// </summary>878    public void Dispose()  879    {880      ReadCheck(4);881882      int result = _data[_index] + (_data[_index + 1] << 8) +883        (_data[_index + 2] << 16) + (_data[_index + 3] << 24);884      _index += 4;885      return result;886    }887888    /// <summary>889    /// Read a short value in little endian form from the last <see cref="Find">found</see> data value.890    /// </summary>891    /// <returns>Returns the short value read.</returns>892    public int ReadShort()893    {894      ReadCheck(2);895      int result = _data[_index] + (_data[_index + 1] << 8);896      _index += 2;897      return result;898    }899900    /// <summary>901    /// Read a byte from an extra data902    /// </summary>903    /// <returns>The byte value read or -1 if the end of data has been reached.</returns>904    public int ReadByte()905    {906      int result = -1;907      if ( (_index < _data.Length) && (_readValueStart + _readValueLength > _index) ) {908        result = _data[_index];909        _index += 1;910      }911      return result;912    }913914    /// <summary>915    /// Skip data during reading.916    /// </summary>917    /// <param name="amount">The number of bytes to skip.</param>918    public void Skip(int amount)919    {920      ReadCheck(amount);921      _index += amount;922    }923924    void ReadCheck(int length)925    {926      if ((_readValueStart > _data.Length) ||927        (_readValueStart < 4) ) {928        throw new ZipException("Find must be called before calling a Read method");929      }930931      if (_index > _readValueStart + _readValueLength - length ) {932        throw new ZipException("End of extra data");933      }934935            if ( _index + length < 4 ) {936                throw new ZipException("Cannot read before start of tag");937            }938    }939940    /// <summary>941    /// Internal form of <see cref="ReadShort"/> that reads data at any location.942    /// </summary>943    /// <returns>Returns the short value read.</returns>944    int ReadShortInternal()945    {946      if ( _index > _data.Length - 2) {947        throw new ZipException("End of extra data");948      }949950      int result = _data[_index] + (_data[_index + 1] << 8);951      _index += 2;952      return result;953    }954955    void SetShort(ref int index, int source)956    {957      _data[index] = (byte)source;958      _data[index + 1] = (byte)(source >> 8);959      index += 2;960    }961962    #endregion963964    #region IDisposable Members965966    /// <summary>967    /// Dispose of this instance.968    /// </summary>969    public void Dispose()970    {971      if ( _newEntry != null ) {972        _newEntry.Close();973      }974    }975976    #endregion977978    #region Instance Fields979    int _index;980    int _readValueStart;981    int _readValueLength;982983    MemoryStream _newEntry;984    byte[] _data;985    #endregion986  }987}880      if (_newEntry != null) {881        _newEntry.Close();882      }883    }884885    #endregion886887    #region Instance Fields888    int _index;889    int _readValueStart;890    int _readValueLength;891892    MemoryStream _newEntry;893    byte[] _data;894    #endregion895  }896} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_NameAndSizeFilter.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_NameAndSizeFilter.htm index 950015f32..77bfa8bd7 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_NameAndSizeFilter.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_NameAndSizeFilter.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:23 Coverable lines:23 -Total lines:336 +Total lines:280 Line coverage:0% Branch coverage:0% @@ -36,344 +36,288 @@

#LineLine coverage - 1// PathFilter.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;37using System.IO;3839namespace ICSharpCode.SharpZipLib.Core40{41  /// <summary>42  /// PathFilter filters directories and files using a form of <see cref="System.Text.RegularExpressions.Regex">regular 43  /// by full path name.44  /// See <see cref="NameFilter">NameFilter</see> for more detail on filtering.45  /// </summary>46  public class PathFilter : IScanFilter47  {48    #region Constructors49    /// <summary>50    /// Initialise a new instance of <see cref="PathFilter"></see>.51    /// </summary>52    /// <param name="filter">The <see cref="NameFilter">filter</see> expression to apply.</param>53    public PathFilter(string filter)54    {55      nameFilter_ = new NameFilter(filter);56    }57    #endregion5859    #region IScanFilter Members60    /// <summary>61    /// Test a name to see if it matches the filter.62    /// </summary>63    /// <param name="name">The name to test.</param>64    /// <returns>True if the name matches, false otherwise.</returns>65    /// <remarks><see cref="Path.GetFullPath(string)"/> is used to get the full path before matching.</remarks>66    public virtual bool IsMatch(string name)67    {68      bool result = false;6970      if ( name != null ) {71        string cooked = (name.Length > 0) ? Path.GetFullPath(name) : "";72        result = nameFilter_.IsMatch(cooked);73      }74      return result;75    }7677    readonly78    #endregion7980    #region Instance Fields81    NameFilter nameFilter_;82    #endregion83  }1using System;2using System.IO;34namespace ICSharpCode.SharpZipLib.Core5{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 : IScanFilter12  {13    #region Constructors14    /// <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    #endregion2324    #region IScanFilter Members25    /// <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;3435      if (name != null) {36        string cooked = (name.Length > 0) ? Path.GetFullPath(name) : "";37        result = nameFilter_.IsMatch(cooked);38      }39      return result;40    }4142    readonly43    #endregion4445    #region Instance Fields46    NameFilter nameFilter_;47    #endregion48  }4950  /// <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 : PathFilter55  {56    #region Constructors57    /// <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    }7071    /// <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    }  8485  /// <summary>86  /// ExtendedPathFilter filters based on name, file size, and the last write time of the file.87  /// </summary>88  /// <remarks>Provides an example of how to customise filtering.</remarks>89  public class ExtendedPathFilter : PathFilter90  {91    #region Constructors92    /// <summary>93    /// Initialise a new instance of ExtendedPathFilter.94    /// </summary>95    /// <param name="filter">The filter to apply.</param>96    /// <param name="minSize">The minimum file size to include.</param>97    /// <param name="maxSize">The maximum file size to include.</param>98    public ExtendedPathFilter(string filter,99      long minSize, long maxSize)100      : base(filter)101    {102      MinSize = minSize;103      MaxSize = maxSize;104    }10585    /// <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    #endregion104105    #region IScanFilter Members  106    /// <summary>107    /// Initialise a new instance of ExtendedPathFilter.107    /// Test a filename to see if it matches the filter.  108    /// </summary>109    /// <param name="filter">The filter to apply.</param>110    /// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>111    /// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>112    public ExtendedPathFilter(string filter,113      DateTime minDate, DateTime maxDate)114      : base(filter)115    {116      MinDate = minDate;117      MaxDate = maxDate;118    }119120    /// <summary>121    /// Initialise a new instance of ExtendedPathFilter.122    /// </summary>123    /// <param name="filter">The filter to apply.</param>124    /// <param name="minSize">The minimum file size to include.</param>125    /// <param name="maxSize">The maximum file size to include.</param>126    /// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>127    /// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>128    public ExtendedPathFilter(string filter,129      long minSize, long maxSize,130      DateTime minDate, DateTime maxDate)131      : base(filter)132    {133      MinSize = minSize;134      MaxSize = maxSize;135      MinDate = minDate;136      MaxDate = maxDate;137    }138    #endregion139140    #region IScanFilter Members141    /// <summary>142    /// Test a filename to see if it matches the filter.143    /// </summary>144    /// <param name="name">The filename to test.</param>145    /// <returns>True if the filter matches, false otherwise.</returns>146    /// <exception cref="System.IO.FileNotFoundException">The <see paramref="fileName"/> doesnt exist</exception>147    public override bool IsMatch(string name)148    {149      bool result = base.IsMatch(name);150151      if ( result ) {152        var fileInfo = new FileInfo(name);153        result =154          (MinSize <= fileInfo.Length) &&155          (MaxSize >= fileInfo.Length) &&156          (MinDate <= fileInfo.LastWriteTime) &&157          (MaxDate >= fileInfo.LastWriteTime)158          ;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);115116      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    #endregion128129    #region Properties130    /// <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"/></excep135    public long MinSize {136      get { return minSize_; }137      set {138        if ((value < 0) || (maxSize_ < value)) {139          throw new ArgumentOutOfRangeException(nameof(value));140        }141142        minSize_ = value;143      }144    }145146    /// <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"/></except151    public long MaxSize {152      get { return maxSize_; }153      set {154        if ((value < 0) || (minSize_ > value)) {155          throw new ArgumentOutOfRangeException(nameof(value));156        }157158        maxSize_ = value;  159      }160      return result;161    }162    #endregion163164    #region Properties165    /// <summary>166    /// Get/set the minimum size/length for a file that will match this filter.167    /// </summary>168    /// <remarks>The default value is zero.</remarks>169    /// <exception cref="ArgumentOutOfRangeException">value is less than zero; greater than <see cref="MaxSize"/></excep170    public long MinSize171    {172      get { return minSize_; }173      set174      {175        if ( (value < 0) || (maxSize_ < value) ) {176          throw new ArgumentOutOfRangeException(nameof(value));177        }178179        minSize_ = value;180      }181    }182183    /// <summary>184    /// Get/set the maximum size/length for a file that will match this filter.185    /// </summary>186    /// <remarks>The default value is <see cref="System.Int64.MaxValue"/></remarks>187    /// <exception cref="ArgumentOutOfRangeException">value is less than zero or less than <see cref="MinSize"/></except188    public long MaxSize189    {190      get { return maxSize_; }191      set192      {193        if ( (value < 0) || (minSize_ > value) ) {194          throw new ArgumentOutOfRangeException(nameof(value));195        }196197        maxSize_ = value;198      }199    }200201    /// <summary>202    /// Get/set the minimum <see cref="DateTime"/> value that will match for this filter.203    /// </summary>204    /// <remarks>Files with a LastWrite time less than this value are excluded by the filter.</remarks>205    public DateTime MinDate206    {207      get208      {209        return minDate_;210      }211212      set213      {214        if ( value > maxDate_ ) {215#if NETCF_1_0216          throw new ArgumentOutOfRangeException("value");217#else218          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MaxDate");219#endif220        }221222        minDate_ = value;223      }224    }225226    /// <summary>227    /// Get/set the maximum <see cref="DateTime"/> value that will match for this filter.228    /// </summary>229    /// <remarks>Files with a LastWrite time greater than this value are excluded by the filter.</remarks>230    public DateTime MaxDate231    {232      get233      {234        return maxDate_;235      }160    }161162    /// <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      }170171      set {172        if (value > maxDate_) {173          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MaxDate");174        }175176        minDate_ = value;177      }178    }179180    /// <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      }188189      set {190        if (minDate_ > value) {191          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MinDate");192        }193194        maxDate_ = value;195      }196    }197    #endregion198199    #region Instance Fields200    long minSize_;201    long maxSize_ = long.MaxValue;202    DateTime minDate_ = DateTime.MinValue;203    DateTime maxDate_ = DateTime.MaxValue;204    #endregion205  }206207  /// <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 : PathFilter213  {214215    /// <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    }227228    /// <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);  236237      set238      {239        if ( minDate_ > value ) {240#if NETCF_1_0241          throw new ArgumentOutOfRangeException("value");242#else243          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MinDate");244#endif245        } + 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    }  246247        maxDate_ = value;248      }249    }250    #endregion251252    #region Instance Fields253    long minSize_;254    long maxSize_ = long.MaxValue;255    DateTime minDate_ = DateTime.MinValue;256    DateTime maxDate_ = DateTime.MaxValue;257    #endregion258  }259260  /// <summary>261  /// NameAndSizeFilter filters based on name and file size.262  /// </summary>263  /// <remarks>A sample showing how filters might be extended.</remarks>264  [Obsolete("Use ExtendedPathFilter instead")]265  public class NameAndSizeFilter : PathFilter266  {267268    /// <summary>269    /// Initialise a new instance of NameAndSizeFilter.270    /// </summary>271    /// <param name="filter">The filter to apply.</param>272    /// <param name="minSize">The minimum file size to include.</param>273    /// <param name="maxSize">The maximum file size to include.</param>274    public NameAndSizeFilter(string filter, long minSize, long maxSize) - 0275      : base(filter)276    { - 0277      MinSize = minSize; - 0278      MaxSize = maxSize; - 0279    }280281    /// <summary>282    /// Test a filename to see if it matches the filter.283    /// </summary>284    /// <param name="name">The filename to test.</param>285    /// <returns>True if the filter matches, false otherwise.</returns>286    public override bool IsMatch(string name)287    { - 0288      bool result = base.IsMatch(name);289 - 0290       if ( result ) { - 0291        var fileInfo = new FileInfo(name); - 0292        long length = fileInfo.Length; - 0293        result = - 0294          (MinSize <= length) && - 0295          (MaxSize >= length);296      } - 0297      return result;298    }299300    /// <summary>301    /// Get/set the minimum size for a file that will match this filter.302    /// </summary>303    public long MinSize304    { - 0305      get { return minSize_; }306      set { - 0307         if ( (value < 0) || (maxSize_ < value) ) { - 0308          throw new ArgumentOutOfRangeException(nameof(value));309        }310 - 0311        minSize_ = value; - 0312      }313    }314315    /// <summary>316    /// Get/set the maximum size for a file that will match this filter.317    /// </summary>318    public long MaxSize319    { - 0320      get { return maxSize_; }321      set322      { - 0323         if ( (value < 0) || (minSize_ > value) ) { - 0324          throw new ArgumentOutOfRangeException(nameof(value));325        }326 - 0327        maxSize_ = value; - 0328      }329    }330331    #region Instance Fields332    long minSize_; - 0333    long maxSize_ = long.MaxValue;334    #endregion335  }336}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    }260261    /// <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    }274275    #region Instance Fields276    long minSize_; + 0277    long maxSize_ = long.MaxValue;278    #endregion279  }280} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_NameFilter.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_NameFilter.htm index 0673704e1..86343fd9a 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_NameFilter.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_NameFilter.htm @@ -15,11 +15,11 @@

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:70 -Uncovered lines:21 -Coverable lines:91 -Total lines:288 -Line coverage:76.9% +Covered lines:68 +Uncovered lines:18 +Coverable lines:86 +Total lines:235 +Line coverage:79% Branch coverage:73.9% @@ -43,296 +43,243 @@

#LineLine coverage - 1// NameFilter.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536// HISTORY37//  2010-03-03  Z-1654  Fixed bug where escape characters were excluded in SplitQuoted()3839using System;40using System.Collections;41using System.Text;42using System.Text.RegularExpressions;4344namespace ICSharpCode.SharpZipLib.Core45{46  /// <summary>47  /// NameFilter is a string matching class which allows for both positive and negative48  /// matching.49  /// A filter is a sequence of independant <see cref="Regex">regular expressions</see> separated by semi-colons ';'.50  /// To include a semi-colon it may be quoted as in \;. Each expression can be prefixed by a plus '+' sign or51  /// a minus '-' sign to denote the expression is intended to include or exclude names.52  /// If neither a plus or minus sign is found include is the default.53  /// A given name is tested for inclusion before checking exclusions.  Only names matching an include spec54  /// and not matching an exclude spec are deemed to match the filter.55  /// An empty filter matches any name.56  /// </summary>57  /// <example>The following expression includes all name ending in '.dat' with the exception of 'dummy.dat'58  /// "+\.dat$;-^dummy\.dat$"59  /// </example>60  public class NameFilter : IScanFilter61  {62    #region Constructors63    /// <summary>64    /// Construct an instance based on the filter expression passed65    /// </summary>66    /// <param name="filter">The filter expression.</param> - 1567    public NameFilter(string filter)68    { - 1569      filter_ = filter; - 1570      inclusions_ = new ArrayList(); - 1571      exclusions_ = new ArrayList(); - 1572      Compile(); - 1573    }74    #endregion7576    /// <summary>77    /// Test a string to see if it is a valid regular expression.78    /// </summary>79    /// <param name="expression">The expression to test.</param>80    /// <returns>True if expression is a valid <see cref="System.Text.RegularExpressions.Regex"/> false otherwise.</retu81    public static bool IsValidExpression(string expression)82    { - 083      bool result = true;84      try { - 085        var exp = new Regex(expression, RegexOptions.IgnoreCase | RegexOptions.Singleline); - 086      } - 087      catch (ArgumentException) { - 088        result = false; - 089      } - 090      return result;91    }9293    /// <summary>94    /// Test an expression to see if it is valid as a filter.95    /// </summary>96    /// <param name="toTest">The filter expression to test.</param>97    /// <returns>True if the expression is valid, false otherwise.</returns>98    public static bool IsValidFilterExpression(string toTest)99    { - 5100      bool result = true;101102      try { - 5103                 if (toTest != null) { - 4104                    string[] items = SplitQuoted(toTest); - 10105                     for (int i = 0; i < items.Length; ++i) { - 3106                         if ((items[i] != null) && (items[i].Length > 0)) {107                            string toCompile;108 - 3109                             if (items[i][0] == '+') { - 0110                                toCompile = items[i].Substring(1, items[i].Length - 1); - 0111                            } - 3112                             else if (items[i][0] == '-') { - 0113                                toCompile = items[i].Substring(1, items[i].Length - 1); - 0114                            }115                            else { - 3116                                toCompile = items[i];117                            }118 - 3119                            var testRegex = new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Singleline);120                        }121                    }122                } - 3123      } - 2124      catch (ArgumentException) { - 2125        result = false; - 2126      }127 - 5128      return result;129    }130131    /// <summary>132    /// Split a string into its component pieces133    /// </summary>134    /// <param name="original">The original string</param>135    /// <returns>Returns an array of <see cref="T:System.String"/> values containing the individual filter elements.</re136    public static string[] SplitQuoted(string original)137    { - 14138      char escape = '\\'; - 14139      char[] separators = { ';' };140 - 14141      var result = new ArrayList();142 - 14143       if (!string.IsNullOrEmpty(original)) { - 12144        int endIndex = -1; - 12145        var b = new StringBuilder();146 - 85147         while (endIndex < original.Length) { - 73148          endIndex += 1; - 73149           if (endIndex >= original.Length) { - 12150            result.Add(b.ToString()); - 12151          } - 61152           else if (original[endIndex] == escape) { - 12153            endIndex += 1; - 12154             if (endIndex >= original.Length) {155#if NETCF_1_0156              throw new ArgumentException("Missing terminating escape character");157#else - 0158              throw new ArgumentException("Missing terminating escape character", nameof(original));159#endif160            }161            // include escape if this is not an escaped separator - 12162             if (Array.IndexOf(separators, original[endIndex]) < 0) - 7163              b.Append(escape);164 - 12165            b.Append(original[endIndex]); - 12166          }167          else { - 49168             if (Array.IndexOf(separators, original[endIndex]) >= 0) { - 11169              result.Add(b.ToString()); - 11170              b.Length = 0; - 11171            }172            else { - 38173              b.Append(original[endIndex]);174            }175          }176        }177      }178 - 14179      return (string[])result.ToArray(typeof(string));180    }181182    /// <summary>183    /// Convert this filter to its string equivalent.184    /// </summary>185    /// <returns>The string equivalent for this filter.</returns>186    public override string ToString()1using System;2using System.Collections;3using System.Text;4using System.Text.RegularExpressions;56namespace ICSharpCode.SharpZipLib.Core7{8  /// <summary>9  /// NameFilter is a string matching class which allows for both positive and negative10  /// 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 or13  /// 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 spec16  /// 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 : IScanFilter23  {24    #region Constructors25    /// <summary>26    /// Construct an instance based on the filter expression passed27    /// </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    #endregion3738    /// <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.</retu43    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    }5354    /// <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;6263      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    }8889    /// <summary>90    /// Split a string into its component pieces91    /// </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.</re94    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    }132133    /// <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    }141142    /// <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    }162163    /// <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    }179180    #region IScanFilter Members181    /// <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    { - 0188      return filter_; + 14148188      return (IsIncluded(name) && !IsExcluded(name));  189    }190191    /// <summary>192    /// Test a value to see if it is included by the filter.193    /// </summary>194    /// <param name="name">The value to test.</param>195    /// <returns>True if the value is included, false otherwise.</returns>196    public bool IsIncluded(string name)197    { - 14086198      bool result = false; - 14086199       if ( inclusions_.Count == 0 ) { - 2200        result = true; - 2201      }202      else { - 56331203        foreach ( Regex r in inclusions_ ) { - 14084204           if ( r.IsMatch(name) ) { - 5205            result = true; - 5206            break;207          }208        }209      } - 14086210      return result;211    }212213    /// <summary>214    /// Test a value to see if it is excluded by the filter.215    /// </summary>216    /// <param name="name">The value to test.</param>217    /// <returns>True if the value is excluded, false otherwise.</returns>218    public bool IsExcluded(string name)219    { - 6220      bool result = false; - 12221      foreach ( Regex r in exclusions_ ) { - 0222         if ( r.IsMatch(name) ) { - 0223          result = true; - 0224          break;190    #endregion191192    /// <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          }216217          // NOTE: Regular expressions can fail to compile here for a number of reasons that cause an exception218          // 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.Singleli224          }  225        }  226      } - 6227      return result;228    }229230    #region IScanFilter Members231    /// <summary>232    /// Test a value to see if it matches the filter.233    /// </summary>234    /// <param name="name">The value to test.</param>235    /// <returns>True if the value matches, false otherwise.</returns>236    public bool IsMatch(string name)237    { - 14085238      return (IsIncluded(name) && !IsExcluded(name));239    }240    #endregion241242    /// <summary>243    /// Compile this filter.244    /// </summary>245    void Compile()246    {247      // TODO: Check to see if combining RE's makes it faster/smaller.248      // simple scheme would be to have one RE for inclusion and one for exclusion. - 15249       if ( filter_ == null ) { - 9250        return;251      }252 - 6253      string[] items = SplitQuoted(filter_); - 24254       for ( int i = 0; i < items.Length; ++i ) { - 6255         if ( (items[i] != null) && (items[i].Length > 0) ) { - 6256          bool include = (items[i][0] != '-');257          string toCompile;258 - 6259           if ( items[i][0] == '+' ) { - 0260            toCompile = items[i].Substring(1, items[i].Length - 1); - 0261          } - 6262           else if ( items[i][0] == '-' ) { - 0263            toCompile = items[i].Substring(1, items[i].Length - 1); - 0264          }265          else { - 6266            toCompile = items[i];267          }268269          // NOTE: Regular expressions can fail to compile here for a number of reasons that cause an exception270          // these are left unhandled here as the caller is responsible for ensuring all is valid.271          // several functions IsValidFilterExpression and IsValidExpression are provided for such checking - 6272           if ( include ) { - 6273            inclusions_.Add(new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleli - 6274          }275          else { - 0276            exclusions_.Add(new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleli277          }278        }279      } - 6280    }281282    #region Instance Fields283    string filter_;284    ArrayList inclusions_;285    ArrayList exclusions_;286    #endregion287  }288} + 5227    }228229    #region Instance Fields230    string filter_;231    ArrayList inclusions_;232    ArrayList exclusions_;233    #endregion234  }235} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_OutputWindow.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_OutputWindow.htm index c3ba72e5a..98eea7b90 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_OutputWindow.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_OutputWindow.htm @@ -18,7 +18,7 @@

Summary

Covered lines:46 Uncovered lines:20 Coverable lines:66 -Total lines:235 +Total lines:195 Line coverage:69.6% Branch coverage:53.3% @@ -44,243 +44,203 @@

#LineLine coverage - 1// OutputWindow.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839using System;1using System;23namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams4{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 stream8  /// to repeat stuff.<br/>9  /// Author of the original java version : John Leuner10  /// </summary>11  public class OutputWindow12  {13    #region Constants14    const int WindowSize = 1 << 15;15    const int WindowMask = WindowSize - 1;16    #endregion1718    #region Instance Fields + 43519    byte[] window = new byte[WindowSize]; //The window is 2^15 bytes20    int windowEnd;21    int windowFilled;22    #endregion2324    /// <summary>25    /// Write a byte to this output window26    /// </summary>27    /// <param name="value">value to write</param>28    /// <exception cref="InvalidOperationException">29    /// if window is full30    /// </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  404142namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams43{4445  /// <summary>46  /// Contains the output from the Inflation process.47  /// We need to have a window so that we can refer backwards into the output stream48  /// to repeat stuff.<br/>49  /// Author of the original java version : John Leuner50  /// </summary>51  public class OutputWindow52  {53    #region Constants54    const int WindowSize = 1 << 15;55    const int WindowMask = WindowSize - 1;56    #endregion5758    #region Instance Fields - 44159    byte[] window = new byte[WindowSize]; //The window is 2^15 bytes60    int windowEnd;61    int windowFilled;62    #endregion41    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    }4950    /// <summary>51    /// Append a byte pattern already in the window itself52    /// </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 window57    /// </exception>58    public void Repeat(int length, int distance)59    { + 9760       if ((windowFilled += length) > WindowSize) { + 061        throw new InvalidOperationException("Window full");62      }  6364    /// <summary>65    /// Write a byte to this output window66    /// </summary>67    /// <param name="value">value to write</param>68    /// <exception cref="InvalidOperationException">69    /// if window is full70    /// </exception>71    public void Write(int value)72    { - 923973       if (windowFilled++ == WindowSize) { - 074        throw new InvalidOperationException("Window full");75      } - 923976      window[windowEnd++] = (byte) value; - 923977      windowEnd &= WindowMask; - 923978    }79 + 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    }  8081    private void SlowRepeat(int repStart, int length, int distance)82    { - 083       while (length-- > 0) { - 084        window[windowEnd++] = window[repStart++]; - 085        windowEnd &= WindowMask; - 086        repStart &= WindowMask;87      } - 088    }8990    /// <summary>91    /// Append a byte pattern already in the window itself92    /// </summary>93    /// <param name="length">length of pattern to copy</param>94    /// <param name="distance">distance from end of window pattern occurs</param>95    /// <exception cref="InvalidOperationException">96    /// If the repeated data overflows the window97    /// </exception>98    public void Repeat(int length, int distance)99    { - 101100       if ((windowFilled += length) > WindowSize) { - 0101        throw new InvalidOperationException("Window full");102      }103 - 101104      int repStart = (windowEnd - distance) & WindowMask; - 101105      int border = WindowSize - length; - 101106       if ( (repStart <= border) && (windowEnd < border) ) { - 101107         if (length <= distance) { - 39108          System.Array.Copy(window, repStart, window, windowEnd, length); - 39109          windowEnd += length; - 39110        } else {111          // We have to copy manually, since the repeat pattern overlaps. - 11470112           while (length-- > 0) { - 11408113            window[windowEnd++] = window[repStart++];114          }115        } - 62116      } else { - 0117        SlowRepeat(repStart, length, distance);118      } - 0119    }120121    /// <summary>122    /// Copy from input manipulator to internal window123    /// </summary>124    /// <param name="input">source of data</param>125    /// <param name="length">length of data to copy</param>126    /// <returns>the number of bytes copied</returns>127    public int CopyStored(StreamManipulator input, int length)128    { - 2335129      length = Math.Min(Math.Min(length, WindowSize - windowFilled), input.AvailableBytes);130      int copied;131 - 2335132      int tailLen = WindowSize - windowEnd; - 2335133       if (length > tailLen) { - 99134        copied = input.CopyBytes(window, windowEnd, tailLen); - 99135         if (copied == tailLen) { - 99136          copied += input.CopyBytes(window, 0, length - tailLen);137        } - 99138      } else { - 2236139        copied = input.CopyBytes(window, windowEnd, length);140      }141 - 2335142      windowEnd = (windowEnd + copied) & WindowMask; - 2335143      windowFilled += copied; - 2335144      return copied;145    }146147    /// <summary>148    /// Copy dictionary to window149    /// </summary>150    /// <param name="dictionary">source dictionary</param>151    /// <param name="offset">offset of start in source dictionary</param>152    /// <param name="length">length of dictionary</param>153    /// <exception cref="InvalidOperationException">154    /// If window isnt empty155    /// </exception>156    public void CopyDict(byte[] dictionary, int offset, int length)157    { - 0158       if ( dictionary == null ) { - 0159        throw new ArgumentNullException(nameof(dictionary));160      }161 - 0162       if (windowFilled > 0) { - 0163        throw new InvalidOperationException();164      }165 - 0166       if (length > WindowSize) { - 0167        offset += length - WindowSize; - 0168        length = WindowSize;81    /// <summary>82    /// Copy from input manipulator to internal window83    /// </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    }106107    /// <summary>108    /// Copy dictionary to window109    /// </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 empty115    /// </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    }133134    /// <summary>135    /// Get remaining unfilled space in window136    /// </summary>137    /// <returns>Number of bytes left in window</returns>138    public int GetFreeSpace()139    { + 371140      return WindowSize - windowFilled;141    }142143    /// <summary>144    /// Get bytes available for output in window145    /// </summary>146    /// <returns>Number of bytes filled</returns>147    public int GetAvailable()148    { + 3783149      return windowFilled;150    }151152    /// <summary>153    /// Copy contents of window to output154    /// </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 occurs161    /// </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      } - 0170      System.Array.Copy(dictionary, offset, window, 0, length); - 0171      windowEnd = length & WindowMask; - 0172    }170 + 4523171      int copied = len; + 4523172      int tailLen = len - copyEnd;  173174    /// <summary>175    /// Get remaining unfilled space in window176    /// </summary>177    /// <returns>Number of bytes left in window</returns>178    public int GetFreeSpace()179    { - 373180      return WindowSize - windowFilled;181    }182183    /// <summary>184    /// Get bytes available for output in window185    /// </summary>186    /// <returns>Number of bytes filled</returns>187    public int GetAvailable()188    { - 3836189      return windowFilled;190    }191192    /// <summary>193    /// Copy contents of window to output194    /// </summary>195    /// <param name="output">buffer to copy to</param>196    /// <param name="offset">offset to start at</param>197    /// <param name="len">number of bytes to count</param>198    /// <returns>The number of bytes copied</returns>199    /// <exception cref="InvalidOperationException">200    /// If a window underflow occurs201    /// </exception>202    public int CopyOutput(byte[] output, int offset, int len)203    { - 4599204      int copyEnd = windowEnd; - 4599205       if (len > windowFilled) { - 4469206        len = windowFilled; - 4469207      } else { - 130208        copyEnd = (windowEnd - windowFilled + len) & WindowMask;209      }210 - 4599211      int copied = len; - 4599212      int tailLen = len - copyEnd;213 - 4599214       if (tailLen > 0) { - 105215        System.Array.Copy(window, WindowSize - tailLen, output, offset, tailLen); - 105216        offset += tailLen; - 105217        len = copyEnd;218      } - 4599219      System.Array.Copy(window, copyEnd - len, output, offset, len); - 4599220      windowFilled -= copied; - 4599221       if (windowFilled < 0) { - 0222        throw new InvalidOperationException();223      } - 4599224      return copied;225    }226227    /// <summary>228    /// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see> returns 0229    /// </summary>230    public void Reset()231    { - 44232      windowFilled = windowEnd = 0; - 44233    }234  }235} + 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    }186187    /// <summary>188    /// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see> returns 0189    /// </summary>190    public void Reset()191    { + 41192      windowFilled = windowEnd = 0; + 41193    }194  }195} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_PathFilter.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_PathFilter.htm index aca5daf6d..b72a9e78e 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_PathFilter.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_PathFilter.htm @@ -18,7 +18,7 @@

Summary

Covered lines:8 Uncovered lines:0 Coverable lines:8 -Total lines:336 +Total lines:280 Line coverage:100% Branch coverage:50% @@ -36,344 +36,288 @@

#LineLine coverage - 1// PathFilter.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;37using System.IO;3839namespace ICSharpCode.SharpZipLib.Core40{41  /// <summary>42  /// PathFilter filters directories and files using a form of <see cref="System.Text.RegularExpressions.Regex">regular 43  /// by full path name.44  /// See <see cref="NameFilter">NameFilter</see> for more detail on filtering.45  /// </summary>46  public class PathFilter : IScanFilter47  {48    #region Constructors49    /// <summary>50    /// Initialise a new instance of <see cref="PathFilter"></see>.51    /// </summary>52    /// <param name="filter">The <see cref="NameFilter">filter</see> expression to apply.</param> - 1253    public PathFilter(string filter)54    { - 1255      nameFilter_ = new NameFilter(filter); - 1256    }57    #endregion5859    #region IScanFilter Members60    /// <summary>61    /// Test a name to see if it matches the filter.62    /// </summary>63    /// <param name="name">The name to test.</param>64    /// <returns>True if the name matches, false otherwise.</returns>65    /// <remarks><see cref="Path.GetFullPath(string)"/> is used to get the full path before matching.</remarks>66    public virtual bool IsMatch(string name)67    { - 1408468      bool result = false;69 - 1408470       if ( name != null ) { - 1408471         string cooked = (name.Length > 0) ? Path.GetFullPath(name) : ""; - 1408472        result = nameFilter_.IsMatch(cooked);73      } - 1408474      return result;75    }7677    readonly78    #endregion7980    #region Instance Fields81    NameFilter nameFilter_;82    #endregion83  }1using System;2using System.IO;34namespace ICSharpCode.SharpZipLib.Core5{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 : IScanFilter12  {13    #region Constructors14    /// <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    #endregion2324    #region IScanFilter Members25    /// <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    }4142    readonly43    #endregion4445    #region Instance Fields46    NameFilter nameFilter_;47    #endregion48  }4950  /// <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 : PathFilter55  {56    #region Constructors57    /// <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    }7071    /// <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    }  8485  /// <summary>86  /// ExtendedPathFilter filters based on name, file size, and the last write time of the file.87  /// </summary>88  /// <remarks>Provides an example of how to customise filtering.</remarks>89  public class ExtendedPathFilter : PathFilter90  {91    #region Constructors92    /// <summary>93    /// Initialise a new instance of ExtendedPathFilter.94    /// </summary>95    /// <param name="filter">The filter to apply.</param>96    /// <param name="minSize">The minimum file size to include.</param>97    /// <param name="maxSize">The maximum file size to include.</param>98    public ExtendedPathFilter(string filter,99      long minSize, long maxSize)100      : base(filter)101    {102      MinSize = minSize;103      MaxSize = maxSize;104    }10585    /// <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    #endregion104105    #region IScanFilter Members  106    /// <summary>107    /// Initialise a new instance of ExtendedPathFilter.107    /// Test a filename to see if it matches the filter.  108    /// </summary>109    /// <param name="filter">The filter to apply.</param>110    /// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>111    /// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>112    public ExtendedPathFilter(string filter,113      DateTime minDate, DateTime maxDate)114      : base(filter)115    {116      MinDate = minDate;117      MaxDate = maxDate;118    }119120    /// <summary>121    /// Initialise a new instance of ExtendedPathFilter.122    /// </summary>123    /// <param name="filter">The filter to apply.</param>124    /// <param name="minSize">The minimum file size to include.</param>125    /// <param name="maxSize">The maximum file size to include.</param>126    /// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>127    /// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>128    public ExtendedPathFilter(string filter,129      long minSize, long maxSize,130      DateTime minDate, DateTime maxDate)131      : base(filter)132    {133      MinSize = minSize;134      MaxSize = maxSize;135      MinDate = minDate;136      MaxDate = maxDate;137    }138    #endregion139140    #region IScanFilter Members141    /// <summary>142    /// Test a filename to see if it matches the filter.143    /// </summary>144    /// <param name="name">The filename to test.</param>145    /// <returns>True if the filter matches, false otherwise.</returns>146    /// <exception cref="System.IO.FileNotFoundException">The <see paramref="fileName"/> doesnt exist</exception>147    public override bool IsMatch(string name)148    {149      bool result = base.IsMatch(name);150151      if ( result ) {152        var fileInfo = new FileInfo(name);153        result =154          (MinSize <= fileInfo.Length) &&155          (MaxSize >= fileInfo.Length) &&156          (MinDate <= fileInfo.LastWriteTime) &&157          (MaxDate >= fileInfo.LastWriteTime)158          ;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);115116      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    #endregion128129    #region Properties130    /// <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"/></excep135    public long MinSize {136      get { return minSize_; }137      set {138        if ((value < 0) || (maxSize_ < value)) {139          throw new ArgumentOutOfRangeException(nameof(value));140        }141142        minSize_ = value;143      }144    }145146    /// <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"/></except151    public long MaxSize {152      get { return maxSize_; }153      set {154        if ((value < 0) || (minSize_ > value)) {155          throw new ArgumentOutOfRangeException(nameof(value));156        }157158        maxSize_ = value;  159      }160      return result;161    }162    #endregion163164    #region Properties165    /// <summary>166    /// Get/set the minimum size/length for a file that will match this filter.167    /// </summary>168    /// <remarks>The default value is zero.</remarks>169    /// <exception cref="ArgumentOutOfRangeException">value is less than zero; greater than <see cref="MaxSize"/></excep170    public long MinSize171    {172      get { return minSize_; }173      set174      {175        if ( (value < 0) || (maxSize_ < value) ) {176          throw new ArgumentOutOfRangeException(nameof(value));177        }178179        minSize_ = value;180      }181    }182183    /// <summary>184    /// Get/set the maximum size/length for a file that will match this filter.185    /// </summary>186    /// <remarks>The default value is <see cref="System.Int64.MaxValue"/></remarks>187    /// <exception cref="ArgumentOutOfRangeException">value is less than zero or less than <see cref="MinSize"/></except188    public long MaxSize189    {190      get { return maxSize_; }191      set192      {193        if ( (value < 0) || (minSize_ > value) ) {194          throw new ArgumentOutOfRangeException(nameof(value));195        }196197        maxSize_ = value;198      }199    }200201    /// <summary>202    /// Get/set the minimum <see cref="DateTime"/> value that will match for this filter.203    /// </summary>204    /// <remarks>Files with a LastWrite time less than this value are excluded by the filter.</remarks>205    public DateTime MinDate206    {207      get208      {209        return minDate_;210      }211212      set213      {214        if ( value > maxDate_ ) {215#if NETCF_1_0216          throw new ArgumentOutOfRangeException("value");217#else218          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MaxDate");219#endif220        }221222        minDate_ = value;223      }224    }225226    /// <summary>227    /// Get/set the maximum <see cref="DateTime"/> value that will match for this filter.228    /// </summary>229    /// <remarks>Files with a LastWrite time greater than this value are excluded by the filter.</remarks>230    public DateTime MaxDate231    {232      get233      {234        return maxDate_;235      }160    }161162    /// <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      }170171      set {172        if (value > maxDate_) {173          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MaxDate");174        }175176        minDate_ = value;177      }178    }179180    /// <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      }188189      set {190        if (minDate_ > value) {191          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MinDate");192        }193194        maxDate_ = value;195      }196    }197    #endregion198199    #region Instance Fields200    long minSize_;201    long maxSize_ = long.MaxValue;202    DateTime minDate_ = DateTime.MinValue;203    DateTime maxDate_ = DateTime.MaxValue;204    #endregion205  }206207  /// <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 : PathFilter213  {214215    /// <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    }227228    /// <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);  236237      set238      {239        if ( minDate_ > value ) {240#if NETCF_1_0241          throw new ArgumentOutOfRangeException("value");242#else243          throw new ArgumentOutOfRangeException(nameof(value), "Exceeds MinDate");244#endif245        }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    }  246247        maxDate_ = value;248      }249    }250    #endregion251252    #region Instance Fields253    long minSize_;254    long maxSize_ = long.MaxValue;255    DateTime minDate_ = DateTime.MinValue;256    DateTime maxDate_ = DateTime.MaxValue;257    #endregion258  }259260  /// <summary>261  /// NameAndSizeFilter filters based on name and file size.262  /// </summary>263  /// <remarks>A sample showing how filters might be extended.</remarks>264  [Obsolete("Use ExtendedPathFilter instead")]265  public class NameAndSizeFilter : PathFilter266  {267268    /// <summary>269    /// Initialise a new instance of NameAndSizeFilter.270    /// </summary>271    /// <param name="filter">The filter to apply.</param>272    /// <param name="minSize">The minimum file size to include.</param>273    /// <param name="maxSize">The maximum file size to include.</param>274    public NameAndSizeFilter(string filter, long minSize, long maxSize)275      : base(filter)276    {277      MinSize = minSize;278      MaxSize = maxSize;279    }280281    /// <summary>282    /// Test a filename to see if it matches the filter.283    /// </summary>284    /// <param name="name">The filename to test.</param>285    /// <returns>True if the filter matches, false otherwise.</returns>286    public override bool IsMatch(string name)287    {288      bool result = base.IsMatch(name);289290      if ( result ) {291        var fileInfo = new FileInfo(name);292        long length = fileInfo.Length;293        result =294          (MinSize <= length) &&295          (MaxSize >= length);296      }297      return result;298    }299300    /// <summary>301    /// Get/set the minimum size for a file that will match this filter.302    /// </summary>303    public long MinSize304    {305      get { return minSize_; }306      set {307        if ( (value < 0) || (maxSize_ < value) ) {308          throw new ArgumentOutOfRangeException(nameof(value));309        }310311        minSize_ = value;312      }313    }314315    /// <summary>316    /// Get/set the maximum size for a file that will match this filter.317    /// </summary>318    public long MaxSize319    {320      get { return maxSize_; }321      set322      {323        if ( (value < 0) || (minSize_ > value) ) {324          throw new ArgumentOutOfRangeException(nameof(value));325        }326327        maxSize_ = value;328      }329    }330331    #region Instance Fields332    long minSize_;333    long maxSize_ = long.MaxValue;334    #endregion335  }336}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        }256257        minSize_ = value;258      }259    }260261    /// <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        }270271        maxSize_ = value;272      }273    }274275    #region Instance Fields276    long minSize_;277    long maxSize_ = long.MaxValue;278    #endregion279  }280} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_PendingBuffer.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_PendingBuffer.htm index 4c6e89bcc..44fe308b7 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_PendingBuffer.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_PendingBuffer.htm @@ -18,7 +18,7 @@

Summary

Covered lines:40 Uncovered lines:18 Coverable lines:58 -Total lines:295 +Total lines:255 Line coverage:68.9% Branch coverage:90% @@ -46,303 +46,263 @@

#LineLine coverage - 1// PendingBuffer.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839using System;4041namespace ICSharpCode.SharpZipLib.Zip.Compression42{4344  /// <summary>45  /// This class is general purpose class for writing data to a buffer.46  ///47  /// It allows you to write bits as well as bytes48  /// Based on DeflaterPending.java49  ///50  /// author of the original java version : Jochen Hoenicke51  /// </summary>52  public class PendingBuffer53  {54    readonly55    #region Instance Fields56    /// <summary>57    /// Internal work buffer58    /// </summary>59    byte[] buffer_;6061    int    start;62    int    end;6364    uint   bits;65    int    bitCount;66    #endregion6768    #region Constructors69    /// <summary>70    /// construct instance using default buffer size of 409671    /// </summary> - 072    public PendingBuffer() : this( 4096 )73    { - 074    }7576    /// <summary>77    /// construct instance using specified buffer size78    /// </summary>79    /// <param name="bufferSize">80    /// size to use for internal buffer81    /// </param> - 27982    public PendingBuffer(int bufferSize)83    { - 27984      buffer_ = new byte[bufferSize]; - 27985    }8687    #endregion8889    /// <summary>90    /// Clear internal state/buffers91    /// </summary>92    public void Reset()93    { - 40194      start = end = bitCount = 0; - 40195    }9697    /// <summary>98    /// Write a byte to buffer99    /// </summary>100    /// <param name="value">101    /// The value to write102    /// </param>103    public void WriteByte(int value)104    {105#if DebugDeflation106      if (DeflaterConstants.DEBUGGING && (start != 0) )107      {108        throw new SharpZipBaseException("Debug check: start != 0");109      }110#endif - 0111      buffer_[end++] = unchecked((byte) value); - 0112    }113114    /// <summary>115    /// Write a short value to buffer LSB first116    /// </summary>117    /// <param name="value">118    /// The value to write.119    /// </param>120    public void WriteShort(int value)121    {122#if DebugDeflation123      if (DeflaterConstants.DEBUGGING && (start != 0) )124      {125        throw new SharpZipBaseException("Debug check: start != 0");126      }127#endif - 604128      buffer_[end++] = unchecked((byte) value); - 604129      buffer_[end++] = unchecked((byte) (value >> 8)); - 604130    }131132    /// <summary>133    /// write an integer LSB first134    /// </summary>135    /// <param name="value">The value to write.</param>136    public void WriteInt(int value)137    {138#if DebugDeflation139      if (DeflaterConstants.DEBUGGING && (start != 0) )140      {141        throw new SharpZipBaseException("Debug check: start != 0");142      }143#endif - 0144      buffer_[end++] = unchecked((byte) value); - 0145      buffer_[end++] = unchecked((byte) (value >> 8)); - 0146      buffer_[end++] = unchecked((byte) (value >> 16)); - 0147      buffer_[end++] = unchecked((byte) (value >> 24)); - 0148    }149150    /// <summary>151    /// Write a block of data to buffer152    /// </summary>153    /// <param name="block">data to write</param>154    /// <param name="offset">offset of first byte to write</param>155    /// <param name="length">number of bytes to write</param>156    public void WriteBlock(byte[] block, int offset, int length)157    {158#if DebugDeflation159      if (DeflaterConstants.DEBUGGING && (start != 0) )160      {161        throw new SharpZipBaseException("Debug check: start != 0");162      }163#endif - 302164      System.Array.Copy(block, offset, buffer_, end, length); - 302165      end += length; - 302166    }167168    /// <summary>169    /// The number of bits written to the buffer170    /// </summary>171    public int BitCount {172      get { - 0173        return bitCount;174      }175    }176177    /// <summary>178    /// Align internal buffer on a byte boundary179    /// </summary>180    public void AlignToByte()181    {182#if DebugDeflation183      if (DeflaterConstants.DEBUGGING && (start != 0) )184      {185        throw new SharpZipBaseException("Debug check: start != 0");186      }187#endif - 611188       if (bitCount > 0)189      { - 541190        buffer_[end++] = unchecked((byte) bits); - 541191         if (bitCount > 8) { - 173192          buffer_[end++] = unchecked((byte) (bits >> 8));193        }194      } - 611195      bits = 0; - 611196      bitCount = 0; - 611197    }198199    /// <summary>200    /// Write bits to internal buffer201    /// </summary>202    /// <param name="b">source of bits</param>203    /// <param name="count">number of bits to write</param>204    public void WriteBits(int b, int count)205    {206#if DebugDeflation207      if (DeflaterConstants.DEBUGGING && (start != 0) )208      {209        throw new SharpZipBaseException("Debug check: start != 0");210      }211212      //      if (DeflaterConstants.DEBUGGING) {213      //        //Console.WriteLine("writeBits("+b+","+count+")");214      //      }215#endif - 8967216      bits |= (uint)(b << bitCount); - 8967217      bitCount += count; - 8967218       if (bitCount >= 16) { - 4183219        buffer_[end++] = unchecked((byte) bits); - 4183220        buffer_[end++] = unchecked((byte) (bits >> 8)); - 4183221        bits >>= 16; - 4183222        bitCount -= 16;223      } - 8967224    }225226    /// <summary>227    /// Write a short value to internal buffer most significant byte first228    /// </summary>229    /// <param name="s">value to write</param>230    public void WriteShortMSB(int s)231    {232#if DebugDeflation233      if (DeflaterConstants.DEBUGGING && (start != 0) )234      {235        throw new SharpZipBaseException("Debug check: start != 0");236      }237#endif - 42238      buffer_[end++] = unchecked((byte) (s >> 8)); - 42239      buffer_[end++] = unchecked((byte) s); - 42240    }241242    /// <summary>243    /// Indicates if buffer has been flushed244    /// </summary>245    public bool IsFlushed {246      get { - 10201247        return end == 0;248      }249    }250251    /// <summary>252    /// Flushes the pending buffer into the given output array.  If the253    /// output array is to small, only a partial flush is done.254    /// </summary>255    /// <param name="output">The output array.</param>256    /// <param name="offset">The offset into output array.</param>257    /// <param name="length">The maximum number of bytes to store.</param>258    /// <returns>The number of bytes flushed.</returns>259    public int Flush(byte[] output, int offset, int length)260    { - 13290261       if (bitCount >= 8) { - 0262        buffer_[end++] = unchecked((byte) bits); - 0263        bits >>= 8; - 0264        bitCount -= 8;265      }266 - 13290267       if (length > end - start) { - 5201268        length = end - start; - 5201269        System.Array.Copy(buffer_, start, output, offset, length); - 5201270        start = 0; - 5201271        end = 0; - 5201272      } else { - 8089273        System.Array.Copy(buffer_, start, output, offset, length); - 8089274        start += length;275      } - 13290276      return length;277    }278279    /// <summary>280    /// Convert internal buffer to byte array.281    /// Buffer is empty on completion282    /// </summary>283    /// <returns>284    /// The internal buffer contents converted to a byte array.285    /// </returns>286    public byte[] ToByteArray()287    { - 0288      byte[] result = new byte[end - start]; - 0289      System.Array.Copy(buffer_, start, result, 0, result.Length); - 0290      start = 0; - 0291      end = 0; - 0292      return result;293    }294  }295}1using System;23namespace ICSharpCode.SharpZipLib.Zip.Compression4{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 bytes9  /// Based on DeflaterPending.java10  ///11  /// author of the original java version : Jochen Hoenicke12  /// </summary>13  public class PendingBuffer14  {15    readonly16    #region Instance Fields17    /// <summary>18    /// Internal work buffer19    /// </summary>20    byte[] buffer_;2122    int start;23    int end;2425    uint bits;26    int bitCount;27    #endregion2829    #region Constructors30    /// <summary>31    /// construct instance using default buffer size of 409632    /// </summary> + 033    public PendingBuffer() : this(4096)34    { + 035    }3637    /// <summary>38    /// construct instance using specified buffer size39    /// </summary>40    /// <param name="bufferSize">41    /// size to use for internal buffer42    /// </param> + 27343    public PendingBuffer(int bufferSize)44    { + 27345      buffer_ = new byte[bufferSize]; + 27346    }4748    #endregion4950    /// <summary>51    /// Clear internal state/buffers52    /// </summary>53    public void Reset()54    { + 39255      start = end = bitCount = 0; + 39256    }5758    /// <summary>59    /// Write a byte to buffer60    /// </summary>61    /// <param name="value">62    /// The value to write63    /// </param>64    public void WriteByte(int value)65    {66#if DebugDeflation67      if (DeflaterConstants.DEBUGGING && (start != 0) )68      {69        throw new SharpZipBaseException("Debug check: start != 0");70      }71#endif + 072      buffer_[end++] = unchecked((byte)value); + 073    }7475    /// <summary>76    /// Write a short value to buffer LSB first77    /// </summary>78    /// <param name="value">79    /// The value to write.80    /// </param>81    public void WriteShort(int value)82    {83#if DebugDeflation84      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    }9293    /// <summary>94    /// write an integer LSB first95    /// </summary>96    /// <param name="value">The value to write.</param>97    public void WriteInt(int value)98    {99#if DebugDeflation100      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    }110111    /// <summary>112    /// Write a block of data to buffer113    /// </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 DebugDeflation120      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    }128129    /// <summary>130    /// The number of bits written to the buffer131    /// </summary>132    public int BitCount {133      get { + 0134        return bitCount;135      }136    }137138    /// <summary>139    /// Align internal buffer on a byte boundary140    /// </summary>141    public void AlignToByte()142    {143#if DebugDeflation144      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    }158159    /// <summary>160    /// Write bits to internal buffer161    /// </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 DebugDeflation167      if (DeflaterConstants.DEBUGGING && (start != 0) )168      {169        throw new SharpZipBaseException("Debug check: start != 0");170      }171172      //      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    }185186    /// <summary>187    /// Write a short value to internal buffer most significant byte first188    /// </summary>189    /// <param name="s">value to write</param>190    public void WriteShortMSB(int s)191    {192#if DebugDeflation193      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    }201202    /// <summary>203    /// Indicates if buffer has been flushed204    /// </summary>205    public bool IsFlushed {206      get { + 10175207        return end == 0;208      }209    }210211    /// <summary>212    /// Flushes the pending buffer into the given output array.  If the213    /// 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    }238239    /// <summary>240    /// Convert internal buffer to byte array.241    /// Buffer is empty on completion242    /// </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/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassic.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassic.htm index 41a5d7d05..cccf63232 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassic.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassic.htm @@ -18,7 +18,7 @@

Summary

Covered lines:26 Uncovered lines:2 Coverable lines:28 -Total lines:498 +Total lines:445 Line coverage:92.8% Branch coverage:66.6% @@ -35,506 +35,453 @@

#LineLine coverage - 1//2// PkzipClassic encryption3//4// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team5//6// This program is free software; you can redistribute it and/or7// modify it under the terms of the GNU General Public License8// as published by the Free Software Foundation; either version 29// of the License, or (at your option) any later version.10//11// This program is distributed in the hope that it will be useful,12// but WITHOUT ANY WARRANTY; without even the implied warranty of13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the14// GNU General Public License for more details.15//16// You should have received a copy of the GNU General Public License17// along with this program; if not, write to the Free Software18// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.19//20// Linking this library statically or dynamically with other modules is21// making a combined work based on this library.  Thus, the terms and22// conditions of the GNU General Public License cover the whole23// combination.24//25// As a special exception, the copyright holders of this library give you26// permission to link this library with independent modules to produce an27// executable, regardless of the license terms of these independent28// modules, and to copy and distribute the resulting executable under29// terms of your choice, provided that you also meet, for each linked30// independent module, the terms and conditions of the license of that31// module.  An independent module is a module which is not derived from32// or based on this library.  If you modify this library, you may extend33// this exception to your version of the library, but you are not34// obligated to do so.  If you do not wish to do so, delete this35// exception statement from your version.36//373839#if !NETCF_1_04041using System;42using System.Security.Cryptography;43using ICSharpCode.SharpZipLib.Checksums;4445namespace ICSharpCode.SharpZipLib.Encryption46{47  /// <summary>48  /// PkzipClassic embodies the classic or original encryption facilities used in Pkzip archives.49  /// While it has been superceded by more recent and more powerful algorithms, its still in use and50  /// is viable for preventing casual snooping51  /// </summary>52  public abstract class PkzipClassic : SymmetricAlgorithm53  {54    /// <summary>55    /// Generates new encryption keys based on given seed56    /// </summary>57    /// <param name="seed">The seed value to initialise keys with.</param>58    /// <returns>A new key value.</returns>59    static public byte[] GenerateKeys(byte[] seed)60    { - 7461       if ( seed == null ) { - 062        throw new ArgumentNullException(nameof(seed));63      }64 - 7465       if ( seed.Length == 0 ) { - 066        throw new ArgumentException("Length is zero", nameof(seed));67      }68 - 7469      uint[] newKeys = { - 7470        0x12345678, - 7471        0x23456789, - 7472        0x34567890 - 7473       };74 - 111475       for (int i = 0; i < seed.Length; ++i) { - 48376        newKeys[0] = Crc32.ComputeCrc32(newKeys[0], seed[i]); - 48377        newKeys[1] = newKeys[1] + (byte)newKeys[0]; - 48378        newKeys[1] = newKeys[1] * 134775813 + 1; - 48379        newKeys[2] = Crc32.ComputeCrc32(newKeys[2], (byte)(newKeys[1] >> 24));80      }81 - 7482      byte[] result = new byte[12]; - 7483      result[0] = (byte)(newKeys[0] & 0xff); - 7484      result[1] = (byte)((newKeys[0] >> 8) & 0xff); - 7485      result[2] = (byte)((newKeys[0] >> 16) & 0xff); - 7486      result[3] = (byte)((newKeys[0] >> 24) & 0xff); - 7487      result[4] = (byte)(newKeys[1] & 0xff); - 7488      result[5] = (byte)((newKeys[1] >> 8) & 0xff); - 7489      result[6] = (byte)((newKeys[1] >> 16) & 0xff); - 7490      result[7] = (byte)((newKeys[1] >> 24) & 0xff); - 7491      result[8] = (byte)(newKeys[2] & 0xff); - 7492      result[9] = (byte)((newKeys[2] >> 8) & 0xff); - 7493      result[10] = (byte)((newKeys[2] >> 16) & 0xff); - 7494      result[11] = (byte)((newKeys[2] >> 24) & 0xff); - 7495      return result;96    }97  }9899  /// <summary>100  /// PkzipClassicCryptoBase provides the low level facilities for encryption101  /// and decryption using the PkzipClassic algorithm.102  /// </summary>103  class PkzipClassicCryptoBase104  {105    /// <summary>106    /// Transform a single byte107    /// </summary>108    /// <returns>109    /// The transformed value110    /// </returns>111    protected byte TransformByte()1using System;2using System.Security.Cryptography;3using ICSharpCode.SharpZipLib.Checksum;45namespace ICSharpCode.SharpZipLib.Encryption6{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 and10  /// is viable for preventing casual snooping11  /// </summary>12  public abstract class PkzipClassic : SymmetricAlgorithm13  {14    /// <summary>15    /// Generates new encryption keys based on given seed16    /// </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  }5859  /// <summary>60  /// PkzipClassicCryptoBase provides the low level facilities for encryption61  /// and decryption using the PkzipClassic algorithm.62  /// </summary>63  class PkzipClassicCryptoBase64  {65    /// <summary>66    /// Transform a single byte67    /// </summary>68    /// <returns>69    /// The transformed value70    /// </returns>71    protected byte TransformByte()72    {73      uint temp = ((keys[2] & 0xFFFF) | 2);74      return (byte)((temp * (temp ^ 1)) >> 8);75    }7677    /// <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      }8687      if (keyData.Length != 12) {88        throw new InvalidOperationException("Key length is not valid");89      }9091      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    }9697    /// <summary>98    /// Update encryption keys99    /// </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    }107108    /// <summary>109    /// Reset the internal state.110    /// </summary>111    protected void Reset()  112    {113      uint temp = ((keys[2] & 0xFFFF) | 2);114      return (byte)((temp * (temp ^ 1)) >> 8);115    }116117    /// <summary>118    /// Set the key schedule for encryption/decryption.119    /// </summary>120    /// <param name="keyData">The data use to set the keys from.</param>121    protected void SetKeys(byte[] keyData)122    {123      if ( keyData == null ) {124        throw new ArgumentNullException(nameof(keyData));125      }126127      if ( keyData.Length != 12 ) {128        throw new InvalidOperationException("Key length is not valid");129      }130131      keys = new uint[3];132      keys[0] = (uint)((keyData[3] << 24) | (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]);133      keys[1] = (uint)((keyData[7] << 24) | (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]);134      keys[2] = (uint)((keyData[11] << 24) | (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]);113      keys[0] = 0;114      keys[1] = 0;115      keys[2] = 0;116    }117118    #region Instance Fields119    uint[] keys;120    #endregion121  }122123  /// <summary>124  /// PkzipClassic CryptoTransform for encryption.125  /// </summary>126  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform127  {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    }  136137    /// <summary>138    /// Update encryption keys139    /// </summary>140    protected void UpdateKeys(byte ch)141    {142      keys[0] = Crc32.ComputeCrc32(keys[0], ch);143      keys[1] = keys[1] + (byte)keys[0];144      keys[1] = keys[1] * 134775813 + 1;145      keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));146    }147148    /// <summary>149    /// Reset the internal state.150    /// </summary>151    protected void Reset()152    {153      keys[0] = 0;154      keys[1] = 0;155      keys[2] = 0;156    }157158    #region Instance Fields159    uint[] keys;160    #endregion161  }162163  /// <summary>164  /// PkzipClassic CryptoTransform for encryption.165  /// </summary>166  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform167  {168    /// <summary>169    /// Initialise a new instance of <see cref="PkzipClassicEncryptCryptoTransform"></see>170    /// </summary>171    /// <param name="keyBlock">The key block to use.</param>172    internal PkzipClassicEncryptCryptoTransform(byte[] keyBlock)173    {174      SetKeys(keyBlock);175    }176177    #region ICryptoTransform Members178179    /// <summary>180    /// Transforms the specified region of the specified byte array.181    /// </summary>182    /// <param name="inputBuffer">The input for which to compute the transform.</param>183    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>184    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>185    /// <returns>The computed transform.</returns>186    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)187    {188      byte[] result = new byte[inputCount];189      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);190      return result;191    }192193    /// <summary>194    /// Transforms the specified region of the input byte array and copies195    /// the resulting transform to the specified region of the output byte array.196    /// </summary>197    /// <param name="inputBuffer">The input for which to compute the transform.</param>198    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>199    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>200    /// <param name="outputBuffer">The output to which to write the transform.</param>201    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>202    /// <returns>The number of bytes written.</returns>203    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset204    {205      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {206        byte oldbyte = inputBuffer[i];207        outputBuffer[outputOffset++] = (byte)(inputBuffer[i] ^ TransformByte());208        UpdateKeys(oldbyte);209      }210      return inputCount;211    }137    #region ICryptoTransform Members138139    /// <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    }152153    /// <summary>154    /// Transforms the specified region of the input byte array and copies155    /// 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 outputOffset164    {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    }172173    /// <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    }181182    /// <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    }190191    /// <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    }199200    /// <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    }208209    #endregion210211    #region IDisposable Members  212  213    /// <summary>214    /// Gets a value indicating whether the current transform can be reused.214    /// Cleanup internal state.  215    /// </summary>216    public bool CanReuseTransform216    public void Dispose()  217    {218      get {219        return true;220      }221    }222223    /// <summary>224    /// Gets the size of the input data blocks in bytes.225    /// </summary>226    public int InputBlockSize227    {228      get {229        return 1;230      }231    }232233    /// <summary>234    /// Gets the size of the output data blocks in bytes.235    /// </summary>236    public int OutputBlockSize237    {238      get {239        return 1;240      }241    }242243    /// <summary>244    /// Gets a value indicating whether multiple blocks can be transformed.245    /// </summary>246    public bool CanTransformMultipleBlocks247    {248      get {249        return true;250      }251    }252253    #endregion218      Reset();219    }220221    #endregion222  }223224225  /// <summary>226  /// PkzipClassic CryptoTransform for decryption.227  /// </summary>228  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform229  {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    }238239    #region ICryptoTransform Members240241    /// <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    }  254255    #region IDisposable Members256257    /// <summary>258    /// Cleanup internal state.259    /// </summary>260    public void Dispose()261    {262      Reset();263    }264265    #endregion266  }267268269  /// <summary>270  /// PkzipClassic CryptoTransform for decryption.271  /// </summary>272  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform273  {274    /// <summary>275    /// Initialise a new instance of <see cref="PkzipClassicDecryptCryptoTransform"></see>.276    /// </summary>277    /// <param name="keyBlock">The key block to decrypt with.</param>278    internal PkzipClassicDecryptCryptoTransform(byte[] keyBlock)279    {280      SetKeys(keyBlock);281    }282283    #region ICryptoTransform Members284285    /// <summary>286    /// Transforms the specified region of the specified byte array.287    /// </summary>288    /// <param name="inputBuffer">The input for which to compute the transform.</param>289    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>290    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>291    /// <returns>The computed transform.</returns>292    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)293    {294      byte[] result = new byte[inputCount];295      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);296      return result;297    }298299    /// <summary>300    /// Transforms the specified region of the input byte array and copies301    /// the resulting transform to the specified region of the output byte array.302    /// </summary>303    /// <param name="inputBuffer">The input for which to compute the transform.</param>304    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>305    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>306    /// <param name="outputBuffer">The output to which to write the transform.</param>307    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>308    /// <returns>The number of bytes written.</returns>309    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset310    {311      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {312        var newByte = (byte)(inputBuffer[i] ^ TransformByte());313        outputBuffer[outputOffset++] = newByte;314        UpdateKeys(newByte);315      }316      return inputCount;317    }318319    /// <summary>320    /// Gets a value indicating whether the current transform can be reused.321    /// </summary>322    public bool CanReuseTransform323    {324      get {325        return true;326      }327    }328329    /// <summary>330    /// Gets the size of the input data blocks in bytes.331    /// </summary>332    public int InputBlockSize333    {334      get {335        return 1;336      }337    }338339    /// <summary>340    /// Gets the size of the output data blocks in bytes.341    /// </summary>342    public int OutputBlockSize343    {344      get {345        return 1;346      }347    }348349    /// <summary>350    /// Gets a value indicating whether multiple blocks can be transformed.351    /// </summary>352    public bool CanTransformMultipleBlocks353    {354      get {355        return true;255    /// <summary>256    /// Transforms the specified region of the input byte array and copies257    /// 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 outputOffset266    {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    }274275    /// <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    }283284    /// <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    }292293    /// <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    }301302    /// <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    }310311    #endregion312313    #region IDisposable Members314315    /// <summary>316    /// Cleanup internal state.317    /// </summary>318    public void Dispose()319    {320      Reset();321    }322323    #endregion324  }325326  /// <summary>327  /// Defines a wrapper object to access the Pkzip algorithm.328  /// This class cannot be inherited.329  /// </summary>330  public sealed class PkzipClassicManaged : PkzipClassic331  {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      }340341      set {342        if (value != 8) {343          throw new CryptographicException("Block size is invalid");344        }345      }346    }347348    /// <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    }  358359    #endregion360361    #region IDisposable Members362363    /// <summary>364    /// Cleanup internal state.365    /// </summary>366    public void Dispose()367    {368      Reset();369    }370371    #endregion372  }373374  /// <summary>375  /// Defines a wrapper object to access the Pkzip algorithm.376  /// This class cannot be inherited.377  /// </summary>378  public sealed class PkzipClassicManaged : PkzipClassic379  {380    /// <summary>381    /// Get / set the applicable block size in bits.382    /// </summary>383    /// <remarks>The only valid block size is 8.</remarks>384    public override int BlockSize385    {386      get {387        return 8;359    /// <summary>360    /// Generate an initial vector.361    /// </summary>362    public override void GenerateIV()363    {364      // Do nothing.365    }366367    /// <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    }377378    /// <summary>379    /// Get / set the key value applicable.380    /// </summary>381    public override byte[] Key {382      get {383        if (key_ == null) {384          GenerateKey();385        }386387        return (byte[])key_.Clone();  388      }  389  390      set {391        if (value != 8) {392          throw new CryptographicException("Block size is invalid");391        if (value == null) {392          throw new ArgumentNullException(nameof(value));  393        }394      }395    }396397    /// <summary>398    /// Get an array of legal <see cref="KeySizes">key sizes.</see>399    /// </summary>400    public override KeySizes[] LegalKeySizes401    {402      get {403        KeySizes[] keySizes = new KeySizes[1];404        keySizes[0] = new KeySizes(12 * 8, 12 * 8, 0);405        return keySizes;406      }407    }408409    /// <summary>410    /// Generate an initial vector.411    /// </summary>412    public override void GenerateIV()413    {414      // Do nothing.415    }416417    /// <summary>418    /// Get an array of legal <see cref="KeySizes">block sizes</see>.419    /// </summary>420    public override KeySizes[] LegalBlockSizes421    {422      get {423        KeySizes[] keySizes = new KeySizes[1];424        keySizes[0] = new KeySizes(1 * 8, 1 * 8, 0);425        return keySizes;426      }427    }428429    /// <summary>430    /// Get / set the key value applicable.431    /// </summary>432    public override byte[] Key433    {434      get {435        if ( key_ == null ) {436          GenerateKey();437        }438439        return (byte[]) key_.Clone();440      }441442      set {443        if ( value == null ) {444          throw new ArgumentNullException(nameof(value));445        }446447        if ( value.Length != 12 ) {448          throw new CryptographicException("Key size is illegal");449        }450451        key_ = (byte[]) value.Clone();452      }453    }454455    /// <summary>456    /// Generate a new random key.457    /// </summary>458    public override void GenerateKey()459    {460      key_ = new byte[12];461      var rnd = new Random();462      rnd.NextBytes(key_);463    }464465    /// <summary>466    /// Create an encryptor.467    /// </summary>468    /// <param name="rgbKey">The key to use for this encryptor.</param>469    /// <param name="rgbIV">Initialisation vector for the new encryptor.</param>470    /// <returns>Returns a new PkzipClassic encryptor</returns>471    public override ICryptoTransform CreateEncryptor(472      byte[] rgbKey,473      byte[] rgbIV)474    {475      key_ = rgbKey;476      return new PkzipClassicEncryptCryptoTransform(Key);477    }478479    /// <summary>480    /// Create a decryptor.481    /// </summary>482    /// <param name="rgbKey">Keys to use for this new decryptor.</param>483    /// <param name="rgbIV">Initialisation vector for the new decryptor.</param>484    /// <returns>Returns a new decryptor.</returns>485    public override ICryptoTransform CreateDecryptor(486      byte[] rgbKey,487      byte[] rgbIV)488    {489      key_ = rgbKey;490      return new PkzipClassicDecryptCryptoTransform(Key);491    }492493    #region Instance Fields494    byte[] key_;495    #endregion496  }497}498#endif394395        if (value.Length != 12) {396          throw new CryptographicException("Key size is illegal");397        }398399        key_ = (byte[])value.Clone();400      }401    }402403    /// <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    }412413    /// <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    }426427    /// <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    }440441    #region Instance Fields442    byte[] key_;443    #endregion444  }445} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicCryptoBase.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicCryptoBase.htm index f67890fc9..b846bbe8d 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicCryptoBase.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicCryptoBase.htm @@ -18,7 +18,7 @@

Summary

Covered lines:18 Uncovered lines:2 Coverable lines:20 -Total lines:498 +Total lines:445 Line coverage:90% Branch coverage:50% @@ -38,506 +38,453 @@

#LineLine coverage - 1//2// PkzipClassic encryption3//4// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team5//6// This program is free software; you can redistribute it and/or7// modify it under the terms of the GNU General Public License8// as published by the Free Software Foundation; either version 29// of the License, or (at your option) any later version.10//11// This program is distributed in the hope that it will be useful,12// but WITHOUT ANY WARRANTY; without even the implied warranty of13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the14// GNU General Public License for more details.15//16// You should have received a copy of the GNU General Public License17// along with this program; if not, write to the Free Software18// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.19//20// Linking this library statically or dynamically with other modules is21// making a combined work based on this library.  Thus, the terms and22// conditions of the GNU General Public License cover the whole23// combination.24//25// As a special exception, the copyright holders of this library give you26// permission to link this library with independent modules to produce an27// executable, regardless of the license terms of these independent28// modules, and to copy and distribute the resulting executable under29// terms of your choice, provided that you also meet, for each linked30// independent module, the terms and conditions of the license of that31// module.  An independent module is a module which is not derived from32// or based on this library.  If you modify this library, you may extend33// this exception to your version of the library, but you are not34// obligated to do so.  If you do not wish to do so, delete this35// exception statement from your version.36//373839#if !NETCF_1_04041using System;42using System.Security.Cryptography;43using ICSharpCode.SharpZipLib.Checksums;4445namespace ICSharpCode.SharpZipLib.Encryption46{47  /// <summary>48  /// PkzipClassic embodies the classic or original encryption facilities used in Pkzip archives.49  /// While it has been superceded by more recent and more powerful algorithms, its still in use and50  /// is viable for preventing casual snooping51  /// </summary>52  public abstract class PkzipClassic : SymmetricAlgorithm53  {54    /// <summary>55    /// Generates new encryption keys based on given seed56    /// </summary>57    /// <param name="seed">The seed value to initialise keys with.</param>58    /// <returns>A new key value.</returns>59    static public byte[] GenerateKeys(byte[] seed)60    {61      if ( seed == null ) {62        throw new ArgumentNullException(nameof(seed));63      }6465      if ( seed.Length == 0 ) {66        throw new ArgumentException("Length is zero", nameof(seed));67      }6869      uint[] newKeys = {70        0x12345678,71        0x23456789,72        0x3456789073       };7475      for (int i = 0; i < seed.Length; ++i) {76        newKeys[0] = Crc32.ComputeCrc32(newKeys[0], seed[i]);77        newKeys[1] = newKeys[1] + (byte)newKeys[0];78        newKeys[1] = newKeys[1] * 134775813 + 1;79        newKeys[2] = Crc32.ComputeCrc32(newKeys[2], (byte)(newKeys[1] >> 24));80      }8182      byte[] result = new byte[12];83      result[0] = (byte)(newKeys[0] & 0xff);84      result[1] = (byte)((newKeys[0] >> 8) & 0xff);85      result[2] = (byte)((newKeys[0] >> 16) & 0xff);86      result[3] = (byte)((newKeys[0] >> 24) & 0xff);87      result[4] = (byte)(newKeys[1] & 0xff);88      result[5] = (byte)((newKeys[1] >> 8) & 0xff);89      result[6] = (byte)((newKeys[1] >> 16) & 0xff);90      result[7] = (byte)((newKeys[1] >> 24) & 0xff);91      result[8] = (byte)(newKeys[2] & 0xff);92      result[9] = (byte)((newKeys[2] >> 8) & 0xff);93      result[10] = (byte)((newKeys[2] >> 16) & 0xff);94      result[11] = (byte)((newKeys[2] >> 24) & 0xff);95      return result;96    }97  }9899  /// <summary>100  /// PkzipClassicCryptoBase provides the low level facilities for encryption101  /// and decryption using the PkzipClassic algorithm.102  /// </summary>103  class PkzipClassicCryptoBase104  {105    /// <summary>106    /// Transform a single byte107    /// </summary>108    /// <returns>109    /// The transformed value110    /// </returns>111    protected byte TransformByte()1using System;2using System.Security.Cryptography;3using ICSharpCode.SharpZipLib.Checksum;45namespace ICSharpCode.SharpZipLib.Encryption6{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 and10  /// is viable for preventing casual snooping11  /// </summary>12  public abstract class PkzipClassic : SymmetricAlgorithm13  {14    /// <summary>15    /// Generates new encryption keys based on given seed16    /// </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      }2425      if (seed.Length == 0) {26        throw new ArgumentException("Length is zero", nameof(seed));27      }2829      uint[] newKeys = {30        0x12345678,31        0x23456789,32        0x3456789033       };3435      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      }4142      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  }5859  /// <summary>60  /// PkzipClassicCryptoBase provides the low level facilities for encryption61  /// and decryption using the PkzipClassic algorithm.62  /// </summary>63  class PkzipClassicCryptoBase64  {65    /// <summary>66    /// Transform a single byte67    /// </summary>68    /// <returns>69    /// The transformed value70    /// </returns>71    protected byte TransformByte()72    { + 225787273      uint temp = ((keys[2] & 0xFFFF) | 2); + 225787274      return (byte)((temp * (temp ^ 1)) >> 8);75    }7677    /// <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    }9697    /// <summary>98    /// Update encryption keys99    /// </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    }107108    /// <summary>109    /// Reset the internal state.110    /// </summary>111    protected void Reset()  112    { - 2260344113      uint temp = ((keys[2] & 0xFFFF) | 2); - 2260344114      return (byte)((temp * (temp ^ 1)) >> 8);115    }116117    /// <summary>118    /// Set the key schedule for encryption/decryption.119    /// </summary>120    /// <param name="keyData">The data use to set the keys from.</param>121    protected void SetKeys(byte[] keyData)122    { - 78123       if ( keyData == null ) { - 0124        throw new ArgumentNullException(nameof(keyData));125      }126 - 78127       if ( keyData.Length != 12 ) { - 0128        throw new InvalidOperationException("Key length is not valid");129      }130 - 78131      keys = new uint[3]; - 78132      keys[0] = (uint)((keyData[3] << 24) | (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]); - 78133      keys[1] = (uint)((keyData[7] << 24) | (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]); - 78134      keys[2] = (uint)((keyData[11] << 24) | (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]); - 78135    } + 32113      keys[0] = 0; + 32114      keys[1] = 0; + 32115      keys[2] = 0; + 32116    }117118    #region Instance Fields119    uint[] keys;120    #endregion121  }122123  /// <summary>124  /// PkzipClassic CryptoTransform for encryption.125  /// </summary>126  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform127  {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    }  136137    /// <summary>138    /// Update encryption keys139    /// </summary>140    protected void UpdateKeys(byte ch)141    { - 2260344142      keys[0] = Crc32.ComputeCrc32(keys[0], ch); - 2260344143      keys[1] = keys[1] + (byte)keys[0]; - 2260344144      keys[1] = keys[1] * 134775813 + 1; - 2260344145      keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24)); - 2260344146    }147148    /// <summary>149    /// Reset the internal state.150    /// </summary>151    protected void Reset()152    { - 35153      keys[0] = 0; - 35154      keys[1] = 0; - 35155      keys[2] = 0; - 35156    }157158    #region Instance Fields159    uint[] keys;160    #endregion161  }162163  /// <summary>164  /// PkzipClassic CryptoTransform for encryption.165  /// </summary>166  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform167  {168    /// <summary>169    /// Initialise a new instance of <see cref="PkzipClassicEncryptCryptoTransform"></see>170    /// </summary>171    /// <param name="keyBlock">The key block to use.</param>172    internal PkzipClassicEncryptCryptoTransform(byte[] keyBlock)173    {174      SetKeys(keyBlock);175    }176177    #region ICryptoTransform Members178179    /// <summary>180    /// Transforms the specified region of the specified byte array.181    /// </summary>182    /// <param name="inputBuffer">The input for which to compute the transform.</param>183    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>184    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>185    /// <returns>The computed transform.</returns>186    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)187    {188      byte[] result = new byte[inputCount];189      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);190      return result;191    }192193    /// <summary>194    /// Transforms the specified region of the input byte array and copies195    /// the resulting transform to the specified region of the output byte array.196    /// </summary>197    /// <param name="inputBuffer">The input for which to compute the transform.</param>198    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>199    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>200    /// <param name="outputBuffer">The output to which to write the transform.</param>201    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>202    /// <returns>The number of bytes written.</returns>203    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset204    {205      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {206        byte oldbyte = inputBuffer[i];207        outputBuffer[outputOffset++] = (byte)(inputBuffer[i] ^ TransformByte());208        UpdateKeys(oldbyte);209      }210      return inputCount;211    }137    #region ICryptoTransform Members138139    /// <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    }152153    /// <summary>154    /// Transforms the specified region of the input byte array and copies155    /// 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 outputOffset164    {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    }172173    /// <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    }181182    /// <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    }190191    /// <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    }199200    /// <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    }208209    #endregion210211    #region IDisposable Members  212  213    /// <summary>214    /// Gets a value indicating whether the current transform can be reused.214    /// Cleanup internal state.  215    /// </summary>216    public bool CanReuseTransform216    public void Dispose()  217    {218      get {219        return true;220      }221    }222223    /// <summary>224    /// Gets the size of the input data blocks in bytes.225    /// </summary>226    public int InputBlockSize227    {228      get {229        return 1;230      }231    }232233    /// <summary>234    /// Gets the size of the output data blocks in bytes.235    /// </summary>236    public int OutputBlockSize237    {238      get {239        return 1;240      }241    }242243    /// <summary>244    /// Gets a value indicating whether multiple blocks can be transformed.245    /// </summary>246    public bool CanTransformMultipleBlocks247    {248      get {249        return true;250      }251    }252253    #endregion218      Reset();219    }220221    #endregion222  }223224225  /// <summary>226  /// PkzipClassic CryptoTransform for decryption.227  /// </summary>228  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform229  {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    }238239    #region ICryptoTransform Members240241    /// <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    }  254255    #region IDisposable Members256257    /// <summary>258    /// Cleanup internal state.259    /// </summary>260    public void Dispose()261    {262      Reset();263    }264265    #endregion266  }267268269  /// <summary>270  /// PkzipClassic CryptoTransform for decryption.271  /// </summary>272  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform273  {274    /// <summary>275    /// Initialise a new instance of <see cref="PkzipClassicDecryptCryptoTransform"></see>.276    /// </summary>277    /// <param name="keyBlock">The key block to decrypt with.</param>278    internal PkzipClassicDecryptCryptoTransform(byte[] keyBlock)279    {280      SetKeys(keyBlock);281    }282283    #region ICryptoTransform Members284285    /// <summary>286    /// Transforms the specified region of the specified byte array.287    /// </summary>288    /// <param name="inputBuffer">The input for which to compute the transform.</param>289    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>290    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>291    /// <returns>The computed transform.</returns>292    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)293    {294      byte[] result = new byte[inputCount];295      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);296      return result;297    }298299    /// <summary>300    /// Transforms the specified region of the input byte array and copies301    /// the resulting transform to the specified region of the output byte array.302    /// </summary>303    /// <param name="inputBuffer">The input for which to compute the transform.</param>304    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>305    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>306    /// <param name="outputBuffer">The output to which to write the transform.</param>307    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>308    /// <returns>The number of bytes written.</returns>309    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset310    {311      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {312        var newByte = (byte)(inputBuffer[i] ^ TransformByte());313        outputBuffer[outputOffset++] = newByte;314        UpdateKeys(newByte);315      }316      return inputCount;317    }318319    /// <summary>320    /// Gets a value indicating whether the current transform can be reused.321    /// </summary>322    public bool CanReuseTransform323    {324      get {325        return true;326      }327    }328329    /// <summary>330    /// Gets the size of the input data blocks in bytes.331    /// </summary>332    public int InputBlockSize333    {334      get {335        return 1;336      }337    }338339    /// <summary>340    /// Gets the size of the output data blocks in bytes.341    /// </summary>342    public int OutputBlockSize343    {344      get {345        return 1;346      }347    }348349    /// <summary>350    /// Gets a value indicating whether multiple blocks can be transformed.351    /// </summary>352    public bool CanTransformMultipleBlocks353    {354      get {355        return true;255    /// <summary>256    /// Transforms the specified region of the input byte array and copies257    /// 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 outputOffset266    {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    }274275    /// <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    }283284    /// <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    }292293    /// <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    }301302    /// <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    }310311    #endregion312313    #region IDisposable Members314315    /// <summary>316    /// Cleanup internal state.317    /// </summary>318    public void Dispose()319    {320      Reset();321    }322323    #endregion324  }325326  /// <summary>327  /// Defines a wrapper object to access the Pkzip algorithm.328  /// This class cannot be inherited.329  /// </summary>330  public sealed class PkzipClassicManaged : PkzipClassic331  {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      }340341      set {342        if (value != 8) {343          throw new CryptographicException("Block size is invalid");344        }345      }346    }347348    /// <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    }  358359    #endregion360361    #region IDisposable Members362363    /// <summary>364    /// Cleanup internal state.365    /// </summary>366    public void Dispose()367    {368      Reset();369    }370371    #endregion372  }373374  /// <summary>375  /// Defines a wrapper object to access the Pkzip algorithm.376  /// This class cannot be inherited.377  /// </summary>378  public sealed class PkzipClassicManaged : PkzipClassic379  {380    /// <summary>381    /// Get / set the applicable block size in bits.382    /// </summary>383    /// <remarks>The only valid block size is 8.</remarks>384    public override int BlockSize385    {386      get {387        return 8;359    /// <summary>360    /// Generate an initial vector.361    /// </summary>362    public override void GenerateIV()363    {364      // Do nothing.365    }366367    /// <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    }377378    /// <summary>379    /// Get / set the key value applicable.380    /// </summary>381    public override byte[] Key {382      get {383        if (key_ == null) {384          GenerateKey();385        }386387        return (byte[])key_.Clone();  388      }  389  390      set {391        if (value != 8) {392          throw new CryptographicException("Block size is invalid");391        if (value == null) {392          throw new ArgumentNullException(nameof(value));  393        }394      }395    }396397    /// <summary>398    /// Get an array of legal <see cref="KeySizes">key sizes.</see>399    /// </summary>400    public override KeySizes[] LegalKeySizes401    {402      get {403        KeySizes[] keySizes = new KeySizes[1];404        keySizes[0] = new KeySizes(12 * 8, 12 * 8, 0);405        return keySizes;406      }407    }408409    /// <summary>410    /// Generate an initial vector.411    /// </summary>412    public override void GenerateIV()413    {414      // Do nothing.415    }416417    /// <summary>418    /// Get an array of legal <see cref="KeySizes">block sizes</see>.419    /// </summary>420    public override KeySizes[] LegalBlockSizes421    {422      get {423        KeySizes[] keySizes = new KeySizes[1];424        keySizes[0] = new KeySizes(1 * 8, 1 * 8, 0);425        return keySizes;426      }427    }428429    /// <summary>430    /// Get / set the key value applicable.431    /// </summary>432    public override byte[] Key433    {434      get {435        if ( key_ == null ) {436          GenerateKey();437        }438439        return (byte[]) key_.Clone();440      }441442      set {443        if ( value == null ) {444          throw new ArgumentNullException(nameof(value));445        }446447        if ( value.Length != 12 ) {448          throw new CryptographicException("Key size is illegal");449        }450451        key_ = (byte[]) value.Clone();452      }453    }454455    /// <summary>456    /// Generate a new random key.457    /// </summary>458    public override void GenerateKey()459    {460      key_ = new byte[12];461      var rnd = new Random();462      rnd.NextBytes(key_);463    }464465    /// <summary>466    /// Create an encryptor.467    /// </summary>468    /// <param name="rgbKey">The key to use for this encryptor.</param>469    /// <param name="rgbIV">Initialisation vector for the new encryptor.</param>470    /// <returns>Returns a new PkzipClassic encryptor</returns>471    public override ICryptoTransform CreateEncryptor(472      byte[] rgbKey,473      byte[] rgbIV)474    {475      key_ = rgbKey;476      return new PkzipClassicEncryptCryptoTransform(Key);477    }478479    /// <summary>480    /// Create a decryptor.481    /// </summary>482    /// <param name="rgbKey">Keys to use for this new decryptor.</param>483    /// <param name="rgbIV">Initialisation vector for the new decryptor.</param>484    /// <returns>Returns a new decryptor.</returns>485    public override ICryptoTransform CreateDecryptor(486      byte[] rgbKey,487      byte[] rgbIV)488    {489      key_ = rgbKey;490      return new PkzipClassicDecryptCryptoTransform(Key);491    }492493    #region Instance Fields494    byte[] key_;495    #endregion496  }497}498#endif394395        if (value.Length != 12) {396          throw new CryptographicException("Key size is illegal");397        }398399        key_ = (byte[])value.Clone();400      }401    }402403    /// <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    }412413    /// <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    }426427    /// <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    }440441    #region Instance Fields442    byte[] key_;443    #endregion444  }445} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicDecryptCryptoTransform.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicDecryptCryptoTransform.htm index 98ed7381a..ef82a6e09 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicDecryptCryptoTransform.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicDecryptCryptoTransform.htm @@ -18,7 +18,7 @@

Summary

Covered lines:14 Uncovered lines:3 Coverable lines:17 -Total lines:498 +Total lines:445 Line coverage:82.3% Branch coverage:100% @@ -38,506 +38,453 @@

#LineLine coverage - 1//2// PkzipClassic encryption3//4// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team5//6// This program is free software; you can redistribute it and/or7// modify it under the terms of the GNU General Public License8// as published by the Free Software Foundation; either version 29// of the License, or (at your option) any later version.10//11// This program is distributed in the hope that it will be useful,12// but WITHOUT ANY WARRANTY; without even the implied warranty of13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the14// GNU General Public License for more details.15//16// You should have received a copy of the GNU General Public License17// along with this program; if not, write to the Free Software18// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.19//20// Linking this library statically or dynamically with other modules is21// making a combined work based on this library.  Thus, the terms and22// conditions of the GNU General Public License cover the whole23// combination.24//25// As a special exception, the copyright holders of this library give you26// permission to link this library with independent modules to produce an27// executable, regardless of the license terms of these independent28// modules, and to copy and distribute the resulting executable under29// terms of your choice, provided that you also meet, for each linked30// independent module, the terms and conditions of the license of that31// module.  An independent module is a module which is not derived from32// or based on this library.  If you modify this library, you may extend33// this exception to your version of the library, but you are not34// obligated to do so.  If you do not wish to do so, delete this35// exception statement from your version.36//373839#if !NETCF_1_04041using System;42using System.Security.Cryptography;43using ICSharpCode.SharpZipLib.Checksums;4445namespace ICSharpCode.SharpZipLib.Encryption46{47  /// <summary>48  /// PkzipClassic embodies the classic or original encryption facilities used in Pkzip archives.49  /// While it has been superceded by more recent and more powerful algorithms, its still in use and50  /// is viable for preventing casual snooping51  /// </summary>52  public abstract class PkzipClassic : SymmetricAlgorithm53  {54    /// <summary>55    /// Generates new encryption keys based on given seed56    /// </summary>57    /// <param name="seed">The seed value to initialise keys with.</param>58    /// <returns>A new key value.</returns>59    static public byte[] GenerateKeys(byte[] seed)60    {61      if ( seed == null ) {62        throw new ArgumentNullException(nameof(seed));63      }6465      if ( seed.Length == 0 ) {66        throw new ArgumentException("Length is zero", nameof(seed));67      }6869      uint[] newKeys = {70        0x12345678,71        0x23456789,72        0x3456789073       };7475      for (int i = 0; i < seed.Length; ++i) {76        newKeys[0] = Crc32.ComputeCrc32(newKeys[0], seed[i]);77        newKeys[1] = newKeys[1] + (byte)newKeys[0];78        newKeys[1] = newKeys[1] * 134775813 + 1;79        newKeys[2] = Crc32.ComputeCrc32(newKeys[2], (byte)(newKeys[1] >> 24));80      }8182      byte[] result = new byte[12];83      result[0] = (byte)(newKeys[0] & 0xff);84      result[1] = (byte)((newKeys[0] >> 8) & 0xff);85      result[2] = (byte)((newKeys[0] >> 16) & 0xff);86      result[3] = (byte)((newKeys[0] >> 24) & 0xff);87      result[4] = (byte)(newKeys[1] & 0xff);88      result[5] = (byte)((newKeys[1] >> 8) & 0xff);89      result[6] = (byte)((newKeys[1] >> 16) & 0xff);90      result[7] = (byte)((newKeys[1] >> 24) & 0xff);91      result[8] = (byte)(newKeys[2] & 0xff);92      result[9] = (byte)((newKeys[2] >> 8) & 0xff);93      result[10] = (byte)((newKeys[2] >> 16) & 0xff);94      result[11] = (byte)((newKeys[2] >> 24) & 0xff);95      return result;96    }97  }9899  /// <summary>100  /// PkzipClassicCryptoBase provides the low level facilities for encryption101  /// and decryption using the PkzipClassic algorithm.102  /// </summary>103  class PkzipClassicCryptoBase104  {105    /// <summary>106    /// Transform a single byte107    /// </summary>108    /// <returns>109    /// The transformed value110    /// </returns>111    protected byte TransformByte()1using System;2using System.Security.Cryptography;3using ICSharpCode.SharpZipLib.Checksum;45namespace ICSharpCode.SharpZipLib.Encryption6{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 and10  /// is viable for preventing casual snooping11  /// </summary>12  public abstract class PkzipClassic : SymmetricAlgorithm13  {14    /// <summary>15    /// Generates new encryption keys based on given seed16    /// </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      }2425      if (seed.Length == 0) {26        throw new ArgumentException("Length is zero", nameof(seed));27      }2829      uint[] newKeys = {30        0x12345678,31        0x23456789,32        0x3456789033       };3435      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      }4142      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  }5859  /// <summary>60  /// PkzipClassicCryptoBase provides the low level facilities for encryption61  /// and decryption using the PkzipClassic algorithm.62  /// </summary>63  class PkzipClassicCryptoBase64  {65    /// <summary>66    /// Transform a single byte67    /// </summary>68    /// <returns>69    /// The transformed value70    /// </returns>71    protected byte TransformByte()72    {73      uint temp = ((keys[2] & 0xFFFF) | 2);74      return (byte)((temp * (temp ^ 1)) >> 8);75    }7677    /// <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      }8687      if (keyData.Length != 12) {88        throw new InvalidOperationException("Key length is not valid");89      }9091      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    }9697    /// <summary>98    /// Update encryption keys99    /// </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    }107108    /// <summary>109    /// Reset the internal state.110    /// </summary>111    protected void Reset()  112    {113      uint temp = ((keys[2] & 0xFFFF) | 2);114      return (byte)((temp * (temp ^ 1)) >> 8);115    }116117    /// <summary>118    /// Set the key schedule for encryption/decryption.119    /// </summary>120    /// <param name="keyData">The data use to set the keys from.</param>121    protected void SetKeys(byte[] keyData)122    {123      if ( keyData == null ) {124        throw new ArgumentNullException(nameof(keyData));125      }126127      if ( keyData.Length != 12 ) {128        throw new InvalidOperationException("Key length is not valid");129      }130131      keys = new uint[3];132      keys[0] = (uint)((keyData[3] << 24) | (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]);133      keys[1] = (uint)((keyData[7] << 24) | (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]);134      keys[2] = (uint)((keyData[11] << 24) | (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]);113      keys[0] = 0;114      keys[1] = 0;115      keys[2] = 0;116    }117118    #region Instance Fields119    uint[] keys;120    #endregion121  }122123  /// <summary>124  /// PkzipClassic CryptoTransform for encryption.125  /// </summary>126  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform127  {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    }  136137    /// <summary>138    /// Update encryption keys139    /// </summary>140    protected void UpdateKeys(byte ch)141    {142      keys[0] = Crc32.ComputeCrc32(keys[0], ch);143      keys[1] = keys[1] + (byte)keys[0];144      keys[1] = keys[1] * 134775813 + 1;145      keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));146    }147148    /// <summary>149    /// Reset the internal state.150    /// </summary>151    protected void Reset()152    {153      keys[0] = 0;154      keys[1] = 0;155      keys[2] = 0;156    }157158    #region Instance Fields159    uint[] keys;160    #endregion161  }162163  /// <summary>164  /// PkzipClassic CryptoTransform for encryption.165  /// </summary>166  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform167  {168    /// <summary>169    /// Initialise a new instance of <see cref="PkzipClassicEncryptCryptoTransform"></see>170    /// </summary>171    /// <param name="keyBlock">The key block to use.</param>172    internal PkzipClassicEncryptCryptoTransform(byte[] keyBlock)173    {174      SetKeys(keyBlock);175    }176177    #region ICryptoTransform Members178179    /// <summary>180    /// Transforms the specified region of the specified byte array.181    /// </summary>182    /// <param name="inputBuffer">The input for which to compute the transform.</param>183    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>184    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>185    /// <returns>The computed transform.</returns>186    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)187    {188      byte[] result = new byte[inputCount];189      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);190      return result;191    }192193    /// <summary>194    /// Transforms the specified region of the input byte array and copies195    /// the resulting transform to the specified region of the output byte array.196    /// </summary>197    /// <param name="inputBuffer">The input for which to compute the transform.</param>198    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>199    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>200    /// <param name="outputBuffer">The output to which to write the transform.</param>201    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>202    /// <returns>The number of bytes written.</returns>203    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset204    {205      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {206        byte oldbyte = inputBuffer[i];207        outputBuffer[outputOffset++] = (byte)(inputBuffer[i] ^ TransformByte());208        UpdateKeys(oldbyte);209      }210      return inputCount;211    }137    #region ICryptoTransform Members138139    /// <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    }152153    /// <summary>154    /// Transforms the specified region of the input byte array and copies155    /// 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 outputOffset164    {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    }172173    /// <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    }181182    /// <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    }190191    /// <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    }199200    /// <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    }208209    #endregion210211    #region IDisposable Members  212  213    /// <summary>214    /// Gets a value indicating whether the current transform can be reused.214    /// Cleanup internal state.  215    /// </summary>216    public bool CanReuseTransform216    public void Dispose()  217    {218      get {219        return true;220      }221    }222223    /// <summary>224    /// Gets the size of the input data blocks in bytes.225    /// </summary>226    public int InputBlockSize227    {228      get {229        return 1;230      }231    }232233    /// <summary>234    /// Gets the size of the output data blocks in bytes.235    /// </summary>236    public int OutputBlockSize237    {238      get {239        return 1;240      }241    }242243    /// <summary>244    /// Gets a value indicating whether multiple blocks can be transformed.245    /// </summary>246    public bool CanTransformMultipleBlocks247    {248      get {249        return true;250      }251    }252253    #endregion218      Reset();219    }220221    #endregion222  }223224225  /// <summary>226  /// PkzipClassic CryptoTransform for decryption.227  /// </summary>228  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform229  {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    }238239    #region ICryptoTransform Members240241    /// <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    }  254255    #region IDisposable Members256257    /// <summary>258    /// Cleanup internal state.259    /// </summary>260    public void Dispose()261    {262      Reset();263    }264265    #endregion266  }267268269  /// <summary>270  /// PkzipClassic CryptoTransform for decryption.271  /// </summary>272  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform273  {274    /// <summary>275    /// Initialise a new instance of <see cref="PkzipClassicDecryptCryptoTransform"></see>.276    /// </summary>277    /// <param name="keyBlock">The key block to decrypt with.</param> - 37278    internal PkzipClassicDecryptCryptoTransform(byte[] keyBlock)279    { - 37280      SetKeys(keyBlock); - 37281    }282283    #region ICryptoTransform Members284285    /// <summary>286    /// Transforms the specified region of the specified byte array.287    /// </summary>288    /// <param name="inputBuffer">The input for which to compute the transform.</param>289    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>290    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>291    /// <returns>The computed transform.</returns>292    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)293    { - 10294      byte[] result = new byte[inputCount]; - 10295      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0); - 10296      return result;297    }298299    /// <summary>300    /// Transforms the specified region of the input byte array and copies301    /// the resulting transform to the specified region of the output byte array.302    /// </summary>303    /// <param name="inputBuffer">The input for which to compute the transform.</param>304    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>305    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>306    /// <param name="outputBuffer">The output to which to write the transform.</param>307    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>308    /// <returns>The number of bytes written.</returns>309    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset310    { - 2264888311       for (int i = inputOffset; i < inputOffset + inputCount; ++i) { - 1132117312        var newByte = (byte)(inputBuffer[i] ^ TransformByte()); - 1132117313        outputBuffer[outputOffset++] = newByte; - 1132117314        UpdateKeys(newByte);315      } - 327316      return inputCount;317    }318319    /// <summary>320    /// Gets a value indicating whether the current transform can be reused.321    /// </summary>322    public bool CanReuseTransform323    {324      get { - 0325        return true;326      }327    }328329    /// <summary>330    /// Gets the size of the input data blocks in bytes.331    /// </summary>332    public int InputBlockSize333    {334      get { - 10335        return 1;336      }337    }338339    /// <summary>340    /// Gets the size of the output data blocks in bytes.341    /// </summary>342    public int OutputBlockSize343    {344      get { - 10345        return 1;346      }347    }348349    /// <summary>350    /// Gets a value indicating whether multiple blocks can be transformed.351    /// </summary>352    public bool CanTransformMultipleBlocks353    {354      get { - 26355        return true;255    /// <summary>256    /// Transforms the specified region of the input byte array and copies257    /// 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 outputOffset266    { + 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    }274275    /// <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    }283284    /// <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    }292293    /// <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    }301302    /// <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    }310311    #endregion312313    #region IDisposable Members314315    /// <summary>316    /// Cleanup internal state.317    /// </summary>318    public void Dispose()319    { + 0320      Reset(); + 0321    }322323    #endregion324  }325326  /// <summary>327  /// Defines a wrapper object to access the Pkzip algorithm.328  /// This class cannot be inherited.329  /// </summary>330  public sealed class PkzipClassicManaged : PkzipClassic331  {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      }340341      set {342        if (value != 8) {343          throw new CryptographicException("Block size is invalid");344        }345      }346    }347348    /// <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    }  358359    #endregion360361    #region IDisposable Members362363    /// <summary>364    /// Cleanup internal state.365    /// </summary>366    public void Dispose()367    { - 0368      Reset(); - 0369    }370371    #endregion372  }373374  /// <summary>375  /// Defines a wrapper object to access the Pkzip algorithm.376  /// This class cannot be inherited.377  /// </summary>378  public sealed class PkzipClassicManaged : PkzipClassic379  {380    /// <summary>381    /// Get / set the applicable block size in bits.382    /// </summary>383    /// <remarks>The only valid block size is 8.</remarks>384    public override int BlockSize385    {386      get {387        return 8;359    /// <summary>360    /// Generate an initial vector.361    /// </summary>362    public override void GenerateIV()363    {364      // Do nothing.365    }366367    /// <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    }377378    /// <summary>379    /// Get / set the key value applicable.380    /// </summary>381    public override byte[] Key {382      get {383        if (key_ == null) {384          GenerateKey();385        }386387        return (byte[])key_.Clone();  388      }  389  390      set {391        if (value != 8) {392          throw new CryptographicException("Block size is invalid");391        if (value == null) {392          throw new ArgumentNullException(nameof(value));  393        }394      }395    }396397    /// <summary>398    /// Get an array of legal <see cref="KeySizes">key sizes.</see>399    /// </summary>400    public override KeySizes[] LegalKeySizes401    {402      get {403        KeySizes[] keySizes = new KeySizes[1];404        keySizes[0] = new KeySizes(12 * 8, 12 * 8, 0);405        return keySizes;406      }407    }408409    /// <summary>410    /// Generate an initial vector.411    /// </summary>412    public override void GenerateIV()413    {414      // Do nothing.415    }416417    /// <summary>418    /// Get an array of legal <see cref="KeySizes">block sizes</see>.419    /// </summary>420    public override KeySizes[] LegalBlockSizes421    {422      get {423        KeySizes[] keySizes = new KeySizes[1];424        keySizes[0] = new KeySizes(1 * 8, 1 * 8, 0);425        return keySizes;426      }427    }428429    /// <summary>430    /// Get / set the key value applicable.431    /// </summary>432    public override byte[] Key433    {434      get {435        if ( key_ == null ) {436          GenerateKey();437        }438439        return (byte[]) key_.Clone();440      }441442      set {443        if ( value == null ) {444          throw new ArgumentNullException(nameof(value));445        }446447        if ( value.Length != 12 ) {448          throw new CryptographicException("Key size is illegal");449        }450451        key_ = (byte[]) value.Clone();452      }453    }454455    /// <summary>456    /// Generate a new random key.457    /// </summary>458    public override void GenerateKey()459    {460      key_ = new byte[12];461      var rnd = new Random();462      rnd.NextBytes(key_);463    }464465    /// <summary>466    /// Create an encryptor.467    /// </summary>468    /// <param name="rgbKey">The key to use for this encryptor.</param>469    /// <param name="rgbIV">Initialisation vector for the new encryptor.</param>470    /// <returns>Returns a new PkzipClassic encryptor</returns>471    public override ICryptoTransform CreateEncryptor(472      byte[] rgbKey,473      byte[] rgbIV)474    {475      key_ = rgbKey;476      return new PkzipClassicEncryptCryptoTransform(Key);477    }478479    /// <summary>480    /// Create a decryptor.481    /// </summary>482    /// <param name="rgbKey">Keys to use for this new decryptor.</param>483    /// <param name="rgbIV">Initialisation vector for the new decryptor.</param>484    /// <returns>Returns a new decryptor.</returns>485    public override ICryptoTransform CreateDecryptor(486      byte[] rgbKey,487      byte[] rgbIV)488    {489      key_ = rgbKey;490      return new PkzipClassicDecryptCryptoTransform(Key);491    }492493    #region Instance Fields494    byte[] key_;495    #endregion496  }497}498#endif394395        if (value.Length != 12) {396          throw new CryptographicException("Key size is illegal");397        }398399        key_ = (byte[])value.Clone();400      }401    }402403    /// <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    }412413    /// <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    }426427    /// <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    }440441    #region Instance Fields442    byte[] key_;443    #endregion444  }445} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicEncryptCryptoTransform.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicEncryptCryptoTransform.htm index 1d1b3dcd4..03a234a44 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicEncryptCryptoTransform.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicEncryptCryptoTransform.htm @@ -18,7 +18,7 @@

Summary

Covered lines:13 Uncovered lines:4 Coverable lines:17 -Total lines:498 +Total lines:445 Line coverage:76.4% Branch coverage:100% @@ -38,506 +38,453 @@

#LineLine coverage - 1//2// PkzipClassic encryption3//4// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team5//6// This program is free software; you can redistribute it and/or7// modify it under the terms of the GNU General Public License8// as published by the Free Software Foundation; either version 29// of the License, or (at your option) any later version.10//11// This program is distributed in the hope that it will be useful,12// but WITHOUT ANY WARRANTY; without even the implied warranty of13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the14// GNU General Public License for more details.15//16// You should have received a copy of the GNU General Public License17// along with this program; if not, write to the Free Software18// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.19//20// Linking this library statically or dynamically with other modules is21// making a combined work based on this library.  Thus, the terms and22// conditions of the GNU General Public License cover the whole23// combination.24//25// As a special exception, the copyright holders of this library give you26// permission to link this library with independent modules to produce an27// executable, regardless of the license terms of these independent28// modules, and to copy and distribute the resulting executable under29// terms of your choice, provided that you also meet, for each linked30// independent module, the terms and conditions of the license of that31// module.  An independent module is a module which is not derived from32// or based on this library.  If you modify this library, you may extend33// this exception to your version of the library, but you are not34// obligated to do so.  If you do not wish to do so, delete this35// exception statement from your version.36//373839#if !NETCF_1_04041using System;42using System.Security.Cryptography;43using ICSharpCode.SharpZipLib.Checksums;4445namespace ICSharpCode.SharpZipLib.Encryption46{47  /// <summary>48  /// PkzipClassic embodies the classic or original encryption facilities used in Pkzip archives.49  /// While it has been superceded by more recent and more powerful algorithms, its still in use and50  /// is viable for preventing casual snooping51  /// </summary>52  public abstract class PkzipClassic : SymmetricAlgorithm53  {54    /// <summary>55    /// Generates new encryption keys based on given seed56    /// </summary>57    /// <param name="seed">The seed value to initialise keys with.</param>58    /// <returns>A new key value.</returns>59    static public byte[] GenerateKeys(byte[] seed)60    {61      if ( seed == null ) {62        throw new ArgumentNullException(nameof(seed));63      }6465      if ( seed.Length == 0 ) {66        throw new ArgumentException("Length is zero", nameof(seed));67      }6869      uint[] newKeys = {70        0x12345678,71        0x23456789,72        0x3456789073       };7475      for (int i = 0; i < seed.Length; ++i) {76        newKeys[0] = Crc32.ComputeCrc32(newKeys[0], seed[i]);77        newKeys[1] = newKeys[1] + (byte)newKeys[0];78        newKeys[1] = newKeys[1] * 134775813 + 1;79        newKeys[2] = Crc32.ComputeCrc32(newKeys[2], (byte)(newKeys[1] >> 24));80      }8182      byte[] result = new byte[12];83      result[0] = (byte)(newKeys[0] & 0xff);84      result[1] = (byte)((newKeys[0] >> 8) & 0xff);85      result[2] = (byte)((newKeys[0] >> 16) & 0xff);86      result[3] = (byte)((newKeys[0] >> 24) & 0xff);87      result[4] = (byte)(newKeys[1] & 0xff);88      result[5] = (byte)((newKeys[1] >> 8) & 0xff);89      result[6] = (byte)((newKeys[1] >> 16) & 0xff);90      result[7] = (byte)((newKeys[1] >> 24) & 0xff);91      result[8] = (byte)(newKeys[2] & 0xff);92      result[9] = (byte)((newKeys[2] >> 8) & 0xff);93      result[10] = (byte)((newKeys[2] >> 16) & 0xff);94      result[11] = (byte)((newKeys[2] >> 24) & 0xff);95      return result;96    }97  }9899  /// <summary>100  /// PkzipClassicCryptoBase provides the low level facilities for encryption101  /// and decryption using the PkzipClassic algorithm.102  /// </summary>103  class PkzipClassicCryptoBase104  {105    /// <summary>106    /// Transform a single byte107    /// </summary>108    /// <returns>109    /// The transformed value110    /// </returns>111    protected byte TransformByte()1using System;2using System.Security.Cryptography;3using ICSharpCode.SharpZipLib.Checksum;45namespace ICSharpCode.SharpZipLib.Encryption6{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 and10  /// is viable for preventing casual snooping11  /// </summary>12  public abstract class PkzipClassic : SymmetricAlgorithm13  {14    /// <summary>15    /// Generates new encryption keys based on given seed16    /// </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      }2425      if (seed.Length == 0) {26        throw new ArgumentException("Length is zero", nameof(seed));27      }2829      uint[] newKeys = {30        0x12345678,31        0x23456789,32        0x3456789033       };3435      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      }4142      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  }5859  /// <summary>60  /// PkzipClassicCryptoBase provides the low level facilities for encryption61  /// and decryption using the PkzipClassic algorithm.62  /// </summary>63  class PkzipClassicCryptoBase64  {65    /// <summary>66    /// Transform a single byte67    /// </summary>68    /// <returns>69    /// The transformed value70    /// </returns>71    protected byte TransformByte()72    {73      uint temp = ((keys[2] & 0xFFFF) | 2);74      return (byte)((temp * (temp ^ 1)) >> 8);75    }7677    /// <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      }8687      if (keyData.Length != 12) {88        throw new InvalidOperationException("Key length is not valid");89      }9091      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    }9697    /// <summary>98    /// Update encryption keys99    /// </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    }107108    /// <summary>109    /// Reset the internal state.110    /// </summary>111    protected void Reset()  112    {113      uint temp = ((keys[2] & 0xFFFF) | 2);114      return (byte)((temp * (temp ^ 1)) >> 8);115    }116117    /// <summary>118    /// Set the key schedule for encryption/decryption.119    /// </summary>120    /// <param name="keyData">The data use to set the keys from.</param>121    protected void SetKeys(byte[] keyData)122    {123      if ( keyData == null ) {124        throw new ArgumentNullException(nameof(keyData));125      }126127      if ( keyData.Length != 12 ) {128        throw new InvalidOperationException("Key length is not valid");129      }130131      keys = new uint[3];132      keys[0] = (uint)((keyData[3] << 24) | (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]);133      keys[1] = (uint)((keyData[7] << 24) | (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]);134      keys[2] = (uint)((keyData[11] << 24) | (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]);135    }113      keys[0] = 0;114      keys[1] = 0;115      keys[2] = 0;116    }117118    #region Instance Fields119    uint[] keys;120    #endregion121  }122123  /// <summary>124  /// PkzipClassic CryptoTransform for encryption.125  /// </summary>126  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform127  {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    }  136137    /// <summary>138    /// Update encryption keys139    /// </summary>140    protected void UpdateKeys(byte ch)141    {142      keys[0] = Crc32.ComputeCrc32(keys[0], ch);143      keys[1] = keys[1] + (byte)keys[0];144      keys[1] = keys[1] * 134775813 + 1;145      keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));146    }147148    /// <summary>149    /// Reset the internal state.150    /// </summary>151    protected void Reset()152    {153      keys[0] = 0;154      keys[1] = 0;155      keys[2] = 0;156    }157158    #region Instance Fields159    uint[] keys;160    #endregion161  }162163  /// <summary>164  /// PkzipClassic CryptoTransform for encryption.165  /// </summary>166  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform167  {168    /// <summary>169    /// Initialise a new instance of <see cref="PkzipClassicEncryptCryptoTransform"></see>170    /// </summary>171    /// <param name="keyBlock">The key block to use.</param> - 41172    internal PkzipClassicEncryptCryptoTransform(byte[] keyBlock)173    { - 41174      SetKeys(keyBlock); - 41175    }176177    #region ICryptoTransform Members178179    /// <summary>180    /// Transforms the specified region of the specified byte array.181    /// </summary>182    /// <param name="inputBuffer">The input for which to compute the transform.</param>183    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>184    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>185    /// <returns>The computed transform.</returns>186    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)187    { - 0188      byte[] result = new byte[inputCount]; - 0189      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0); - 0190      return result;191    }192193    /// <summary>194    /// Transforms the specified region of the input byte array and copies195    /// the resulting transform to the specified region of the output byte array.196    /// </summary>197    /// <param name="inputBuffer">The input for which to compute the transform.</param>198    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>199    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>200    /// <param name="outputBuffer">The output to which to write the transform.</param>201    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>202    /// <returns>The number of bytes written.</returns>203    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset204    { - 2261096205       for (int i = inputOffset; i < inputOffset + inputCount; ++i) { - 1128227206        byte oldbyte = inputBuffer[i]; - 1128227207        outputBuffer[outputOffset++] = (byte)(inputBuffer[i] ^ TransformByte()); - 1128227208        UpdateKeys(oldbyte);209      } - 2321210      return inputCount;211    }137    #region ICryptoTransform Members138139    /// <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    }152153    /// <summary>154    /// Transforms the specified region of the input byte array and copies155    /// 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 outputOffset164    { + 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    }172173    /// <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    }181182    /// <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    }190191    /// <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    }199200    /// <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    }208209    #endregion210211    #region IDisposable Members  212  213    /// <summary>214    /// Gets a value indicating whether the current transform can be reused.214    /// Cleanup internal state.  215    /// </summary>216    public bool CanReuseTransform216    public void Dispose()  217    {218      get { - 0219        return true;220      }221    }222223    /// <summary>224    /// Gets the size of the input data blocks in bytes.225    /// </summary>226    public int InputBlockSize227    {228      get { - 5229        return 1;230      }231    }232233    /// <summary>234    /// Gets the size of the output data blocks in bytes.235    /// </summary>236    public int OutputBlockSize237    {238      get { - 5239        return 1;240      }241    }242243    /// <summary>244    /// Gets a value indicating whether multiple blocks can be transformed.245    /// </summary>246    public bool CanTransformMultipleBlocks247    {248      get { - 10249        return true;250      }251    }252253    #endregion + 32218      Reset(); + 32219    }220221    #endregion222  }223224225  /// <summary>226  /// PkzipClassic CryptoTransform for decryption.227  /// </summary>228  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform229  {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    }238239    #region ICryptoTransform Members240241    /// <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    }  254255    #region IDisposable Members256257    /// <summary>258    /// Cleanup internal state.259    /// </summary>260    public void Dispose()261    { - 35262      Reset(); - 35263    }264265    #endregion266  }267268269  /// <summary>270  /// PkzipClassic CryptoTransform for decryption.271  /// </summary>272  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform273  {274    /// <summary>275    /// Initialise a new instance of <see cref="PkzipClassicDecryptCryptoTransform"></see>.276    /// </summary>277    /// <param name="keyBlock">The key block to decrypt with.</param>278    internal PkzipClassicDecryptCryptoTransform(byte[] keyBlock)279    {280      SetKeys(keyBlock);281    }282283    #region ICryptoTransform Members284285    /// <summary>286    /// Transforms the specified region of the specified byte array.287    /// </summary>288    /// <param name="inputBuffer">The input for which to compute the transform.</param>289    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>290    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>291    /// <returns>The computed transform.</returns>292    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)293    {294      byte[] result = new byte[inputCount];295      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);296      return result;297    }298299    /// <summary>300    /// Transforms the specified region of the input byte array and copies301    /// the resulting transform to the specified region of the output byte array.302    /// </summary>303    /// <param name="inputBuffer">The input for which to compute the transform.</param>304    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>305    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>306    /// <param name="outputBuffer">The output to which to write the transform.</param>307    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>308    /// <returns>The number of bytes written.</returns>309    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset310    {311      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {312        var newByte = (byte)(inputBuffer[i] ^ TransformByte());313        outputBuffer[outputOffset++] = newByte;314        UpdateKeys(newByte);315      }316      return inputCount;317    }318319    /// <summary>320    /// Gets a value indicating whether the current transform can be reused.321    /// </summary>322    public bool CanReuseTransform323    {324      get {325        return true;326      }327    }328329    /// <summary>330    /// Gets the size of the input data blocks in bytes.331    /// </summary>332    public int InputBlockSize333    {334      get {335        return 1;336      }337    }338339    /// <summary>340    /// Gets the size of the output data blocks in bytes.341    /// </summary>342    public int OutputBlockSize343    {344      get {345        return 1;346      }347    }348349    /// <summary>350    /// Gets a value indicating whether multiple blocks can be transformed.351    /// </summary>352    public bool CanTransformMultipleBlocks353    {354      get {355        return true;255    /// <summary>256    /// Transforms the specified region of the input byte array and copies257    /// 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 outputOffset266    {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    }274275    /// <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    }283284    /// <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    }292293    /// <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    }301302    /// <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    }310311    #endregion312313    #region IDisposable Members314315    /// <summary>316    /// Cleanup internal state.317    /// </summary>318    public void Dispose()319    {320      Reset();321    }322323    #endregion324  }325326  /// <summary>327  /// Defines a wrapper object to access the Pkzip algorithm.328  /// This class cannot be inherited.329  /// </summary>330  public sealed class PkzipClassicManaged : PkzipClassic331  {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      }340341      set {342        if (value != 8) {343          throw new CryptographicException("Block size is invalid");344        }345      }346    }347348    /// <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    }  358359    #endregion360361    #region IDisposable Members362363    /// <summary>364    /// Cleanup internal state.365    /// </summary>366    public void Dispose()367    {368      Reset();369    }370371    #endregion372  }373374  /// <summary>375  /// Defines a wrapper object to access the Pkzip algorithm.376  /// This class cannot be inherited.377  /// </summary>378  public sealed class PkzipClassicManaged : PkzipClassic379  {380    /// <summary>381    /// Get / set the applicable block size in bits.382    /// </summary>383    /// <remarks>The only valid block size is 8.</remarks>384    public override int BlockSize385    {386      get {387        return 8;359    /// <summary>360    /// Generate an initial vector.361    /// </summary>362    public override void GenerateIV()363    {364      // Do nothing.365    }366367    /// <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    }377378    /// <summary>379    /// Get / set the key value applicable.380    /// </summary>381    public override byte[] Key {382      get {383        if (key_ == null) {384          GenerateKey();385        }386387        return (byte[])key_.Clone();  388      }  389  390      set {391        if (value != 8) {392          throw new CryptographicException("Block size is invalid");391        if (value == null) {392          throw new ArgumentNullException(nameof(value));  393        }394      }395    }396397    /// <summary>398    /// Get an array of legal <see cref="KeySizes">key sizes.</see>399    /// </summary>400    public override KeySizes[] LegalKeySizes401    {402      get {403        KeySizes[] keySizes = new KeySizes[1];404        keySizes[0] = new KeySizes(12 * 8, 12 * 8, 0);405        return keySizes;406      }407    }408409    /// <summary>410    /// Generate an initial vector.411    /// </summary>412    public override void GenerateIV()413    {414      // Do nothing.415    }416417    /// <summary>418    /// Get an array of legal <see cref="KeySizes">block sizes</see>.419    /// </summary>420    public override KeySizes[] LegalBlockSizes421    {422      get {423        KeySizes[] keySizes = new KeySizes[1];424        keySizes[0] = new KeySizes(1 * 8, 1 * 8, 0);425        return keySizes;426      }427    }428429    /// <summary>430    /// Get / set the key value applicable.431    /// </summary>432    public override byte[] Key433    {434      get {435        if ( key_ == null ) {436          GenerateKey();437        }438439        return (byte[]) key_.Clone();440      }441442      set {443        if ( value == null ) {444          throw new ArgumentNullException(nameof(value));445        }446447        if ( value.Length != 12 ) {448          throw new CryptographicException("Key size is illegal");449        }450451        key_ = (byte[]) value.Clone();452      }453    }454455    /// <summary>456    /// Generate a new random key.457    /// </summary>458    public override void GenerateKey()459    {460      key_ = new byte[12];461      var rnd = new Random();462      rnd.NextBytes(key_);463    }464465    /// <summary>466    /// Create an encryptor.467    /// </summary>468    /// <param name="rgbKey">The key to use for this encryptor.</param>469    /// <param name="rgbIV">Initialisation vector for the new encryptor.</param>470    /// <returns>Returns a new PkzipClassic encryptor</returns>471    public override ICryptoTransform CreateEncryptor(472      byte[] rgbKey,473      byte[] rgbIV)474    {475      key_ = rgbKey;476      return new PkzipClassicEncryptCryptoTransform(Key);477    }478479    /// <summary>480    /// Create a decryptor.481    /// </summary>482    /// <param name="rgbKey">Keys to use for this new decryptor.</param>483    /// <param name="rgbIV">Initialisation vector for the new decryptor.</param>484    /// <returns>Returns a new decryptor.</returns>485    public override ICryptoTransform CreateDecryptor(486      byte[] rgbKey,487      byte[] rgbIV)488    {489      key_ = rgbKey;490      return new PkzipClassicDecryptCryptoTransform(Key);491    }492493    #region Instance Fields494    byte[] key_;495    #endregion496  }497}498#endif394395        if (value.Length != 12) {396          throw new CryptographicException("Key size is illegal");397        }398399        key_ = (byte[])value.Clone();400      }401    }402403    /// <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    }412413    /// <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    }426427    /// <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    }440441    #region Instance Fields442    byte[] key_;443    #endregion444  }445} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicManaged.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicManaged.htm index 2d02b6aad..0db63705d 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicManaged.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_PkzipClassicManaged.htm @@ -18,7 +18,7 @@

Summary

Covered lines:6 Uncovered lines:22 Coverable lines:28 -Total lines:498 +Total lines:445 Line coverage:21.4% Branch coverage:12.5% @@ -38,506 +38,453 @@

#LineLine coverage - 1//2// PkzipClassic encryption3//4// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team5//6// This program is free software; you can redistribute it and/or7// modify it under the terms of the GNU General Public License8// as published by the Free Software Foundation; either version 29// of the License, or (at your option) any later version.10//11// This program is distributed in the hope that it will be useful,12// but WITHOUT ANY WARRANTY; without even the implied warranty of13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the14// GNU General Public License for more details.15//16// You should have received a copy of the GNU General Public License17// along with this program; if not, write to the Free Software18// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.19//20// Linking this library statically or dynamically with other modules is21// making a combined work based on this library.  Thus, the terms and22// conditions of the GNU General Public License cover the whole23// combination.24//25// As a special exception, the copyright holders of this library give you26// permission to link this library with independent modules to produce an27// executable, regardless of the license terms of these independent28// modules, and to copy and distribute the resulting executable under29// terms of your choice, provided that you also meet, for each linked30// independent module, the terms and conditions of the license of that31// module.  An independent module is a module which is not derived from32// or based on this library.  If you modify this library, you may extend33// this exception to your version of the library, but you are not34// obligated to do so.  If you do not wish to do so, delete this35// exception statement from your version.36//373839#if !NETCF_1_04041using System;42using System.Security.Cryptography;43using ICSharpCode.SharpZipLib.Checksums;4445namespace ICSharpCode.SharpZipLib.Encryption46{47  /// <summary>48  /// PkzipClassic embodies the classic or original encryption facilities used in Pkzip archives.49  /// While it has been superceded by more recent and more powerful algorithms, its still in use and50  /// is viable for preventing casual snooping51  /// </summary>52  public abstract class PkzipClassic : SymmetricAlgorithm53  {54    /// <summary>55    /// Generates new encryption keys based on given seed56    /// </summary>57    /// <param name="seed">The seed value to initialise keys with.</param>58    /// <returns>A new key value.</returns>59    static public byte[] GenerateKeys(byte[] seed)60    {61      if ( seed == null ) {62        throw new ArgumentNullException(nameof(seed));63      }6465      if ( seed.Length == 0 ) {66        throw new ArgumentException("Length is zero", nameof(seed));67      }6869      uint[] newKeys = {70        0x12345678,71        0x23456789,72        0x3456789073       };7475      for (int i = 0; i < seed.Length; ++i) {76        newKeys[0] = Crc32.ComputeCrc32(newKeys[0], seed[i]);77        newKeys[1] = newKeys[1] + (byte)newKeys[0];78        newKeys[1] = newKeys[1] * 134775813 + 1;79        newKeys[2] = Crc32.ComputeCrc32(newKeys[2], (byte)(newKeys[1] >> 24));80      }8182      byte[] result = new byte[12];83      result[0] = (byte)(newKeys[0] & 0xff);84      result[1] = (byte)((newKeys[0] >> 8) & 0xff);85      result[2] = (byte)((newKeys[0] >> 16) & 0xff);86      result[3] = (byte)((newKeys[0] >> 24) & 0xff);87      result[4] = (byte)(newKeys[1] & 0xff);88      result[5] = (byte)((newKeys[1] >> 8) & 0xff);89      result[6] = (byte)((newKeys[1] >> 16) & 0xff);90      result[7] = (byte)((newKeys[1] >> 24) & 0xff);91      result[8] = (byte)(newKeys[2] & 0xff);92      result[9] = (byte)((newKeys[2] >> 8) & 0xff);93      result[10] = (byte)((newKeys[2] >> 16) & 0xff);94      result[11] = (byte)((newKeys[2] >> 24) & 0xff);95      return result;96    }97  }9899  /// <summary>100  /// PkzipClassicCryptoBase provides the low level facilities for encryption101  /// and decryption using the PkzipClassic algorithm.102  /// </summary>103  class PkzipClassicCryptoBase104  {105    /// <summary>106    /// Transform a single byte107    /// </summary>108    /// <returns>109    /// The transformed value110    /// </returns>111    protected byte TransformByte()1using System;2using System.Security.Cryptography;3using ICSharpCode.SharpZipLib.Checksum;45namespace ICSharpCode.SharpZipLib.Encryption6{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 and10  /// is viable for preventing casual snooping11  /// </summary>12  public abstract class PkzipClassic : SymmetricAlgorithm13  {14    /// <summary>15    /// Generates new encryption keys based on given seed16    /// </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      }2425      if (seed.Length == 0) {26        throw new ArgumentException("Length is zero", nameof(seed));27      }2829      uint[] newKeys = {30        0x12345678,31        0x23456789,32        0x3456789033       };3435      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      }4142      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  }5859  /// <summary>60  /// PkzipClassicCryptoBase provides the low level facilities for encryption61  /// and decryption using the PkzipClassic algorithm.62  /// </summary>63  class PkzipClassicCryptoBase64  {65    /// <summary>66    /// Transform a single byte67    /// </summary>68    /// <returns>69    /// The transformed value70    /// </returns>71    protected byte TransformByte()72    {73      uint temp = ((keys[2] & 0xFFFF) | 2);74      return (byte)((temp * (temp ^ 1)) >> 8);75    }7677    /// <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      }8687      if (keyData.Length != 12) {88        throw new InvalidOperationException("Key length is not valid");89      }9091      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    }9697    /// <summary>98    /// Update encryption keys99    /// </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    }107108    /// <summary>109    /// Reset the internal state.110    /// </summary>111    protected void Reset()  112    {113      uint temp = ((keys[2] & 0xFFFF) | 2);114      return (byte)((temp * (temp ^ 1)) >> 8);115    }116117    /// <summary>118    /// Set the key schedule for encryption/decryption.119    /// </summary>120    /// <param name="keyData">The data use to set the keys from.</param>121    protected void SetKeys(byte[] keyData)122    {123      if ( keyData == null ) {124        throw new ArgumentNullException(nameof(keyData));125      }126127      if ( keyData.Length != 12 ) {128        throw new InvalidOperationException("Key length is not valid");129      }130131      keys = new uint[3];132      keys[0] = (uint)((keyData[3] << 24) | (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]);133      keys[1] = (uint)((keyData[7] << 24) | (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]);134      keys[2] = (uint)((keyData[11] << 24) | (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]);113      keys[0] = 0;114      keys[1] = 0;115      keys[2] = 0;116    }117118    #region Instance Fields119    uint[] keys;120    #endregion121  }122123  /// <summary>124  /// PkzipClassic CryptoTransform for encryption.125  /// </summary>126  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform127  {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    }  136137    /// <summary>138    /// Update encryption keys139    /// </summary>140    protected void UpdateKeys(byte ch)141    {142      keys[0] = Crc32.ComputeCrc32(keys[0], ch);143      keys[1] = keys[1] + (byte)keys[0];144      keys[1] = keys[1] * 134775813 + 1;145      keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));146    }147148    /// <summary>149    /// Reset the internal state.150    /// </summary>151    protected void Reset()152    {153      keys[0] = 0;154      keys[1] = 0;155      keys[2] = 0;156    }157158    #region Instance Fields159    uint[] keys;160    #endregion161  }162163  /// <summary>164  /// PkzipClassic CryptoTransform for encryption.165  /// </summary>166  class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform167  {168    /// <summary>169    /// Initialise a new instance of <see cref="PkzipClassicEncryptCryptoTransform"></see>170    /// </summary>171    /// <param name="keyBlock">The key block to use.</param>172    internal PkzipClassicEncryptCryptoTransform(byte[] keyBlock)173    {174      SetKeys(keyBlock);175    }176177    #region ICryptoTransform Members178179    /// <summary>180    /// Transforms the specified region of the specified byte array.181    /// </summary>182    /// <param name="inputBuffer">The input for which to compute the transform.</param>183    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>184    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>185    /// <returns>The computed transform.</returns>186    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)187    {188      byte[] result = new byte[inputCount];189      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);190      return result;191    }192193    /// <summary>194    /// Transforms the specified region of the input byte array and copies195    /// the resulting transform to the specified region of the output byte array.196    /// </summary>197    /// <param name="inputBuffer">The input for which to compute the transform.</param>198    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>199    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>200    /// <param name="outputBuffer">The output to which to write the transform.</param>201    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>202    /// <returns>The number of bytes written.</returns>203    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset204    {205      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {206        byte oldbyte = inputBuffer[i];207        outputBuffer[outputOffset++] = (byte)(inputBuffer[i] ^ TransformByte());208        UpdateKeys(oldbyte);209      }210      return inputCount;211    }137    #region ICryptoTransform Members138139    /// <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    }152153    /// <summary>154    /// Transforms the specified region of the input byte array and copies155    /// 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 outputOffset164    {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    }172173    /// <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    }181182    /// <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    }190191    /// <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    }199200    /// <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    }208209    #endregion210211    #region IDisposable Members  212  213    /// <summary>214    /// Gets a value indicating whether the current transform can be reused.214    /// Cleanup internal state.  215    /// </summary>216    public bool CanReuseTransform216    public void Dispose()  217    {218      get {219        return true;220      }221    }222223    /// <summary>224    /// Gets the size of the input data blocks in bytes.225    /// </summary>226    public int InputBlockSize227    {228      get {229        return 1;230      }231    }232233    /// <summary>234    /// Gets the size of the output data blocks in bytes.235    /// </summary>236    public int OutputBlockSize237    {238      get {239        return 1;240      }241    }242243    /// <summary>244    /// Gets a value indicating whether multiple blocks can be transformed.245    /// </summary>246    public bool CanTransformMultipleBlocks247    {248      get {249        return true;250      }251    }252253    #endregion218      Reset();219    }220221    #endregion222  }223224225  /// <summary>226  /// PkzipClassic CryptoTransform for decryption.227  /// </summary>228  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform229  {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    }238239    #region ICryptoTransform Members240241    /// <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    }  254255    #region IDisposable Members256257    /// <summary>258    /// Cleanup internal state.259    /// </summary>260    public void Dispose()261    {262      Reset();263    }264265    #endregion266  }267268269  /// <summary>270  /// PkzipClassic CryptoTransform for decryption.271  /// </summary>272  class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform273  {274    /// <summary>275    /// Initialise a new instance of <see cref="PkzipClassicDecryptCryptoTransform"></see>.276    /// </summary>277    /// <param name="keyBlock">The key block to decrypt with.</param>278    internal PkzipClassicDecryptCryptoTransform(byte[] keyBlock)279    {280      SetKeys(keyBlock);281    }282283    #region ICryptoTransform Members284285    /// <summary>286    /// Transforms the specified region of the specified byte array.287    /// </summary>288    /// <param name="inputBuffer">The input for which to compute the transform.</param>289    /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>290    /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>291    /// <returns>The computed transform.</returns>292    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)293    {294      byte[] result = new byte[inputCount];295      TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);296      return result;297    }298299    /// <summary>300    /// Transforms the specified region of the input byte array and copies301    /// the resulting transform to the specified region of the output byte array.302    /// </summary>303    /// <param name="inputBuffer">The input for which to compute the transform.</param>304    /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>305    /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>306    /// <param name="outputBuffer">The output to which to write the transform.</param>307    /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>308    /// <returns>The number of bytes written.</returns>309    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset310    {311      for (int i = inputOffset; i < inputOffset + inputCount; ++i) {312        var newByte = (byte)(inputBuffer[i] ^ TransformByte());313        outputBuffer[outputOffset++] = newByte;314        UpdateKeys(newByte);315      }316      return inputCount;317    }318319    /// <summary>320    /// Gets a value indicating whether the current transform can be reused.321    /// </summary>322    public bool CanReuseTransform323    {324      get {325        return true;326      }327    }328329    /// <summary>330    /// Gets the size of the input data blocks in bytes.331    /// </summary>332    public int InputBlockSize333    {334      get {335        return 1;336      }337    }338339    /// <summary>340    /// Gets the size of the output data blocks in bytes.341    /// </summary>342    public int OutputBlockSize343    {344      get {345        return 1;346      }347    }348349    /// <summary>350    /// Gets a value indicating whether multiple blocks can be transformed.351    /// </summary>352    public bool CanTransformMultipleBlocks353    {354      get {355        return true;255    /// <summary>256    /// Transforms the specified region of the input byte array and copies257    /// 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 outputOffset266    {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    }274275    /// <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    }283284    /// <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    }292293    /// <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    }301302    /// <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    }310311    #endregion312313    #region IDisposable Members314315    /// <summary>316    /// Cleanup internal state.317    /// </summary>318    public void Dispose()319    {320      Reset();321    }322323    #endregion324  }325326  /// <summary>327  /// Defines a wrapper object to access the Pkzip algorithm.328  /// This class cannot be inherited.329  /// </summary>330  public sealed class PkzipClassicManaged : PkzipClassic331  {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      }340341      set { + 0342         if (value != 8) { + 0343          throw new CryptographicException("Block size is invalid");344        } + 0345      }346    }347348    /// <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    }  358359    #endregion360361    #region IDisposable Members362363    /// <summary>364    /// Cleanup internal state.365    /// </summary>366    public void Dispose()367    {368      Reset();369    }370371    #endregion372  }373374  /// <summary>375  /// Defines a wrapper object to access the Pkzip algorithm.376  /// This class cannot be inherited.377  /// </summary>378  public sealed class PkzipClassicManaged : PkzipClassic379  {380    /// <summary>381    /// Get / set the applicable block size in bits.382    /// </summary>383    /// <remarks>The only valid block size is 8.</remarks>384    public override int BlockSize385    {386      get { - 0387        return 8;359    /// <summary>360    /// Generate an initial vector.361    /// </summary>362    public override void GenerateIV()363    {364      // Do nothing. + 0365    }366367    /// <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    }377378    /// <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 != 8) { - 0392          throw new CryptographicException("Block size is invalid"); + 0391         if (value == null) { + 0392          throw new ArgumentNullException(nameof(value));  393        } - 0394      }395    }396397    /// <summary>398    /// Get an array of legal <see cref="KeySizes">key sizes.</see>399    /// </summary>400    public override KeySizes[] LegalKeySizes401    {402      get { - 0403        KeySizes[] keySizes = new KeySizes[1]; - 0404        keySizes[0] = new KeySizes(12 * 8, 12 * 8, 0); - 0405        return keySizes;406      }407    }408409    /// <summary>410    /// Generate an initial vector.411    /// </summary>412    public override void GenerateIV()413    {414      // Do nothing. - 0415    }416417    /// <summary>418    /// Get an array of legal <see cref="KeySizes">block sizes</see>.419    /// </summary>420    public override KeySizes[] LegalBlockSizes421    {422      get { - 0423        KeySizes[] keySizes = new KeySizes[1]; - 0424        keySizes[0] = new KeySizes(1 * 8, 1 * 8, 0); - 0425        return keySizes;426      }427    }428429    /// <summary>430    /// Get / set the key value applicable.431    /// </summary>432    public override byte[] Key433    {434      get { - 78435         if ( key_ == null ) { - 0436          GenerateKey();437        }438 - 78439        return (byte[]) key_.Clone();440      }441442      set { - 0443         if ( value == null ) { - 0444          throw new ArgumentNullException(nameof(value));445        }446 - 0447         if ( value.Length != 12 ) { - 0448          throw new CryptographicException("Key size is illegal");449        }450 - 0451        key_ = (byte[]) value.Clone(); - 0452      }453    }454455    /// <summary>456    /// Generate a new random key.457    /// </summary>458    public override void GenerateKey()459    { - 0460      key_ = new byte[12]; - 0461      var rnd = new Random(); - 0462      rnd.NextBytes(key_); - 0463    }464465    /// <summary>466    /// Create an encryptor.467    /// </summary>468    /// <param name="rgbKey">The key to use for this encryptor.</param>469    /// <param name="rgbIV">Initialisation vector for the new encryptor.</param>470    /// <returns>Returns a new PkzipClassic encryptor</returns>471    public override ICryptoTransform CreateEncryptor(472      byte[] rgbKey,473      byte[] rgbIV)474    { - 41475      key_ = rgbKey; - 41476      return new PkzipClassicEncryptCryptoTransform(Key);477    }478479    /// <summary>480    /// Create a decryptor.481    /// </summary>482    /// <param name="rgbKey">Keys to use for this new decryptor.</param>483    /// <param name="rgbIV">Initialisation vector for the new decryptor.</param>484    /// <returns>Returns a new decryptor.</returns>485    public override ICryptoTransform CreateDecryptor(486      byte[] rgbKey,487      byte[] rgbIV)488    { - 37489      key_ = rgbKey; - 37490      return new PkzipClassicDecryptCryptoTransform(Key);491    }492493    #region Instance Fields494    byte[] key_;495    #endregion496  }497}498#endif394 + 0395         if (value.Length != 12) { + 0396          throw new CryptographicException("Key size is illegal");397        }398 + 0399        key_ = (byte[])value.Clone(); + 0400      }401    }402403    /// <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    }412413    /// <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    }426427    /// <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    }440441    #region Instance Fields442    byte[] key_;443    #endregion444  }445} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ProcessFileHandler.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ProcessFileHandler.htm index b3b99442a..76a26ebdb 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ProcessFileHandler.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ProcessFileHandler.htm @@ -24,6 +24,6 @@

Summary

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/Documentation/opencover/ICSharpCode.SharpZipLib_ProgressEventArgs.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ProgressEventArgs.htm index 5b1f9c2b1..00cc0b5b4 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ProgressEventArgs.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ProgressEventArgs.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:16 Coverable lines:16 -Total lines:530 +Total lines:475 Line coverage:0% Branch coverage:0% @@ -35,538 +35,483 @@

#LineLine coverage - 1// FileSystemScanner.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.351using System;23namespace ICSharpCode.SharpZipLib.Core4{5  #region EventArgs6  /// <summary>7  /// Event arguments for scanning.8  /// </summary>9  public class ScanEventArgs : EventArgs10  {11    #region Constructors12    /// <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    #endregion2122    /// <summary>23    /// The file or directory name for this event.24    /// </summary>25    public string Name {26      get { return name_; }27    }2829    /// <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    }  3637using System;3839namespace ICSharpCode.SharpZipLib.Core40{41  #region EventArgs42  /// <summary>43  /// Event arguments for scanning.44  /// </summary>45  public class ScanEventArgs : EventArgs46  {47    #region Constructors48    /// <summary>49    /// Initialise a new instance of <see cref="ScanEventArgs"/>50    /// </summary>51    /// <param name="name">The file or directory name.</param>52    public ScanEventArgs(string name)53    {54      name_ = name;55    }56    #endregion5758    /// <summary>59    /// The file or directory name for this event.60    /// </summary>61    public string Name62    {63      get { return name_; }64    }6566    /// <summary>67    /// Get set a value indicating if scanning should continue or not.68    /// </summary>69    public bool ContinueRunning70    {71      get { return continueRunning_; }72      set { continueRunning_ = value; }73    }7475    #region Instance Fields76    string name_;77    bool continueRunning_ = true;78    #endregion79  }8081  /// <summary>82  /// Event arguments during processing of a single file or directory.83  /// </summary>84  public class ProgressEventArgs : EventArgs85  {86    #region Constructors87    /// <summary>88    /// Initialise a new instance of <see cref="ScanEventArgs"/>89    /// </summary>90    /// <param name="name">The file or directory name if known.</param>91    /// <param name="processed">The number of bytes processed so far</param>92    /// <param name="target">The total number of bytes to process, 0 if not known</param> - 093    public ProgressEventArgs(string name, long processed, long target)94    { - 095      name_ = name; - 096      processed_ = processed; - 097      target_ = target; - 098    }99    #endregion37    #region Instance Fields38    string name_;39    bool continueRunning_ = true;40    #endregion41  }4243  /// <summary>44  /// Event arguments during processing of a single file or directory.45  /// </summary>46  public class ProgressEventArgs : EventArgs47  {48    #region Constructors49    /// <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    #endregion6263    /// <summary>64    /// The name for this event if known.65    /// </summary>66    public string Name { + 067      get { return name_; }68    }6970    /// <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    }7778    /// <summary>79    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed80    /// </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    }9394    /// <summary>95    /// The number of bytes processed so far96    /// </summary>97    public long Processed { + 098      get { return processed_; }99    }  100  101    /// <summary>102    /// The name for this event if known.102    /// The number of bytes to process.  103    /// </summary>104    public string Name105    { - 0106      get { return name_; }104    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>105    public long Target { + 0106      get { return target_; }  107    }  108109    /// <summary>110    /// Get set a value indicating wether scanning should continue or not.111    /// </summary>112    public bool ContinueRunning113    { - 0114      get { return continueRunning_; } - 0115      set { continueRunning_ = value; }116    }117118    /// <summary>119    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed120    /// </summary>121    /// <value>0.0 to 100.0 percent; 0 if target is not known.</value>122    public float PercentComplete123    {124      get125      {126          float result; - 0127         if (target_ <= 0)128        { - 0129          result = 0; - 0130        }131        else132        { - 0133          result = ((float)processed_ / (float)target_) * 100.0f;134        } - 0135          return result;136      }137    }138139    /// <summary>140    /// The number of bytes processed so far141    /// </summary>142    public long Processed143    { - 0144      get { return processed_; }145    }146147    /// <summary>148    /// The number of bytes to process.149    /// </summary>150    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>151    public long Target152    { - 0153      get { return target_; }154    }155156    #region Instance Fields157    string name_;158    long processed_;159    long target_; - 0160    bool continueRunning_ = true;161    #endregion162  }163164  /// <summary>165  /// Event arguments for directories.166  /// </summary>167  public class DirectoryEventArgs : ScanEventArgs168  {169    #region Constructors170    /// <summary>171    /// Initialize an instance of <see cref="DirectoryEventArgs"></see>.172    /// </summary>173    /// <param name="name">The name for this directory.</param>174    /// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</par175    public DirectoryEventArgs(string name, bool hasMatchingFiles)176      : base (name)177    {178      hasMatchingFiles_ = hasMatchingFiles;179    }180    #endregion109    #region Instance Fields110    string name_;111    long processed_;112    long target_; + 0113    bool continueRunning_ = true;114    #endregion115  }116117  /// <summary>118  /// Event arguments for directories.119  /// </summary>120  public class DirectoryEventArgs : ScanEventArgs121  {122    #region Constructors123    /// <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.</par128    public DirectoryEventArgs(string name, bool hasMatchingFiles)129      : base(name)130    {131      hasMatchingFiles_ = hasMatchingFiles;132    }133    #endregion134135    /// <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    }141142    readonly143144    #region Instance Fields145    bool hasMatchingFiles_;146    #endregion147  }148149  /// <summary>150  /// Arguments passed when scan failures are detected.151  /// </summary>152  public class ScanFailureEventArgs : EventArgs153  {154    #region Constructors155    /// <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    #endregion167168    /// <summary>169    /// The applicable name.170    /// </summary>171    public string Name {172      get { return name_; }173    }174175    /// <summary>176    /// The applicable exception.177    /// </summary>178    public Exception Exception {179      get { return exception_; }180    }  181  182    /// <summary>183    /// Get a value indicating if the directory contains any matching files or not.183    /// Get / set a value indicating wether scanning should continue.  184    /// </summary>185    public bool HasMatchingFiles186    {187      get { return hasMatchingFiles_; }185    public bool ContinueRunning {186      get { return continueRunning_; }187      set { continueRunning_ = value; }  188    }  189190    readonly191192    #region Instance Fields193    bool hasMatchingFiles_;190    #region Instance Fields191    string name_;192    Exception exception_;193    bool continueRunning_;  194    #endregion  195  }  196197  /// <summary>198  /// Arguments passed when scan failures are detected.199  /// </summary>200  public class ScanFailureEventArgs : EventArgs201  {202    #region Constructors203    /// <summary>204    /// Initialise a new instance of <see cref="ScanFailureEventArgs"></see>205    /// </summary>206    /// <param name="name">The name to apply.</param>207    /// <param name="e">The exception to use.</param>208    public ScanFailureEventArgs(string name, Exception e)209    {210      name_ = name;211      exception_ = e;212      continueRunning_ = true;213    }214    #endregion215216    /// <summary>217    /// The applicable name.218    /// </summary>219    public string Name220    {221      get { return name_; }222    }223224    /// <summary>225    /// The applicable exception.226    /// </summary>227    public Exception Exception228    {229      get { return exception_; }230    }231232    /// <summary>233    /// Get / set a value indicating wether scanning should continue.234    /// </summary>235    public bool ContinueRunning236    {237      get { return continueRunning_; }238      set { continueRunning_ = value; }239    }240241    #region Instance Fields242    string name_;243    Exception exception_;244    bool continueRunning_;245    #endregion246  }247248  #endregion249250  #region Delegates251  /// <summary>252  /// Delegate invoked before starting to process a file.253  /// </summary>254  /// <param name="sender">The source of the event</param>255  /// <param name="e">The event arguments.</param>256  public delegate void ProcessFileHandler(object sender, ScanEventArgs e);257258  /// <summary>259  /// Delegate invoked during processing of a file or directory260  /// </summary>261  /// <param name="sender">The source of the event</param>262  /// <param name="e">The event arguments.</param>263  public delegate void ProgressHandler(object sender, ProgressEventArgs e);264265  /// <summary>266  /// Delegate invoked when a file has been completely processed.267  /// </summary>268  /// <param name="sender">The source of the event</param>269  /// <param name="e">The event arguments.</param>270  public delegate void CompletedFileHandler(object sender, ScanEventArgs e);271272  /// <summary>273  /// Delegate invoked when a directory failure is detected.274  /// </summary>275  /// <param name="sender">The source of the event</param>276  /// <param name="e">The event arguments.</param>277  public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e);278279  /// <summary>280  /// Delegate invoked when a file failure is detected.281  /// </summary>282  /// <param name="sender">The source of the event</param>283  /// <param name="e">The event arguments.</param>284  public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e);285  #endregion286287  /// <summary>288  /// FileSystemScanner provides facilities scanning of files and directories.289  /// </summary>290  public class FileSystemScanner291  {292    #region Constructors293    /// <summary>294    /// Initialise a new instance of <see cref="FileSystemScanner"></see>295    /// </summary>296    /// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param>297    public FileSystemScanner(string filter)298    {299      fileFilter_ = new PathFilter(filter);300    }301302    /// <summary>303    /// Initialise a new instance of <see cref="FileSystemScanner"></see>304    /// </summary>305    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>306    /// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param>307    public FileSystemScanner(string fileFilter, string directoryFilter)308    {309      fileFilter_ = new PathFilter(fileFilter);310      directoryFilter_ = new PathFilter(directoryFilter);311    }312313    /// <summary>314    /// Initialise a new instance of <see cref="FileSystemScanner"></see>315    /// </summary>316    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param>317    public FileSystemScanner(IScanFilter fileFilter)318    {319      fileFilter_ = fileFilter;320    }321322    /// <summary>323    /// Initialise a new instance of <see cref="FileSystemScanner"></see>324    /// </summary>325    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see>  to apply.</param>326    /// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see>  to apply.</param>327    public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter)328    {329      fileFilter_ = fileFilter;330      directoryFilter_ = directoryFilter;331    }332    #endregion333334    #region Delegates335    /// <summary>336    /// Delegate to invoke when a directory is processed.337    /// </summary>338    public event EventHandler<DirectoryEventArgs> ProcessDirectory;339340    /// <summary>341    /// Delegate to invoke when a file is processed.342    /// </summary>343    public ProcessFileHandler ProcessFile;344345    /// <summary>346    /// Delegate to invoke when processing for a file has finished.347    /// </summary>348    public CompletedFileHandler CompletedFile;349350    /// <summary>351    /// Delegate to invoke when a directory failure is detected.352    /// </summary>353    public DirectoryFailureHandler DirectoryFailure;354355    /// <summary>356    /// Delegate to invoke when a file failure is detected.357    /// </summary>358    public FileFailureHandler FileFailure;359    #endregion197  #endregion198199  #region Delegates200  /// <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);206207  /// <summary>208  /// Delegate invoked during processing of a file or directory209  /// </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);213214  /// <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);220221  /// <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);227228  /// <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  #endregion235236  /// <summary>237  /// FileSystemScanner provides facilities scanning of files and directories.238  /// </summary>239  public class FileSystemScanner240  {241    #region Constructors242    /// <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    }250251    /// <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    }261262    /// <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    }270271    /// <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    #endregion282283    #region Delegates284    /// <summary>285    /// Delegate to invoke when a directory is processed.286    /// </summary>287    public event EventHandler<DirectoryEventArgs> ProcessDirectory;288289    /// <summary>290    /// Delegate to invoke when a file is processed.291    /// </summary>292    public ProcessFileHandler ProcessFile;293294    /// <summary>295    /// Delegate to invoke when processing for a file has finished.296    /// </summary>297    public CompletedFileHandler CompletedFile;298299    /// <summary>300    /// Delegate to invoke when a directory failure is detected.301    /// </summary>302    public DirectoryFailureHandler DirectoryFailure;303304    /// <summary>305    /// Delegate to invoke when a file failure is detected.306    /// </summary>307    public FileFailureHandler FileFailure;308    #endregion309310    /// <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    }326327    /// <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;335336      bool result = (handler != null);337338      if (result) {339        var args = new ScanFailureEventArgs(file, e);340        FileFailure(this, args);341        alive_ = args.ContinueRunning;342      }343      return result;344    }345346    /// <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;353354      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 DirectoryFailure event.362    /// Raise the complete file event  363    /// </summary>364    /// <param name="directory">The directory name.</param>365    /// <param name="e">The exception detected.</param>366    bool OnDirectoryFailure(string directory, Exception e)367    {368            DirectoryFailureHandler handler = DirectoryFailure;369            bool result = (handler != null);370            if ( result ) {371        var args = new ScanFailureEventArgs(directory, e);372        handler(this, args);373        alive_ = args.ContinueRunning;374      }375            return result;376    }377378    /// <summary>379    /// Raise the FileFailure event.380    /// </summary>381    /// <param name="file">The file name.</param>382    /// <param name="e">The exception detected.</param>383    bool OnFileFailure(string file, Exception e)384    {385            FileFailureHandler handler = FileFailure;386387            bool result = (handler != null);388389      if ( result ){390        var args = new ScanFailureEventArgs(file, e);391        FileFailure(this, args);392        alive_ = args.ContinueRunning;393      }394            return result;395    }396397    /// <summary>398    /// Raise the ProcessFile event.399    /// </summary>400    /// <param name="file">The file name.</param>401    void OnProcessFile(string file)402    {403      ProcessFileHandler handler = ProcessFile;404405      if ( handler!= null ) {406        var args = new ScanEventArgs(file);407        handler(this, args);408        alive_ = args.ContinueRunning;409      }410    }411412    /// <summary>413    /// Raise the complete file event414    /// </summary>415    /// <param name="file">The file name</param>416    void OnCompleteFile(string file)417    {418      CompletedFileHandler handler = CompletedFile;419420      if (handler != null)421      {422        var args = new ScanEventArgs(file);423        handler(this, args);424        alive_ = args.ContinueRunning;425      }426    }427428    /// <summary>429    /// Raise the ProcessDirectory event.430    /// </summary>431    /// <param name="directory">The directory name.</param>432    /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param>433    void OnProcessDirectory(string directory, bool hasMatchingFiles)434    {435      EventHandler<DirectoryEventArgs> handler = ProcessDirectory;436437      if ( handler != null ) {438        var args = new DirectoryEventArgs(directory, hasMatchingFiles);439        handler(this, args);440        alive_ = args.ContinueRunning;441      }442    }443444    /// <summary>445    /// Scan a directory.446    /// </summary>447    /// <param name="directory">The base directory to scan.</param>448    /// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param>449    public void Scan(string directory, bool recurse)450    {451      alive_ = true;452      ScanDir(directory, recurse);453    }454455    void ScanDir(string directory, bool recurse)456    {457458      try {459        string[] names = System.IO.Directory.GetFiles(directory);460        bool hasMatch = false;461        for (int fileIndex = 0; fileIndex < names.Length; ++fileIndex) {462          if ( !fileFilter_.IsMatch(names[fileIndex]) ) {463            names[fileIndex] = null;464          } else {465            hasMatch = true;466          }467        }468469        OnProcessDirectory(directory, hasMatch);470471        if ( alive_ && hasMatch ) {472          foreach (string fileName in names) {473            try {474              if ( fileName != null ) {475                OnProcessFile(fileName);476                if ( !alive_ ) {477                  break;478                }479              }480            }481            catch (Exception e) {482                            if (!OnFileFailure(fileName, e)) {483                                throw;484                            }485            }486          }487        }488      }489      catch (Exception e) {490                if (!OnDirectoryFailure(directory, e)) {491                    throw;492                }493      }494495      if ( alive_ && recurse ) {496        try {497          string[] names = System.IO.Directory.GetDirectories(directory);498          foreach (string fulldir in names) {499            if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir))) {500              ScanDir(fulldir, true);501              if ( !alive_ ) {502                break;503              }504            }505          }506        }507        catch (Exception e) {508                    if (!OnDirectoryFailure(directory, e)) {509                        throw;510                    }511        }512      }513    }514515    #region Instance Fields516    /// <summary>517    /// The file filter currently in use.518    /// </summary>519    IScanFilter fileFilter_;520    /// <summary>521    /// The directory filter currently in use.522    /// </summary>523    IScanFilter directoryFilter_;524    /// <summary>525    /// Flag indicating if scanning should continue running.526    /// </summary>527    bool alive_;528    #endregion529  }530}364    /// <param name="file">The file name</param>365    void OnCompleteFile(string file)366    {367      CompletedFileHandler handler = CompletedFile;368369      if (handler != null) {370        var args = new ScanEventArgs(file);371        handler(this, args);372        alive_ = args.ContinueRunning;373      }374    }375376    /// <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;384385      if (handler != null) {386        var args = new DirectoryEventArgs(directory, hasMatchingFiles);387        handler(this, args);388        alive_ = args.ContinueRunning;389      }390    }391392    /// <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    }402403    void ScanDir(string directory, bool recurse)404    {405406      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        }416417        OnProcessDirectory(directory, hasMatch);418419        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      }440441      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    }459460    #region Instance Fields461    /// <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    #endregion474  }475} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ProgressHandler.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ProgressHandler.htm index f2a3ab37f..5180ae3a9 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ProgressHandler.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ProgressHandler.htm @@ -24,6 +24,6 @@

Summary

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/Documentation/opencover/ICSharpCode.SharpZipLib_ProgressMessageHandler.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ProgressMessageHandler.htm index 6c8376acc..1d12148d5 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ProgressMessageHandler.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ProgressMessageHandler.htm @@ -24,6 +24,6 @@

Summary

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/Documentation/opencover/ICSharpCode.SharpZipLib_RawTaggedData.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_RawTaggedData.htm index d4a51bef2..9585e12fe 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_RawTaggedData.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_RawTaggedData.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:13 Coverable lines:13 -Total lines:987 +Total lines:896 Line coverage:0% Branch coverage:0% @@ -37,995 +37,904 @@

#LineLine coverage - 1//2// ZipExtraData.cs3//4// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team5//6// This program is free software; you can redistribute it and/or7// modify it under the terms of the GNU General Public License8// as published by the Free Software Foundation; either version 29// of the License, or (at your option) any later version.10//11// This program is distributed in the hope that it will be useful,12// but WITHOUT ANY WARRANTY; without even the implied warranty of13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the14// GNU General Public License for more details.15//16// You should have received a copy of the GNU General Public License17// along with this program; if not, write to the Free Software18// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.19//20// Linking this library statically or dynamically with other modules is21// making a combined work based on this library.  Thus, the terms and22// conditions of the GNU General Public License cover the whole23// combination.24//25// As a special exception, the copyright holders of this library give you26// permission to link this library with independent modules to produce an27// executable, regardless of the license terms of these independent28// modules, and to copy and distribute the resulting executable under29// terms of your choice, provided that you also meet, for each linked30// independent module, the terms and conditions of the license of that31// module.  An independent module is a module which is not derived from32// or based on this library.  If you modify this library, you may extend33// this exception to your version of the library, but you are not34// obligated to do so.  If you do not wish to do so, delete this35// exception statement from your version.3637using System;38using System.IO;3940namespace ICSharpCode.SharpZipLib.Zip41{42  // TODO: Sort out wether tagged data is useful and what a good implementation might look like.43  // Its just a sketch of an idea at the moment.4445  /// <summary>46  /// ExtraData tagged value interface.47  /// </summary>48  public interface ITaggedData49  {1using System;2using System.IO;34namespace ICSharpCode.SharpZipLib.Zip5{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.89  /// <summary>10  /// ExtraData tagged value interface.11  /// </summary>12  public interface ITaggedData13  {14    /// <summary>15    /// Get the ID for this tagged data value.16    /// </summary>17    short TagID { get; }1819    /// <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);2627    /// <summary>28    /// Get the data representing this instance.29    /// </summary>30    /// <returns>Returns the data for this instance.</returns>31    byte[] GetData();32  }3334  /// <summary>35  /// A raw binary tagged value36  /// </summary>37  public class RawTaggedData : ITaggedData38  {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    }4748    #region ITaggedData Members49  50    /// <summary>  51    /// Get the ID for this tagged data value.  52    /// </summary>53    short TagID { get; }5455    /// <summary>56    /// Set the contents of this instance from the data passed.57    /// </summary>58    /// <param name="data">The data to extract contents from.</param>59    /// <param name="offset">The offset to begin extracting data from.</param>60    /// <param name="count">The number of bytes to extract.</param>61    void SetData(byte[] data, int offset, int count);6263    /// <summary>64    /// Get the data representing this instance.65    /// </summary>66    /// <returns>Returns the data for this instance.</returns>67    byte[] GetData();68  }53    public short TagID { + 054      get { return _tag; } + 055      set { _tag = value; }56    }5758    /// <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      }  6970  /// <summary>71  /// A raw binary tagged value72  /// </summary>73  public class RawTaggedData : ITaggedData74  {75    /// <summary>76    /// Initialise a new instance.77    /// </summary>78    /// <param name="tag">The tag ID.</param> - 079    public RawTaggedData(short tag)80    { - 081      _tag = tag; - 082    }8384    #region ITaggedData Members8586    /// <summary>87    /// Get the ID for this tagged data value.88    /// </summary>89    public short TagID90    { - 091      get { return _tag; } - 092      set { _tag = value; }93    }94 + 070      _data = new byte[count]; + 071      Array.Copy(data, offset, _data, 0, count); + 072    }7374    /// <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    }8283    #endregion8485    /// <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    }9394    #region Instance Fields  95    /// <summary>96    /// Set the data from the raw values provided.96    /// The tag ID for this instance.  97    /// </summary>98    /// <param name="data">The raw data to extract values from.</param>99    /// <param name="offset">The index to start extracting values from.</param>100    /// <param name="count">The number of bytes available.</param>101    public void SetData(byte[] data, int offset, int count)102    { - 0103       if( data==null )104      { - 0105        throw new ArgumentNullException(nameof(data));106      }107 - 0108      _data=new byte[count]; - 0109      Array.Copy(data, offset, _data, 0, count); - 0110    }111112    /// <summary>113    /// Get the binary data representing this instance.114    /// </summary>115    /// <returns>The raw binary data representing this instance.</returns>116    public byte[] GetData()117    { - 0118      return _data;119    }120121    #endregion122123    /// <summary>124    /// Get /set the binary data representing this instance.125    /// </summary>126    /// <returns>The raw binary data representing this instance.</returns>127    public byte[] Data128    { - 0129      get { return _data; } - 0130      set { _data=value; }131    }98    short _tag;99100    byte[] _data;101    #endregion102  }103104  /// <summary>105  /// Class representing extended unix date time values.106  /// </summary>107  public class ExtendedUnixData : ITaggedData108  {109    /// <summary>110    /// Flags indicate which values are included in this instance.111    /// </summary>112    [Flags]113    public enum Flags : byte114    {115      /// <summary>116      /// The modification time is included117      /// </summary>118      ModificationTime = 0x01,119120      /// <summary>121      /// The access time is included122      /// </summary>123      AccessTime = 0x02,124125      /// <summary>126      /// The create time is included.127      /// </summary>128      CreateTime = 0x04,129    }130131    #region ITaggedData Members  132133    #region Instance Fields134    /// <summary>135    /// The tag ID for this instance.136    /// </summary>137    short _tag;138139    byte[] _data;140    #endregion141  }142143  /// <summary>144  /// Class representing extended unix date time values.145  /// </summary>146  public class ExtendedUnixData : ITaggedData147  {148    /// <summary>149    /// Flags indicate which values are included in this instance.150    /// </summary>151    [Flags]152    public enum Flags : byte153    {154      /// <summary>155      /// The modification time is included156      /// </summary>157      ModificationTime = 0x01,133    /// <summary>134    /// Get the ID135    /// </summary>136    public short TagID {137      get { return 0x5455; }138    }139140    /// <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 present151        // bit 1           if set, access time is present152        // bit 2           if set, creation time is present153154        _flags = (Flags)helperStream.ReadByte();155        if (((_flags & Flags.ModificationTime) != 0))156        {157          int iTime = helperStream.ReadLEInt();  158159      /// <summary>160      /// The access time is included161      /// </summary>162      AccessTime = 0x02,163164      /// <summary>165      /// The create time is included.166      /// </summary>167      CreateTime = 0x04,168    }169170    #region ITaggedData Members171172    /// <summary>173    /// Get the ID174    /// </summary>175    public short TagID176    {177      get { return 0x5455; }178    }179180    /// <summary>181    /// Set the data from the raw values provided.182    /// </summary>183    /// <param name="data">The raw data to extract values from.</param>184    /// <param name="index">The index to start extracting values from.</param>185    /// <param name="count">The number of bytes available.</param>186    public void SetData(byte[] data, int index, int count)159          _modificationTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +160            new TimeSpan(0, 0, 0, iTime, 0);161162          // Central-header version is truncated after modification time163          if (count <= 5) return;164        }165166        if ((_flags & Flags.AccessTime) != 0) {167          int iTime = helperStream.ReadLEInt();168169          _lastAccessTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +170            new TimeSpan(0, 0, 0, iTime, 0);171        }172173        if ((_flags & Flags.CreateTime) != 0) {174          int iTime = helperStream.ReadLEInt();175176          _createTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +177            new TimeSpan(0, 0, 0, iTime, 0);178        }179      }180    }181182    /// <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(data, index, count, false))189      using (ZipHelperStream helperStream = new ZipHelperStream(ms))190      {191        // bit 0           if set, modification time is present192        // bit 1           if set, access time is present193        // bit 2           if set, creation time is present194195        _flags = (Flags)helperStream.ReadByte();196        if (((_flags & Flags.ModificationTime) != 0) && (count >= 5))197        {198          int iTime = helperStream.ReadLEInt();199200          _modificationTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +201            new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();202        }203204        if ((_flags & Flags.AccessTime) != 0)205        {206          int iTime = helperStream.ReadLEInt();207208          _lastAccessTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +209            new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();210        }211212        if ((_flags & Flags.CreateTime) != 0)213        {214          int iTime = helperStream.ReadLEInt();215216          _createTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +217            new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();218        }219      }220    }221222    /// <summary>223    /// Get the binary data representing this instance.224    /// </summary>225    /// <returns>The raw binary data representing this instance.</returns>226    public byte[] GetData()227    {228      using (MemoryStream ms = new MemoryStream())229      using (ZipHelperStream helperStream = new ZipHelperStream(ms))230      {231        helperStream.IsStreamOwner = false;232        helperStream.WriteByte((byte)_flags);     // Flags233        if ( (_flags & Flags.ModificationTime) != 0) {234          TimeSpan span = _modificationTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();235          var seconds = (int)span.TotalSeconds;236          helperStream.WriteLEInt(seconds);237        }238        if ( (_flags & Flags.AccessTime) != 0) {239          TimeSpan span = _lastAccessTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();240          var seconds = (int)span.TotalSeconds;241          helperStream.WriteLEInt(seconds);242        }243        if ( (_flags & Flags.CreateTime) != 0) {244          TimeSpan span = _createTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();245          var seconds = (int)span.TotalSeconds;246          helperStream.WriteLEInt(seconds);247        }248        return ms.ToArray();249      }250    }251252    #endregion253254    /// <summary>255    /// Test a <see cref="DateTime"> value to see if is valid and can be represented here.</see>256    /// </summary>257    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>258    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>259    /// <remarks>The standard Unix time is a signed integer data type, directly encoding the Unix time number,260    /// which is the number of seconds since 1970-01-01.261    /// Being 32 bits means the values here cover a range of about 136 years.262    /// The minimum representable time is 1901-12-13 20:45:52,263    /// and the maximum representable time is 2038-01-19 03:14:07.264    /// </remarks>265    public static bool IsValidValue(DateTime value)266    {267      return (( value >= new DateTime(1901, 12, 13, 20, 45, 52)) ||268          ( value <= new DateTime(2038, 1, 19, 03, 14, 07) ));269    }270271    /// <summary>272    /// Get /set the Modification Time273    /// </summary>274    /// <exception cref="ArgumentOutOfRangeException"></exception>275    /// <seealso cref="IsValidValue"></seealso>276    public DateTime ModificationTime277    {278      get { return _modificationTime; }279      set280      {281        if ( !IsValidValue(value) ) {282          throw new ArgumentOutOfRangeException(nameof(value));283        }284285        _flags |= Flags.ModificationTime;286        _modificationTime=value;287      }188      using (MemoryStream ms = new MemoryStream())189      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {190        helperStream.IsStreamOwner = false;191        helperStream.WriteByte((byte)_flags);     // Flags192        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    }210211    #endregion212213    /// <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    }229230    /// <summary>231    /// Get /set the Modification Time232    /// </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        }241242        _flags |= Flags.ModificationTime;243        _modificationTime = value;244      }245    }246247    /// <summary>248    /// Get / set the Access Time249    /// </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        }258259        _flags |= Flags.AccessTime;260        _lastAccessTime = value;261      }262    }263264    /// <summary>265    /// Get / Set the Create Time266    /// </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        }275276        _flags |= Flags.CreateTime;277        _createTime = value;278      }279    }280281    /// <summary>282    /// Get/set the <see cref="Flags">values</see> to include.283    /// </summary>284    public Flags Include285    {286      get { return _flags; }287      set { _flags = value; }  288    }  289290    /// <summary>291    /// Get / set the Access Time292    /// </summary>293    /// <exception cref="ArgumentOutOfRangeException"></exception>294    /// <seealso cref="IsValidValue"></seealso>295    public DateTime AccessTime296    {297      get { return _lastAccessTime; }298      set {299        if ( !IsValidValue(value) ) {300          throw new ArgumentOutOfRangeException(nameof(value));301        }302303        _flags |= Flags.AccessTime;304        _lastAccessTime=value;305      }306    }307308    /// <summary>309    /// Get / Set the Create Time310    /// </summary>311    /// <exception cref="ArgumentOutOfRangeException"></exception>312    /// <seealso cref="IsValidValue"></seealso>313    public DateTime CreateTime314    {315      get { return _createTime; }316      set {317        if ( !IsValidValue(value) ) {318          throw new ArgumentOutOfRangeException(nameof(value));319        }320321        _flags |= Flags.CreateTime;322        _createTime=value;323      }324    }325326    /// <summary>327    /// Get/set the <see cref="Flags">values</see> to include.328    /// </summary>329    Flags Include330    {331      get { return _flags; }332      set { _flags = value; }333    }334335    #region Instance Fields336    Flags _flags;337    DateTime _modificationTime = new DateTime(1970,1,1);338    DateTime _lastAccessTime = new DateTime(1970, 1, 1);339    DateTime _createTime = new DateTime(1970, 1, 1);340    #endregion341  }342343  /// <summary>344  /// Class handling NT date time values.345  /// </summary>346  public class NTTaggedData : ITaggedData347  {348    /// <summary>349    /// Get the ID for this tagged data value.350    /// </summary>351    public short TagID352    {353      get { return 10; }354    }355356    /// <summary>357    /// Set the data from the raw values provided.358    /// </summary>359    /// <param name="data">The raw data to extract values from.</param>360    /// <param name="index">The index to start extracting values from.</param>361    /// <param name="count">The number of bytes available.</param>362    public void SetData(byte[] data, int index, int count)363    {364      using (MemoryStream ms = new MemoryStream(data, index, count, false))365      using (ZipHelperStream helperStream = new ZipHelperStream(ms))366      {367        helperStream.ReadLEInt(); // Reserved368        while (helperStream.Position < helperStream.Length)369        {370          int ntfsTag = helperStream.ReadLEShort();371          int ntfsLength = helperStream.ReadLEShort();372          if (ntfsTag == 1)373          {374            if (ntfsLength >= 24)375            {376              long lastModificationTicks = helperStream.ReadLELong();377              _lastModificationTime = DateTime.FromFileTime(lastModificationTicks);378379              long lastAccessTicks = helperStream.ReadLELong();380              _lastAccessTime = DateTime.FromFileTime(lastAccessTicks);381382              long createTimeTicks = helperStream.ReadLELong();383              _createTime = DateTime.FromFileTime(createTimeTicks);384            }385            break;386          }387          else388          {389            // An unknown NTFS tag so simply skip it.390            helperStream.Seek(ntfsLength, SeekOrigin.Current);391          }392        }393      }394    }395396    /// <summary>397    /// Get the binary data representing this instance.398    /// </summary>399    /// <returns>The raw binary data representing this instance.</returns>400    public byte[] GetData()401    {402      using (MemoryStream ms = new MemoryStream())403      using (ZipHelperStream helperStream = new ZipHelperStream(ms))404      {405        helperStream.IsStreamOwner = false;406        helperStream.WriteLEInt(0);       // Reserved407        helperStream.WriteLEShort(1);     // Tag408        helperStream.WriteLEShort(24);    // Length = 3 x 8.409        helperStream.WriteLELong(_lastModificationTime.ToFileTime());410        helperStream.WriteLELong(_lastAccessTime.ToFileTime());411        helperStream.WriteLELong(_createTime.ToFileTime());412        return ms.ToArray();413      }414    }415416    /// <summary>417    /// Test a <see cref="DateTime"> valuie to see if is valid and can be represented here.</see>418    /// </summary>419    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>420    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>421    /// <remarks>422    /// NTFS filetimes are 64-bit unsigned integers, stored in Intel423    /// (least significant byte first) byte order. They determine the424    /// number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",425    /// which is "01-Jan-1601 00:00:00 UTC". 28 May 60056 is the upper limit426    /// </remarks>427    public static bool IsValidValue(DateTime value)428    {429      bool result = true;430      try431      {432        value.ToFileTimeUtc();433      }434      catch435      {436        result = false;437      }438      return result;439    }440441    /// <summary>442    /// Get/set the <see cref="DateTime">last modification time</see>.443    /// </summary>444    public DateTime LastModificationTime445    {446      get { return _lastModificationTime; }447      set {448        if (! IsValidValue(value))449        {450          throw new ArgumentOutOfRangeException(nameof(value));451        }452        _lastModificationTime = value;453      }454    }455456    /// <summary>457    /// Get /set the <see cref="DateTime">create time</see>458    /// </summary>459    public DateTime CreateTime460    {461      get { return _createTime; }462      set {463        if ( !IsValidValue(value)) {464          throw new ArgumentOutOfRangeException(nameof(value));465        }466        _createTime = value;467      }468    }469470    /// <summary>471    /// Get /set the <see cref="DateTime">last access time</see>.472    /// </summary>473    public DateTime LastAccessTime290    #region Instance Fields291    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    #endregion296  }297298  /// <summary>299  /// Class handling NT date time values.300  /// </summary>301  public class NTTaggedData : ITaggedData302  {303    /// <summary>304    /// Get the ID for this tagged data value.305    /// </summary>306    public short TagID {307      get { return 10; }308    }309310    /// <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(); // Reserved321        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);328329              long lastAccessTicks = helperStream.ReadLELong();330              _lastAccessTime = DateTime.FromFileTimeUtc(lastAccessTicks);331332              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    }343344    /// <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);       // Reserved354        helperStream.WriteLEShort(1);     // Tag355        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    }362363    /// <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 Intel370    /// (least significant byte first) byte order. They determine the371    /// 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 limit373    /// </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    }384385    /// <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    }397398    /// <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    }410411    /// <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    }423424    #region Instance Fields425    DateTime _lastAccessTime = DateTime.FromFileTimeUtc(0);426    DateTime _lastModificationTime = DateTime.FromFileTimeUtc(0);427    DateTime _createTime = DateTime.FromFileTimeUtc(0);428    #endregion429  }430431  /// <summary>432  /// A factory that creates <see cref="ITaggedData">tagged data</see> instances.433  /// </summary>434  interface ITaggedDataFactory435  {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  }446447  ///448  /// <summary>449  /// A class to handle the extra data field for Zip entries450  /// </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 but455  /// means that for extra data created by passing in data can have the values modified by the caller456  /// in some circumstances.457  /// </remarks>458  sealed public class ZipExtraData : IDisposable459  {460    #region Constructors461    /// <summary>462    /// Initialise a default instance.463    /// </summary>464    public ZipExtraData()465    {466      Clear();467    }468469    /// <summary>470    /// Initialise with known extra data.471    /// </summary>472    /// <param name="data">The extra data.</param>473    public ZipExtraData(byte[] data)  474    {475      get { return _lastAccessTime; }476      set {477        if (!IsValidValue(value)) {478          throw new ArgumentOutOfRangeException(nameof(value));479        }480        _lastAccessTime = value;481      }482    }483484    #region Instance Fields485    DateTime _lastAccessTime = DateTime.FromFileTime(0);486    DateTime _lastModificationTime = DateTime.FromFileTime(0);487    DateTime _createTime = DateTime.FromFileTime(0);488    #endregion489  }490491  /// <summary>492  /// A factory that creates <see cref="ITaggedData">tagged data</see> instances.493  /// </summary>494  interface ITaggedDataFactory495  {475      if (data == null) {476        _data = new byte[0];477      } else {478        _data = data;479      }480    }481    #endregion482483    /// <summary>484    /// Get the raw extra data value485    /// </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      }492493      return (byte[])_data.Clone();494    }495  496    /// <summary>497    /// Get data for a specific tag value.497    /// Clear the stored data.  498    /// </summary>499    /// <param name="tag">The tag ID to find.</param>500    /// <param name="data">The data to search.</param>501    /// <param name="offset">The offset to begin extracting data from.</param>502    /// <param name="count">The number of bytes to extract.</param>503    /// <returns>The located <see cref="ITaggedData">value found</see>, or null if not found.</returns>504    ITaggedData Create(short tag, byte[] data, int offset, int count);505  }506507  ///508  /// <summary>509  /// A class to handle the extra data field for Zip entries510  /// </summary>511  /// <remarks>512  /// Extra data contains 0 or more values each prefixed by a header tag and length.513  /// They contain zero or more bytes of actual data.514  /// The data is held internally using a copy on write strategy.  This is more efficient but515  /// means that for extra data created by passing in data can have the values modified by the caller516  /// in some circumstances.517  /// </remarks>518  sealed public class ZipExtraData : IDisposable519  {520    #region Constructors521    /// <summary>522    /// Initialise a default instance.523    /// </summary>524    public ZipExtraData()525    {526      Clear();527    }528529    /// <summary>530    /// Initialise with known extra data.531    /// </summary>532    /// <param name="data">The extra data.</param>533    public ZipExtraData(byte[] data)499    public void Clear()500    {501      if ((_data == null) || (_data.Length != 0)) {502        _data = new byte[0];503      }504    }505506    /// <summary>507    /// Gets the current extra data length.508    /// </summary>509    public int Length {510      get { return _data.Length; }511    }512513    /// <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    }526527    /// <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      if ( data == null )536      {537        _data = new byte[0];538      }539      else540      {541        _data = data;542      }543    }544    #endregion545546    /// <summary>547    /// Get the raw extra data value548    /// </summary>549    /// <returns>Returns the raw byte[] extra data this instance represents.</returns>550    public byte[] GetEntryData()551    {552      if ( Length > ushort.MaxValue ) {553        throw new ZipException("Data exceeds maximum length");554      }555556      return (byte[])_data.Clone();557    }558559    /// <summary>560    /// Clear the stored data.561    /// </summary>562    public void Clear()563    {564      if ( (_data == null) || (_data.Length != 0) ) {565        _data = new byte[0];566      }567    }568569    /// <summary>570    /// Gets the current extra data length.571    /// </summary>572    public int Length573    {574      get { return _data.Length; }575    }576577    /// <summary>578    /// Get a read-only <see cref="Stream"/> for the associated tag.579    /// </summary>580    /// <param name="tag">The tag to locate data for.</param>581    /// <returns>Returns a <see cref="Stream"/> containing tag data or null if no tag was found.</returns>582    public Stream GetStreamForTag(int tag)583    {584      Stream result = null;585      if ( Find(tag) ) {586        result = new MemoryStream(_data, _index, _readValueLength, false);587      }588      return result;589    }590591    /// <summary>592    /// Get the <see cref="ITaggedData">tagged data</see> for a tag.593    /// </summary>594    /// <param name="tag">The tag to search for.</param>595    /// <returns>Returns a <see cref="ITaggedData">tagged value</see> or null if none found.</returns>596    private ITaggedData GetData(short tag)597    {598      ITaggedData result = null;599      if (Find(tag))600      {601        result = Create(tag, _data, _readValueStart, _readValueLength);602      }603      return result;604    }605606    static ITaggedData Create(short tag, byte[] data, int offset, int count)607    {608      ITaggedData result = null;609      switch ( tag )610      {611        case 0x000A:612          result = new NTTaggedData();613          break;614        case 0x5455:615          result = new ExtendedUnixData();616          break;617        default:618          result = new RawTaggedData(tag);619          break;620      }621      result.SetData(data, offset, count);622      return result;623    }624625    /// <summary>626    /// Get the length of the last value found by <see cref="Find"/>627    /// </summary>628    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.</remarks>629    public int ValueLength630    {631      get { return _readValueLength; }632    }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    }543544    /// <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    }551552    /// <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 to557    /// <see cref="ReadInt"/>, <see cref="ReadShort"/> and <see cref="ReadLong"/>. </remarks>558    public int CurrentReadIndex {559      get { return _index; }560    }561562    /// <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        }571572        return _readValueStart + _readValueLength - _index;573      }574    }575576    /// <summary>577    /// Find an extra data value578    /// </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;586587      int localLength = _readValueStart;588      int localTag = headerID - 1;589590      // Trailing bytes that cant make up an entry (as there arent enough591      // 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      }599600      bool result = (localTag == headerID) && ((_index + localLength) <= _data.Length);601602      if (result) {603        _readValueStart = _index;604        _readValueLength = localLength;605      }606607      return result;608    }609610    /// <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    }621622    /// <summary>623    /// Add a new entry to extra data624    /// </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      }  633634    /// <summary>635    /// Get the index for the current read value.636    /// </summary>637    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.638    /// Initially the result will be the index of the first byte of actual data.  The value is updated after calls to639    /// <see cref="ReadInt"/>, <see cref="ReadShort"/> and <see cref="ReadLong"/>. </remarks>640    public int CurrentReadIndex641    {642      get { return _index; }643    }644645    /// <summary>646    /// Get the number of bytes remaining to be read for the current value;647    /// </summary>648    public int UnreadCount649    {650      get651      {652        if ((_readValueStart > _data.Length) ||653          (_readValueStart < 4) ) {654          throw new ZipException("Find must be called before calling a Read method");655        }656657        return _readValueStart + _readValueLength - _index;658      }659    }660661    /// <summary>662    /// Find an extra data value663    /// </summary>664    /// <param name="headerID">The identifier for the value to find.</param>665    /// <returns>Returns true if the value was found; false otherwise.</returns>666    public bool Find(int headerID)667    {668      _readValueStart = _data.Length;669      _readValueLength = 0;670      _index = 0;671672      int localLength = _readValueStart;673      int localTag = headerID - 1;634      int addLength = (fieldData == null) ? 0 : fieldData.Length;635636      if (addLength > ushort.MaxValue) {637        throw new ArgumentOutOfRangeException(nameof(fieldData), "exceeds maximum length");638      }639640      // Test for new length before adjusting data.641      int newLength = _data.Length + addLength + 4;642643      if (Find(headerID)) {644        newLength -= (ValueLength + 4);645      }646647      if (newLength > ushort.MaxValue) {648        throw new ZipException("Data exceeds maximum length");649      }650651      Delete(headerID);652653      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    }663664    /// <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 <see668    /// 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    }  674675      // Trailing bytes that cant make up an entry (as there arent enough676      // bytes for a tag and length) are ignored!677      while ( (localTag != headerID) && (_index < _data.Length - 3) ) {678        localTag = ReadShortInternal();679        localLength = ReadShortInternal();680        if ( localTag != headerID ) {681          _index += localLength;682        }683      }684685      bool result = (localTag == headerID) && ((_index + localLength) <= _data.Length);686687      if ( result ) {688        _readValueStart = _index;689        _readValueLength = localLength;690      }691692      return result;693    }694695    /// <summary>696    /// Add a new entry to extra data.697    /// </summary>698    /// <param name="taggedData">The <see cref="ITaggedData"/> value to add.</param>699    public void AddEntry(ITaggedData taggedData)700    {701      if (taggedData == null)702      {703        throw new ArgumentNullException(nameof(taggedData));704      }705      AddEntry(taggedData.TagID, taggedData.GetData());706    }707708    /// <summary>709    /// Add a new entry to extra data710    /// </summary>711    /// <param name="headerID">The ID for this entry.</param>712    /// <param name="fieldData">The data to add.</param>713    /// <remarks>If the ID already exists its contents are replaced.</remarks>714    public void AddEntry(int headerID, byte[] fieldData)715    {716      if ( (headerID > ushort.MaxValue) || (headerID < 0)) {717        throw new ArgumentOutOfRangeException(nameof(headerID));718      }719720      int addLength = (fieldData == null) ? 0 : fieldData.Length;721722      if ( addLength > ushort.MaxValue ) {723#if NETCF_1_0724        throw new ArgumentOutOfRangeException("fieldData");725#else726        throw new ArgumentOutOfRangeException(nameof(fieldData), "exceeds maximum length");727#endif728      }729730      // Test for new length before adjusting data.731      int newLength = _data.Length + addLength + 4;732733      if ( Find(headerID) )734      {735        newLength -= (ValueLength + 4);736      }737738      if ( newLength > ushort.MaxValue ) {739        throw new ZipException("Data exceeds maximum length");740      }741742      Delete(headerID);743744      byte[] newData = new byte[newLength];745      _data.CopyTo(newData, 0);746      int index = _data.Length;747      _data = newData;748      SetShort(ref index, headerID);749      SetShort(ref index, addLength);750      if ( fieldData != null ) {751        fieldData.CopyTo(newData, index);752      }753    }754755    /// <summary>756    /// Start adding a new entry.757    /// </summary>758    /// <remarks>Add data using <see cref="AddData(byte[])"/>, <see cref="AddLeShort"/>, <see cref="AddLeInt"/>, or <see759    /// The new entry is completed and actually added by calling <see cref="AddNewEntry"/></remarks>760    /// <seealso cref="AddEntry(ITaggedData)"/>761    public void StartNewEntry()762    {763      _newEntry = new MemoryStream();764    }765766    /// <summary>767    /// Add entry data added since <see cref="StartNewEntry"/> using the ID passed.768    /// </summary>769    /// <param name="headerID">The identifier to use for this entry.</param>770    public void AddNewEntry(int headerID)771    {772      byte[] newData = _newEntry.ToArray();773      _newEntry = null;774      AddEntry(headerID, newData);775    }776777    /// <summary>778    /// Add a byte of data to the pending new entry.779    /// </summary>780    /// <param name="data">The byte to add.</param>781    /// <seealso cref="StartNewEntry"/>782    public void AddData(byte data)783    {784      _newEntry.WriteByte(data);785    }786787    /// <summary>788    /// Add data to a pending new entry.789    /// </summary>790    /// <param name="data">The data to add.</param>791    /// <seealso cref="StartNewEntry"/>792    public void AddData(byte[] data)793    {794      if ( data == null ) {795        throw new ArgumentNullException(nameof(data));796      }797798      _newEntry.Write(data, 0, data.Length);799    }800801    /// <summary>802    /// Add a short value in little endian order to the pending new entry.803    /// </summary>804    /// <param name="toAdd">The data to add.</param>805    /// <seealso cref="StartNewEntry"/>806    public void AddLeShort(int toAdd)807    {808      unchecked {809        _newEntry.WriteByte(( byte )toAdd);810        _newEntry.WriteByte(( byte )(toAdd >> 8));811      }812    }813814    /// <summary>815    /// Add an integer value in little endian order to the pending new entry.816    /// </summary>817    /// <param name="toAdd">The data to add.</param>818    /// <seealso cref="StartNewEntry"/>819    public void AddLeInt(int toAdd)820    {821      unchecked {822        AddLeShort(( short )toAdd);823        AddLeShort(( short )(toAdd >> 16));824      }825    }826827    /// <summary>828    /// Add a long value in little endian order to the pending new entry.829    /// </summary>830    /// <param name="toAdd">The data to add.</param>831    /// <seealso cref="StartNewEntry"/>832    public void AddLeLong(long toAdd)833    {834      unchecked {835        AddLeInt(( int )(toAdd & 0xffffffff));836        AddLeInt(( int )(toAdd >> 32));837      }838    }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    }685686    /// <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    }695696    /// <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      }706707      _newEntry.Write(data, 0, data.Length);708    }709710    /// <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    }722723    /// <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    }735736    /// <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    }748749    /// <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;757758      if (Find(headerID)) {759        result = true;760        int trueStart = _readValueStart - 4;761762        byte[] newData = new byte[_data.Length - (ValueLength + 4)];763        Array.Copy(_data, 0, newData, 0, trueStart);764765        int trueEnd = trueStart + ValueLength + 4;766        Array.Copy(_data, trueEnd, newData, trueStart, _data.Length - trueEnd);767        _data = newData;768      }769      return result;770    }771772    #region Reading Support773    /// <summary>774    /// Read a long in little endian form from the last <see cref="Find">found</see> data value775    /// </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    }782783    /// <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);790791      int result = _data[_index] + (_data[_index + 1] << 8) +792        (_data[_index + 2] << 16) + (_data[_index + 3] << 24);793      _index += 4;794      return result;795    }796797    /// <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    }808809    /// <summary>810    /// Read a byte from an extra data811    /// </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    }822823    /// <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    }832833    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      }  839840    /// <summary>841    /// Delete an extra data field.842    /// </summary>843    /// <param name="headerID">The identifier of the field to delete.</param>844    /// <returns>Returns true if the field was found and deleted.</returns>845    public bool Delete(int headerID)846    {847      bool result = false;840      if (_index > _readValueStart + _readValueLength - length) {841        throw new ZipException("End of extra data");842      }843844      if (_index + length < 4) {845        throw new ZipException("Cannot read before start of tag");846      }847    }  848849      if ( Find(headerID) ) {850        result = true;851        int trueStart = _readValueStart - 4;852853        byte[] newData = new byte[_data.Length - (ValueLength + 4)];854        Array.Copy(_data, 0, newData, 0, trueStart);855856        int trueEnd = trueStart + ValueLength + 4;857        Array.Copy(_data, trueEnd, newData, trueStart, _data.Length - trueEnd);858        _data = newData;859      }860      return result;861    }862863    #region Reading Support864    /// <summary>865    /// Read a long in little endian form from the last <see cref="Find">found</see> data value866    /// </summary>867    /// <returns>Returns the long value read.</returns>868    public long ReadLong()869    {870      ReadCheck(8);871      return (ReadInt() & 0xffffffff) | ((( long )ReadInt()) << 32);872    }873874    /// <summary>875    /// Read an integer in little endian form from the last <see cref="Find">found</see> data value.876    /// </summary>877    /// <returns>Returns the integer read.</returns>878    public int ReadInt()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      }858859      int result = _data[_index] + (_data[_index + 1] << 8);860      _index += 2;861      return result;862    }863864    void SetShort(ref int index, int source)865    {866      _data[index] = (byte)source;867      _data[index + 1] = (byte)(source >> 8);868      index += 2;869    }870871    #endregion872873    #region IDisposable Members874875    /// <summary>876    /// Dispose of this instance.877    /// </summary>878    public void Dispose()  879    {880      ReadCheck(4);881882      int result = _data[_index] + (_data[_index + 1] << 8) +883        (_data[_index + 2] << 16) + (_data[_index + 3] << 24);884      _index += 4;885      return result;886    }887888    /// <summary>889    /// Read a short value in little endian form from the last <see cref="Find">found</see> data value.890    /// </summary>891    /// <returns>Returns the short value read.</returns>892    public int ReadShort()893    {894      ReadCheck(2);895      int result = _data[_index] + (_data[_index + 1] << 8);896      _index += 2;897      return result;898    }899900    /// <summary>901    /// Read a byte from an extra data902    /// </summary>903    /// <returns>The byte value read or -1 if the end of data has been reached.</returns>904    public int ReadByte()905    {906      int result = -1;907      if ( (_index < _data.Length) && (_readValueStart + _readValueLength > _index) ) {908        result = _data[_index];909        _index += 1;910      }911      return result;912    }913914    /// <summary>915    /// Skip data during reading.916    /// </summary>917    /// <param name="amount">The number of bytes to skip.</param>918    public void Skip(int amount)919    {920      ReadCheck(amount);921      _index += amount;922    }923924    void ReadCheck(int length)925    {926      if ((_readValueStart > _data.Length) ||927        (_readValueStart < 4) ) {928        throw new ZipException("Find must be called before calling a Read method");929      }930931      if (_index > _readValueStart + _readValueLength - length ) {932        throw new ZipException("End of extra data");933      }934935            if ( _index + length < 4 ) {936                throw new ZipException("Cannot read before start of tag");937            }938    }939940    /// <summary>941    /// Internal form of <see cref="ReadShort"/> that reads data at any location.942    /// </summary>943    /// <returns>Returns the short value read.</returns>944    int ReadShortInternal()945    {946      if ( _index > _data.Length - 2) {947        throw new ZipException("End of extra data");948      }949950      int result = _data[_index] + (_data[_index + 1] << 8);951      _index += 2;952      return result;953    }954955    void SetShort(ref int index, int source)956    {957      _data[index] = (byte)source;958      _data[index + 1] = (byte)(source >> 8);959      index += 2;960    }961962    #endregion963964    #region IDisposable Members965966    /// <summary>967    /// Dispose of this instance.968    /// </summary>969    public void Dispose()970    {971      if ( _newEntry != null ) {972        _newEntry.Close();973      }974    }975976    #endregion977978    #region Instance Fields979    int _index;980    int _readValueStart;981    int _readValueLength;982983    MemoryStream _newEntry;984    byte[] _data;985    #endregion986  }987}880      if (_newEntry != null) {881        _newEntry.Close();882      }883    }884885    #endregion886887    #region Instance Fields888    int _index;889    int _readValueStart;890    int _readValueLength;891892    MemoryStream _newEntry;893    byte[] _data;894    #endregion895  }896} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ScanEventArgs.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ScanEventArgs.htm index 3c9d4a736..b00a12c01 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ScanEventArgs.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ScanEventArgs.htm @@ -18,7 +18,7 @@

Summary

Covered lines:6 Uncovered lines:1 Coverable lines:7 -Total lines:530 +Total lines:475 Line coverage:85.7% @@ -34,538 +34,483 @@

#LineLine coverage - 1// FileSystemScanner.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.351using System;23namespace ICSharpCode.SharpZipLib.Core4{5  #region EventArgs6  /// <summary>7  /// Event arguments for scanning.8  /// </summary>9  public class ScanEventArgs : EventArgs10  {11    #region Constructors12    /// <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    #endregion2122    /// <summary>23    /// The file or directory name for this event.24    /// </summary>25    public string Name { + 1226      get { return name_; }27    }2829    /// <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    }  3637using System;3839namespace ICSharpCode.SharpZipLib.Core40{41  #region EventArgs42  /// <summary>43  /// Event arguments for scanning.44  /// </summary>45  public class ScanEventArgs : EventArgs46  {47    #region Constructors48    /// <summary>49    /// Initialise a new instance of <see cref="ScanEventArgs"/>50    /// </summary>51    /// <param name="name">The file or directory name.</param> - 552    public ScanEventArgs(string name)53    { - 554      name_ = name; - 555    }56    #endregion5758    /// <summary>59    /// The file or directory name for this event.60    /// </summary>61    public string Name62    { - 1363      get { return name_; }64    }6566    /// <summary>67    /// Get set a value indicating if scanning should continue or not.68    /// </summary>69    public bool ContinueRunning70    { - 971      get { return continueRunning_; } - 072      set { continueRunning_ = value; }73    }7475    #region Instance Fields76    string name_; - 577    bool continueRunning_ = true;78    #endregion79  }8081  /// <summary>82  /// Event arguments during processing of a single file or directory.83  /// </summary>84  public class ProgressEventArgs : EventArgs85  {86    #region Constructors87    /// <summary>88    /// Initialise a new instance of <see cref="ScanEventArgs"/>89    /// </summary>90    /// <param name="name">The file or directory name if known.</param>91    /// <param name="processed">The number of bytes processed so far</param>92    /// <param name="target">The total number of bytes to process, 0 if not known</param>93    public ProgressEventArgs(string name, long processed, long target)94    {95      name_ = name;96      processed_ = processed;97      target_ = target;98    }99    #endregion37    #region Instance Fields38    string name_; + 439    bool continueRunning_ = true;40    #endregion41  }4243  /// <summary>44  /// Event arguments during processing of a single file or directory.45  /// </summary>46  public class ProgressEventArgs : EventArgs47  {48    #region Constructors49    /// <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    #endregion6263    /// <summary>64    /// The name for this event if known.65    /// </summary>66    public string Name {67      get { return name_; }68    }6970    /// <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    }7778    /// <summary>79    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed80    /// </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    }9394    /// <summary>95    /// The number of bytes processed so far96    /// </summary>97    public long Processed {98      get { return processed_; }99    }  100  101    /// <summary>102    /// The name for this event if known.102    /// The number of bytes to process.  103    /// </summary>104    public string Name105    {106      get { return name_; }104    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>105    public long Target {106      get { return target_; }  107    }  108109    /// <summary>110    /// Get set a value indicating wether scanning should continue or not.111    /// </summary>112    public bool ContinueRunning113    {114      get { return continueRunning_; }115      set { continueRunning_ = value; }116    }117118    /// <summary>119    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed120    /// </summary>121    /// <value>0.0 to 100.0 percent; 0 if target is not known.</value>122    public float PercentComplete123    {124      get125      {126          float result;127        if (target_ <= 0)128        {129          result = 0;130        }131        else132        {133          result = ((float)processed_ / (float)target_) * 100.0f;134        }135          return result;136      }137    }138139    /// <summary>140    /// The number of bytes processed so far141    /// </summary>142    public long Processed143    {144      get { return processed_; }145    }146147    /// <summary>148    /// The number of bytes to process.149    /// </summary>150    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>151    public long Target152    {153      get { return target_; }154    }155156    #region Instance Fields157    string name_;158    long processed_;159    long target_;160    bool continueRunning_ = true;161    #endregion162  }163164  /// <summary>165  /// Event arguments for directories.166  /// </summary>167  public class DirectoryEventArgs : ScanEventArgs168  {169    #region Constructors170    /// <summary>171    /// Initialize an instance of <see cref="DirectoryEventArgs"></see>.172    /// </summary>173    /// <param name="name">The name for this directory.</param>174    /// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</par175    public DirectoryEventArgs(string name, bool hasMatchingFiles)176      : base (name)177    {178      hasMatchingFiles_ = hasMatchingFiles;179    }180    #endregion109    #region Instance Fields110    string name_;111    long processed_;112    long target_;113    bool continueRunning_ = true;114    #endregion115  }116117  /// <summary>118  /// Event arguments for directories.119  /// </summary>120  public class DirectoryEventArgs : ScanEventArgs121  {122    #region Constructors123    /// <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.</par128    public DirectoryEventArgs(string name, bool hasMatchingFiles)129      : base(name)130    {131      hasMatchingFiles_ = hasMatchingFiles;132    }133    #endregion134135    /// <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    }141142    readonly143144    #region Instance Fields145    bool hasMatchingFiles_;146    #endregion147  }148149  /// <summary>150  /// Arguments passed when scan failures are detected.151  /// </summary>152  public class ScanFailureEventArgs : EventArgs153  {154    #region Constructors155    /// <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    #endregion167168    /// <summary>169    /// The applicable name.170    /// </summary>171    public string Name {172      get { return name_; }173    }174175    /// <summary>176    /// The applicable exception.177    /// </summary>178    public Exception Exception {179      get { return exception_; }180    }  181  182    /// <summary>183    /// Get a value indicating if the directory contains any matching files or not.183    /// Get / set a value indicating wether scanning should continue.  184    /// </summary>185    public bool HasMatchingFiles186    {187      get { return hasMatchingFiles_; }185    public bool ContinueRunning {186      get { return continueRunning_; }187      set { continueRunning_ = value; }  188    }  189190    readonly191192    #region Instance Fields193    bool hasMatchingFiles_;190    #region Instance Fields191    string name_;192    Exception exception_;193    bool continueRunning_;  194    #endregion  195  }  196197  /// <summary>198  /// Arguments passed when scan failures are detected.199  /// </summary>200  public class ScanFailureEventArgs : EventArgs201  {202    #region Constructors203    /// <summary>204    /// Initialise a new instance of <see cref="ScanFailureEventArgs"></see>205    /// </summary>206    /// <param name="name">The name to apply.</param>207    /// <param name="e">The exception to use.</param>208    public ScanFailureEventArgs(string name, Exception e)209    {210      name_ = name;211      exception_ = e;212      continueRunning_ = true;213    }214    #endregion215216    /// <summary>217    /// The applicable name.218    /// </summary>219    public string Name220    {221      get { return name_; }222    }223224    /// <summary>225    /// The applicable exception.226    /// </summary>227    public Exception Exception228    {229      get { return exception_; }230    }231232    /// <summary>233    /// Get / set a value indicating wether scanning should continue.234    /// </summary>235    public bool ContinueRunning236    {237      get { return continueRunning_; }238      set { continueRunning_ = value; }239    }240241    #region Instance Fields242    string name_;243    Exception exception_;244    bool continueRunning_;245    #endregion246  }247248  #endregion249250  #region Delegates251  /// <summary>252  /// Delegate invoked before starting to process a file.253  /// </summary>254  /// <param name="sender">The source of the event</param>255  /// <param name="e">The event arguments.</param>256  public delegate void ProcessFileHandler(object sender, ScanEventArgs e);257258  /// <summary>259  /// Delegate invoked during processing of a file or directory260  /// </summary>261  /// <param name="sender">The source of the event</param>262  /// <param name="e">The event arguments.</param>263  public delegate void ProgressHandler(object sender, ProgressEventArgs e);264265  /// <summary>266  /// Delegate invoked when a file has been completely processed.267  /// </summary>268  /// <param name="sender">The source of the event</param>269  /// <param name="e">The event arguments.</param>270  public delegate void CompletedFileHandler(object sender, ScanEventArgs e);271272  /// <summary>273  /// Delegate invoked when a directory failure is detected.274  /// </summary>275  /// <param name="sender">The source of the event</param>276  /// <param name="e">The event arguments.</param>277  public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e);278279  /// <summary>280  /// Delegate invoked when a file failure is detected.281  /// </summary>282  /// <param name="sender">The source of the event</param>283  /// <param name="e">The event arguments.</param>284  public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e);285  #endregion286287  /// <summary>288  /// FileSystemScanner provides facilities scanning of files and directories.289  /// </summary>290  public class FileSystemScanner291  {292    #region Constructors293    /// <summary>294    /// Initialise a new instance of <see cref="FileSystemScanner"></see>295    /// </summary>296    /// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param>297    public FileSystemScanner(string filter)298    {299      fileFilter_ = new PathFilter(filter);300    }301302    /// <summary>303    /// Initialise a new instance of <see cref="FileSystemScanner"></see>304    /// </summary>305    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>306    /// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param>307    public FileSystemScanner(string fileFilter, string directoryFilter)308    {309      fileFilter_ = new PathFilter(fileFilter);310      directoryFilter_ = new PathFilter(directoryFilter);311    }312313    /// <summary>314    /// Initialise a new instance of <see cref="FileSystemScanner"></see>315    /// </summary>316    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param>317    public FileSystemScanner(IScanFilter fileFilter)318    {319      fileFilter_ = fileFilter;320    }321322    /// <summary>323    /// Initialise a new instance of <see cref="FileSystemScanner"></see>324    /// </summary>325    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see>  to apply.</param>326    /// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see>  to apply.</param>327    public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter)328    {329      fileFilter_ = fileFilter;330      directoryFilter_ = directoryFilter;331    }332    #endregion333334    #region Delegates335    /// <summary>336    /// Delegate to invoke when a directory is processed.337    /// </summary>338    public event EventHandler<DirectoryEventArgs> ProcessDirectory;339340    /// <summary>341    /// Delegate to invoke when a file is processed.342    /// </summary>343    public ProcessFileHandler ProcessFile;344345    /// <summary>346    /// Delegate to invoke when processing for a file has finished.347    /// </summary>348    public CompletedFileHandler CompletedFile;349350    /// <summary>351    /// Delegate to invoke when a directory failure is detected.352    /// </summary>353    public DirectoryFailureHandler DirectoryFailure;354355    /// <summary>356    /// Delegate to invoke when a file failure is detected.357    /// </summary>358    public FileFailureHandler FileFailure;359    #endregion197  #endregion198199  #region Delegates200  /// <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);206207  /// <summary>208  /// Delegate invoked during processing of a file or directory209  /// </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);213214  /// <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);220221  /// <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);227228  /// <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  #endregion235236  /// <summary>237  /// FileSystemScanner provides facilities scanning of files and directories.238  /// </summary>239  public class FileSystemScanner240  {241    #region Constructors242    /// <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    }250251    /// <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    }261262    /// <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    }270271    /// <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    #endregion282283    #region Delegates284    /// <summary>285    /// Delegate to invoke when a directory is processed.286    /// </summary>287    public event EventHandler<DirectoryEventArgs> ProcessDirectory;288289    /// <summary>290    /// Delegate to invoke when a file is processed.291    /// </summary>292    public ProcessFileHandler ProcessFile;293294    /// <summary>295    /// Delegate to invoke when processing for a file has finished.296    /// </summary>297    public CompletedFileHandler CompletedFile;298299    /// <summary>300    /// Delegate to invoke when a directory failure is detected.301    /// </summary>302    public DirectoryFailureHandler DirectoryFailure;303304    /// <summary>305    /// Delegate to invoke when a file failure is detected.306    /// </summary>307    public FileFailureHandler FileFailure;308    #endregion309310    /// <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    }326327    /// <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;335336      bool result = (handler != null);337338      if (result) {339        var args = new ScanFailureEventArgs(file, e);340        FileFailure(this, args);341        alive_ = args.ContinueRunning;342      }343      return result;344    }345346    /// <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;353354      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 DirectoryFailure event.362    /// Raise the complete file event  363    /// </summary>364    /// <param name="directory">The directory name.</param>365    /// <param name="e">The exception detected.</param>366    bool OnDirectoryFailure(string directory, Exception e)367    {368            DirectoryFailureHandler handler = DirectoryFailure;369            bool result = (handler != null);370            if ( result ) {371        var args = new ScanFailureEventArgs(directory, e);372        handler(this, args);373        alive_ = args.ContinueRunning;374      }375            return result;376    }377378    /// <summary>379    /// Raise the FileFailure event.380    /// </summary>381    /// <param name="file">The file name.</param>382    /// <param name="e">The exception detected.</param>383    bool OnFileFailure(string file, Exception e)384    {385            FileFailureHandler handler = FileFailure;386387            bool result = (handler != null);388389      if ( result ){390        var args = new ScanFailureEventArgs(file, e);391        FileFailure(this, args);392        alive_ = args.ContinueRunning;393      }394            return result;395    }396397    /// <summary>398    /// Raise the ProcessFile event.399    /// </summary>400    /// <param name="file">The file name.</param>401    void OnProcessFile(string file)402    {403      ProcessFileHandler handler = ProcessFile;404405      if ( handler!= null ) {406        var args = new ScanEventArgs(file);407        handler(this, args);408        alive_ = args.ContinueRunning;409      }410    }411412    /// <summary>413    /// Raise the complete file event414    /// </summary>415    /// <param name="file">The file name</param>416    void OnCompleteFile(string file)417    {418      CompletedFileHandler handler = CompletedFile;419420      if (handler != null)421      {422        var args = new ScanEventArgs(file);423        handler(this, args);424        alive_ = args.ContinueRunning;425      }426    }427428    /// <summary>429    /// Raise the ProcessDirectory event.430    /// </summary>431    /// <param name="directory">The directory name.</param>432    /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param>433    void OnProcessDirectory(string directory, bool hasMatchingFiles)434    {435      EventHandler<DirectoryEventArgs> handler = ProcessDirectory;436437      if ( handler != null ) {438        var args = new DirectoryEventArgs(directory, hasMatchingFiles);439        handler(this, args);440        alive_ = args.ContinueRunning;441      }442    }443444    /// <summary>445    /// Scan a directory.446    /// </summary>447    /// <param name="directory">The base directory to scan.</param>448    /// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param>449    public void Scan(string directory, bool recurse)450    {451      alive_ = true;452      ScanDir(directory, recurse);453    }454455    void ScanDir(string directory, bool recurse)456    {457458      try {459        string[] names = System.IO.Directory.GetFiles(directory);460        bool hasMatch = false;461        for (int fileIndex = 0; fileIndex < names.Length; ++fileIndex) {462          if ( !fileFilter_.IsMatch(names[fileIndex]) ) {463            names[fileIndex] = null;464          } else {465            hasMatch = true;466          }467        }468469        OnProcessDirectory(directory, hasMatch);470471        if ( alive_ && hasMatch ) {472          foreach (string fileName in names) {473            try {474              if ( fileName != null ) {475                OnProcessFile(fileName);476                if ( !alive_ ) {477                  break;478                }479              }480            }481            catch (Exception e) {482                            if (!OnFileFailure(fileName, e)) {483                                throw;484                            }485            }486          }487        }488      }489      catch (Exception e) {490                if (!OnDirectoryFailure(directory, e)) {491                    throw;492                }493      }494495      if ( alive_ && recurse ) {496        try {497          string[] names = System.IO.Directory.GetDirectories(directory);498          foreach (string fulldir in names) {499            if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir))) {500              ScanDir(fulldir, true);501              if ( !alive_ ) {502                break;503              }504            }505          }506        }507        catch (Exception e) {508                    if (!OnDirectoryFailure(directory, e)) {509                        throw;510                    }511        }512      }513    }514515    #region Instance Fields516    /// <summary>517    /// The file filter currently in use.518    /// </summary>519    IScanFilter fileFilter_;520    /// <summary>521    /// The directory filter currently in use.522    /// </summary>523    IScanFilter directoryFilter_;524    /// <summary>525    /// Flag indicating if scanning should continue running.526    /// </summary>527    bool alive_;528    #endregion529  }530}364    /// <param name="file">The file name</param>365    void OnCompleteFile(string file)366    {367      CompletedFileHandler handler = CompletedFile;368369      if (handler != null) {370        var args = new ScanEventArgs(file);371        handler(this, args);372        alive_ = args.ContinueRunning;373      }374    }375376    /// <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;384385      if (handler != null) {386        var args = new DirectoryEventArgs(directory, hasMatchingFiles);387        handler(this, args);388        alive_ = args.ContinueRunning;389      }390    }391392    /// <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    }402403    void ScanDir(string directory, bool recurse)404    {405406      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        }416417        OnProcessDirectory(directory, hasMatch);418419        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      }440441      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    }459460    #region Instance Fields461    /// <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    #endregion474  }475} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ScanFailureEventArgs.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ScanFailureEventArgs.htm index 8f64c2537..13ec860b5 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ScanFailureEventArgs.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ScanFailureEventArgs.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:9 Coverable lines:9 -Total lines:530 +Total lines:475 Line coverage:0% @@ -34,538 +34,483 @@

#LineLine coverage - 1// FileSystemScanner.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.351using System;23namespace ICSharpCode.SharpZipLib.Core4{5  #region EventArgs6  /// <summary>7  /// Event arguments for scanning.8  /// </summary>9  public class ScanEventArgs : EventArgs10  {11    #region Constructors12    /// <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    #endregion2122    /// <summary>23    /// The file or directory name for this event.24    /// </summary>25    public string Name {26      get { return name_; }27    }2829    /// <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    }  3637using System;3839namespace ICSharpCode.SharpZipLib.Core40{41  #region EventArgs42  /// <summary>43  /// Event arguments for scanning.44  /// </summary>45  public class ScanEventArgs : EventArgs46  {47    #region Constructors48    /// <summary>49    /// Initialise a new instance of <see cref="ScanEventArgs"/>50    /// </summary>51    /// <param name="name">The file or directory name.</param>52    public ScanEventArgs(string name)53    {54      name_ = name;55    }56    #endregion5758    /// <summary>59    /// The file or directory name for this event.60    /// </summary>61    public string Name62    {63      get { return name_; }64    }6566    /// <summary>67    /// Get set a value indicating if scanning should continue or not.68    /// </summary>69    public bool ContinueRunning70    {71      get { return continueRunning_; }72      set { continueRunning_ = value; }73    }7475    #region Instance Fields76    string name_;77    bool continueRunning_ = true;78    #endregion79  }8081  /// <summary>82  /// Event arguments during processing of a single file or directory.83  /// </summary>84  public class ProgressEventArgs : EventArgs85  {86    #region Constructors87    /// <summary>88    /// Initialise a new instance of <see cref="ScanEventArgs"/>89    /// </summary>90    /// <param name="name">The file or directory name if known.</param>91    /// <param name="processed">The number of bytes processed so far</param>92    /// <param name="target">The total number of bytes to process, 0 if not known</param>93    public ProgressEventArgs(string name, long processed, long target)94    {95      name_ = name;96      processed_ = processed;97      target_ = target;98    }99    #endregion37    #region Instance Fields38    string name_;39    bool continueRunning_ = true;40    #endregion41  }4243  /// <summary>44  /// Event arguments during processing of a single file or directory.45  /// </summary>46  public class ProgressEventArgs : EventArgs47  {48    #region Constructors49    /// <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    #endregion6263    /// <summary>64    /// The name for this event if known.65    /// </summary>66    public string Name {67      get { return name_; }68    }6970    /// <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    }7778    /// <summary>79    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed80    /// </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    }9394    /// <summary>95    /// The number of bytes processed so far96    /// </summary>97    public long Processed {98      get { return processed_; }99    }  100  101    /// <summary>102    /// The name for this event if known.102    /// The number of bytes to process.  103    /// </summary>104    public string Name105    {106      get { return name_; }104    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>105    public long Target {106      get { return target_; }  107    }  108109    /// <summary>110    /// Get set a value indicating wether scanning should continue or not.111    /// </summary>112    public bool ContinueRunning113    {114      get { return continueRunning_; }115      set { continueRunning_ = value; }116    }117118    /// <summary>119    /// Get a percentage representing how much of the <see cref="Target"></see> has been processed120    /// </summary>121    /// <value>0.0 to 100.0 percent; 0 if target is not known.</value>122    public float PercentComplete123    {124      get125      {126          float result;127        if (target_ <= 0)128        {129          result = 0;130        }131        else132        {133          result = ((float)processed_ / (float)target_) * 100.0f;134        }135          return result;136      }137    }138139    /// <summary>140    /// The number of bytes processed so far141    /// </summary>142    public long Processed143    {144      get { return processed_; }145    }146147    /// <summary>148    /// The number of bytes to process.149    /// </summary>150    /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>151    public long Target152    {153      get { return target_; }154    }155156    #region Instance Fields157    string name_;158    long processed_;159    long target_;160    bool continueRunning_ = true;161    #endregion162  }163164  /// <summary>165  /// Event arguments for directories.166  /// </summary>167  public class DirectoryEventArgs : ScanEventArgs168  {169    #region Constructors170    /// <summary>171    /// Initialize an instance of <see cref="DirectoryEventArgs"></see>.172    /// </summary>173    /// <param name="name">The name for this directory.</param>174    /// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</par175    public DirectoryEventArgs(string name, bool hasMatchingFiles)176      : base (name)177    {178      hasMatchingFiles_ = hasMatchingFiles;179    }180    #endregion109    #region Instance Fields110    string name_;111    long processed_;112    long target_;113    bool continueRunning_ = true;114    #endregion115  }116117  /// <summary>118  /// Event arguments for directories.119  /// </summary>120  public class DirectoryEventArgs : ScanEventArgs121  {122    #region Constructors123    /// <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.</par128    public DirectoryEventArgs(string name, bool hasMatchingFiles)129      : base(name)130    {131      hasMatchingFiles_ = hasMatchingFiles;132    }133    #endregion134135    /// <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    }141142    readonly143144    #region Instance Fields145    bool hasMatchingFiles_;146    #endregion147  }148149  /// <summary>150  /// Arguments passed when scan failures are detected.151  /// </summary>152  public class ScanFailureEventArgs : EventArgs153  {154    #region Constructors155    /// <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    #endregion167168    /// <summary>169    /// The applicable name.170    /// </summary>171    public string Name { + 0172      get { return name_; }173    }174175    /// <summary>176    /// The applicable exception.177    /// </summary>178    public Exception Exception { + 0179      get { return exception_; }180    }  181  182    /// <summary>183    /// Get a value indicating if the directory contains any matching files or not.183    /// Get / set a value indicating wether scanning should continue.  184    /// </summary>185    public bool HasMatchingFiles186    {187      get { return hasMatchingFiles_; }185    public bool ContinueRunning { + 0186      get { return continueRunning_; } + 0187      set { continueRunning_ = value; }  188    }  189190    readonly191192    #region Instance Fields193    bool hasMatchingFiles_;190    #region Instance Fields191    string name_;192    Exception exception_;193    bool continueRunning_;  194    #endregion  195  }  196197  /// <summary>198  /// Arguments passed when scan failures are detected.199  /// </summary>200  public class ScanFailureEventArgs : EventArgs201  {202    #region Constructors203    /// <summary>204    /// Initialise a new instance of <see cref="ScanFailureEventArgs"></see>205    /// </summary>206    /// <param name="name">The name to apply.</param>207    /// <param name="e">The exception to use.</param> - 0208    public ScanFailureEventArgs(string name, Exception e)209    { - 0210      name_ = name; - 0211      exception_ = e; - 0212      continueRunning_ = true; - 0213    }214    #endregion215216    /// <summary>217    /// The applicable name.218    /// </summary>219    public string Name220    { - 0221      get { return name_; }222    }223224    /// <summary>225    /// The applicable exception.226    /// </summary>227    public Exception Exception228    { - 0229      get { return exception_; }230    }231232    /// <summary>233    /// Get / set a value indicating wether scanning should continue.234    /// </summary>235    public bool ContinueRunning236    { - 0237      get { return continueRunning_; } - 0238      set { continueRunning_ = value; }239    }240241    #region Instance Fields242    string name_;243    Exception exception_;244    bool continueRunning_;245    #endregion246  }247248  #endregion249250  #region Delegates251  /// <summary>252  /// Delegate invoked before starting to process a file.253  /// </summary>254  /// <param name="sender">The source of the event</param>255  /// <param name="e">The event arguments.</param>256  public delegate void ProcessFileHandler(object sender, ScanEventArgs e);257258  /// <summary>259  /// Delegate invoked during processing of a file or directory260  /// </summary>261  /// <param name="sender">The source of the event</param>262  /// <param name="e">The event arguments.</param>263  public delegate void ProgressHandler(object sender, ProgressEventArgs e);264265  /// <summary>266  /// Delegate invoked when a file has been completely processed.267  /// </summary>268  /// <param name="sender">The source of the event</param>269  /// <param name="e">The event arguments.</param>270  public delegate void CompletedFileHandler(object sender, ScanEventArgs e);271272  /// <summary>273  /// Delegate invoked when a directory failure is detected.274  /// </summary>275  /// <param name="sender">The source of the event</param>276  /// <param name="e">The event arguments.</param>277  public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e);278279  /// <summary>280  /// Delegate invoked when a file failure is detected.281  /// </summary>282  /// <param name="sender">The source of the event</param>283  /// <param name="e">The event arguments.</param>284  public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e);285  #endregion286287  /// <summary>288  /// FileSystemScanner provides facilities scanning of files and directories.289  /// </summary>290  public class FileSystemScanner291  {292    #region Constructors293    /// <summary>294    /// Initialise a new instance of <see cref="FileSystemScanner"></see>295    /// </summary>296    /// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param>297    public FileSystemScanner(string filter)298    {299      fileFilter_ = new PathFilter(filter);300    }301302    /// <summary>303    /// Initialise a new instance of <see cref="FileSystemScanner"></see>304    /// </summary>305    /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>306    /// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param>307    public FileSystemScanner(string fileFilter, string directoryFilter)308    {309      fileFilter_ = new PathFilter(fileFilter);310      directoryFilter_ = new PathFilter(directoryFilter);311    }312313    /// <summary>314    /// Initialise a new instance of <see cref="FileSystemScanner"></see>315    /// </summary>316    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param>317    public FileSystemScanner(IScanFilter fileFilter)318    {319      fileFilter_ = fileFilter;320    }321322    /// <summary>323    /// Initialise a new instance of <see cref="FileSystemScanner"></see>324    /// </summary>325    /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see>  to apply.</param>326    /// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see>  to apply.</param>327    public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter)328    {329      fileFilter_ = fileFilter;330      directoryFilter_ = directoryFilter;331    }332    #endregion333334    #region Delegates335    /// <summary>336    /// Delegate to invoke when a directory is processed.337    /// </summary>338    public event EventHandler<DirectoryEventArgs> ProcessDirectory;339340    /// <summary>341    /// Delegate to invoke when a file is processed.342    /// </summary>343    public ProcessFileHandler ProcessFile;344345    /// <summary>346    /// Delegate to invoke when processing for a file has finished.347    /// </summary>348    public CompletedFileHandler CompletedFile;349350    /// <summary>351    /// Delegate to invoke when a directory failure is detected.352    /// </summary>353    public DirectoryFailureHandler DirectoryFailure;354355    /// <summary>356    /// Delegate to invoke when a file failure is detected.357    /// </summary>358    public FileFailureHandler FileFailure;359    #endregion197  #endregion198199  #region Delegates200  /// <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);206207  /// <summary>208  /// Delegate invoked during processing of a file or directory209  /// </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);213214  /// <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);220221  /// <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);227228  /// <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  #endregion235236  /// <summary>237  /// FileSystemScanner provides facilities scanning of files and directories.238  /// </summary>239  public class FileSystemScanner240  {241    #region Constructors242    /// <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    }250251    /// <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    }261262    /// <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    }270271    /// <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    #endregion282283    #region Delegates284    /// <summary>285    /// Delegate to invoke when a directory is processed.286    /// </summary>287    public event EventHandler<DirectoryEventArgs> ProcessDirectory;288289    /// <summary>290    /// Delegate to invoke when a file is processed.291    /// </summary>292    public ProcessFileHandler ProcessFile;293294    /// <summary>295    /// Delegate to invoke when processing for a file has finished.296    /// </summary>297    public CompletedFileHandler CompletedFile;298299    /// <summary>300    /// Delegate to invoke when a directory failure is detected.301    /// </summary>302    public DirectoryFailureHandler DirectoryFailure;303304    /// <summary>305    /// Delegate to invoke when a file failure is detected.306    /// </summary>307    public FileFailureHandler FileFailure;308    #endregion309310    /// <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    }326327    /// <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;335336      bool result = (handler != null);337338      if (result) {339        var args = new ScanFailureEventArgs(file, e);340        FileFailure(this, args);341        alive_ = args.ContinueRunning;342      }343      return result;344    }345346    /// <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;353354      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 DirectoryFailure event.362    /// Raise the complete file event  363    /// </summary>364    /// <param name="directory">The directory name.</param>365    /// <param name="e">The exception detected.</param>366    bool OnDirectoryFailure(string directory, Exception e)367    {368            DirectoryFailureHandler handler = DirectoryFailure;369            bool result = (handler != null);370            if ( result ) {371        var args = new ScanFailureEventArgs(directory, e);372        handler(this, args);373        alive_ = args.ContinueRunning;374      }375            return result;376    }377378    /// <summary>379    /// Raise the FileFailure event.380    /// </summary>381    /// <param name="file">The file name.</param>382    /// <param name="e">The exception detected.</param>383    bool OnFileFailure(string file, Exception e)384    {385            FileFailureHandler handler = FileFailure;386387            bool result = (handler != null);388389      if ( result ){390        var args = new ScanFailureEventArgs(file, e);391        FileFailure(this, args);392        alive_ = args.ContinueRunning;393      }394            return result;395    }396397    /// <summary>398    /// Raise the ProcessFile event.399    /// </summary>400    /// <param name="file">The file name.</param>401    void OnProcessFile(string file)402    {403      ProcessFileHandler handler = ProcessFile;404405      if ( handler!= null ) {406        var args = new ScanEventArgs(file);407        handler(this, args);408        alive_ = args.ContinueRunning;409      }410    }411412    /// <summary>413    /// Raise the complete file event414    /// </summary>415    /// <param name="file">The file name</param>416    void OnCompleteFile(string file)417    {418      CompletedFileHandler handler = CompletedFile;419420      if (handler != null)421      {422        var args = new ScanEventArgs(file);423        handler(this, args);424        alive_ = args.ContinueRunning;425      }426    }427428    /// <summary>429    /// Raise the ProcessDirectory event.430    /// </summary>431    /// <param name="directory">The directory name.</param>432    /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param>433    void OnProcessDirectory(string directory, bool hasMatchingFiles)434    {435      EventHandler<DirectoryEventArgs> handler = ProcessDirectory;436437      if ( handler != null ) {438        var args = new DirectoryEventArgs(directory, hasMatchingFiles);439        handler(this, args);440        alive_ = args.ContinueRunning;441      }442    }443444    /// <summary>445    /// Scan a directory.446    /// </summary>447    /// <param name="directory">The base directory to scan.</param>448    /// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param>449    public void Scan(string directory, bool recurse)450    {451      alive_ = true;452      ScanDir(directory, recurse);453    }454455    void ScanDir(string directory, bool recurse)456    {457458      try {459        string[] names = System.IO.Directory.GetFiles(directory);460        bool hasMatch = false;461        for (int fileIndex = 0; fileIndex < names.Length; ++fileIndex) {462          if ( !fileFilter_.IsMatch(names[fileIndex]) ) {463            names[fileIndex] = null;464          } else {465            hasMatch = true;466          }467        }468469        OnProcessDirectory(directory, hasMatch);470471        if ( alive_ && hasMatch ) {472          foreach (string fileName in names) {473            try {474              if ( fileName != null ) {475                OnProcessFile(fileName);476                if ( !alive_ ) {477                  break;478                }479              }480            }481            catch (Exception e) {482                            if (!OnFileFailure(fileName, e)) {483                                throw;484                            }485            }486          }487        }488      }489      catch (Exception e) {490                if (!OnDirectoryFailure(directory, e)) {491                    throw;492                }493      }494495      if ( alive_ && recurse ) {496        try {497          string[] names = System.IO.Directory.GetDirectories(directory);498          foreach (string fulldir in names) {499            if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir))) {500              ScanDir(fulldir, true);501              if ( !alive_ ) {502                break;503              }504            }505          }506        }507        catch (Exception e) {508                    if (!OnDirectoryFailure(directory, e)) {509                        throw;510                    }511        }512      }513    }514515    #region Instance Fields516    /// <summary>517    /// The file filter currently in use.518    /// </summary>519    IScanFilter fileFilter_;520    /// <summary>521    /// The directory filter currently in use.522    /// </summary>523    IScanFilter directoryFilter_;524    /// <summary>525    /// Flag indicating if scanning should continue running.526    /// </summary>527    bool alive_;528    #endregion529  }530}364    /// <param name="file">The file name</param>365    void OnCompleteFile(string file)366    {367      CompletedFileHandler handler = CompletedFile;368369      if (handler != null) {370        var args = new ScanEventArgs(file);371        handler(this, args);372        alive_ = args.ContinueRunning;373      }374    }375376    /// <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;384385      if (handler != null) {386        var args = new DirectoryEventArgs(directory, hasMatchingFiles);387        handler(this, args);388        alive_ = args.ContinueRunning;389      }390    }391392    /// <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    }402403    void ScanDir(string directory, bool recurse)404    {405406      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        }416417        OnProcessDirectory(directory, hasMatch);418419        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      }440441      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    }459460    #region Instance Fields461    /// <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    #endregion474  }475} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_SharpZipBaseException.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_SharpZipBaseException.htm index 20fecd5af..986d556ce 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_SharpZipBaseException.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_SharpZipBaseException.htm @@ -18,7 +18,7 @@

Summary

Covered lines:2 Uncovered lines:6 Coverable lines:8 -Total lines:94 +Total lines:52 Line coverage:25% @@ -37,102 +37,60 @@

#LineLine coverage - 1// SharpZipBaseException.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;3738#if !NETCF_1_0 && !NETCF_2_039using System.Runtime.Serialization;40#endif4142namespace ICSharpCode.SharpZipLib43{44  /// <summary>45  /// SharpZipBaseException is the base exception class for SharpZipLib.46  /// All library exceptions are derived from this.47  /// </summary>48  /// <remarks>NOTE: Not all exceptions thrown will be derived from this class.49  /// A variety of other exceptions are possible for example <see cref="ArgumentNullException"></see></remarks>50#if !NETCF_1_0 && !NETCF_2_051  [Serializable]52#endif53  public class SharpZipBaseException : ApplicationException54  {55#if !NETCF_1_0 && !NETCF_2_056    /// <summary>57    /// Deserialization constructor58    /// </summary>59    /// <param name="info"><see cref="System.Runtime.Serialization.SerializationInfo"/> for this constructor</param>60    /// <param name="context"><see cref="StreamingContext"/> for this constructor</param>61    protected SharpZipBaseException(SerializationInfo info, StreamingContext context ) - 062      : base( info, context )63    { - 064    }65#endif6667    /// <summary>68    /// Initializes a new instance of the SharpZipBaseException class.69    /// </summary> - 070    public SharpZipBaseException()71    { - 072    }7374    /// <summary>75    /// Initializes a new instance of the SharpZipBaseException class with a specified error message.76    /// </summary>77    /// <param name="message">A message describing the exception.</param>78    public SharpZipBaseException(string message) - 1879      : base(message)80    { - 1881    }8283    /// <summary>84    /// Initializes a new instance of the SharpZipBaseException class with a specified85    /// error message and a reference to the inner exception that is the cause of this exception.86    /// </summary>87    /// <param name="message">A message describing the exception.</param>88    /// <param name="innerException">The inner exception</param>89    public SharpZipBaseException(string message, Exception innerException) - 090      : base(message, innerException)91    { - 092    }93  }94}1using System;2using System.Runtime.Serialization;34namespace ICSharpCode.SharpZipLib5{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 : Exception14  {15    /// <summary>16    /// Deserialization constructor17    /// </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    }2425    /// <summary>26    /// Initializes a new instance of the SharpZipBaseException class.27    /// </summary> + 028    public SharpZipBaseException()29    { + 030    }3132    /// <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    }4041    /// <summary>42    /// Initializes a new instance of the SharpZipBaseException class with a specified43    /// 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/Documentation/opencover/ICSharpCode.SharpZipLib_StaticDiskDataSource.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_StaticDiskDataSource.htm index 81de1ec9b..dfb94ee0c 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_StaticDiskDataSource.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_StaticDiskDataSource.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:4 Coverable lines:4 -Total lines:4476 +Total lines:4263 Line coverage:0% @@ -35,4484 +35,4271 @@

#LineLine coverage - 1// ZipFile.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  2009-12-22  Z-1649  Added AES support41//  2010-03-02  Z-1650  Fixed updating ODT archives in memory. Exposed exceptions in updating.42//  2010-05-25  Z-1663  Fixed exception when testing local header compressed size of -143//  2012-11-29  Z-1684  Fixed ZipFile.Add(string fileName, string entryName) losing the file TimeStamp4445using System;46using System.Collections;47using System.IO;48using System.Text;49using System.Globalization;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;1213namespace ICSharpCode.SharpZipLib.Zip14{15  #region Keys Required Event Args16  /// <summary>17  /// Arguments used with KeysRequiredEvent18  /// </summary>19  public class KeysRequiredEventArgs : EventArgs20  {21    #region Constructors22    /// <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    }3031    /// <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    }4142    #endregion43    #region Properties44    /// <summary>45    /// Gets the name of the file for which keys are required.46    /// </summary>47    public string FileName {48      get { return fileName; }49    }  5051#if !NETCF_1_052using System.Security.Cryptography;53using ICSharpCode.SharpZipLib.Encryption;54#endif5556using ICSharpCode.SharpZipLib.Core;57using ICSharpCode.SharpZipLib.Checksums;58using ICSharpCode.SharpZipLib.Zip.Compression.Streams;59using ICSharpCode.SharpZipLib.Zip.Compression;6061namespace ICSharpCode.SharpZipLib.Zip62{63  #region Keys Required Event Args64  /// <summary>65  /// Arguments used with KeysRequiredEvent66  /// </summary>67  public class KeysRequiredEventArgs : EventArgs68  {69    #region Constructors70    /// <summary>71    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>72    /// </summary>73    /// <param name="name">The name of the file for which keys are required.</param>74    public KeysRequiredEventArgs(string name)75    {76      fileName = name;77    }7879    /// <summary>80    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>81    /// </summary>82    /// <param name="name">The name of the file for which keys are required.</param>83    /// <param name="keyValue">The current key value.</param>84    public KeysRequiredEventArgs(string name, byte[] keyValue)85    {86      fileName = name;87      key = keyValue;88    }8990    #endregion91    #region Properties92    /// <summary>93    /// Gets the name of the file for which keys are required.94    /// </summary>95    public string FileName96    {97      get { return fileName; }98    }99100    /// <summary>101    /// Gets or sets the key value102    /// </summary>103    public byte[] Key104    {105      get { return key; }106      set { key = value; }107    }108    #endregion109110    #region Instance Fields111    string fileName;112    byte[] key;113    #endregion114  }115  #endregion116117  #region Test Definitions118  /// <summary>119  /// The strategy to apply to testing.120  /// </summary>121  public enum TestStrategy122  {123    /// <summary>124    /// Find the first error only.125    /// </summary>126    FindFirstError,51    /// <summary>52    /// Gets or sets the key value53    /// </summary>54    public byte[] Key {55      get { return key; }56      set { key = value; }57    }58    #endregion5960    #region Instance Fields61    string fileName;62    byte[] key;63    #endregion64  }65  #endregion6667  #region Test Definitions68  /// <summary>69  /// The strategy to apply to testing.70  /// </summary>71  public enum TestStrategy72  {73    /// <summary>74    /// Find the first error only.75    /// </summary>76    FindFirstError,77    /// <summary>78    /// Find all possible errors.79    /// </summary>80    FindAllErrors,81  }8283  /// <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 TestOperation88  {89    /// <summary>90    /// Setting up testing.91    /// </summary>92    Initialising,9394    /// <summary>95    /// Testing an individual entries header96    /// </summary>97    EntryHeader,9899    /// <summary>100    /// Testing an individual entries data101    /// </summary>102    EntryData,103104    /// <summary>105    /// Testing an individual entry has completed.106    /// </summary>107    EntryComplete,108109    /// <summary>110    /// Running miscellaneous tests111    /// </summary>112    MiscellaneousTests,113114    /// <summary>115    /// Testing is complete116    /// </summary>117    Complete,118  }119120  /// <summary>121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.122  /// </summary>123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>124  public class TestStatus125  {126    #region Constructors  127    /// <summary>128    /// Find all possible errors.128    /// Initialise a new instance of <see cref="TestStatus"/>  129    /// </summary>130    FindAllErrors,131  }132133  /// <summary>134  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.135  /// </summary>136  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>137  public enum TestOperation138  {130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>131    public TestStatus(ZipFile file)132    {133      file_ = file;134    }135    #endregion136137    #region Properties138  139    /// <summary>140    /// Setting up testing.140    /// Get the current <see cref="TestOperation"/> in progress.  141    /// </summary>142    Initialising,143144    /// <summary>145    /// Testing an individual entries header146    /// </summary>147    EntryHeader,148149    /// <summary>150    /// Testing an individual entries data151    /// </summary>152    EntryData,153154    /// <summary>155    /// Testing an individual entry has completed.156    /// </summary>157    EntryComplete,158159    /// <summary>160    /// Running miscellaneous tests161    /// </summary>162    MiscellaneousTests,163164    /// <summary>165    /// Testing is complete166    /// </summary>167    Complete,168  }169170  /// <summary>171  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.172  /// </summary>173  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>174  public class TestStatus175  {176    #region Constructors177    /// <summary>178    /// Initialise a new instance of <see cref="TestStatus"/>179    /// </summary>180    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>181    public TestStatus(ZipFile file)182    {183      file_ = file;184    }185    #endregion186187    #region Properties142    public TestOperation Operation {143      get { return operation_; }144    }145146    /// <summary>147    /// Get the <see cref="ZipFile"/> this status is applicable to.148    /// </summary>149    public ZipFile File {150      get { return file_; }151    }152153    /// <summary>154    /// Get the current/last entry tested.155    /// </summary>156    public ZipEntry Entry {157      get { return entry_; }158    }159160    /// <summary>161    /// Get the number of errors detected so far.162    /// </summary>163    public int ErrorCount {164      get { return errorCount_; }165    }166167    /// <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    }173174    /// <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    #endregion181182    #region Internal API183    internal void AddError()184    {185      errorCount_++;186      entryValid_ = false;187    }  188189    /// <summary>190    /// Get the current <see cref="TestOperation"/> in progress.191    /// </summary>192    public TestOperation Operation193    {194      get { return operation_; }195    }196197    /// <summary>198    /// Get the <see cref="ZipFile"/> this status is applicable to.199    /// </summary>200    public ZipFile File201    {202      get { return file_; }203    }204205    /// <summary>206    /// Get the current/last entry tested.207    /// </summary>208    public ZipEntry Entry209    {210      get { return entry_; }211    }212213    /// <summary>214    /// Get the number of errors detected so far.215    /// </summary>216    public int ErrorCount217    {218      get { return errorCount_; }219    }220221    /// <summary>222    /// Get the number of bytes tested so far for the current entry.223    /// </summary>224    public long BytesTested225    {226      get { return bytesTested_; }227    }228229    /// <summary>230    /// Get a value indicating wether the last entry test was valid.231    /// </summary>232    public bool EntryValid233    {234      get { return entryValid_; }235    }236    #endregion237238    #region Internal API239    internal void AddError()240    {241      errorCount_++;242      entryValid_ = false;243    }244245    internal void SetOperation(TestOperation operation)246    {247      operation_ = operation;248    }249250    internal void SetEntry(ZipEntry entry)251    {252      entry_ = entry;253      entryValid_ = true;254      bytesTested_ = 0;255    }256257    internal void SetBytesTested(long value)258    {259      bytesTested_ = value;260    }261    #endregion262263    #region Instance Fields264    ZipFile file_;265    ZipEntry entry_;266    bool entryValid_;267    int errorCount_;268    long bytesTested_;269    TestOperation operation_;270    #endregion271  }272273  /// <summary>274  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if275  /// </summary>276  /// <remarks>If the message is non-null an error has occured.  If the message is null277  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>278  public delegate void ZipTestResultHandler(TestStatus status, string message);279  #endregion280281  #region Update Definitions282  /// <summary>283  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.284  /// </summary>285  public enum FileUpdateMode286  {287    /// <summary>288    /// Perform all updates on temporary files ensuring that the original file is saved.289    /// </summary>290    Safe,291    /// <summary>292    /// Update the archive directly, which is faster but less safe.293    /// </summary>294    Direct,295  }296  #endregion189    internal void SetOperation(TestOperation operation)190    {191      operation_ = operation;192    }193194    internal void SetEntry(ZipEntry entry)195    {196      entry_ = entry;197      entryValid_ = true;198      bytesTested_ = 0;199    }200201    internal void SetBytesTested(long value)202    {203      bytesTested_ = value;204    }205    #endregion206207    #region Instance Fields208    ZipFile file_;209    ZipEntry entry_;210    bool entryValid_;211    int errorCount_;212    long bytesTested_;213    TestOperation operation_;214    #endregion215  }216217  /// <summary>218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if219  /// </summary>220  /// <remarks>If the message is non-null an error has occured.  If the message is null221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>222  public delegate void ZipTestResultHandler(TestStatus status, string message);223  #endregion224225  #region Update Definitions226  /// <summary>227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.228  /// </summary>229  public enum FileUpdateMode230  {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  #endregion241242  #region ZipFile Class243  /// <summary>244  /// This class represents a Zip archive.  You can ask for the contained245  /// entries, or get an input stream for a file entry.  The entry is246  /// 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 arbitrary251  /// entries in different threads.252  /// <br/>253  /// <br/>Author of the original java version : Jochen Hoenicke254  /// </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 MainClass265  /// {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, IDisposable287  {288    #region KeyHandling289290    /// <summary>291    /// Delegate for handling keys/password setting during compresion/decompression.292    /// </summary>293    public delegate void KeysRequiredEventHandler(294      object sender,295      KeysRequiredEventArgs e296    );  297298  #region ZipFile Class299  /// <summary>300  /// This class represents a Zip archive.  You can ask for the contained301  /// entries, or get an input stream for a file entry.  The entry is302  /// automatically decompressed.303  ///304  /// You can also update the archive adding or deleting entries.305  ///306  /// This class is thread safe for input:  You can open input streams for arbitrary307  /// entries in different threads.308  /// <br/>309  /// <br/>Author of the original java version : Jochen Hoenicke310  /// </summary>311  /// <example>312  /// <code>313  /// using System;314  /// using System.Text;315  /// using System.Collections;316  /// using System.IO;317  ///318  /// using ICSharpCode.SharpZipLib.Zip;319  ///320  /// class MainClass321  /// {322  ///   static public void Main(string[] args)323  ///   {324  ///     using (ZipFile zFile = new ZipFile(args[0])) {325  ///       Console.WriteLine("Listing of : " + zFile.Name);326  ///       Console.WriteLine("");327  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");328  ///       Console.WriteLine("--------  --------  --------  ------  ---------");329  ///       foreach (ZipEntry e in zFile) {330  ///         if ( e.IsFile ) {331  ///           DateTime d = e.DateTime;332  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,333  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),334  ///             e.Name);335  ///         }336  ///       }337  ///     }338  ///   }339  /// }340  /// </code>341  /// </example>342  public class ZipFile : IEnumerable, IDisposable343  {344    #region KeyHandling345346    /// <summary>347    /// Delegate for handling keys/password setting during compresion/decompression.348    /// </summary>349    public delegate void KeysRequiredEventHandler(350      object sender,351      KeysRequiredEventArgs e352    );353354    /// <summary>355    /// Event handler for handling encryption keys.356    /// </summary>357    public KeysRequiredEventHandler KeysRequired;358359    /// <summary>360    /// Handles getting of encryption keys when required.361    /// </summary>362    /// <param name="fileName">The file for which encryption keys are required.</param>363    void OnKeysRequired(string fileName)364    {365      if (KeysRequired != null) {366        var krea = new KeysRequiredEventArgs(fileName, key);367        KeysRequired(this, krea);368        key = krea.Key;369      }370    }371372    /// <summary>373    /// Get/set the encryption key value.374    /// </summary>375    byte[] Key376    {377      get { return key; }378      set { key = value; }379    }380381#if !NETCF_1_0382    /// <summary>383    /// Password to be used for encrypting/decrypting files.384    /// </summary>385    /// <remarks>Set to null if no password is required.</remarks>386    public string Password387    {388      set389      {390        if ( string.IsNullOrEmpty(value)) {391          key = null;392        }393        else {394          rawPassword_ = value;395          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));396        }298    /// <summary>299    /// Event handler for handling encryption keys.300    /// </summary>301    public KeysRequiredEventHandler KeysRequired;302303    /// <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    }315316    /// <summary>317    /// Get/set the encryption key value.318    /// </summary>319    byte[] Key {320      get { return key; }321      set { key = value; }322    }323324    /// <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    }338339    /// <summary>340    /// Get a value indicating wether encryption keys are currently available.341    /// </summary>342    bool HaveKeys {343      get { return key != null; }344    }345    #endregion346347    #region Constructors348    /// <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 occurs355    /// </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      }364365      name_ = name;366367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);368      isStreamOwner = true;369370      try {371        ReadEntries();372      } catch {373        DisposeInternal(true);374        throw;375      }376    }377378    /// <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      }394395      if (!file.CanSeek) {396        throw new ArgumentException("Stream is not seekable", nameof(file));  397      }398    }399#endif400401    /// <summary>402    /// Get a value indicating wether encryption keys are currently available.403    /// </summary>404    bool HaveKeys405    {406      get { return key != null; }407    }408    #endregion409410    #region Constructors398399      baseStream_ = file;400      name_ = file.Name;401      isStreamOwner = true;402403      try {404        ReadEntries();405      } catch {406        DisposeInternal(true);407        throw;408      }409    }410  411    /// <summary>412    /// Opens a Zip file with the given name for reading.412    /// Opens a Zip file reading the given <see cref="Stream"/>.  413    /// </summary>414    /// <param name="name">The name of the file to open.</param>415    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>416    /// <exception cref="IOException">417    /// An i/o error occurs418    /// </exception>419    /// <exception cref="ZipException">420    /// The file doesn't contain a valid zip archive.421    /// </exception>422    public ZipFile(string name)423    {424      if ( name == null ) {425        throw new ArgumentNullException(nameof(name));426      }427428      name_ = name;429430      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);431      isStreamOwner = true;414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>415    /// <exception cref="IOException">416    /// An i/o error occurs417    /// </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      }  432433      try {434        ReadEntries();433      if (!stream.CanSeek) {434        throw new ArgumentException("Stream is not seekable", nameof(stream));  435      }436      catch {437        DisposeInternal(true);438        throw;439      }440    }441442    /// <summary>443    /// Opens a Zip file reading the given <see cref="FileStream"/>.444    /// </summary>445    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>446    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>447    /// <exception cref="IOException">448    /// An i/o error occurs.449    /// </exception>450    /// <exception cref="ZipException">451    /// The file doesn't contain a valid zip archive.452    /// </exception>453    public ZipFile(FileStream file)454    {455      if ( file == null ) {456        throw new ArgumentNullException(nameof(file));457      }458459      if ( !file.CanSeek ) {460        throw new ArgumentException("Stream is not seekable", nameof(file));461      }462463      baseStream_  = file;464      name_ = file.Name;465      isStreamOwner = true;466467      try {468        ReadEntries();469      }470      catch {471        DisposeInternal(true);472        throw;473      }474    }475476    /// <summary>477    /// Opens a Zip file reading the given <see cref="Stream"/>.478    /// </summary>479    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>480    /// <exception cref="IOException">481    /// An i/o error occurs482    /// </exception>483    /// <exception cref="ZipException">484    /// The stream doesn't contain a valid zip archive.<br/>485    /// </exception>486    /// <exception cref="ArgumentException">487    /// The <see cref="Stream">stream</see> doesnt support seeking.488    /// </exception>489    /// <exception cref="ArgumentNullException">490    /// The <see cref="Stream">stream</see> argument is null.491    /// </exception>492    public ZipFile(Stream stream)493    {494      if ( stream == null ) {495        throw new ArgumentNullException(nameof(stream));496      }497498      if ( !stream.CanSeek ) {499        throw new ArgumentException("Stream is not seekable", nameof(stream));500      }501502      baseStream_  = stream;503      isStreamOwner = true;504505      if ( baseStream_.Length > 0 ) {506        try {507          ReadEntries();508        }509        catch {510          DisposeInternal(true);511          throw;512        }513      } else {514        entries_ = new ZipEntry[0];515        isNewArchive_ = true;516      }517    }518519    /// <summary>520    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.521    /// </summary>522    internal ZipFile()523    {524      entries_ = new ZipEntry[0];525      isNewArchive_ = true;526    }527528    #endregion529530    #region Destructors and Closing531    /// <summary>532    /// Finalize this instance.533    /// </summary>534    ~ZipFile()535    {536      Dispose(false);537    }538436437      baseStream_ = stream;438      isStreamOwner = true;439440      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    }452453    /// <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    }461462    #endregion463464    #region Destructors and Closing465    /// <summary>466    /// Finalize this instance.467    /// </summary>468    ~ZipFile()469    {470      Dispose(false);471    }472473    /// <summary>474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying475    /// 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    }485486    #endregion487488    #region Creators489    /// <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      }500501      FileStream fs = File.Create(fileName);502503      var result = new ZipFile();504      result.name_ = fileName;505      result.baseStream_ = fs;506      result.isStreamOwner = true;507      return result;508    }509510    /// <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      }522523      if (!outStream.CanWrite) {524        throw new ArgumentException("Stream is not writeable", nameof(outStream));525      }526527      if (!outStream.CanSeek) {528        throw new ArgumentException("Stream is not seekable", nameof(outStream));529      }530531      var result = new ZipFile();532      result.baseStream_ = outStream;533      return result;534    }535536    #endregion537538    #region Properties  539    /// <summary>540    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying541    /// Once closed, no further instance methods should be called.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    /// <exception cref="System.IO.IOException">544    /// An i/o error occurs.545    /// </exception>546    public void Close()547    {548      DisposeInternal(true);549      GC.SuppressFinalize(this);550    }551552    #endregion553554    #region Creators555    /// <summary>556    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.557    /// </summary>558    /// <param name="fileName">The name of the archive to create.</param>559    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>560    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>561    public static ZipFile Create(string fileName)562    {563      if ( fileName == null ) {564        throw new ArgumentNullException(nameof(fileName));565      }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    }550551    /// <summary>552    /// Get a value indicating wether553    /// this archive is embedded in another file or not.554    /// </summary>555    public bool IsEmbeddedArchive {556      // Not strictly correct in all circumstances currently557      get { return offsetOfFirstEntry > 0; }558    }559560    /// <summary>561    /// Get a value indicating that this archive is a new one.562    /// </summary>563    public bool IsNewArchive {564      get { return isNewArchive_; }565    }  566567      FileStream fs = File.Create(fileName);568569      var result = new ZipFile();570      result.name_ = fileName;571      result.baseStream_ = fs;572      result.isStreamOwner = true;573      return result;574    }575576    /// <summary>577    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.578    /// </summary>579    /// <param name="outStream">The stream providing data storage.</param>580    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>581    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>582    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>583    public static ZipFile Create(Stream outStream)584    {585      if ( outStream == null ) {586        throw new ArgumentNullException(nameof(outStream));587      }588589      if ( !outStream.CanWrite ) {590        throw new ArgumentException("Stream is not writeable", nameof(outStream));567    /// <summary>568    /// Gets the comment for the zip file.569    /// </summary>570    public string ZipFileComment {571      get { return comment_; }572    }573574    /// <summary>575    /// Gets the name of this zip file.576    /// </summary>577    public string Name {578      get { return name_; }579    }580581    /// <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      }592593      if ( !outStream.CanSeek ) {594        throw new ArgumentException("Stream is not seekable", nameof(outStream));595      }596597      var result = new ZipFile();598      result.baseStream_ = outStream;599      return result;600    }601602    #endregion603604    #region Properties605    /// <summary>606    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.607    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.608    /// </summary>609    /// <remarks>610    /// The default value is true in all cases.611    /// </remarks>612    public bool IsStreamOwner613    {614      get { return isStreamOwner; }615      set { isStreamOwner = value; }616    }617618    /// <summary>619    /// Get a value indicating wether620    /// this archive is embedded in another file or not.621    /// </summary>622    public bool IsEmbeddedArchive623    {624      // Not strictly correct in all circumstances currently625      get { return offsetOfFirstEntry > 0; }626    }627628    /// <summary>629    /// Get a value indicating that this archive is a new one.630    /// </summary>631    public bool IsNewArchive632    {633      get { return isNewArchive_; }634    }635636    /// <summary>637    /// Gets the comment for the zip file.638    /// </summary>639    public string ZipFileComment640    {641      get { return comment_; }642    }643644    /// <summary>645    /// Gets the name of this zip file.646    /// </summary>647    public string Name648    {649      get { return name_; }650    }651652    /// <summary>653    /// Gets the number of entries in this zip file.654    /// </summary>655    /// <exception cref="InvalidOperationException">656    /// The Zip file has been closed.657    /// </exception>658    [Obsolete("Use the Count property instead")]659    public int Size660    {661      get662      {663        return entries_.Length;664      }665    }666667    /// <summary>668    /// Get the number of entries contained in this <see cref="ZipFile"/>.669    /// </summary>670    public long Count671    {672      get673      {674        return entries_.Length;675      }676    }677678    /// <summary>679    /// Indexer property for ZipEntries680    /// </summary>681    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]682    public ZipEntry this[int index]683    {684      get {685        return (ZipEntry) entries_[index].Clone();686      }687    }688689    #endregion690691    #region Input Handling692    /// <summary>693    /// Gets an enumerator for the Zip entries in this Zip file.694    /// </summary>695    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>696    /// <exception cref="ObjectDisposedException">697    /// The Zip file has been closed.698    /// </exception>699    public IEnumerator GetEnumerator()700    {701      if (isDisposed_) {702        throw new ObjectDisposedException("ZipFile");703      }704705      return new ZipEntryEnumerator(entries_);706    }707708    /// <summary>709    /// Return the index of the entry with a matching name710    /// </summary>711    /// <param name="name">Entry name to find</param>712    /// <param name="ignoreCase">If true the comparison is case insensitive</param>713    /// <returns>The index position of the matching entry or -1 if not found</returns>714    /// <exception cref="ObjectDisposedException">715    /// The Zip file has been closed.716    /// </exception>717    public int FindEntry(string name, bool ignoreCase)718    {719      if (isDisposed_) {720        throw new ObjectDisposedException("ZipFile");721      }722723      // TODO: This will be slow as the next ice age for huge archives!724      for (int i = 0; i < entries_.Length; i++) {725        if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {726          return i;727        }728      }729      return -1;730    }731732    /// <summary>733    /// Searches for a zip entry in this archive with the given name.734    /// String comparisons are case insensitive735    /// </summary>736    /// <param name="name">737    /// The name to find. May contain directory components separated by slashes ('/').738    /// </param>739    /// <returns>740    /// A clone of the zip entry, or null if no entry with that name exists.741    /// </returns>742    /// <exception cref="ObjectDisposedException">743    /// The Zip file has been closed.744    /// </exception>745    public ZipEntry GetEntry(string name)746    {747      if (isDisposed_) {748        throw new ObjectDisposedException("ZipFile");749      }750751      int index = FindEntry(name, true);752      return (index >= 0) ? (ZipEntry) entries_[index].Clone() : null;753    }754755    /// <summary>756    /// Gets an input stream for reading the given zip entry data in an uncompressed form.757    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().758    /// </summary>759    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>760    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>761    /// <exception cref="ObjectDisposedException">762    /// The ZipFile has already been closed763    /// </exception>764    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">765    /// The compression method for the entry is unknown766    /// </exception>767    /// <exception cref="IndexOutOfRangeException">768    /// The entry is not found in the ZipFile769    /// </exception>770    public Stream GetInputStream(ZipEntry entry)771    {772      if ( entry == null ) {773        throw new ArgumentNullException(nameof(entry));774      }775776      if ( isDisposed_ ) {777        throw new ObjectDisposedException("ZipFile");778      }779780      long index = entry.ZipFileIndex;781      if ( (index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name) ) {782        index = FindEntry(entry.Name, true);783        if (index < 0) {784          throw new ZipException("Entry cannot be found");785        }786      }787      return GetInputStream(index);788    }789790    /// <summary>791    /// Creates an input stream reading a zip entry792    /// </summary>793    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>794    /// <returns>795    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>796    /// </returns>797    /// <exception cref="ObjectDisposedException">798    /// The ZipFile has already been closed799    /// </exception>800    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">801    /// The compression method for the entry is unknown802    /// </exception>803    /// <exception cref="IndexOutOfRangeException">804    /// The entry is not found in the ZipFile805    /// </exception>806    public Stream GetInputStream(long entryIndex)807    {808      if ( isDisposed_ ) {809        throw new ObjectDisposedException("ZipFile");810      }592    }593594    /// <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    }602603    /// <summary>604    /// Indexer property for ZipEntries605    /// </summary>606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]607    public ZipEntry this[int index] {608      get {609        return (ZipEntry)entries_[index].Clone();610      }611    }612613    #endregion614615    #region Input Handling616    /// <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      }628629      return new ZipEntryEnumerator(entries_);630    }631632    /// <summary>633    /// Return the index of the entry with a matching name634    /// </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      }646647      // 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    }655656    /// <summary>657    /// Searches for a zip entry in this archive with the given name.658    /// String comparisons are case insensitive659    /// </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      }674675      int index = FindEntry(name, true);676      return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;677    }678679    /// <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 closed687    /// </exception>688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">689    /// The compression method for the entry is unknown690    /// </exception>691    /// <exception cref="IndexOutOfRangeException">692    /// The entry is not found in the ZipFile693    /// </exception>694    public Stream GetInputStream(ZipEntry entry)695    {696      if (entry == null) {697        throw new ArgumentNullException(nameof(entry));698      }699700      if (isDisposed_) {701        throw new ObjectDisposedException("ZipFile");702      }703704      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    }713714    /// <summary>715    /// Creates an input stream reading a zip entry716    /// </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 closed723    /// </exception>724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">725    /// The compression method for the entry is unknown726    /// </exception>727    /// <exception cref="IndexOutOfRangeException">728    /// The entry is not found in the ZipFile729    /// </exception>730    public Stream GetInputStream(long entryIndex)731    {732      if (isDisposed_) {733        throw new ObjectDisposedException("ZipFile");734      }735736      long start = LocateEntry(entries_[entryIndex]);737      CompressionMethod method = entries_[entryIndex].CompressionMethod;738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);739740      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      }746747      switch (method) {748        case CompressionMethod.Stored:749          // read as is.750          break;751752        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;756757        default:758          throw new ZipException("Unsupported compression method " + method);759      }760761      return result;762    }763764    #endregion765766    #region Archive Testing767    /// <summary>768    /// Test an archive for integrity/validity769    /// </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    }777778    /// <summary>779    /// Test an archive for integrity/validity780    /// </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      }791792      var status = new TestStatus(this);793794      if (resultHandler != null) {795        resultHandler(status, null);796      }797798      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;799800      bool testing = true;801802      try {803        int entryIndex = 0;804805        while (testing && (entryIndex < Count)) {806          if (resultHandler != null) {807            status.SetEntry(this[entryIndex]);808            status.SetOperation(TestOperation.EntryHeader);809            resultHandler(status, null);810          }  811812      long start = LocateEntry(entries_[entryIndex]);813      CompressionMethod method = entries_[entryIndex].CompressionMethod;814      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);815816      if (entries_[entryIndex].IsCrypted == true) {817#if NETCF_1_0818        throw new ZipException("decryption not supported for Compact Framework 1.0");819#else820        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);821        if (result == null) {822          throw new ZipException("Unable to decrypt this entry");823        }824#endif825      }826827      switch (method) {828        case CompressionMethod.Stored:829          // read as is.830          break;831832        case CompressionMethod.Deflated:833          // No need to worry about ownership and closing as underlying stream close does nothing.834          result = new InflaterInputStream(result, new Inflater(true));835          break;836837        default:838          throw new ZipException("Unsupported compression method " + method);839      }812          try {813            TestLocalHeader(this[entryIndex], test);814          } catch (ZipException ex) {815            status.AddError();816817            if (resultHandler != null) {818              resultHandler(status,819                string.Format("Exception during test - '{0}'", ex.Message));820            }821822            testing &= strategy != TestStrategy.FindFirstError;823          }824825          if (testing && testData && this[entryIndex].IsFile) {826            if (resultHandler != null) {827              status.SetOperation(TestOperation.EntryData);828              resultHandler(status, null);829            }830831            var crc = new Crc32();832833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {834835              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);  840841      return result;842    }843844    #endregion845846    #region Archive Testing847    /// <summary>848    /// Test an archive for integrity/validity849    /// </summary>850    /// <param name="testData">Perform low level data Crc check</param>851    /// <returns>true if all tests pass, false otherwise</returns>852    /// <remarks>Testing will terminate on the first error found.</remarks>853    public bool TestArchive(bool testData)854    {855      return TestArchive(testData, TestStrategy.FindFirstError, null);856    }857858    /// <summary>859    /// Test an archive for integrity/validity860    /// </summary>861    /// <param name="testData">Perform low level data Crc check</param>862    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>863    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>864    /// <returns>true if all tests pass, false otherwise</returns>865    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>866    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)867    {868      if (isDisposed_) {869        throw new ObjectDisposedException("ZipFile");870      }871872      var status = new TestStatus(this);873874      if ( resultHandler != null ) {875        resultHandler(status, null);876      }877878      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;879880      bool testing = true;841                if (resultHandler != null) {842                  totalBytes += bytesRead;843                  status.SetBytesTested(totalBytes);844                  resultHandler(status, null);845                }846              }847            }848849            if (this[entryIndex].Crc != crc.Value) {850              status.AddError();851852              if (resultHandler != null) {853                resultHandler(status, "CRC mismatch");854              }855856              testing &= strategy != TestStrategy.FindFirstError;857            }858859            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              }866867              if (this[entryIndex].CompressedSize != data.CompressedSize) {868                status.AddError();869              }870871              if (this[entryIndex].Size != data.Size) {872                status.AddError();873              }874            }875          }876877          if (resultHandler != null) {878            status.SetOperation(TestOperation.EntryComplete);879            resultHandler(status, null);880          }  881882      try {883        int entryIndex = 0;882          entryIndex += 1;883        }  884885        while ( testing && (entryIndex < Count) ) {886          if ( resultHandler != null ) {887            status.SetEntry(this[entryIndex]);888            status.SetOperation(TestOperation.EntryHeader);889            resultHandler(status, null);890          }891892          try  {893            TestLocalHeader(this[entryIndex], test);894          }895          catch(ZipException ex) {896            status.AddError();897898            if ( resultHandler != null ) {899              resultHandler(status,900                string.Format("Exception during test - '{0}'", ex.Message));901            }902903            testing &= strategy != TestStrategy.FindFirstError;904          }885        if (resultHandler != null) {886          status.SetOperation(TestOperation.MiscellaneousTests);887          resultHandler(status, null);888        }889890        // TODO: the 'Corrina Johns' test where local headers are missing from891        // the central directory.  They are therefore invisible to many archivers.892      } catch (Exception ex) {893        status.AddError();894895        if (resultHandler != null) {896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));897        }898      }899900      if (resultHandler != null) {901        status.SetOperation(TestOperation.Complete);902        status.SetEntry(null);903        resultHandler(status, null);904      }  905906          if ( testing && testData && this[entryIndex].IsFile ) {907            if ( resultHandler != null ) {908              status.SetOperation(TestOperation.EntryData);909              resultHandler(status, null);910            }911912                        var crc = new Crc32();913914                        using (Stream entryStream = this.GetInputStream(this[entryIndex]))915                        {916917                            byte[] buffer = new byte[4096];918                            long totalBytes = 0;919                            int bytesRead;920                            while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0)921                            {922                                crc.Update(buffer, 0, bytesRead);923924                                if (resultHandler != null)925                                {926                                    totalBytes += bytesRead;927                                    status.SetBytesTested(totalBytes);928                                    resultHandler(status, null);929                                }930                            }931                        }932933            if (this[entryIndex].Crc != crc.Value) {934              status.AddError();935936              if ( resultHandler != null ) {937                resultHandler(status, "CRC mismatch");938              }939940              testing &= strategy != TestStrategy.FindFirstError;941            }942943            if (( this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0 ) {944              var helper = new ZipHelperStream(baseStream_);945              var data = new DescriptorData();946              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);947              if (this[entryIndex].Crc != data.Crc) {948                status.AddError();949              }950951              if (this[entryIndex].CompressedSize != data.CompressedSize) {952                status.AddError();953              }954955              if (this[entryIndex].Size != data.Size) {956                status.AddError();957              }958            }959          }960961          if ( resultHandler != null ) {962            status.SetOperation(TestOperation.EntryComplete);963            resultHandler(status, null);964          }965966          entryIndex += 1;967        }968969        if ( resultHandler != null ) {970          status.SetOperation(TestOperation.MiscellaneousTests);971          resultHandler(status, null);972        }973974        // TODO: the 'Corrina Johns' test where local headers are missing from975        // the central directory.  They are therefore invisible to many archivers.976      }977      catch (Exception ex) {978        status.AddError();906      return (status.ErrorCount == 0);907    }908909    [Flags]910    enum HeaderTest911    {912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted913      Header = 0x02,     // Check that this header contents are valid914    }915916    /// <summary>917    /// Test a local header against that provided from the central directory918    /// </summary>919    /// <param name="entry">920    /// The entry to test against921    /// </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;929930        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        }934935        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();945946        byte[] nameData = new byte[storedNameLength];947        StreamUtils.ReadFully(baseStream_, nameData);948949        byte[] extraData = new byte[extraDataLength];950        StreamUtils.ReadFully(baseStream_, extraData);951952        var localExtraData = new ZipExtraData(extraData);953954        // Extra data / zip64 checks955        if (localExtraData.Find(1)) {956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64957          // and size or compressedSize = MaxValue, due to rogue creators.958959          size = localExtraData.ReadLong();960          compressedSize = localExtraData.ReadLong();961962          if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {963            // These may be valid if patched later964            if ((size != -1) && (size != entry.Size)) {965              throw new ZipException("Size invalid for descriptor");966            }967968            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        }  979980        if ( resultHandler != null ) {981          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));982        }983      }984985      if ( resultHandler != null ) {986        status.SetOperation(TestOperation.Complete);987        status.SetEntry(null);988        resultHandler(status, null);989      }980        if (testData) {981          if (entry.IsFile) {982            if (!entry.IsCompressionMethodSupported()) {983              throw new ZipException("Compression method not supported");984            }985986            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})", extract989            }  990991      return (status.ErrorCount == 0);992    }993994    [Flags]995    enum HeaderTest996    {997      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted998      Header  = 0x02,     // Check that this header contents are valid999    }10001001    /// <summary>1002    /// Test a local header against that provided from the central directory1003    /// </summary>1004    /// <param name="entry">1005    /// The entry to test against1006    /// </param>1007    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>1008    /// <returns>The offset of the entries data in the file</returns>1009    long TestLocalHeader(ZipEntry entry, HeaderTest tests)1010    {1011      lock(baseStream_)1012      {1013        bool testHeader = (tests & HeaderTest.Header) != 0;1014        bool testData = (tests & HeaderTest.Extract) != 0;10151016        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);1017        if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {1018          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)1019        }10201021        var extractVersion = ( short ) (ReadLEUshort() & 0x00ff);1022        var localFlags = ( short )ReadLEUshort();1023        var compressionMethod = ( short )ReadLEUshort();1024        var fileTime = ( short )ReadLEUshort();1025        var fileDate = ( short )ReadLEUshort();1026        uint crcValue = ReadLEUint();1027        long compressedSize = ReadLEUint();1028        long size = ReadLEUint();1029        int storedNameLength = ReadLEUshort();1030        int extraDataLength = ReadLEUshort();10311032        byte[] nameData = new byte[storedNameLength];1033        StreamUtils.ReadFully(baseStream_, nameData);10341035        byte[] extraData = new byte[extraDataLength];1036        StreamUtils.ReadFully(baseStream_, extraData);991            if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance992              throw new ZipException("The library does not support the zip version required to extract this entry");993            }994          }995        }996997        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})", extractVersi1015          }10161017          // Local entry flags dont have reserved bit set on.1018          if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R1019            throw new ZipException("Reserved bit flags cannot be set.");1020          }10211022          // Encryption requires extract version >= 201023          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          }10261027          // 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            }10321033            if (extractVersion < 50) {1034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({01035            }1036          }  10371038        var localExtraData = new ZipExtraData(extraData);10391040        // Extra data / zip64 checks1041        if (localExtraData.Find(1))1042        {1043          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip641044          // and size or compressedSize = MaxValue, due to rogue creators.10451046          size = localExtraData.ReadLong();1047          compressedSize = localExtraData.ReadLong();10481049                    if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0)1050                    {1051                        // These may be valid if patched later1052                        if ( (size != -1) && (size != entry.Size)) {1053                            throw new ZipException("Size invalid for descriptor");1054                        }10551056                        if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {1057                            throw new ZipException("Compressed size invalid for descriptor");1058                        }1059                    }1060                }1061        else1062        {1063          // No zip64 extra data but entry requires it.1064          if ((extractVersion >= ZipConstants.VersionZip64) &&1065            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue)))1066          {1067            throw new ZipException("Required Zip64 extended information missing");1038          // Patched entries require extract version >= 271039          if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {1040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));1041          }10421043          // Central header flags match local entry flags.1044          if (localFlags != entry.Flags) {1045            throw new ZipException("Central header/local header flags mismatch");1046          }10471048          // Central header compression method matches local entry1049          if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {1050            throw new ZipException("Central header/local header compression method mismatch");1051          }10521053          if (entry.Version != extractVersion) {1054            throw new ZipException("Extract version mismatch");1055          }10561057          // Strong encryption and extract version match1058          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          }10631064          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        }10701071        if ( testData ) {1072          if ( entry.IsFile ) {1073            if ( !entry.IsCompressionMethodSupported() ) {1074              throw new ZipException("Compression method not supported");1075            }10761077            if ( (extractVersion > ZipConstants.VersionMadeBy)1078              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)) ) {1079              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract1080            }10811082            if ( (localFlags & ( int )(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enha1083              throw new ZipException("The library does not support the zip version required to extract this entry");1084            }1085          }1086        }10871088                if (testHeader)1089                {1090                    if ((extractVersion <= 63) &&  // Ignore later versions as we dont know about them..1091                        (extractVersion != 10) &&1092                        (extractVersion != 11) &&1093                        (extractVersion != 20) &&1094                        (extractVersion != 21) &&1095                        (extractVersion != 25) &&1096                        (extractVersion != 27) &&1097                        (extractVersion != 45) &&1098                        (extractVersion != 46) &&1099                        (extractVersion != 50) &&1100                        (extractVersion != 51) &&1101                        (extractVersion != 52) &&1102                        (extractVersion != 61) &&1103                        (extractVersion != 62) &&1104                        (extractVersion != 63)1105                        )1106                    {1107                        throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", 1108                    }11091110                    // Local entry flags dont have reserved bit set on.1111                    if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | General1112                    {1113                        throw new ZipException("Reserved bit flags cannot be set.");1114                    }11151116                    // Encryption requires extract version >= 201117                    if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20))1118                    {1119                        throw new ZipException(string.Format("Version required to extract this entry is too low for encr1120                    }11211122                    // Strong encryption requires encryption flag to be set and extract version >= 50.1123                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1124                    {1125                        if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0)1126                        {1127                            throw new ZipException("Strong encryption flag set but encryption flag is not set");1128                        }10691070          if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {1071            if (crcValue != (uint)entry.Crc) {1072              throw new ZipException("Central header/local header crc mismatch");1073            }1074          }10751076          // Crc valid for empty entry.1077          // This will also apply to streamed entries where size isnt known and the header cant be patched1078          if ((size == 0) && (compressedSize == 0)) {1079            if (crcValue != 0) {1080              throw new ZipException("Invalid CRC for empty entry");1081            }1082          }10831084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably1086          if (entry.Name.Length > storedNameLength) {1087            throw new ZipException("File name length mismatch");1088          }10891090          // Name data has already been read convert it and compare.1091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);10921093          // Central directory and local entry name match1094          if (localName != entry.Name) {1095            throw new ZipException("Central header and local header file name mismatch");1096          }10971098          // Directories have zero actual size but can have compressed size1099          if (entry.IsDirectory) {1100            if (size > 0) {1101              throw new ZipException("Directory cannot have size");1102            }11031104            // 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 bytes1112              // 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 bytes1114              throw new ZipException("Directory compressed size invalid");1115            }1116          }11171118          if (!ZipNameTransform.IsValidName(localName, true)) {1119            throw new ZipException("Name is invalid");1120          }1121        }11221123        // Tests that apply to both data and header.11241125        // 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)) {  11291130                        if (extractVersion < 50)1131                        {1132                            throw new ZipException(string.Format("Version required to extract this entry is too low for 1133                        }1134                    }11351136                    // Patched entries require extract version >= 271137                    if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27))1138                    {1139                        throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractV1140                    }11411142                    // Central header flags match local entry flags.1143                    if (localFlags != entry.Flags)1144                    {1145                        throw new ZipException("Central header/local header flags mismatch");1146                    }11471148                    // Central header compression method matches local entry1149                    if (entry.CompressionMethod != (CompressionMethod)compressionMethod)1150                    {1151                        throw new ZipException("Central header/local header compression method mismatch");1152                    }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          }11361137          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        }11441145        int extraLength = storedNameLength + extraDataLength;1146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;1147      }1148    }11491150    #endregion11511152    #region Updating  11531154                    if (entry.Version != extractVersion)1155                    {1156                        throw new ZipException("Extract version mismatch");1157                    }11581159                    // Strong encryption and extract version match1160                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1161                    {1162                        if (extractVersion < 62)1163                        {1164                            throw new ZipException("Strong encryption flag set but version not high enough");1165                        }1166                    }11671168                    if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0)1169                    {1170                        if ((fileTime != 0) || (fileDate != 0))1171                        {1172                            throw new ZipException("Header masked set but date/time values non-zero");1173                        }1174                    }11751176                    if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0)1177                    {1178                        if (crcValue != (uint)entry.Crc)1179                        {1180                            throw new ZipException("Central header/local header crc mismatch");1181                        }1182                    }11831184                    // Crc valid for empty entry.1185                    // This will also apply to streamed entries where size isnt known and the header cant be patched1186                    if ((size == 0) && (compressedSize == 0))1187                    {1188                        if (crcValue != 0)1189                        {1190                            throw new ZipException("Invalid CRC for empty entry");1191                        }1192                    }11931194                    // TODO: make test more correct...  can't compare lengths as was done originally as this can fail fo1195                    // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntr1196                    if (entry.Name.Length > storedNameLength)1197                    {1198                        throw new ZipException("File name length mismatch");1199                    }12001201                    // Name data has already been read convert it and compare.1202                    string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);12031204                    // Central directory and local entry name match1205                    if (localName != entry.Name)1206                    {1207                        throw new ZipException("Central header and local header file name mismatch");1208                    }12091210                    // Directories have zero actual size but can have compressed size1211                    if (entry.IsDirectory)1212                    {1213                        if (size > 0)1214                        {1215                            throw new ZipException("Directory cannot have size");1216                        }12171218                        // There may be other cases where the compressed size can be greater than this?1219                        // If so until details are known we will be strict.1220                        if (entry.IsCrypted)1221                        {1222                            if (compressedSize > ZipConstants.CryptoHeaderSize + 2)1223                            {1224                                throw new ZipException("Directory compressed size invalid");1225                            }1226                        }1227                        else if (compressedSize > 2)1228                        {1229                            // When not compressed the directory size can validly be 2 bytes1230                            // if the true size wasnt known when data was originally being written.1231                            // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes1232                            throw new ZipException("Directory compressed size invalid");1233                        }1234                    }12351236                    if (!ZipNameTransform.IsValidName(localName, true))1237                    {1238                        throw new ZipException("Name is invalid");1239                    }1240                }12411242        // Tests that apply to both data and header.1154    const int DefaultBufferSize = 4096;11551156    /// <summary>1157    /// The kind of update to apply.1158    /// </summary>1159    enum UpdateCommand1160    {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    }11651166    #region Properties1167    /// <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      }11741175      set {1176        updateEntryFactory_.NameTransform = value;1177      }1178    }11791180    /// <summary>1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1182    /// during updates.1183    /// </summary>1184    public IEntryFactory EntryFactory {1185      get {1186        return updateEntryFactory_;1187      }11881189      set {1190        if (value == null) {1191          updateEntryFactory_ = new ZipEntryFactory();1192        } else {1193          updateEntryFactory_ = value;1194        }1195      }1196    }11971198    /// <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        }12071208        if (bufferSize_ != value) {1209          bufferSize_ = value;1210          copyBuffer_ = null;1211        }1212      }1213    }12141215    /// <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    }12211222    /// <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    }12291230    #endregion12311232    #region Immediate updating1233    //    TBD: Direct form of updating1234    //1235    //    public void Update(IEntryMatcher deleteMatcher)1236    //    {1237    //    }1238    //1239    //    public void Update(IScanner addScanner)1240    //    {1241    //    }1242    #endregion  12431244        // Size can be verified only if it is known in the local header.1245        // it will always be known in the central header.1246        if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||1247          ((size > 0) || (compressedSize > 0))) {12481249          if (size != entry.Size) {1250            throw new ZipException(1251              string.Format("Size mismatch between central header({0}) and local header({1})",1252                entry.Size, size));1253          }12541255          if (compressedSize != entry.CompressedSize &&1256            compressedSize != 0xFFFFFFFF && compressedSize != -1) {1257            throw new ZipException(1258              string.Format("Compressed size mismatch between central header({0}) and local header({1})",1259              entry.CompressedSize, compressedSize));1260          }1261        }1244    #region Deferred Updating1245    /// <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.</p1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1250    /// <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      }12581259      if (dataSource == null) {1260        throw new ArgumentNullException(nameof(dataSource));1261      }  12621263        int extraLength = storedNameLength + extraDataLength;1264        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;1263      if (isDisposed_) {1264        throw new ObjectDisposedException("ZipFile");  1265      }1266    }12671268    #endregion12691270    #region Updating12711272    const int DefaultBufferSize = 4096;12661267      if (IsEmbeddedArchive) {1268        throw new ZipException("Cannot update embedded/SFX archives");1269      }12701271      archiveStorage_ = archiveStorage;1272      updateDataSource_ = dataSource;  12731274    /// <summary>1275    /// The kind of update to apply.1276    /// </summary>1277    enum UpdateCommand1278    {1279      Copy,       // Copy original file contents.1280      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.1281      Add,        // Add a new file to the archive.1282    }1274      // NOTE: the baseStream_ may not currently support writing or seeking.12751276      updateIndex_ = new Hashtable();12771278      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      }  12831284    #region Properties1285    /// <summary>1286    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.1287    /// </summary>1288    public INameTransform NameTransform1289    {1290      get {1291        return updateEntryFactory_.NameTransform;1292      }12931294      set {1295        updateEntryFactory_.NameTransform = value;1296      }1297    }12981299    /// <summary>1300    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1301    /// during updates.1302    /// </summary>1303    public IEntryFactory EntryFactory1304    {1305      get {1306        return updateEntryFactory_;1307      }13081309      set {1310        if (value == null) {1311          updateEntryFactory_ = new ZipEntryFactory();1312        }1313        else {1314          updateEntryFactory_ = value;1315        }1316      }1317    }13181319    /// <summary>1320    /// Get /set the buffer size to be used when updating this zip file.1321    /// </summary>1322    public int BufferSize1323    {1324      get { return bufferSize_; }1325      set {1326        if ( value < 1024 ) {1327#if NETCF_1_01328          throw new ArgumentOutOfRangeException("value");1329#else1330          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");1331#endif1332        }13331334        if ( bufferSize_ != value ) {1335          bufferSize_ = value;1336          copyBuffer_ = null;1337        }1338      }1339    }1284      // We must sort by offset before using offset's calculated sizes1285      updates_.Sort(new UpdateComparer());12861287      int idx = 0;1288      foreach (ZipUpdate update in updates_) {1289        //If last entry, there is no next entry offset to use1290        if (idx == updates_.Count - 1)1291          break;12921293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;1294        idx++;1295      }1296      updateCount_ = updates_.Count;12971298      contentsEdited_ = false;1299      commentEdited_ = false;1300      newComment_ = null;1301    }13021303    /// <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    }13111312    /// <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    }13261327    /// <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      }13381339      CheckUpdating();  13401341    /// <summary>1342    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.1343    /// </summary>1344    public bool IsUpdating1345    {1346      get { return updates_ != null; }1347    }13481349    /// <summary>1350    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.1351    /// </summary>1352    public UseZip64 UseZip641353    {1354      get { return useZip64_; }1355      set { useZip64_ = value; }1356    }13571358    #endregion13591360    #region Immediate updating1361//    TBD: Direct form of updating1362//1363//    public void Update(IEntryMatcher deleteMatcher)1364//    {1365//    }1366//1367//    public void Update(IScanner addScanner)1368//    {1369//    }1370    #endregion13711372    #region Deferred Updating1373    /// <summary>1374    /// Begin updating this <see cref="ZipFile"/> archive.1375    /// </summary>1376    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p1377    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1341      try {1342        updateIndex_.Clear();1343        updateIndex_ = null;13441345        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        }13581359      } finally {1360        PostUpdateCleanup();1361      }1362    }13631364    /// <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    }13731374    /// <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    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>1380    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1381    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)1382    {1383      if ( archiveStorage == null ) {1384        throw new ArgumentNullException(nameof(archiveStorage));1385      }1379    public void SetComment(string comment)1380    {1381      if (isDisposed_) {1382        throw new ObjectDisposedException("ZipFile");1383      }13841385      CheckUpdating();  13861387      if ( dataSource == null ) {1388        throw new ArgumentNullException(nameof(dataSource));1389      }13901391      if ( isDisposed_ ) {1392        throw new ObjectDisposedException("ZipFile");1393      }13941395      if ( IsEmbeddedArchive ) {1396        throw new ZipException ("Cannot update embedded/SFX archives");1397      }1387      newComment_ = new ZipString(comment);13881389      if (newComment_.RawLength > 0xffff) {1390        newComment_ = null;1391        throw new ZipException("Comment length exceeds maximum - 65535");1392      }13931394      // We dont take account of the original and current comment appearing to be the same1395      // as encoding may be different.1396      commentEdited_ = true;1397    }  13981399      archiveStorage_ = archiveStorage;1400      updateDataSource_ = dataSource;14011402      // NOTE: the baseStream_ may not currently support writing or seeking.14031404      updateIndex_ = new Hashtable();14051406      updates_ = new ArrayList(entries_.Length);1407      foreach(ZipEntry entry in entries_) {1408        int index = updates_.Add(new ZipUpdate(entry));1409        updateIndex_.Add(entry.Name, index);1410      }14111412      // We must sort by offset before using offset's calculated sizes1413      updates_.Sort(new UpdateComparer());14141415      int idx = 0;1416      foreach (ZipUpdate update in updates_) {1417        //If last entry, there is no next entry offset to use1418        if (idx == updates_.Count - 1)1419          break;14201421        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;1422        idx++;1423      }1424      updateCount_ = updates_.Count;14251426      contentsEdited_ = false;1427      commentEdited_ = false;1428      newComment_ = null;1429    }14301431    /// <summary>1432    /// Begin updating to this <see cref="ZipFile"/> archive.1433    /// </summary>1434    /// <param name="archiveStorage">The storage to use during the update.</param>1435    public void BeginUpdate(IArchiveStorage archiveStorage)1436    {1437      BeginUpdate(archiveStorage, new DynamicDiskDataSource());1438    }14391440    /// <summary>1441    /// Begin updating this <see cref="ZipFile"/> archive.1442    /// </summary>1443    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>1444    /// <seealso cref="CommitUpdate"></seealso>1445    /// <seealso cref="AbortUpdate"></seealso>1446    public void BeginUpdate()1447    {1448      if ( Name == null ) {1449        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());1450      }1451      else {1452        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());1453      }1399    #endregion14001401    #region Adding Entries14021403    void AddUpdate(ZipUpdate update)1404    {1405      contentsEdited_ = true;14061407      int index = FindExistingUpdate(update.Entry.Name);14081409      if (index >= 0) {1410        if (updates_[index] == null) {1411          updateCount_ += 1;1412        }14131414        // 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    }14221423    /// <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      }14371438      if (isDisposed_) {1439        throw new ObjectDisposedException("ZipFile");1440      }14411442      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1444      }14451446      CheckUpdating();1447      contentsEdited_ = true;14481449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1450      entry.IsUnicodeText = useUnicodeText;1451      entry.CompressionMethod = compressionMethod;14521453      AddUpdate(new ZipUpdate(fileName, entry));  1454    }  1455  1456    /// <summary>1457    /// Commit current updates, updating this archive.1457    /// Add a new entry to the archive.  1458    /// </summary>1459    /// <seealso cref="BeginUpdate()"></seealso>1460    /// <seealso cref="AbortUpdate"></seealso>1461    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1462    public void CommitUpdate()1463    {1464      if ( isDisposed_ ) {1465        throw new ObjectDisposedException("ZipFile");1466      }14671468      CheckUpdating();14691470      try {1471        updateIndex_.Clear();1472        updateIndex_=null;14731474        if( contentsEdited_ ) {1475          RunUpdates();1476        }1477        else if( commentEdited_ ) {1478          UpdateCommentOnly();1479        }1480        else {1481          // Create an empty archive if none existed originally.1482          if( entries_.Length==0 ) {1483            byte[] theComment=(newComment_!=null)?newComment_.RawComment:ZipConstants.ConvertToArray(comment_);1484            using( ZipHelperStream zhs=new ZipHelperStream(baseStream_) ) {1485              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);1486            }1487          }1488        }14891459    /// <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      }14681469      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1471      }14721473      CheckUpdating();1474      contentsEdited_ = true;14751476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1477      entry.CompressionMethod = compressionMethod;1478      AddUpdate(new ZipUpdate(fileName, entry));1479    }14801481    /// <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      finally {1492        PostUpdateCleanup();1493      }14911492      CheckUpdating();1493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));  1494    }  1495  1496    /// <summary>1497    /// Abort updating leaving the archive unchanged.1497    /// Add a file to the archive.  1498    /// </summary>1499    /// <seealso cref="BeginUpdate()"></seealso>1500    /// <seealso cref="CommitUpdate"></seealso>1501    public void AbortUpdate()1502    {1503      PostUpdateCleanup();1504    }15051506    /// <summary>1507    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.1508    /// </summary>1509    /// <param name="comment">The comment to record.</param>1510    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1511    public void SetComment(string comment)1512    {1513      if ( isDisposed_ ) {1514        throw new ObjectDisposedException("ZipFile");1515      }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      }15071508      if (entryName == null) {1509        throw new ArgumentNullException(nameof(entryName));1510      }15111512      CheckUpdating();1513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));1514    }1515  15161517      CheckUpdating();15181519      newComment_ = new ZipString(comment);15201521      if ( newComment_.RawLength  > 0xffff ) {1522        newComment_ = null;1523        throw new ZipException("Comment length exceeds maximum - 65535");1524      }15251526      // We dont take account of the original and current comment appearing to be the same1527      // as encoding may be different.1528      commentEdited_ = true;1529    }15301531    #endregion15321533    #region Adding Entries15341535    void AddUpdate(ZipUpdate update)1536    {1537      contentsEdited_ = true;15381539      int index = FindExistingUpdate(update.Entry.Name);15401541      if (index >= 0) {1542        if ( updates_[index] == null ) {1543          updateCount_ += 1;1544        }15451546        // Direct replacement is faster than delete and add.1547        updates_[index] = update;1548      }1549      else {1550        index = updates_.Add(update);1551        updateCount_ += 1;1552        updateIndex_.Add(update.Entry.Name, index);1553      }1554    }15551556    /// <summary>1557    /// Add a new entry to the archive.1558    /// </summary>1559    /// <param name="fileName">The name of the file to add.</param>1560    /// <param name="compressionMethod">The compression method to use.</param>1561    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>1562    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1563    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1564    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>1565    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText )1566    {1567      if (fileName == null) {1568        throw new ArgumentNullException(nameof(fileName));1569      }15701571      if ( isDisposed_ ) {1572        throw new ObjectDisposedException("ZipFile");1573      }15741575      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1576        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1577      }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      }15271528      if (entryName == null) {1529        throw new ArgumentNullException(nameof(entryName));1530      }15311532      CheckUpdating();1533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));1534    }15351536    /// <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      }15471548      if (entryName == null) {1549        throw new ArgumentNullException(nameof(entryName));1550      }15511552      CheckUpdating();15531554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1555      entry.CompressionMethod = compressionMethod;15561557      AddUpdate(new ZipUpdate(dataSource, entry));1558    }15591560    /// <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 useUnicode1568    {1569      if (dataSource == null) {1570        throw new ArgumentNullException(nameof(dataSource));1571      }15721573      if (entryName == null) {1574        throw new ArgumentNullException(nameof(entryName));1575      }15761577      CheckUpdating();  15781579      CheckUpdating();1580      contentsEdited_ = true;15811582      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1583      entry.IsUnicodeText = useUnicodeText;1584      entry.CompressionMethod = compressionMethod;1579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1580      entry.IsUnicodeText = useUnicodeText;1581      entry.CompressionMethod = compressionMethod;15821583      AddUpdate(new ZipUpdate(dataSource, entry));1584    }  15851586      AddUpdate(new ZipUpdate(fileName, entry));1587    }15881589    /// <summary>1590    /// Add a new entry to the archive.1591    /// </summary>1592    /// <param name="fileName">The name of the file to add.</param>1593    /// <param name="compressionMethod">The compression method to use.</param>1594    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>1595    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>1596    public void Add(string fileName, CompressionMethod compressionMethod)1597    {1598      if ( fileName == null ) {1599        throw new ArgumentNullException(nameof(fileName));1600      }16011602      if ( !ZipEntry.IsCompressionMethodSupported(compressionMethod) ) {1603        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1604      }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      }15961597      CheckUpdating();15981599      if ((entry.Size != 0) || (entry.CompressedSize != 0)) {1600        throw new ZipException("Entry cannot have any data");1601      }16021603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));1604    }  16051606      CheckUpdating();1607      contentsEdited_ = true;16081609      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1610      entry.CompressionMethod = compressionMethod;1611      AddUpdate(new ZipUpdate(fileName, entry));1612    }16131614    /// <summary>1615    /// Add a file to the archive.1616    /// </summary>1617    /// <param name="fileName">The name of the file to add.</param>1618    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1619    public void Add(string fileName)1620    {1621      if ( fileName == null ) {1622        throw new ArgumentNullException(nameof(fileName));1623      }16241625      CheckUpdating();1626      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));1627    }16281629    /// <summary>1630    /// Add a file to the archive.1631    /// </summary>1632    /// <param name="fileName">The name of the file to add.</param>1633    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>1634    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1635    public void Add(string fileName, string entryName)1636    {1637      if (fileName == null) {1638        throw new ArgumentNullException(nameof(fileName));1639      }16401641      if ( entryName == null ) {1642        throw new ArgumentNullException(nameof(entryName));1643      }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      }16151616      CheckUpdating();16171618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);1619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));1620    }16211622    #endregion16231624    #region Modifying Entries1625    /* 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          }16331634          if ( updated == null ) {1635            throw new ArgumentNullException("updated");1636          }16371638          CheckUpdating();1639          contentsEdited_ = true;1640          updates_.Add(new ZipUpdate(original, updated));1641        }1642    */1643    #endregion  16441645      CheckUpdating();1646      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));1647    }164816491650    /// <summary>1651    /// Add a file entry with data.1652    /// </summary>1653    /// <param name="dataSource">The source of the data for this entry.</param>1654    /// <param name="entryName">The name to give to the entry.</param>1655    public void Add(IStaticDataSource dataSource, string entryName)1656    {1657      if ( dataSource == null ) {1658        throw new ArgumentNullException(nameof(dataSource));1659      }16601661      if ( entryName == null ) {1662        throw new ArgumentNullException(nameof(entryName));1663      }16641665      CheckUpdating();1666      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));1667    }16681669    /// <summary>1670    /// Add a file entry with data.1671    /// </summary>1672    /// <param name="dataSource">The source of the data for this entry.</param>1673    /// <param name="entryName">The name to give to the entry.</param>1674    /// <param name="compressionMethod">The compression method to use.</param>1675    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)1676    {1677      if ( dataSource == null ) {1678        throw new ArgumentNullException(nameof(dataSource));1679      }16801681      if ( entryName == null ) {1682        throw new ArgumentNullException(nameof(entryName));1683      }16841685      CheckUpdating();16861687      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1688      entry.CompressionMethod = compressionMethod;16891690      AddUpdate(new ZipUpdate(dataSource, entry));1691    }16921693    /// <summary>1694    /// Add a file entry with data.1695    /// </summary>1696    /// <param name="dataSource">The source of the data for this entry.</param>1697    /// <param name="entryName">The name to give to the entry.</param>1698    /// <param name="compressionMethod">The compression method to use.</param>1699    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>1700    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode1701    {1702      if (dataSource == null) {1703        throw new ArgumentNullException(nameof(dataSource));1704      }17051706      if ( entryName == null ) {1707        throw new ArgumentNullException(nameof(entryName));1708      }17091710      CheckUpdating();17111712      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1713      entry.IsUnicodeText = useUnicodeText;1714      entry.CompressionMethod = compressionMethod;17151716      AddUpdate(new ZipUpdate(dataSource, entry));1717    }17181719    /// <summary>1720    /// Add a <see cref="ZipEntry"/> that contains no data.1721    /// </summary>1722    /// <param name="entry">The entry to add.</param>1723    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>1724    public void Add(ZipEntry entry)1725    {1726      if ( entry == null ) {1727        throw new ArgumentNullException(nameof(entry));1728      }17291730      CheckUpdating();1645    #region Deleting Entries1646    /// <summary>1647    /// Delete an entry by name1648    /// </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      }16561657      CheckUpdating();16581659      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    }16711672    /// <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      }16811682      CheckUpdating();16831684      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    }16931694    #endregion16951696    #region Update Support16971698    #region Writing Values/Headers1699    void WriteLEShort(int value)1700    {1701      baseStream_.WriteByte((byte)(value & 0xff));1702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));1703    }17041705    /// <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    }17131714    /// <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    }17221723    /// <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    }  17311732      if ( (entry.Size != 0) || (entry.CompressedSize != 0) ) {1733        throw new ZipException("Entry cannot have any data");1734      }17351736      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));1737    }17381739    /// <summary>1740    /// Add a directory entry to the archive.1741    /// </summary>1742    /// <param name="directoryName">The directory to add.</param>1743    public void AddDirectory(string directoryName)1744    {1745      if ( directoryName == null ) {1746        throw new ArgumentNullException(nameof(directoryName));1747      }17481749      CheckUpdating();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    }17401741    void WriteLEUlong(ulong value)1742    {1743      WriteLEUint((uint)(value & 0xffffffff));1744      WriteLEUint((uint)(value >> 32));1745    }17461747    void WriteLocalEntryHeader(ZipUpdate update)1748    {1749      ZipEntry entry = update.OutEntry;  17501751      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);1752      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));1753    }17541755    #endregion17561757    #region Modifying Entries1758/* Modify not yet ready for public consumption.1759   Direct modification of an entry should not overwrite original data before its read.1760   Safe mode is trivial in this sense.1761    public void Modify(ZipEntry original, ZipEntry updated)1762    {1763      if ( original == null ) {1764        throw new ArgumentNullException("original");1765      }1751      // TODO: Local offset will require adjusting for multi-disk zip files.1752      entry.Offset = baseStream_.Position;17531754      // 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        }  17661767      if ( updated == null ) {1768        throw new ArgumentNullException("updated");1769      }17701771      CheckUpdating();1772      contentsEdited_ = true;1773      updates_.Add(new ZipUpdate(original, updated));1774    }1775*/1776    #endregion17771778    #region Deleting Entries1779    /// <summary>1780    /// Delete an entry by name1781    /// </summary>1782    /// <param name="fileName">The filename to delete</param>1783    /// <returns>True if the entry was found and deleted; false otherwise.</returns>1784    public bool Delete(string fileName)1785    {1786      if ( fileName == null ) {1787        throw new ArgumentNullException(nameof(fileName));1788      }17891790      CheckUpdating();17911792      bool result = false;1793      int index = FindExistingUpdate(fileName);1794      if ( (index >= 0) && (updates_[index] != null) ) {1795        result = true;1796        contentsEdited_ = true;1797        updates_[index] = null;1798        updateCount_ -= 1;1799      }1800      else {1801        throw new ZipException("Cannot find entry to delete");1802      }1803      return result;1804    }18051806    /// <summary>1807    /// Delete a <see cref="ZipEntry"/> from the archive.1808    /// </summary>1809    /// <param name="entry">The entry to delete.</param>1810    public void Delete(ZipEntry entry)1811    {1812      if ( entry == null ) {1813        throw new ArgumentNullException(nameof(entry));1814      }18151816      CheckUpdating();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        }17751776        switch (useZip64_) {1777          case UseZip64.Dynamic:1778            if (entry.Size < 0) {1779              entry.ForceZip64();1780            }1781            break;17821783          case UseZip64.On:1784            entry.ForceZip64();1785            break;17861787          case UseZip64.Off:1788            // Do nothing.  The entry itself may be using Zip64 independantly.1789            break;1790        }1791      }17921793      // Write the local file header1794      WriteLEInt(ZipConstants.LocalHeaderSignature);17951796      WriteLEShort(entry.Version);1797      WriteLEShort(entry.Flags);17981799      WriteLEShort((byte)entry.CompressionMethod);1800      WriteLEInt((int)entry.DosTime);18011802      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      }18091810      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        }  18171818      int index = FindExistingUpdate(entry);1819      if ( index >= 0 ) {1820        contentsEdited_ = true;1821        updates_[index] = null;1822        updateCount_ -= 1;1823      }1824      else {1825        throw new ZipException("Cannot find entry to delete");1818        WriteLEInt((int)entry.CompressedSize);1819        WriteLEInt((int)entry.Size);1820      }18211822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);18231824      if (name.Length > 0xFFFF) {1825        throw new ZipException("Entry name too long.");  1826      }1827    }18281829    #endregion18301831    #region Update Support18271828      var ed = new ZipExtraData(entry.ExtraData);18291830      if (entry.LocalHeaderRequiresZip64) {1831        ed.StartNewEntry();  18321833    #region Writing Values/Headers1834    void WriteLEShort(int value)1835    {1836      baseStream_.WriteByte(( byte )(value & 0xff));1837      baseStream_.WriteByte(( byte )((value >> 8) & 0xff));1838    }18391840    /// <summary>1841    /// Write an unsigned short in little endian byte order.1842    /// </summary>1843    void WriteLEUshort(ushort value)1844    {1845      baseStream_.WriteByte(( byte )(value & 0xff));1846      baseStream_.WriteByte(( byte )(value >> 8));1847    }18481849    /// <summary>1850    /// Write an int in little endian byte order.1851    /// </summary>1852    void WriteLEInt(int value)1853    {1854      WriteLEShort(value & 0xffff);1855      WriteLEShort(value >> 16);1856    }18571858    /// <summary>1859    /// Write an unsigned int in little endian byte order.1860    /// </summary>1861    void WriteLEUint(uint value)1862    {1863      WriteLEUshort((ushort)(value & 0xffff));1864      WriteLEUshort((ushort)(value >> 16));1865    }18661867    /// <summary>1868    /// Write a long in little endian byte order.1869    /// </summary>1870    void WriteLeLong(long value)1871    {1872      WriteLEInt(( int )(value & 0xffffffff));1873      WriteLEInt(( int )(value >> 32));1874    }18751876    void WriteLEUlong(ulong value)1877    {1878      WriteLEUint(( uint )(value & 0xffffffff));1879      WriteLEUint(( uint )(value >> 32));1880    }18811882    void WriteLocalEntryHeader(ZipUpdate update)1883    {1884      ZipEntry entry = update.OutEntry;18851886      // TODO: Local offset will require adjusting for multi-disk zip files.1887      entry.Offset = baseStream_.Position;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      }18411842      entry.ExtraData = ed.GetEntryData();18431844      WriteLEShort(name.Length);1845      WriteLEShort(entry.ExtraData.Length);18461847      if (name.Length > 0) {1848        baseStream_.Write(name, 0, name.Length);1849      }18501851      if (entry.LocalHeaderRequiresZip64) {1852        if (!ed.Find(1)) {1853          throw new ZipException("Internal error cannot find extra data");1854        }18551856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1857      }18581859      if (entry.ExtraData.Length > 0) {1860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);1861      }1862    }18631864    int WriteCentralDirectoryHeader(ZipEntry entry)1865    {1866      if (entry.CompressedSize < 0) {1867        throw new ZipException("Attempt to write central directory entry with unknown csize");1868      }18691870      if (entry.Size < 0) {1871        throw new ZipException("Attempt to write central directory entry with unknown size");1872      }18731874      if (entry.Crc < 0) {1875        throw new ZipException("Attempt to write central directory entry with unknown crc");1876      }18771878      // Write the central file header1879      WriteLEInt(ZipConstants.CentralHeaderSignature);18801881      // Version made by1882      WriteLEShort(ZipConstants.VersionMadeBy);18831884      // Version required to extract1885      WriteLEShort(entry.Version);18861887      WriteLEShort(entry.Flags);  18881889      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.1890      if (update.Command != UpdateCommand.Copy) {1891        if (entry.CompressionMethod == CompressionMethod.Deflated) {1892          if (entry.Size == 0) {1893            // No need to compress - no data.1894            entry.CompressedSize = entry.Size;1895            entry.Crc = 0;1896            entry.CompressionMethod = CompressionMethod.Stored;1897          }1898        }1899        else if (entry.CompressionMethod == CompressionMethod.Stored) {1900          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;1901        }19021903        if (HaveKeys) {1904          entry.IsCrypted = true;1905          if (entry.Crc < 0) {1906            entry.Flags |= (int)GeneralBitFlags.Descriptor;1907          }1908        }1909        else {1910          entry.IsCrypted = false;1911        }1889      unchecked {1890        WriteLEShort((byte)entry.CompressionMethod);1891        WriteLEInt((int)entry.DosTime);1892        WriteLEInt((int)entry.Crc);1893      }18941895      if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {1896        WriteLEInt(-1);1897      } else {1898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));1899      }19001901      if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {1902        WriteLEInt(-1);1903      } else {1904        WriteLEInt((int)entry.Size);1905      }19061907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);19081909      if (name.Length > 0xFFFF) {1910        throw new ZipException("Entry name is too long.");1911      }  19121913        switch (useZip64_) {1914          case UseZip64.Dynamic:1915            if (entry.Size < 0) {1916              entry.ForceZip64();1917            }1918            break;19191920          case UseZip64.On:1921            entry.ForceZip64();1922            break;19231924          case UseZip64.Off:1925            // Do nothing.  The entry itself may be using Zip64 independantly.1926            break;1913      WriteLEShort(name.Length);19141915      // Central header extra data is different to local header version so regenerate.1916      var ed = new ZipExtraData(entry.ExtraData);19171918      if (entry.CentralHeaderRequiresZip64) {1919        ed.StartNewEntry();19201921        if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {1922          ed.AddLeLong(entry.Size);1923        }19241925        if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {1926          ed.AddLeLong(entry.CompressedSize);  1927        }1928      }19291930      // Write the local file header1931      WriteLEInt(ZipConstants.LocalHeaderSignature);19281929        if (entry.Offset >= 0xffffffff) {1930          ed.AddLeLong(entry.Offset);1931        }  19321933      WriteLEShort(entry.Version);1934      WriteLEShort(entry.Flags);19351936      WriteLEShort((byte)entry.CompressionMethod);1937      WriteLEInt(( int )entry.DosTime);19381939      if ( !entry.HasCrc ) {1940        // Note patch address for updating CRC later.1941        update.CrcPatchOffset = baseStream_.Position;1942        WriteLEInt(( int )0);1943      }1944      else {1945        WriteLEInt(unchecked(( int )entry.Crc));1946      }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      }19391940      byte[] centralExtraData = ed.GetEntryData();19411942      WriteLEShort(centralExtraData.Length);1943      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);19441945      WriteLEShort(0);    // disk number1946      WriteLEShort(0);    // internal file attributes  19471948      if (entry.LocalHeaderRequiresZip64) {1949        WriteLEInt(-1);1950        WriteLEInt(-1);1951      }1952      else {1953        if ( (entry.CompressedSize < 0) || (entry.Size < 0) ) {1954          update.SizePatchOffset = baseStream_.Position;1955        }19561957        WriteLEInt(( int )entry.CompressedSize);1958        WriteLEInt(( int )entry.Size);1959      }19601961      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);19621963      if ( name.Length > 0xFFFF ) {1964        throw new ZipException("Entry name too long.");1965      }19661967      var ed = new ZipExtraData(entry.ExtraData);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      }19581959      if (entry.Offset >= 0xffffffff) {1960        WriteLEUint(0xffffffff);1961      } else {1962        WriteLEUint((uint)(int)entry.Offset);1963      }19641965      if (name.Length > 0) {1966        baseStream_.Write(name, 0, name.Length);1967      }  19681969      if ( entry.LocalHeaderRequiresZip64 ) {1970        ed.StartNewEntry();19711972        // Local entry header always includes size and compressed size.1973        // NOTE the order of these fields is reversed when compared to the normal headers!1974        ed.AddLeLong(entry.Size);1975        ed.AddLeLong(entry.CompressedSize);1976        ed.AddNewEntry(1);1969      if (centralExtraData.Length > 0) {1970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);1971      }19721973      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];19741975      if (rawComment.Length > 0) {1976        baseStream_.Write(rawComment, 0, rawComment.Length);  1977      }1978      else {1979        ed.Delete(1);1980      }19811982      entry.ExtraData = ed.GetEntryData();19831984      WriteLEShort(name.Length);1985      WriteLEShort(entry.ExtraData.Length);19861987      if ( name.Length > 0 ) {1988        baseStream_.Write(name, 0, name.Length);1989      }19901991      if ( entry.LocalHeaderRequiresZip64 ) {1992        if ( !ed.Find(1) ) {1993          throw new ZipException("Internal error cannot find extra data");1994        }19951996        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1997      }19981999      if ( entry.ExtraData.Length > 0 ) {2000        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);2001      }2002    }20032004    int WriteCentralDirectoryHeader(ZipEntry entry)2005    {2006      if ( entry.CompressedSize < 0 ) {2007        throw new ZipException("Attempt to write central directory entry with unknown csize");2008      }20092010      if ( entry.Size < 0 ) {2011        throw new ZipException("Attempt to write central directory entry with unknown size");2012      }20132014      if ( entry.Crc < 0 ) {2015        throw new ZipException("Attempt to write central directory entry with unknown crc");2016      }20172018      // Write the central file header2019      WriteLEInt(ZipConstants.CentralHeaderSignature);20202021      // Version made by2022      WriteLEShort(ZipConstants.VersionMadeBy);20232024      // Version required to extract2025      WriteLEShort(entry.Version);19781979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;1980    }1981    #endregion19821983    void PostUpdateCleanup()1984    {1985      updateDataSource_ = null;1986      updates_ = null;1987      updateIndex_ = null;19881989      if (archiveStorage_ != null) {1990        archiveStorage_.Dispose();1991        archiveStorage_ = null;1992      }1993    }19941995    string GetTransformedFileName(string name)1996    {1997      INameTransform transform = NameTransform;1998      return (transform != null) ?1999        transform.TransformFile(name) :2000        name;2001    }20022003    string GetTransformedDirectoryName(string name)2004    {2005      INameTransform transform = NameTransform;2006      return (transform != null) ?2007        transform.TransformDirectory(name) :2008        name;2009    }20102011    /// <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    }20222023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2024    {2025      int bytesToCopy = GetDescriptorSize(update);  20262027      WriteLEShort(entry.Flags);20282029      unchecked {2030        WriteLEShort((byte)entry.CompressionMethod);2031        WriteLEInt((int)entry.DosTime);2032        WriteLEInt((int)entry.Crc);2033      }20342035      if ( (entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff) ) {2036        WriteLEInt(-1);2037      }2038      else {2039        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));2040      }20412042      if ( (entry.IsZip64Forced()) || (entry.Size >= 0xffffffff) ) {2043        WriteLEInt(-1);2044      }2045      else {2046        WriteLEInt((int)entry.Size);2047      }20482049      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);2027      if (bytesToCopy > 0) {2028        byte[] buffer = GetBuffer();20292030        while (bytesToCopy > 0) {2031          int readSize = Math.Min(buffer.Length, bytesToCopy);20322033          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    }20432044    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      }  20502051      if ( name.Length > 0xFFFF ) {2052        throw new ZipException("Entry name is too long.");2053      }2051      // NOTE: Compressed size is updated elsewhere.2052      var crc = new Crc32();2053      byte[] buffer = GetBuffer();  20542055      WriteLEShort(name.Length);20562057      // Central header extra data is different to local header version so regenerate.2058      var ed = new ZipExtraData(entry.ExtraData);20592060      if ( entry.CentralHeaderRequiresZip64 ) {2061        ed.StartNewEntry();20622063        if ( (entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On) )2064        {2065          ed.AddLeLong(entry.Size);2066        }20672068        if ( (entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On) )2069        {2070          ed.AddLeLong(entry.CompressedSize);2071        }20722073        if ( entry.Offset >= 0xffffffff ) {2074          ed.AddLeLong(entry.Offset);2075        }20762077        // Number of disk on which this file starts isnt supported and is never written here.2078        ed.AddNewEntry(1);2079      }2080      else {2081        // Should have already be done when local header was added.2082        ed.Delete(1);2083      }20842085      byte[] centralExtraData = ed.GetEntryData();2055      long targetBytes = bytesToCopy;2056      long totalBytesRead = 0;20572058      int bytesRead;2059      do {2060        int readSize = buffer.Length;20612062        if (bytesToCopy < readSize) {2063          readSize = (int)bytesToCopy;2064        }20652066        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));20772078      if (totalBytesRead != targetBytes) {2079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2080      }20812082      if (updateCrc) {2083        update.OutEntry.Crc = crc.Value;2084      }2085    }  20862087      WriteLEShort(centralExtraData.Length);2088      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);20892090      WriteLEShort(0);  // disk number2091      WriteLEShort(0);  // internal file attributes20922093      // External file attributes...2094      if ( entry.ExternalFileAttributes != -1 ) {2095        WriteLEInt(entry.ExternalFileAttributes);2096      }2097      else {2098        if ( entry.IsDirectory ) {2099          WriteLEUint(16);2100        }2101        else {2102          WriteLEUint(0);2103        }2104      }21052106      if ( entry.Offset >= 0xffffffff ) {2107        WriteLEUint(0xffffffff);2108      }2109      else {2110        WriteLEUint((uint)(int)entry.Offset);2111      }21122113      if ( name.Length > 0 ) {2114        baseStream_.Write(name, 0, name.Length);2115      }21162117      if ( centralExtraData.Length > 0 ) {2118        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);2119      }21202121      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];21222123      if ( rawComment.Length > 0 ) {2124        baseStream_.Write(rawComment, 0, rawComment.Length);2125      }21262127      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;2128    }2129    #endregion21302131    void PostUpdateCleanup()2132    {2133            updateDataSource_ = null;2134            updates_ = null;2135            updateIndex_ = null;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    }21032104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2105    {2106      int bytesToCopy = GetDescriptorSize(update);21072108      while (bytesToCopy > 0) {2109        var readSize = (int)bytesToCopy;2110        byte[] buffer = GetBuffer();21112112        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    }21252126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2127    {2128      long bytesToCopy = update.Entry.CompressedSize;21292130      // NOTE: Compressed size is updated elsewhere.2131      var crc = new Crc32();2132      byte[] buffer = GetBuffer();21332134      long targetBytes = bytesToCopy;2135      long totalBytesRead = 0;  21362137            if (archiveStorage_ != null)2138            {2139        archiveStorage_.Dispose();2140        archiveStorage_=null;2141      }2142    }21432144    string GetTransformedFileName(string name)2145    {2146            INameTransform transform = NameTransform;2147      return (transform != null) ?2148        transform.TransformFile(name) :2149        name;2150    }21512152    string GetTransformedDirectoryName(string name)2153    {2154            INameTransform transform = NameTransform;2155            return (transform != null) ?2156        transform.TransformDirectory(name) :2157        name;2158    }21592160    /// <summary>2161    /// Get a raw memory buffer.2162    /// </summary>2163    /// <returns>Returns a raw memory buffer.</returns>2164    byte[] GetBuffer()2165    {2166      if ( copyBuffer_ == null ) {2167        copyBuffer_ = new byte[bufferSize_];2137      int bytesRead;2138      do {2139        int readSize = buffer.Length;21402141        if (bytesToCopy < readSize) {2142          readSize = (int)bytesToCopy;2143        }21442145        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);21532154          destinationPosition += bytesRead;2155          sourcePosition += bytesRead;2156          bytesToCopy -= bytesRead;2157          totalBytesRead += bytesRead;2158        }2159      }2160      while ((bytesRead > 0) && (bytesToCopy > 0));21612162      if (totalBytesRead != targetBytes) {2163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2164      }21652166      if (updateCrc) {2167        update.OutEntry.Crc = crc.Value;  2168      }2169      return copyBuffer_;2170    }21712172    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2173    {2174      int bytesToCopy = GetDescriptorSize(update);2169    }21702171    int FindExistingUpdate(ZipEntry entry)2172    {2173      int result = -1;2174      string convertedName = GetTransformedFileName(entry.Name);  21752176      if ( bytesToCopy > 0 ) {2177        byte[] buffer = GetBuffer();21782179        while ( bytesToCopy > 0 ) {2180          int readSize = Math.Min(buffer.Length, bytesToCopy);21812182          int bytesRead = source.Read(buffer, 0, readSize);2183          if ( bytesRead > 0 ) {2184            dest.Write(buffer, 0, bytesRead);2185            bytesToCopy -= bytesRead;2186          }2187          else {2188            throw new ZipException("Unxpected end of stream");2189          }2190        }2191      }2192    }21932194    void CopyBytes(ZipUpdate update, Stream destination, Stream source,2195      long bytesToCopy, bool updateCrc)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 useful2181            // 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    }21942195    int FindExistingUpdate(string fileName)  2196    {2197      if ( destination == source ) {2198        throw new InvalidOperationException("Destination and source are the same");2199      }2197      int result = -1;21982199      string convertedName = GetTransformedFileName(fileName);  22002201      // NOTE: Compressed size is updated elsewhere.2202      var crc = new Crc32();2203      byte[] buffer = GetBuffer();2201      if (updateIndex_.ContainsKey(convertedName)) {2202        result = (int)updateIndex_[convertedName];2203      }  22042205      long targetBytes = bytesToCopy;2206      long totalBytesRead = 0;22072208      int bytesRead;2209      do {2210        int readSize = buffer.Length;22112212        if ( bytesToCopy < readSize ) {2213          readSize = (int)bytesToCopy;2214        }22152216        bytesRead = source.Read(buffer, 0, readSize);2217        if ( bytesRead > 0 ) {2218          if ( updateCrc ) {2219            crc.Update(buffer, 0, bytesRead);2220          }2221          destination.Write(buffer, 0, bytesRead);2222          bytesToCopy -= bytesRead;2223          totalBytesRead += bytesRead;2224        }2225      }2226      while ( (bytesRead > 0) && (bytesToCopy > 0) );22272228      if ( totalBytesRead != targetBytes ) {2229        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2230      }22312232      if ( updateCrc ) {2233        update.OutEntry.Crc = crc.Value;2234      }2235    }22362237    /// <summary>2238    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.2239    /// </summary>2240    /// <param name="update">The update to get the size for.</param>2241    /// <returns>The descriptor size, zero if there isnt one.</returns>2242    int GetDescriptorSize(ZipUpdate update)2243    {2244      int result = 0;2245      if ( (update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {2246        result = ZipConstants.DataDescriptorSize - 4;2247        if ( update.Entry.LocalHeaderRequiresZip64 ) {2248          result = ZipConstants.Zip64DataDescriptorSize - 4;2249        }2250      }2251      return result;2252    }2205      /*2206            // This is slow like the coming of the next ice age but takes less storage and may be useful2207            // 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       */22162217      return result;2218    }22192220    /// <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_;22282229      if (entry.IsCrypted == true) {2230        result = CreateAndInitEncryptionStream(result, entry);2231      }22322233      switch (entry.CompressionMethod) {2234        case CompressionMethod.Stored:2235          result = new UncompressedStream(result);2236          break;22372238        case CompressionMethod.Deflated:2239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));2240          dos.IsStreamOwner = false;2241          result = dos;2242          break;22432244        default:2245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2246      }2247      return result;2248    }22492250    void AddEntry(ZipFile workFile, ZipUpdate update)2251    {2252      Stream source = null;  22532254    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2255    {2256      int bytesToCopy = GetDescriptorSize(update);22572258      while ( bytesToCopy > 0 ) {2259        var readSize = (int)bytesToCopy;2260        byte[] buffer = GetBuffer();2254      if (update.Entry.IsFile) {2255        source = update.GetSource();22562257        if (source == null) {2258          source = updateDataSource_.GetSource(update.Entry, update.Filename);2259        }2260      }  22612262        stream.Position = sourcePosition;2263        int bytesRead = stream.Read(buffer, 0, readSize);2264        if ( bytesRead > 0 ) {2265          stream.Position = destinationPosition;2266          stream.Write(buffer, 0, bytesRead);2267          bytesToCopy -= bytesRead;2268          destinationPosition += bytesRead;2269          sourcePosition += bytesRead;2270        }2271        else {2272          throw new ZipException("Unxpected end of stream");2273        }2274      }2275    }22762277    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2278    {2279      long bytesToCopy = update.Entry.CompressedSize;22802281      // NOTE: Compressed size is updated elsewhere.2282      var crc = new Crc32();2283      byte[] buffer = GetBuffer();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          }22732274          workFile.WriteLocalEntryHeader(update);22752276          long dataStart = workFile.baseStream_.Position;22772278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {2279            CopyBytes(update, output, source, sourceStreamLength, true);2280          }22812282          long dataEnd = workFile.baseStream_.Position;2283          update.OutEntry.CompressedSize = dataEnd - dataStart;  22842285      long targetBytes = bytesToCopy;2286      long totalBytesRead = 0;22872288      int bytesRead;2289      do2290      {2291        int readSize = buffer.Length;22922293        if ( bytesToCopy < readSize ) {2294          readSize = (int)bytesToCopy;2295        }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      }22942295    }  22962297        stream.Position = sourcePosition;2298        bytesRead = stream.Read(buffer, 0, readSize);2299        if ( bytesRead > 0 ) {2300          if ( updateCrc ) {2301            crc.Update(buffer, 0, bytesRead);2302          }2303          stream.Position = destinationPosition;2304          stream.Write(buffer, 0, bytesRead);23052306          destinationPosition += bytesRead;2307          sourcePosition += bytesRead;2308          bytesToCopy -= bytesRead;2309          totalBytesRead += bytesRead;2310        }2311      }2312      while ( (bytesRead > 0) && (bytesToCopy > 0) );23132314      if ( totalBytesRead != targetBytes ) {2315        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2316      }23172318      if ( updateCrc ) {2319        update.OutEntry.Crc = crc.Value;2320      }2321    }23222323    int FindExistingUpdate(ZipEntry entry)2324    {2325      int result = -1;2326      string convertedName = GetTransformedFileName(entry.Name);23272328      if (updateIndex_.ContainsKey(convertedName)) {2329        result = (int)updateIndex_[convertedName];2330      }2331/*2332      // This is slow like the coming of the next ice age but takes less storage and may be useful2333      // for CF?2334      for (int index = 0; index < updates_.Count; ++index)2335      {2336        ZipUpdate zu = ( ZipUpdate )updates_[index];2337        if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&2338          (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {2339          result = index;2340          break;2341        }2342      }2343 */2344      return result;2345    }23462347    int FindExistingUpdate(string fileName)2348    {2349      int result = -1;23502351      string convertedName = GetTransformedFileName(fileName);23522353      if (updateIndex_.ContainsKey(convertedName)) {2354        result = (int)updateIndex_[convertedName];2355      }23562357/*2358      // This is slow like the coming of the next ice age but takes less storage and may be useful2359      // for CF?2360      for ( int index = 0; index < updates_.Count; ++index ) {2361        if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,2362          true, CultureInfo.InvariantCulture) == 0 ) {2363          result = index;2364          break;2365        }2366      }2367 */23682369      return result;2370    }23712372    /// <summary>2373    /// Get an output stream for the specified <see cref="ZipEntry"/>2374    /// </summary>2375    /// <param name="entry">The entry to get an output stream for.</param>2376    /// <returns>The output stream obtained for the entry.</returns>2377    Stream GetOutputStream(ZipEntry entry)2378    {2379      Stream result = baseStream_;2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)2298    {2299      workFile.WriteLocalEntryHeader(update);2300      long dataStart = workFile.baseStream_.Position;23012302      // 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      }23102311      long dataEnd = workFile.baseStream_.Position;2312      update.Entry.CompressedSize = dataEnd - dataStart;2313    }23142315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2316    {2317      bool skipOver = false || update.Entry.Offset == destinationPosition;23182319      if (!skipOver) {2320        baseStream_.Position = destinationPosition;2321        workFile.WriteLocalEntryHeader(update);2322        destinationPosition = baseStream_.Position;2323      }23242325      long sourcePosition = 0;23262327      const int NameLengthOffset = 26;23282329      // TODO: Add base for SFX friendly handling2330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;23312332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23332334      // 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();23382339      sourcePosition = baseStream_.Position + nameLength + extraLength;23402341      if (skipOver) {2342        if (update.OffsetBasedSize != -1)2343          destinationPosition += update.OffsetBasedSize;2344        else2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2346          // WinZip produces a warning on these entries:2347          // "caution: value of lrec.csize (compressed size) changed from ..."2348          destinationPosition +=2349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size2350            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    }23582359    void CopyEntry(ZipFile workFile, ZipUpdate update)2360    {2361      workFile.WriteLocalEntryHeader(update);23622363      if (update.Entry.CompressedSize > 0) {2364        const int NameLengthOffset = 26;23652366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;23672368        // TODO: This wont work for SFX files!2369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23702371        uint nameLength = ReadLEUshort();2372        uint extraLength = ReadLEUshort();23732374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);23752376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2377      }2378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);2379    }  23802381      if ( entry.IsCrypted == true ) {2382#if NETCF_1_02383        throw new ZipException("Encryption not supported for Compact Framework 1.0");2384#else2385        result = CreateAndInitEncryptionStream(result, entry);2386#endif2387      }23882389      switch ( entry.CompressionMethod ) {2390        case CompressionMethod.Stored:2391          result = new UncompressedStream(result);2392          break;23932394        case CompressionMethod.Deflated:2395          var dos = new DeflaterOutputStream(result, new Deflater(9, true));2396          dos.IsStreamOwner = false;2397          result = dos;2398          break;23992400        default:2401          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2402      }2403      return result;2404    }24052406    void AddEntry(ZipFile workFile, ZipUpdate update)2407    {2408      Stream source = null;24092410      if ( update.Entry.IsFile ) {2411        source = update.GetSource();24122413        if ( source == null ) {2414          source = updateDataSource_.GetSource(update.Entry, update.Filename);2415        }2416      }24172418      if ( source != null ) {2419        using ( source ) {2420          long sourceStreamLength = source.Length;2421          if ( update.OutEntry.Size < 0 ) {2422            update.OutEntry.Size = sourceStreamLength;2423          }2424          else {2425            // Check for errant entries.2426            if ( update.OutEntry.Size != sourceStreamLength ) {2427              throw new ZipException("Entry size/stream size mismatch");2428            }2429          }24302431          workFile.WriteLocalEntryHeader(update);24322433          long dataStart = workFile.baseStream_.Position;24342435          using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {2436            CopyBytes(update, output, source, sourceStreamLength, true);2437          }24382439          long dataEnd = workFile.baseStream_.Position;2440          update.OutEntry.CompressedSize = dataEnd - dataStart;24412442          if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor)2443          {2444            var helper = new ZipHelperStream(workFile.baseStream_);2445            helper.WriteDataDescriptor(update.OutEntry);2446          }2447        }2381    void Reopen(Stream source)2382    {2383      if (source == null) {2384        throw new ZipException("Failed to reopen archive - no source");2385      }23862387      isNewArchive_ = false;2388      baseStream_ = source;2389      ReadEntries();2390    }23912392    void Reopen()2393    {2394      if (Name == null) {2395        throw new InvalidOperationException("Name is not known cannot Reopen");2396      }23972398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));2399    }24002401    void UpdateCommentOnly()2402    {2403      long baseLength = baseStream_.Length;24042405      ZipHelperStream updateFile = null;24062407      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {2408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);2409        updateFile = new ZipHelperStream(copyStream);2410        updateFile.IsStreamOwner = true;24112412        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 doesnt2418          // 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.24212422          // 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      }24312432      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        }24392440        const int CentralHeaderCommentSizeOffset = 16;2441        updateFile.Position += CentralHeaderCommentSizeOffset;24422443        byte[] rawComment = newComment_.RawComment;24442445        updateFile.WriteLEShort(rawComment.Length);2446        updateFile.Write(rawComment, 0, rawComment.Length);2447        updateFile.SetLength(updateFile.Position);  2448      }2449      else {2450        workFile.WriteLocalEntryHeader(update);2451        update.OutEntry.CompressedSize = 0;2452      }24532454    }24552456    void ModifyEntry(ZipFile workFile, ZipUpdate update)2457    {2458      workFile.WriteLocalEntryHeader(update);2459      long dataStart = workFile.baseStream_.Position;24602461      // TODO: This is slow if the changes don't effect the data!!2462      if ( update.Entry.IsFile && (update.Filename != null) ) {2463        using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {2464          using ( Stream source = this.GetInputStream(update.Entry) ) {2465            CopyBytes(update, output, source, source.Length, true);2466          }2467        }2468      }24692470      long dataEnd = workFile.baseStream_.Position;2471      update.Entry.CompressedSize = dataEnd - dataStart;2472    }24732474    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2475    {2476      bool skipOver = false || update.Entry.Offset == destinationPosition;24492450      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {2451        Reopen(archiveStorage_.ConvertTemporaryToFinal());2452      } else {2453        ReadEntries();2454      }2455    }24562457    /// <summary>2458    /// Class used to sort updates.2459    /// </summary>2460    class UpdateComparer : IComparer2461    {2462      /// <summary>2463      /// Compares two objects and returns a value indicating whether one is2464      /// 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;24752476        int result;  24772478      if ( !skipOver ) {2479        baseStream_.Position = destinationPosition;2480        workFile.WriteLocalEntryHeader(update);2481        destinationPosition = baseStream_.Position;2482      }24832484      long sourcePosition = 0;24852486      const int NameLengthOffset = 26;24872488      // TODO: Add base for SFX friendly handling2489      long entryDataOffset = update.Entry.Offset + NameLengthOffset;24902491      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);24922493      // Clumsy way of handling retrieving the original name and extra data length for now.2494      // TODO: Stop re-reading name and data length in CopyEntryDirect.2495      uint nameLength = ReadLEUshort();2496      uint extraLength = ReadLEUshort();24972498      sourcePosition = baseStream_.Position + nameLength + extraLength;24992500      if (skipOver) {2501        if (update.OffsetBasedSize != -1)2502          destinationPosition += update.OffsetBasedSize;2503        else2504          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2505          // WinZip produces a warning on these entries:2506          // "caution: value of lrec.csize (compressed size) changed from ..."2507          destinationPosition +=2508            (sourcePosition - entryDataOffset) + NameLengthOffset +  // Header size2509            update.Entry.CompressedSize + GetDescriptorSize(update);2510      }2511      else {2512        if ( update.Entry.CompressedSize > 0 ) {2513          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition );2514        }2515        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);2516      }2517    }25182519    void CopyEntry(ZipFile workFile, ZipUpdate update)2520    {2521      workFile.WriteLocalEntryHeader(update);25222523      if ( update.Entry.CompressedSize > 0 ) {2524        const int NameLengthOffset = 26;25252526        long entryDataOffset = update.Entry.Offset + NameLengthOffset;25272528        // TODO: This wont work for SFX files!2529        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);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;24892490          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    }25052506    void RunUpdates()2507    {2508      long sizeEntries = 0;2509      long endOfStream = 0;2510      bool directUpdate = false;2511      long destinationPosition = 0; // NOT SFX friendly25122513      ZipFile workFile;25142515      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;25232524        // 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;  25302531        uint nameLength = ReadLEUshort();2532        uint extraLength = ReadLEUshort();25332534        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);2531        if (key != null) {2532          workFile.key = (byte[])key.Clone();2533        }2534      }  25352536        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2537      }2538      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);2539    }25402541    void Reopen(Stream source)2542    {2543      if ( source == null ) {2544        throw new ZipException("Failed to reopen archive - no source");2545      }25462547      isNewArchive_ = false;2548      baseStream_ = source;2549      ReadEntries();2550    }25512552    void Reopen()2553    {2554      if (Name == null) {2555        throw new InvalidOperationException("Name is not known cannot Reopen");2556      }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;25472548              case UpdateCommand.Modify:2549                // TODO: Direct modifying of an entry will take some legwork.2550                ModifyEntry(workFile, update);2551                break;25522553              case UpdateCommand.Add:2554                if (!IsNewArchive && directUpdate) {2555                  workFile.baseStream_.Position = destinationPosition;2556                }  25572558      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));2559    }25602561    void UpdateCommentOnly()2562    {2563      long baseLength = baseStream_.Length;25642565      ZipHelperStream updateFile = null;25662567      if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {2568        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);2569        updateFile = new ZipHelperStream(copyStream);2570        updateFile.IsStreamOwner = true;2558                AddEntry(workFile, update);25592560                if (directUpdate) {2561                  destinationPosition = workFile.baseStream_.Position;2562                }2563                break;2564            }2565          }2566        }25672568        if (!IsNewArchive && directUpdate) {2569          workFile.baseStream_.Position = destinationPosition;2570        }  25712572        baseStream_.Close();2573        baseStream_ = null;2574      }2575      else {2576        if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {2577          // TODO: archiveStorage wasnt originally intended for this use.2578          // Need to revisit this to tidy up handling as archive storage currently doesnt2579          // handle the original stream well.2580          // The problem is when using an existing zip archive with an in memory archive storage.2581          // The open stream wont support writing but the memory storage should open the same file not an in memory one.25822583          // Need to tidy up the archive storage interface and contract basically.2584          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);2585          updateFile = new ZipHelperStream(baseStream_);2586        }2587        else {2588          baseStream_.Close();2589          baseStream_ = null;2590          updateFile = new ZipHelperStream(Name);2591        }2592      }25932594      using ( updateFile ) {2595        long locatedCentralDirOffset =2596          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,2597                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);2598        if ( locatedCentralDirOffset < 0 ) {2599          throw new ZipException("Cannot find central directory");2600        }26012602        const int CentralHeaderCommentSizeOffset = 16;2603        updateFile.Position += CentralHeaderCommentSizeOffset;26042605        byte[] rawComment = newComment_.RawComment;26062607        updateFile.WriteLEShort(rawComment.Length);2608        updateFile.Write(rawComment, 0, rawComment.Length);2609        updateFile.SetLength(updateFile.Position);2610      }26112612      if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {2613        Reopen(archiveStorage_.ConvertTemporaryToFinal());2614      }2615      else {2616        ReadEntries();2617      }2618    }26192620    /// <summary>2621    /// Class used to sort updates.2622    /// </summary>2623    class UpdateComparer : IComparer2624    {2625      /// <summary>2626      /// Compares two objects and returns a value indicating whether one is2627      /// less than, equal to or greater than the other.2628      /// </summary>2629      /// <param name="x">First object to compare</param>2630      /// <param name="y">Second object to compare.</param>2631      /// <returns>Compare result.</returns>2632      public int Compare(2633        object x,2634        object y)2635      {2636        var zx = x as ZipUpdate;2637        var zy = y as ZipUpdate;26382639        int result;26402641        if (zx == null) {2642          if (zy == null) {2643            result = 0;2644          }2645          else {2646            result = -1;2647          }2648        }2649        else if (zy == null) {2650          result = 1;2651        }2652        else {2653          int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;2654          int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;26552656          result = xCmdValue - yCmdValue;2657          if (result == 0) {2658            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;2659            if (offsetDiff < 0) {2660              result = -1;2661            }2662            else if (offsetDiff == 0) {2663              result = 0;2664            }2665            else {2666              result = 1;2667            }2668          }2669        }2670        return result;2671      }2672    }26732674    void RunUpdates()2675    {2676      long sizeEntries = 0;2677      long endOfStream = 0;2678      bool directUpdate = false;2679      long destinationPosition = 0; // NOT SFX friendly26802681      ZipFile workFile;2572        long centralDirOffset = workFile.baseStream_.Position;25732574        foreach (ZipUpdate update in updates_) {2575          if (update != null) {2576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2577          }2578        }25792580        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        }25842585        endOfStream = workFile.baseStream_.Position;25862587        // 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            }25962597            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      }26162617      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    }26272628    void CheckUpdating()2629    {2630      if (updates_ == null) {2631        throw new InvalidOperationException("BeginUpdate has not been called");2632      }2633    }26342635    #endregion26362637    #region ZipUpdate class2638    /// <summary>2639    /// Represents a pending update to a Zip file.2640    /// </summary>2641    class ZipUpdate2642    {2643      #region Constructors2644      public ZipUpdate(string fileName, ZipEntry entry)2645      {2646        command_ = UpdateCommand.Add;2647        entry_ = entry;2648        filename_ = fileName;2649      }26502651      [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      }26592660      [Obsolete]2661      public ZipUpdate(string fileName, string entryName)2662        : this(fileName, entryName, CompressionMethod.Deflated)2663      {2664        // Do nothing.2665      }26662667      [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      }26752676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2677      {2678        command_ = UpdateCommand.Add;2679        entry_ = entry;2680        dataSource_ = dataSource;2681      }  26822683      if ( IsNewArchive ) {2684        workFile = this;2685        workFile.baseStream_.Position = 0;2686        directUpdate = true;2687      }2688      else if ( archiveStorage_.UpdateMode == FileUpdateMode.Direct ) {2689        workFile = this;2690        workFile.baseStream_.Position = 0;2691        directUpdate = true;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      }  26922693        // Sort the updates by offset within copies/modifies, then adds.2694        // This ensures that data required by copies will not be overwritten.2695        updates_.Sort(new UpdateComparer());2696      }2697      else {2698        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());2699        workFile.UseZip64 = UseZip64;27002701        if (key != null) {2702          workFile.key = (byte[])key.Clone();2703        }2704      }27052706      try {2707        foreach ( ZipUpdate update in updates_ ) {2708          if (update != null) {2709            switch (update.Command) {2710              case UpdateCommand.Copy:2711                if (directUpdate) {2712                  CopyEntryDirect(workFile, update, ref destinationPosition);2713                }2714                else {2715                  CopyEntry(workFile, update);2716                }2717                break;2693      public ZipUpdate(UpdateCommand command, ZipEntry entry)2694      {2695        command_ = command;2696        entry_ = (ZipEntry)entry.Clone();2697      }269826992700      /// <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      #endregion27102711      /// <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      }  27182719              case UpdateCommand.Modify:2720                // TODO: Direct modifying of an entry will take some legwork.2721                ModifyEntry(workFile, update);2722                break;27232724              case UpdateCommand.Add:2725                if (!IsNewArchive && directUpdate) {2726                  workFile.baseStream_.Position = destinationPosition;2727                }27282729                AddEntry(workFile, update);27302731                if (directUpdate) {2732                  destinationPosition = workFile.baseStream_.Position;2733                }2734                break;2735            }2736          }2737        }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          }27272728          return outEntry_;2729        }2730      }27312732      /// <summary>2733      /// Get the command for this update.2734      /// </summary>2735      public UpdateCommand Command {2736        get { return command_; }2737      }  27382739        if ( !IsNewArchive && directUpdate ) {2740          workFile.baseStream_.Position = destinationPosition;2741        }27422743        long centralDirOffset = workFile.baseStream_.Position;27442745        foreach ( ZipUpdate update in updates_ ) {2746          if (update != null) {2747            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2748          }2749        }27502751        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);2752        using ( ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_) ) {2753          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);2754        }27552756        endOfStream = workFile.baseStream_.Position;27572758        // And now patch entries...2759        foreach ( ZipUpdate update in updates_ ) {2760          if (update != null)2761          {2762            // If the size of the entry is zero leave the crc as 0 as well.2763            // The calculated crc will be all bits on...2764            if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {2765              workFile.baseStream_.Position = update.CrcPatchOffset;2766              workFile.WriteLEInt((int)update.OutEntry.Crc);2767            }27682769            if (update.SizePatchOffset > 0) {2770              workFile.baseStream_.Position = update.SizePatchOffset;2771              if (update.OutEntry.LocalHeaderRequiresZip64) {2772                workFile.WriteLeLong(update.OutEntry.Size);2773                workFile.WriteLeLong(update.OutEntry.CompressedSize);2774              }2775              else {2776                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);2777                workFile.WriteLEInt((int)update.OutEntry.Size);2778              }2779            }2780          }2781        }2782      }2783      catch {2784        workFile.Close();2785        if (!directUpdate && (workFile.Name != null)) {2786          File.Delete(workFile.Name);2787        }2788        throw;2789      }27902791      if (directUpdate) {2792        workFile.baseStream_.SetLength(endOfStream);2793        workFile.baseStream_.Flush();2794        isNewArchive_ = false;2795        ReadEntries();2796      }2797      else {2798        baseStream_.Close();2799        Reopen(archiveStorage_.ConvertTemporaryToFinal());2800      }2801    }28022803    void CheckUpdating()2804    {2805      if ( updates_ == null ) {2806        throw new InvalidOperationException("BeginUpdate has not been called");2807      }2808    }28092810    #endregion28112812    #region ZipUpdate class2813    /// <summary>2814    /// Represents a pending update to a Zip file.2815    /// </summary>2816    class ZipUpdate2817    {2818      #region Constructors2819      public ZipUpdate(string fileName, ZipEntry entry)2820      {2821        command_ = UpdateCommand.Add;2822        entry_ = entry;2823        filename_ = fileName;2824      }28252826      [Obsolete]2827      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)2828      {2829        command_ = UpdateCommand.Add;2830        entry_ = new ZipEntry(entryName);2831        entry_.CompressionMethod = compressionMethod;2832        filename_ = fileName;2833      }28342835      [Obsolete]2836      public ZipUpdate(string fileName, string entryName)2837        : this(fileName, entryName, CompressionMethod.Deflated)2838      {2839        // Do nothing.2840      }28412842      [Obsolete]2843      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)2844      {2845        command_ = UpdateCommand.Add;2846        entry_ = new ZipEntry(entryName);2847        entry_.CompressionMethod = compressionMethod;2848        dataSource_ = dataSource;2849      }28502851      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2852      {2853        command_ = UpdateCommand.Add;2854        entry_ = entry;2855        dataSource_ = dataSource;2856      }28572858      public ZipUpdate(ZipEntry original, ZipEntry updated)2859      {2860        throw new ZipException("Modify not currently supported");2861      /*2862        command_ = UpdateCommand.Modify;2863        entry_ = ( ZipEntry )original.Clone();2864        outEntry_ = ( ZipEntry )updated.Clone();2865      */2866      }28672868      public ZipUpdate(UpdateCommand command, ZipEntry entry)2869      {2870        command_ = command;2871        entry_ = ( ZipEntry )entry.Clone();2872      }28732739      /// <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      }27452746      /// <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      }27532754      /// <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      }27612762      /// <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      }27702771      public Stream GetSource()2772      {2773        Stream result = null;2774        if (dataSource_ != null) {2775          result = dataSource_.GetSource();2776        }27772778        return result;2779      }27802781      #region Instance Fields2782      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      #endregion2791    }27922793    #endregion2794    #endregion27952796    #region Disposing27972798    #region IDisposable Members2799    void IDisposable.Dispose()2800    {2801      Close();2802    }2803    #endregion28042805    void DisposeInternal(bool disposing)2806    {2807      if (!isDisposed_) {2808        isDisposed_ = true;2809        entries_ = new ZipEntry[0];28102811        if (IsStreamOwner && (baseStream_ != null)) {2812          lock (baseStream_) {2813            baseStream_.Close();2814          }2815        }28162817        PostUpdateCleanup();2818      }2819    }28202821    /// <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    }28302831    #endregion28322833    #region Internal routines2834    #region Reading2835    /// <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 prematurely2841    /// </exception>2842    ushort ReadLEUshort()2843    {2844      int data1 = baseStream_.ReadByte();28452846      if (data1 < 0) {2847        throw new EndOfStreamException("End of stream");2848      }28492850      int data2 = baseStream_.ReadByte();28512852      if (data2 < 0) {2853        throw new EndOfStreamException("End of stream");2854      }285528562857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));2858    }28592860    /// <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 prematurely2869    /// </exception>2870    uint ReadLEUint()2871    {2872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));2873    }  28742875      /// <summary>2876      /// Copy an existing entry.2877      /// </summary>2878      /// <param name="entry">The existing entry to copy.</param>2879      public ZipUpdate(ZipEntry entry)2880        : this(UpdateCommand.Copy, entry)2881      {2882        // Do nothing.2883      }2884      #endregion28852886      /// <summary>2887      /// Get the <see cref="ZipEntry"/> for this update.2888      /// </summary>2889      /// <remarks>This is the source or original entry.</remarks>2890      public ZipEntry Entry2891      {2892        get { return entry_; }2893      }28942895      /// <summary>2896      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.2897      /// </summary>2898      public ZipEntry OutEntry2899      {2900        get {2901          if ( outEntry_ == null ) {2902            outEntry_ = (ZipEntry)entry_.Clone();2903          }29042905          return outEntry_;2906        }2907      }2875    ulong ReadLEUlong()2876    {2877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);2878    }28792880    #endregion2881    // 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    }28882889    /// <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 found2897    /// </exception>2898    void ReadEntries()2899    {2900      // Search for the End Of Central Directory.  When a zip comment is2901      // present the directory will start earlier2902      //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 files2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then2906      // this could be invalid.2907      // Could also speed this up by reading memory in larger blocks.  29082909      /// <summary>2910      /// Get the command for this update.2911      /// </summary>2912      public UpdateCommand Command2913      {2914        get { return command_; }2915      }29162917      /// <summary>2918      /// Get the filename if any for this update.  Null if none exists.2919      /// </summary>2920      public string Filename2921      {2922        get { return filename_; }2923      }29242925      /// <summary>2926      /// Get/set the location of the size patch for this update.2927      /// </summary>2928      public long SizePatchOffset2929      {2930        get { return sizePatchOffset_; }2931        set { sizePatchOffset_ = value; }2932      }29332934      /// <summary>2935      /// Get /set the location of the crc patch for this update.2936      /// </summary>2937      public long CrcPatchOffset2938      {2939        get { return crcPatchOffset_; }2940        set { crcPatchOffset_ = value; }2941      }29422943      /// <summary>2944      /// Get/set the size calculated by offset.2945      /// Specifically, the difference between this and next entry's starting offset.2946      /// </summary>2947      public long OffsetBasedSize2948      {2949        get { return _offsetBasedSize; }2950        set { _offsetBasedSize = value; }2951      }29522953      public Stream GetSource()2954      {2955        Stream result = null;2956        if ( dataSource_ != null ) {2957          result = dataSource_.GetSource();2958        }29592960        return result;2961      }29622963      #region Instance Fields2964      ZipEntry entry_;2965      ZipEntry outEntry_;2966      UpdateCommand command_;2967      IStaticDataSource dataSource_;2968      string filename_;2969      long sizePatchOffset_ = -1;2970      long crcPatchOffset_ = -1;2971      long _offsetBasedSize = -1;2972      #endregion2973    }29742975    #endregion2976    #endregion29772978    #region Disposing29792980    #region IDisposable Members2981    void IDisposable.Dispose()2982    {2983      Close();2984    }2985    #endregion29862987    void DisposeInternal(bool disposing)2988    {2989      if ( !isDisposed_ ) {2990        isDisposed_ = true;2991        entries_ = new ZipEntry[0];29922993        if ( IsStreamOwner && (baseStream_ != null) ) {2994          lock(baseStream_) {2995            baseStream_.Close();2996          }2997        }2909      if (baseStream_.CanSeek == false) {2910        throw new ZipException("ZipFile stream must be seekable");2911      }29122913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,2914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);29152916      if (locatedEndOfCentralDir < 0) {2917        throw new ZipException("Cannot find central directory");2918      }29192920      // Read end of central directory record2921      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();29282929      if (commentSize > 0) {2930        byte[] comment = new byte[commentSize];29312932        StreamUtils.ReadFully(baseStream_, comment);2933        comment_ = ZipConstants.ConvertToString(comment);2934      } else {2935        comment_ = string.Empty;2936      }29372938      bool isZip64 = false;29392940      // 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;29482949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 2950        if (offset < 0) {2951          throw new ZipException("Cannot find Zip64 locator");2952        }29532954        // number of the disk with the start of the zip64 end of central directory 4 bytes2955        // relative offset of the zip64 end of central directory record 8 bytes2956        // total number of disks 4 bytes2957        ReadLEUint(); // startDisk64 is not currently used2958        ulong offset64 = ReadLEUlong();2959        uint totalDisks = ReadLEUint();29602961        baseStream_.Position = (long)offset64;2962        long sig64 = ReadLEUint();29632964        if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {2965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));2966        }29672968        // 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();29782979        // NOTE: zip64 extensible data sector (variable size) is ignored.2980      }29812982      entries_ = new ZipEntry[entriesForThisDisk];29832984      // SFX/embedded support, find the offset of the first entry vis the start of the stream2985      // 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 offsets2988      // 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      }29962997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);  29982999        PostUpdateCleanup();3000      }3001    }30023003    /// <summary>3004    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.3005    /// </summary>3006    /// <param name="disposing">true to release both managed and unmanaged resources;3007    /// false to release only unmanaged resources.</param>3008    protected virtual void Dispose(bool disposing)3009    {3010      DisposeInternal(disposing);3011    }30123013    #endregion30143015    #region Internal routines3016    #region Reading3017    /// <summary>3018    /// Read an unsigned short in little endian byte order.3019    /// </summary>3020    /// <returns>Returns the value read.</returns>3021    /// <exception cref="EndOfStreamException">3022    /// The stream ends prematurely3023    /// </exception>3024    ushort ReadLEUshort()3025    {3026      int data1 = baseStream_.ReadByte();30273028      if ( data1 < 0 ) {3029        throw new EndOfStreamException("End of stream");3030      }30313032      int data2 = baseStream_.ReadByte();30333034      if ( data2 < 0 ) {3035        throw new EndOfStreamException("End of stream");3036      }303730383039      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));3040    }30413042    /// <summary>3043    /// Read a uint in little endian byte order.3044    /// </summary>3045    /// <returns>Returns the value read.</returns>3046    /// <exception cref="IOException">3047    /// An i/o error occurs.3048    /// </exception>3049    /// <exception cref="System.IO.EndOfStreamException">3050    /// The file ends prematurely3051    /// </exception>3052    uint ReadLEUint()3053    {3054      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));3055    }30563057    ulong ReadLEUlong()3058    {3059      return ReadLEUint() | ((ulong)ReadLEUint() << 32);3060    }30613062    #endregion3063    // NOTE this returns the offset of the first byte after the signature.3064    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)3065    {3066      using ( ZipHelperStream les = new ZipHelperStream(baseStream_) ) {3067        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);3068      }3069    }30703071    /// <summary>3072    /// Search for and read the central directory of a zip file filling the entries array.3073    /// </summary>3074    /// <exception cref="System.IO.IOException">3075    /// An i/o error occurs.3076    /// </exception>3077    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3078    /// The central directory is malformed or cannot be found3079    /// </exception>3080    void ReadEntries()3081    {3082      // Search for the End Of Central Directory.  When a zip comment is3083      // present the directory will start earlier3084      //3085      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.3086      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files3087      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then3088      // this could be invalid.3089      // Could also speed this up by reading memory in larger blocks.2999      for (ulong i = 0; i < entriesForThisDisk; i++) {3000        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {3001          throw new ZipException("Wrong Central Directory signature");3002        }30033004        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();30153016        int diskStartNo = ReadLEUshort();  // Not currently used3017        int internalAttributes = ReadLEUshort();  // Not currently used30183019        uint externalAttributes = ReadLEUint();3020        long offset = ReadLEUint();30213022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];30233024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);3025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);30263027        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;30363037        if ((bitFlags & 8) == 0) {3038          entry.CryptoCheckValue = (byte)(crc >> 24);3039        } else {3040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3041        }30423043        if (extraLen > 0) {3044          byte[] extra = new byte[extraLen];3045          StreamUtils.ReadFully(baseStream_, extra);3046          entry.ExtraData = extra;3047        }30483049        entry.ProcessExtraData(false);30503051        if (commentLen > 0) {3052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);3053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3054        }30553056        entries_[i] = entry;3057      }3058    }30593060    /// <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 prematurely3068    /// </exception>3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3070    /// The local header signature is invalid, the entry and central header file name lengths are different3071    /// or the local and entry compression methods dont match3072    /// </exception>3073    long LocateEntry(ZipEntry entry)3074    {3075      return TestLocalHeader(entry, HeaderTest.Extract);3076    }30773078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3079    {3080      CryptoStream result = null;30813082      if ((entry.Version < ZipConstants.VersionStrongEncryption)3083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3084        var classicManaged = new PkzipClassicManaged();30853086        OnKeysRequired(entry.Name);3087        if (HaveKeys == false) {3088          throw new ZipException("No password available for encrypted stream");3089        }  30903091      if (baseStream_.CanSeek == false) {3092        throw new ZipException("ZipFile stream must be seekable");3093      }30943095      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,3096        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);30973098      if (locatedEndOfCentralDir < 0) {3099        throw new ZipException("Cannot find central directory");3100      }31013102      // Read end of central directory record3103      ushort thisDiskNumber           = ReadLEUshort();3104      ushort startCentralDirDisk      = ReadLEUshort();3105      ulong entriesForThisDisk        = ReadLEUshort();3106      ulong entriesForWholeCentralDir = ReadLEUshort();3107      ulong centralDirSize            = ReadLEUint();3108      long offsetOfCentralDir         = ReadLEUint();3109      uint commentSize                = ReadLEUshort();31103111      if ( commentSize > 0 ) {3112        byte[] comment = new byte[commentSize];31133114        StreamUtils.ReadFully(baseStream_, comment);3115        comment_ = ZipConstants.ConvertToString(comment);3116      }3117      else {3118        comment_ = string.Empty;3119      }31203121      bool isZip64 = false;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 bytes31093110          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      }31193120      return result;3121    }  31223123      // Check if zip64 header information is required.3124      if ( (thisDiskNumber == 0xffff) ||3125        (startCentralDirDisk == 0xffff) ||3126        (entriesForThisDisk == 0xffff) ||3127        (entriesForWholeCentralDir == 0xffff) ||3128        (centralDirSize == 0xffffffff) ||3129        (offsetOfCentralDir == 0xffffffff) ) {3130        isZip64 = true;31313132        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 3133        if ( offset < 0 ) {3134          throw new ZipException("Cannot find Zip64 locator");3135        }31363137        // number of the disk with the start of the zip64 end of central directory 4 bytes3138        // relative offset of the zip64 end of central directory record 8 bytes3139        // total number of disks 4 bytes3140        ReadLEUint(); // startDisk64 is not currently used3141        ulong offset64 = ReadLEUlong();3142        uint totalDisks = ReadLEUint();31433144        baseStream_.Position = (long)offset64;3145        long sig64 = ReadLEUint();31463147        if ( sig64 != ZipConstants.Zip64CentralFileHeaderSignature ) {3148          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));3149        }31503151        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.3152        ulong recordSize = ReadLEUlong();3153        int versionMadeBy = ReadLEUshort();3154        int versionToExtract = ReadLEUshort();3155        uint thisDisk = ReadLEUint();3156        uint centralDirDisk = ReadLEUint();3157        entriesForThisDisk = ReadLEUlong();3158        entriesForWholeCentralDir = ReadLEUlong();3159        centralDirSize = ReadLEUlong();3160        offsetOfCentralDir = (long)ReadLEUlong();31613162        // NOTE: zip64 extensible data sector (variable size) is ignored.3163      }31643165      entries_ = new ZipEntry[entriesForThisDisk];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();31293130        OnKeysRequired(entry.Name);3131        if (HaveKeys == false) {3132          throw new ZipException("No password available for encrypted stream");3133        }31343135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3136        // which doesnt do this.3137        result = new CryptoStream(new UncompressedStream(baseStream),3138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);31393140        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    }31483149    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    }31573158    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    }  31663167      // SFX/embedded support, find the offset of the first entry vis the start of the stream3168      // This applies to Zip files that are appended to the end of an SFX stub.3169      // Or are appended as a resource to an executable.3170      // Zip files created by some archivers have the offsets altered to reflect the true offsets3171      // and so dont require any adjustment here...3172      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?3173      if ( !isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize)) ) {3174        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);3175        if (offsetOfFirstEntry <= 0) {3176          throw new ZipException("Invalid embedded zip archive");3177        }3178      }31793180      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);31813182      for (ulong i = 0; i < entriesForThisDisk; i++) {3183        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {3184          throw new ZipException("Wrong Central Directory signature");3185        }3167    #endregion31683169    #region Instance Fields3170    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_;31803181    // Default is dynamic which is not backwards compatible and can cause problems3182    // 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;  31863187        int versionMadeBy      = ReadLEUshort();3188        int versionToExtract   = ReadLEUshort();3189        int bitFlags           = ReadLEUshort();3190        int method             = ReadLEUshort();3191        uint dostime           = ReadLEUint();3192        uint crc               = ReadLEUint();3193        var csize             = (long)ReadLEUint();3194        var size              = (long)ReadLEUint();3195        int nameLen            = ReadLEUshort();3196        int extraLen           = ReadLEUshort();3197        int commentLen         = ReadLEUshort();31983199        int diskStartNo        = ReadLEUshort();  // Not currently used3200        int internalAttributes = ReadLEUshort();  // Not currently used3187    #region Zip Update Instance Fields3188    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    #endregion3200    #endregion  32013202        uint externalAttributes = ReadLEUint();3203        long offset             = ReadLEUint();32043205        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];32063207        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);3208        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);32093210        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);3211        entry.Crc = crc & 0xffffffffL;3212        entry.Size = size & 0xffffffffL;3213        entry.CompressedSize = csize & 0xffffffffL;3214        entry.Flags = bitFlags;3215        entry.DosTime = (uint)dostime;3216        entry.ZipFileIndex = (long)i;3217        entry.Offset = offset;3218        entry.ExternalFileAttributes = (int)externalAttributes;32193220        if ((bitFlags & 8) == 0) {3221          entry.CryptoCheckValue = (byte)(crc >> 24);3222        }3223        else {3224          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3225        }32263227        if (extraLen > 0) {3228          byte[] extra = new byte[extraLen];3229          StreamUtils.ReadFully(baseStream_, extra);3230          entry.ExtraData = extra;3231        }32323233        entry.ProcessExtraData(false);32343235        if (commentLen > 0) {3236          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);3237          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3238        }32393240        entries_[i] = entry;3241      }3242    }32433244    /// <summary>3245    /// Locate the data for a given entry.3246    /// </summary>3247    /// <returns>3248    /// The start offset of the data.3249    /// </returns>3250    /// <exception cref="System.IO.EndOfStreamException">3251    /// The stream ends prematurely3252    /// </exception>3253    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3254    /// The local header signature is invalid, the entry and central header file name lengths are different3255    /// or the local and entry compression methods dont match3256    /// </exception>3257    long LocateEntry(ZipEntry entry)3258    {3259      return TestLocalHeader(entry, HeaderTest.Extract);3260    }32613262#if !NETCF_1_03263    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3264    {3265      CryptoStream result = null;32663267      if ( (entry.Version < ZipConstants.VersionStrongEncryption)3268        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3269        var classicManaged = new PkzipClassicManaged();32703271        OnKeysRequired(entry.Name);3272        if (HaveKeys == false) {3273          throw new ZipException("No password available for encrypted stream");3274        }3202    #region Support Classes3203    /// <summary>3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3205    /// </summary>3206    class ZipString3207    {3208      #region Constructors3209      /// <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      }32183219      /// <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      #endregion32283229      /// <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      }32363237      /// <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      }32463247      /// <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      }32563257      /// <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      }32683269      void MakeTextAvailable()3270      {3271        if (comment_ == null) {3272          comment_ = ZipConstants.ConvertToString(rawComment_);3273        }3274      }  32753276        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);3277        CheckClassicPassword(result, entry);3278      }3279      else {3280#if !NET_1_1 && !NETCF_2_03281        if (entry.Version == ZipConstants.VERSION_AES) {3282          //3283          OnKeysRequired(entry.Name);3284          if (HaveKeys == false) {3285            throw new ZipException("No password available for AES encrypted stream");3286          }3287          int saltLen = entry.AESSaltLen;3288          byte[] saltBytes = new byte[saltLen];3289          int saltIn = baseStream.Read(saltBytes, 0, saltLen);3290          if (saltIn != saltLen)3291            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);3292          //3293          byte[] pwdVerifyRead = new byte[2];3294          baseStream.Read(pwdVerifyRead, 0, 2);3295          int blockSize = entry.AESKeySize / 8;  // bits to bytes32963297          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);3298          byte[] pwdVerifyCalc = decryptor.PwdVerifier;3299          if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])3300            throw new Exception("Invalid password for AES");3301          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);3302        }3303        else3304#endif3305        {3306          throw new ZipException("Decryption method not supported");3307        }3308      }33093310      return result;3311    }33123313    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)3314    {3315      CryptoStream result = null;3316      if ( (entry.Version < ZipConstants.VersionStrongEncryption)3317        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3318        var classicManaged = new PkzipClassicManaged();3276      void MakeBytesAvailable()3277      {3278        if (rawComment_ == null) {3279          rawComment_ = ZipConstants.ConvertToArray(comment_);3280        }3281      }32823283      /// <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      }32933294      #region Instance Fields3295      string comment_;3296      byte[] rawComment_;3297      bool isSourceString_;3298      #endregion3299    }33003301    /// <summary>3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3303    /// </summary>3304    class ZipEntryEnumerator : IEnumerator3305    {3306      #region Constructors3307      public ZipEntryEnumerator(ZipEntry[] entries)3308      {3309        array = entries;3310      }33113312      #endregion3313      #region IEnumerator Members3314      public object Current {3315        get {3316          return array[index];3317        }3318      }  33193320        OnKeysRequired(entry.Name);3321        if (HaveKeys == false) {3322          throw new ZipException("No password available for encrypted stream");3323        }3320      public void Reset()3321      {3322        index = -1;3323      }  33243325        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3326        // which doesnt do this.3327        result = new CryptoStream(new UncompressedStream(baseStream),3328          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);33293330        if ( (entry.Crc < 0) || (entry.Flags & 8) != 0) {3331          WriteEncryptionHeader(result, entry.DosTime << 16);3332        }3333        else {3334          WriteEncryptionHeader(result, entry.Crc);3335        }3336      }3337      return result;3338    }33393340    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)3325      public bool MoveNext()3326      {3327        return (++index < array.Length);3328      }3329      #endregion3330      #region Instance Fields3331      ZipEntry[] array;3332      int index = -1;3333      #endregion3334    }33353336    /// <summary>3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3338    /// to and flush, but cannot read, seek or do anything else to.3339    /// </summary>3340    class UncompressedStream : Stream  3341    {3342      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];3343      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);3344      if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {3345        throw new ZipException("Invalid password");3342      #region Constructors3343      public UncompressedStream(Stream baseStream)3344      {3345        baseStream_ = baseStream;  3346      }3347    }3348#endif33473348      #endregion  33493350    static void WriteEncryptionHeader(Stream stream, long crcValue)3351    {3352      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];3353      var rnd = new Random();3354      rnd.NextBytes(cryptBuffer);3355      cryptBuffer[11] = (byte)(crcValue >> 24);3356      stream.Write(cryptBuffer, 0, cryptBuffer.Length);3357    }33583359    #endregion33603361    #region Instance Fields3362    bool       isDisposed_;3363    string     name_;3364    string     comment_;3365    string     rawPassword_;3366    Stream     baseStream_;3367    bool       isStreamOwner;3368    long       offsetOfFirstEntry;3369    ZipEntry[] entries_;3370    byte[] key;3371    bool isNewArchive_;33723373    // Default is dynamic which is not backwards compatible and can cause problems3374    // with XP's built in compression which cant read Zip64 archives.3375    // However it does avoid the situation were a large file is added and cannot be completed correctly.3376    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.3377    UseZip64 useZip64_ = UseZip64.Dynamic ;33783379    #region Zip Update Instance Fields3380    ArrayList updates_;3381    long updateCount_; // Count is managed manually as updates_ can contain nulls!3382    Hashtable updateIndex_;3383    IArchiveStorage archiveStorage_;3384    IDynamicDataSource updateDataSource_;3385    bool contentsEdited_;3386    int bufferSize_ = DefaultBufferSize;3387    byte[] copyBuffer_;3388    ZipString newComment_;3389    bool commentEdited_;3390    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();3391    #endregion3392    #endregion33933394    #region Support Classes3395    /// <summary>3396    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3397    /// </summary>3398    class ZipString3399    {3400      #region Constructors3401      /// <summary>3402      /// Initialise a <see cref="ZipString"/> with a string.3403      /// </summary>3404      /// <param name="comment">The textual string form.</param>3405      public ZipString(string comment)3406      {3407        comment_ = comment;3408        isSourceString_ = true;3409      }34103411      /// <summary>3412      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.3413      /// </summary>3414      /// <param name="rawString"></param>3415      public ZipString(byte[] rawString)3416      {3417        rawComment_ = rawString;3418      }3419      #endregion34203421      /// <summary>3422      /// Get a value indicating the original source of data for this instance.3423      /// True if the source was a string; false if the source was binary data.3424      /// </summary>3425      public bool IsSourceString3426      {3427        get { return isSourceString_; }3428      }34293430      /// <summary>3431      /// Get the length of the comment when represented as raw bytes.3432      /// </summary>3433      public int RawLength3434      {3435        get {3436          MakeBytesAvailable();3437          return rawComment_.Length;3438        }3439      }34403441      /// <summary>3442      /// Get the comment in its 'raw' form as plain bytes.3443      /// </summary>3444      public byte[] RawComment3445      {3446        get {3447          MakeBytesAvailable();3448          return (byte[])rawComment_.Clone();3449        }3450      }34513452      /// <summary>3453      /// Reset the comment to its initial state.3454      /// </summary>3455      public void Reset()3456      {3457        if ( isSourceString_ ) {3458          rawComment_ = null;3459        }3460        else {3461          comment_ = null;3462        }3463      }34643465      void MakeTextAvailable()3466      {3467        if ( comment_ == null ) {3468          comment_ = ZipConstants.ConvertToString(rawComment_);3469        }3470      }34713472      void MakeBytesAvailable()3473      {3474        if ( rawComment_ == null ) {3475          rawComment_ = ZipConstants.ConvertToArray(comment_);3476        }3477      }34783479      /// <summary>3480      /// Implicit conversion of comment to a string.3481      /// </summary>3482      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>3483      /// <returns>The textual equivalent for the input value.</returns>3484      static public implicit operator string(ZipString zipString)3485      {3486        zipString.MakeTextAvailable();3487        return zipString.comment_;3488      }34893490      #region Instance Fields3491      string comment_;3492      byte[] rawComment_;3493      bool isSourceString_;3494      #endregion3495    }34963497    /// <summary>3498    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3499    /// </summary>3500    class ZipEntryEnumerator : IEnumerator3501    {3502      #region Constructors3503      public ZipEntryEnumerator(ZipEntry[] entries)3504      {3505        array = entries;3506      }35073508      #endregion3509      #region IEnumerator Members3510      public object Current3511      {3512        get {3513          return array[index];3514        }3515      }35163517      public void Reset()3518      {3519        index = -1;3520      }35213522      public bool MoveNext()3523      {3524        return (++index < array.Length);3525      }3526      #endregion3527      #region Instance Fields3528      ZipEntry[] array;3529      int index = -1;3530      #endregion3531    }35323533    /// <summary>3534    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3535    /// to and flush, but cannot read, seek or do anything else to.3536    /// </summary>3537    class UncompressedStream : Stream3538    {3539      #region Constructors3540      public UncompressedStream(Stream baseStream)3541      {3542        baseStream_ = baseStream;3543      }35443545      #endregion35463547      /// <summary>3548      /// Close this stream instance.3549      /// </summary>3550      public override void Close()3551      {3552        // Do nothing3553      }35543555      /// <summary>3556      /// Gets a value indicating whether the current stream supports reading.3557      /// </summary>3558      public override bool CanRead3559      {3560        get {3561          return false;3562        }3563      }35643565      /// <summary>3566      /// Write any buffered data to underlying storage.3567      /// </summary>3568      public override void Flush()3569      {3570        baseStream_.Flush();3571      }35723573      /// <summary>3574      /// Gets a value indicating whether the current stream supports writing.3575      /// </summary>3576      public override bool CanWrite3577      {3578        get {3579          return baseStream_.CanWrite;3580        }3581      }35823583      /// <summary>3584      /// Gets a value indicating whether the current stream supports seeking.3585      /// </summary>3586      public override bool CanSeek3587      {3588        get {3589          return false;3590        }3591      }35923593      /// <summary>3594      /// Get the length in bytes of the stream.3595      /// </summary>3596      public override long Length3597      {3598        get {3599          return 0;3600        }3601      }36023603      /// <summary>3604      /// Gets or sets the position within the current stream.3605      /// </summary>3606      public override long Position3607      {3608        get  {3609          return baseStream_.Position;3610        }3611                set {3612                    throw new NotImplementedException();3613                }3614            }36153616            /// <summary>3617            /// Reads a sequence of bytes from the current stream and advances the position within the stream by the num3618            /// </summary>3619            /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte3620            /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from t3621            /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3622            /// <returns>3623            /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if t3624            /// </returns>3625            /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer lengt3626            /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </ex3627            /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3628            /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3629            /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3630            /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3631            public override int Read(byte[] buffer, int offset, int count)3632      {3633        return 0;3634      }36353636      /// <summary>3637      /// Sets the position within the current stream.3638      /// </summary>3639      /// <param name="offset">A byte offset relative to the origin parameter.</param>3640      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3641      /// <returns>3642      /// The new position within the current stream.3643      /// </returns>3644      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3645      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3646      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3647      public override long Seek(long offset, SeekOrigin origin)3648      {3649        return 0;3650      }36513652      /// <summary>3653      /// Sets the length of the current stream.3654      /// </summary>3655      /// <param name="value">The desired length of the current stream in bytes.</param>3656      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3350      /// <summary>3351      /// Close this stream instance.3352      /// </summary>3353      public override void Close()3354      {3355        // Do nothing3356      }33573358      /// <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      }33663367      /// <summary>3368      /// Write any buffered data to underlying storage.3369      /// </summary>3370      public override void Flush()3371      {3372        baseStream_.Flush();3373      }33743375      /// <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      }33833384      /// <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      }33923393      /// <summary>3394      /// Get the length in bytes of the stream.3395      /// </summary>3396      public override long Length {3397        get {3398          return 0;3399        }3400      }34013402      /// <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      }34133414      /// <summary>3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3416      /// </summary>3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3419      /// <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 ma3422      /// </returns>3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3425      /// <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      }34333434      /// <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 is3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3445      public override long Seek(long offset, SeekOrigin origin)3446      {3447        return 0;3448      }34493450      /// <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 as3455      /// <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. </exceptio3457      public override void SetLength(long value)3458      {3459      }34603461      /// <summary>3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3463      /// </summary>3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3466      /// <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. </exceptio3470      /// <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      }34773478      readonly34793480      #region Instance Fields3481      Stream baseStream_;3482      #endregion3483    }34843485    /// <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 : Stream3490    {3491      #region Constructors3492      /// <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;35023503        // Although this is the only time the zipfile is used3504        // keeping a reference here prevents premature closure of3505        // this zip file and thus the baseStream_.35063507        // Code like this will cause apparently random failures depending3508        // 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      #endregion35193520      /// <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        }35303531        lock (baseStream_) {3532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);3533          return baseStream_.ReadByte();3534        }3535      }35363537      /// <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      }35473548      /// <summary>3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3550      /// </summary>3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3553      /// <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 ma3556      /// </returns>3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3559      /// <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 Seek3573          // (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      }35843585      /// <summary>3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3587      /// </summary>3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3590      /// <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. </exceptio3594      /// <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      }36013602      /// <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 as3607      /// <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. </exceptio3609      public override void SetLength(long value)3610      {3611        throw new NotSupportedException();3612      }36133614      /// <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 is3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3625      public override long Seek(long offset, SeekOrigin origin)3626      {3627        long newPos = readPos_;36283629        switch (origin) {3630          case SeekOrigin.Begin:3631            newPos = start_ + offset;3632            break;36333634          case SeekOrigin.Current:3635            newPos = readPos_ + offset;3636            break;36373638          case SeekOrigin.End:3639            newPos = end_ + offset;3640            break;3641        }36423643        if (newPos < start_) {3644          throw new ArgumentException("Negative position is invalid");3645        }36463647        if (newPos >= end_) {3648          throw new IOException("Cannot seek past end");3649        }3650        readPos_ = newPos;3651        return readPos_;3652      }36533654      /// <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      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3659      public override void SetLength(long value)3660      {3658      public override void Flush()3659      {3660        // Nothing to do.  3661      }  3662  3663      /// <summary>3664      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3664      /// Gets or sets the position within the current stream.  3665      /// </summary>3666      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3667      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3668      /// <param name="count">The number of bytes to be written to the current stream.</param>3669      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3670      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3671      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3672      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3673      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3674      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3675      public override void Write(byte[] buffer, int offset, int count)3676      {3677        baseStream_.Write(buffer, offset, count);3678      }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. </exceptio3671      public override long Position {3672        get { return readPos_ - start_; }3673        set {3674          long newPos = start_ + value;36753676          if (newPos < start_) {3677            throw new ArgumentException("Negative position is invalid");3678          }  36793680      readonly36813682      #region Instance Fields3683      Stream baseStream_;3684      #endregion3685    }3680          if (newPos >= end_) {3681            throw new InvalidOperationException("Cannot seek past end");3682          }3683          readPos_ = newPos;3684        }3685      }  36863687    /// <summary>3688    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>3689    /// whose data is only a part or subsection of a file.3690    /// </summary>3691    class PartialInputStream : Stream3692    {3693      #region Constructors3694      /// <summary>3695      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.3696      /// </summary>3697      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>3698      /// <param name="start">The start of the partial data.</param>3699      /// <param name="length">The length of the partial data.</param>3700      public PartialInputStream(ZipFile zipFile, long start, long length)3701      {3702        start_ = start;3703        length_ = length;37043705        // Although this is the only time the zipfile is used3706        // keeping a reference here prevents premature closure of3707        // this zip file and thus the baseStream_.37083709        // Code like this will cause apparently random failures depending3710        // on the size of the files and when garbage is collected.3711        //3712        // ZipFile z = new ZipFile (stream);3713        // Stream reader = z.GetInputStream(0);3714        // uses reader here....3715        zipFile_ = zipFile;3716        baseStream_ = zipFile_.baseStream_;3717        readPos_ = start;3718        end_ = start + length;3719      }3720      #endregion37213722      /// <summary>3723      /// Read a byte from this stream.3724      /// </summary>3725      /// <returns>Returns the byte read or -1 on end of stream.</returns>3726      public override int ReadByte()3727      {3728        if (readPos_ >= end_) {3729           // -1 is the correct value at end of stream.3730          return -1;3731        }37323733        lock( baseStream_ ) {3734          baseStream_.Seek(readPos_++, SeekOrigin.Begin);3735          return baseStream_.ReadByte();3736        }3737      }37383739      /// <summary>3740      /// Close this <see cref="PartialInputStream">partial input stream</see>.3741      /// </summary>3742      /// <remarks>3743      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.3744      /// </remarks>3745      public override void Close()3746      {3747        // Do nothing at all!3748      }37493750      /// <summary>3751      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3752      /// </summary>3753      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3754      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3755      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3756      /// <returns>3757      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma3758      /// </returns>3759      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3760      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3761      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3762      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3763      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3764      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3765      public override int Read(byte[] buffer, int offset, int count)3766      {3767        lock(baseStream_) {3768          if (count > end_ - readPos_) {3769            count = (int) (end_ - readPos_);3770            if (count == 0) {3771              return 0;3772            }3773          }37743775          baseStream_.Seek(readPos_, SeekOrigin.Begin);3776          int readCount = baseStream_.Read(buffer, offset, count);3777          if (readCount > 0) {3778            readPos_ += readCount;3779          }3780          return readCount;3781        }3782      }37833784      /// <summary>3785      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3786      /// </summary>3787      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3788      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3789      /// <param name="count">The number of bytes to be written to the current stream.</param>3790      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3791      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3792      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3793      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3794      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3795      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3796      public override void Write(byte[] buffer, int offset, int count)3797      {3798        throw new NotSupportedException();3799      }38003801      /// <summary>3802      /// When overridden in a derived class, sets the length of the current stream.3803      /// </summary>3804      /// <param name="value">The desired length of the current stream in bytes.</param>3805      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3806      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3807      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3808      public override void SetLength(long value)3809      {3810        throw new NotSupportedException();3811      }38123813      /// <summary>3814      /// When overridden in a derived class, sets the position within the current stream.3815      /// </summary>3816      /// <param name="offset">A byte offset relative to the origin parameter.</param>3817      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3818      /// <returns>3819      /// The new position within the current stream.3820      /// </returns>3821      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3822      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3823      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3824      public override long Seek(long offset, SeekOrigin origin)3825      {3826        long newPos = readPos_;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. </excep3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3694      public override long Length {3695        get { return length_; }3696      }36973698      /// <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      }37063707      /// <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      }37153716      /// <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      }37243725      /// <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 Fields3734      ZipFile zipFile_;3735      Stream baseStream_;3736      long start_;3737      long length_;3738      long readPos_;3739      long end_;3740      #endregion3741    }3742    #endregion3743  }37443745  #endregion37463747  #region DataSources3748  /// <summary>3749  /// Provides a static way to obtain a source of data for an entry.3750  /// </summary>3751  public interface IStaticDataSource3752  {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  }37603761  /// <summary>3762  /// Represents a source of data that can dynamically provide3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3764  /// </summary>3765  public interface IDynamicDataSource3766  {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  }37763777  /// <summary>3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3779  /// </summary>3780  public class StaticDiskDataSource : IStaticDataSource3781  {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    }37903791    #region IDataSource Members37923793    /// <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    }38013802    readonly38033804    #endregion3805    #region Instance Fields3806    string fileName_;3807    #endregion3808  }380938103811  /// <summary>3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.3813  /// </summary>3814  public class DynamicDiskDataSource : IDynamicDataSource3815  {38163817    #region IDataSource Members3818    /// <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;  38273828        switch ( origin )3829        {3830          case SeekOrigin.Begin:3831            newPos = start_ + offset;3832            break;38333834          case SeekOrigin.Current:3835            newPos = readPos_ + offset;3836            break;3828      if (name != null) {3829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);3830      }38313832      return result;3833    }38343835    #endregion3836  }  38373838          case SeekOrigin.End:3839            newPos = end_ + offset;3840            break;3841        }38423843        if ( newPos < start_ ) {3844          throw new ArgumentException("Negative position is invalid");3845        }38463847        if ( newPos >= end_ ) {3848          throw new IOException("Cannot seek past end");3849        }3850        readPos_ = newPos;3851        return readPos_;3852      }38533854      /// <summary>3855      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.3856      /// </summary>3857      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3858      public override void Flush()3859      {3860        // Nothing to do.3861      }38623863      /// <summary>3864      /// Gets or sets the position within the current stream.3865      /// </summary>3866      /// <value></value>3867      /// <returns>The current position within the stream.</returns>3868      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3869      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>3870      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3871      public override long Position {3872        get { return readPos_ - start_; }3873        set {3874          long newPos = start_ + value;38753876          if ( newPos < start_ ) {3877            throw new ArgumentException("Negative position is invalid");3878          }3838  #endregion38393840  #region Archive Storage3841  /// <summary>3842  /// Defines facilities for data storage when updating Zip Archives.3843  /// </summary>3844  public interface IArchiveStorage3845  {3846    /// <summary>3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.3848    /// </summary>3849    FileUpdateMode UpdateMode { get; }38503851    /// <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();38573858    /// <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();38643865    /// <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);38713872    /// <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);  38793880          if ( newPos >= end_ ) {3881            throw new InvalidOperationException("Cannot seek past end");3882          }3883          readPos_ = newPos;3884        }3885      }38863887      /// <summary>3888      /// Gets the length in bytes of the stream.3889      /// </summary>3890      /// <value></value>3891      /// <returns>A long value representing the length of the stream in bytes.</returns>3892      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep3893      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3894      public override long Length {3895        get { return length_; }3896      }38973898      /// <summary>3899      /// Gets a value indicating whether the current stream supports writing.3900      /// </summary>3901      /// <value>false</value>3902      /// <returns>true if the stream supports writing; otherwise, false.</returns>3903      public override bool CanWrite {3904        get { return false; }3905      }39063907      /// <summary>3908      /// Gets a value indicating whether the current stream supports seeking.3909      /// </summary>3910      /// <value>true</value>3911      /// <returns>true if the stream supports seeking; otherwise, false.</returns>3912      public override bool CanSeek {3913        get { return true; }3914      }39153916      /// <summary>3917      /// Gets a value indicating whether the current stream supports reading.3918      /// </summary>3919      /// <value>true.</value>3920      /// <returns>true if the stream supports reading; otherwise, false.</returns>3921      public override bool CanRead {3922        get { return true; }3923      }39243925#if !NET_1_0 && !NET_1_1 && !NETCF_1_03926      /// <summary>3927      /// Gets a value that determines whether the current stream can time out.3928      /// </summary>3929      /// <value></value>3930      /// <returns>A value that determines whether the current stream can time out.</returns>3931      public override bool CanTimeout {3932        get { return baseStream_.CanTimeout; }3933      }3934#endif3935      #region Instance Fields3936      ZipFile zipFile_;3937      Stream baseStream_;3938      long start_;3939      long length_;3940      long readPos_;3941      long end_;3942      #endregion3943    }3944    #endregion3945  }39463947  #endregion39483949  #region DataSources3950  /// <summary>3951  /// Provides a static way to obtain a source of data for an entry.3952  /// </summary>3953  public interface IStaticDataSource3954  {3955    /// <summary>3956    /// Get a source of data by creating a new stream.3957    /// </summary>3958    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3959    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3960    Stream GetSource();3961  }39623963  /// <summary>3964  /// Represents a source of data that can dynamically provide3965  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3966  /// </summary>3967  public interface IDynamicDataSource3968  {3969    /// <summary>3970    /// Get a data source.3971    /// </summary>3972    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>3973    /// <param name="name">The name for data if known.</param>3974    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3975    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3976    Stream GetSource(ZipEntry entry, string name);3977  }39783979  /// <summary>3980  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3981  /// </summary>3982  public class StaticDiskDataSource : IStaticDataSource3983  {3984    /// <summary>3985    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>3986    /// </summary>3987    /// <param name="fileName">The name of the file to obtain data from.</param> - 03988    public StaticDiskDataSource(string fileName)3989    { - 03990      fileName_ = fileName; - 03991    }39923993    #region IDataSource Members39943995    /// <summary>3996    /// Get a <see cref="Stream"/> providing data.3997    /// </summary>3998    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>3999    public Stream GetSource()4000    { - 04001      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4002    }3880    /// <summary>3881    /// Dispose of this instance.3882    /// </summary>3883    void Dispose();3884  }38853886  /// <summary>3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.3888  /// </summary>3889  abstract public class BaseArchiveStorage : IArchiveStorage3890  {3891    #region Constructors3892    /// <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    #endregion39013902    #region IArchiveStorage Members39033904    /// <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();39103911    /// <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 read3915    /// the final storage for the archive.</returns>3916    /// <seealso cref="GetTemporaryOutput"/>3917    public abstract Stream ConvertTemporaryToFinal();39183919    /// <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);39253926    /// <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);39323933    /// <summary>3934    /// Disposes this instance.3935    /// </summary>3936    public abstract void Dispose();39373938    /// <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    }39473948    #endregion39493950    #region Instance Fields3951    FileUpdateMode updateMode_;3952    #endregion3953  }39543955  /// <summary>3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.3957  /// </summary>3958  public class DiskArchiveStorage : BaseArchiveStorage3959  {3960    #region Constructors3961    /// <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      }39723973      fileName_ = file.Name;3974    }39753976    /// <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    #endregion39853986    #region IArchiveStorage Members39873988    /// <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      }  40034004    readonly40054006    #endregion4007    #region Instance Fields4008    string fileName_;4009    #endregion4010  }401140124013  /// <summary>4014  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.4015  /// </summary>4016  public class DynamicDiskDataSource : IDynamicDataSource4017  {40184019    #region IDataSource Members4020    /// <summary>4021    /// Get a <see cref="Stream"/> providing data for an entry.4022    /// </summary>4023    /// <param name="entry">The entry to provide data for.</param>4024    /// <param name="name">The file name for data if known.</param>4025    /// <returns>Returns a stream providing data; or null if not available</returns>4026    public Stream GetSource(ZipEntry entry, string name)4027    {4028      Stream result = null;4004      return temporaryStream_;4005    }40064007    /// <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 read4011    /// 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      }40174018      Stream result = null;40194020      string moveTempName = GetTempFileName(fileName_, false);4021      bool newFileCreated = false;40224023      try {4024        temporaryStream_.Close();4025        File.Move(fileName_, moveTempName);4026        File.Move(temporaryName_, fileName_);4027        newFileCreated = true;4028        File.Delete(moveTempName);  40294030      if ( name != null ) {4031        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);4032      }4030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4031      } catch (Exception) {4032        result = null;  40334034      return result;4035    }40364037    #endregion4038  }4034        // Try to roll back changes...4035        if (!newFileCreated) {4036          File.Move(moveTempName, fileName_);4037          File.Delete(temporaryName_);4038        }  40394040  #endregion40414042  #region Archive Storage4043  /// <summary>4044  /// Defines facilities for data storage when updating Zip Archives.4045  /// </summary>4046  public interface IArchiveStorage4047  {4048    /// <summary>4049    /// Get the <see cref="FileUpdateMode"/> to apply during updates.4050    /// </summary>4051    FileUpdateMode UpdateMode { get; }40524053    /// <summary>4054    /// Get an empty <see cref="Stream"/> that can be used for temporary output.4055    /// </summary>4056    /// <returns>Returns a temporary output <see cref="Stream"/></returns>4057    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4058    Stream GetTemporaryOutput();40594060    /// <summary>4061    /// Convert a temporary output stream to a final stream.4062    /// </summary>4063    /// <returns>The resulting final <see cref="Stream"/></returns>4064    /// <seealso cref="GetTemporaryOutput"/>4065    Stream ConvertTemporaryToFinal();40664067    /// <summary>4068    /// Make a temporary copy of the original stream.4069    /// </summary>4070    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4071    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4072    Stream MakeTemporaryCopy(Stream stream);40734074    /// <summary>4075    /// Return a stream suitable for performing direct updates on the original source.4076    /// </summary>4077    /// <param name="stream">The current stream.</param>4078    /// <returns>Returns a stream suitable for direct updating.</returns>4079    /// <remarks>This may be the current stream passed.</remarks>4080    Stream OpenForDirectUpdate(Stream stream);40814082    /// <summary>4083    /// Dispose of this instance.4084    /// </summary>4085    void Dispose();4086  }4040        throw;4041      }40424043      return result;4044    }40454046    /// <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();40544055      temporaryName_ = GetTempFileName(fileName_, true);4056      File.Copy(fileName_, temporaryName_, true);40574058      temporaryStream_ = new FileStream(temporaryName_,4059        FileMode.Open,4060        FileAccess.ReadWrite);4061      return temporaryStream_;4062    }40634064    /// <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        }40774078        result = new FileStream(fileName_,4079            FileMode.Open,4080            FileAccess.ReadWrite);4081      } else {4082        result = stream;4083      }40844085      return result;4086    }  40874088  /// <summary>4089  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.4090  /// </summary>4091  abstract public class BaseArchiveStorage : IArchiveStorage4092  {4093    #region Constructors4094    /// <summary>4095    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.4096    /// </summary>4097    /// <param name="updateMode">The update mode.</param>4098    protected BaseArchiveStorage(FileUpdateMode updateMode)4099    {4100      updateMode_ = updateMode;4101    }4102    #endregion41034104    #region IArchiveStorage Members41054106    /// <summary>4107    /// Gets a temporary output <see cref="Stream"/>4108    /// </summary>4109    /// <returns>Returns the temporary output stream.</returns>4110    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4111    public abstract Stream GetTemporaryOutput();41124113    /// <summary>4114    /// Converts the temporary <see cref="Stream"/> to its final form.4115    /// </summary>4116    /// <returns>Returns a <see cref="Stream"/> that can be used to read4117    /// the final storage for the archive.</returns>4118    /// <seealso cref="GetTemporaryOutput"/>4119    public abstract Stream ConvertTemporaryToFinal();41204121    /// <summary>4122    /// Make a temporary copy of a <see cref="Stream"/>.4123    /// </summary>4124    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>4125    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4126    public abstract Stream MakeTemporaryCopy(Stream stream);41274128    /// <summary>4129    /// Return a stream suitable for performing direct updates on the original source.4130    /// </summary>4131    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>4132    /// <returns>Returns a stream suitable for direct updating.</returns>4133    public abstract Stream OpenForDirectUpdate(Stream stream);41344135    /// <summary>4136    /// Disposes this instance.4137    /// </summary>4138    public abstract void Dispose();41394140    /// <summary>4141    /// Gets the update mode applicable.4142    /// </summary>4143    /// <value>The update mode.</value>4144    public FileUpdateMode UpdateMode4145    {4146      get {4147        return updateMode_;4148      }4149    }41504151    #endregion41524153    #region Instance Fields4154    FileUpdateMode updateMode_;4155    #endregion4156  }41574158  /// <summary>4159  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.4160  /// </summary>4161  public class DiskArchiveStorage : BaseArchiveStorage4162  {4163    #region Constructors4164    /// <summary>4165    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4166    /// </summary>4167    /// <param name="file">The file.</param>4168    /// <param name="updateMode">The update mode.</param>4169    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)4170      : base(updateMode)4171    {4172      if ( file.Name == null ) {4173        throw new ZipException("Cant handle non file archives");4174      }41754176      fileName_ = file.Name;4177    }4088    /// <summary>4089    /// Disposes this instance.4090    /// </summary>4091    public override void Dispose()4092    {4093      if (temporaryStream_ != null) {4094        temporaryStream_.Close();4095      }4096    }40974098    #endregion40994100    #region Internal routines4101    static string GetTempFileName(string original, bool makeTempFile)4102    {4103      string result = null;41044105      if (original == null) {4106        result = Path.GetTempFileName();4107      } else {4108        int counter = 0;4109        int suffixSeed = DateTime.Now.Second;41104111        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    #endregion41334134    #region Instance Fields4135    Stream temporaryStream_;4136    string fileName_;4137    string temporaryName_;4138    #endregion4139  }41404141  /// <summary>4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4143  /// </summary>4144  public class MemoryArchiveStorage : BaseArchiveStorage4145  {4146    #region Constructors4147    /// <summary>4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4149    /// </summary>4150    public MemoryArchiveStorage()4151      : base(FileUpdateMode.Direct)4152    {4153    }41544155    /// <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    }41644165    #endregion41664167    #region Properties4168    /// <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    }41744175    #endregion41764177    #region IArchiveStorage Members  4178  4179    /// <summary>4180    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4180    /// Gets the temporary output <see cref="Stream"/>  4181    /// </summary>4182    /// <param name="file">The file.</param>4183    public DiskArchiveStorage(ZipFile file)4184      : this(file, FileUpdateMode.Safe)4185    {4186    }4187    #endregion4182    /// <returns>Returns the temporary output stream.</returns>4183    public override Stream GetTemporaryOutput()4184    {4185      temporaryStream_ = new MemoryStream();4186      return temporaryStream_;4187    }  41884189    #region IArchiveStorage Members41904191    /// <summary>4192    /// Gets a temporary output <see cref="Stream"/> for performing updates on.4193    /// </summary>4194    /// <returns>Returns the temporary output stream.</returns>4195    public override Stream GetTemporaryOutput()4196    {4197      if ( temporaryName_ != null ) {4198        temporaryName_ = GetTempFileName(temporaryName_, true);4199        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4200      }4201      else {4202        // Determine where to place files based on internal strategy.4203        // Currently this is always done in system temp directory.4204        temporaryName_ = Path.GetTempFileName();4205        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4206      }42074208      return temporaryStream_;4209    }42104211    /// <summary>4212    /// Converts a temporary <see cref="Stream"/> to its final form.4213    /// </summary>4214    /// <returns>Returns a <see cref="Stream"/> that can be used to read4215    /// the final storage for the archive.</returns>4216    public override Stream ConvertTemporaryToFinal()4217    {4218      if ( temporaryStream_ == null ) {4219        throw new ZipException("No temporary stream has been created");4220      }42214222      Stream result = null;42234224      string moveTempName = GetTempFileName(fileName_, false);4225      bool newFileCreated = false;42264227      try  {4228        temporaryStream_.Close();4229        File.Move(fileName_, moveTempName);4230        File.Move(temporaryName_, fileName_);4231        newFileCreated = true;4232        File.Delete(moveTempName);42334234        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4235      }4236      catch(Exception) {4237        result  = null;42384239        // Try to roll back changes...4240        if ( !newFileCreated ) {4241          File.Move(moveTempName, fileName_);4242          File.Delete(temporaryName_);4243        }42444245        throw;4246      }42474248      return result;4249    }42504251    /// <summary>4252    /// Make a temporary copy of a stream.4253    /// </summary>4254    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4255    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4256    public override Stream MakeTemporaryCopy(Stream stream)4257    {4258      stream.Close();42594260      temporaryName_ = GetTempFileName(fileName_, true);4261      File.Copy(fileName_, temporaryName_, true);42624263      temporaryStream_ = new FileStream(temporaryName_,4264        FileMode.Open,4265        FileAccess.ReadWrite);4266      return temporaryStream_;4267    }42684269    /// <summary>4270    /// Return a stream suitable for performing direct updates on the original source.4271    /// </summary>4272    /// <param name="stream">The current stream.</param>4273    /// <returns>Returns a stream suitable for direct updating.</returns>4274    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>4275    public override Stream OpenForDirectUpdate(Stream stream)4276    {4277      Stream result;4278      if ((stream == null) || !stream.CanWrite)4279      {4280        if (stream != null) {4281          stream.Close();4282        }42834284        result = new FileStream(fileName_,4285            FileMode.Open,4286            FileAccess.ReadWrite);4287      }4288      else4289      {4290        result = stream;4291      }42924293      return result;4294    }42954296    /// <summary>4297    /// Disposes this instance.4298    /// </summary>4299    public override void Dispose()4300    {4301      if ( temporaryStream_ != null ) {4302        temporaryStream_.Close();4303      }4304    }43054306    #endregion43074308    #region Internal routines4309    static string GetTempFileName(string original, bool makeTempFile)4310    {4311      string result = null;43124313      if ( original == null ) {4314        result = Path.GetTempFileName();4315      }4316      else {4317        int counter = 0;4318        int suffixSeed = DateTime.Now.Second;43194320        while ( result == null ) {4321          counter += 1;4322          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);4323          if ( !File.Exists(newName) ) {4324            if ( makeTempFile) {4325              try  {4326                // Try and create the file.4327                using ( FileStream stream = File.Create(newName) ) {4328                }4329                result = newName;4330              }4331              catch {4332                suffixSeed = DateTime.Now.Second;4333              }4334            }4335            else {4336              result = newName;4337            }4338          }4339        }4340      }4341      return result;4342    }4343    #endregion43444345    #region Instance Fields4346    Stream temporaryStream_;4347    string fileName_;4348    string temporaryName_;4349    #endregion4350  }43514352  /// <summary>4353  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4354  /// </summary>4355  public class MemoryArchiveStorage : BaseArchiveStorage4356  {4357    #region Constructors4358    /// <summary>4359    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4360    /// </summary>4361    public MemoryArchiveStorage()4362      : base(FileUpdateMode.Direct)4363    {4364    }43654366    /// <summary>4367    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4368    /// </summary>4369    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>4370    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>4371    public MemoryArchiveStorage(FileUpdateMode updateMode)4372      : base(updateMode)4373    {4374    }43754376    #endregion43774378    #region Properties4379    /// <summary>4380    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.4381    /// </summary>4382    public MemoryStream FinalStream4383    {4384      get { return finalStream_; }4385    }43864387    #endregion43884389    #region IArchiveStorage Members43904391    /// <summary>4392    /// Gets the temporary output <see cref="Stream"/>4393    /// </summary>4394    /// <returns>Returns the temporary output stream.</returns>4395    public override Stream GetTemporaryOutput()4396    {4397      temporaryStream_ = new MemoryStream();4398      return temporaryStream_;4399    }44004401    /// <summary>4402    /// Converts the temporary <see cref="Stream"/> to its final form.4403    /// </summary>4404    /// <returns>Returns a <see cref="Stream"/> that can be used to read4405    /// the final storage for the archive.</returns>4406    public override Stream ConvertTemporaryToFinal()4407    {4408      if ( temporaryStream_ == null ) {4409        throw new ZipException("No temporary stream has been created");4410      }44114412      finalStream_ = new MemoryStream(temporaryStream_.ToArray());4413      return finalStream_;4414    }44154416    /// <summary>4417    /// Make a temporary copy of the original stream.4418    /// </summary>4419    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4420    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4421    public override Stream MakeTemporaryCopy(Stream stream)4422    {4423      temporaryStream_ = new MemoryStream();4424      stream.Position = 0;4425      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);4426      return temporaryStream_;4427    }44284429    /// <summary>4430    /// Return a stream suitable for performing direct updates on the original source.4431    /// </summary>4432    /// <param name="stream">The original source stream</param>4433    /// <returns>Returns a stream suitable for direct updating.</returns>4434    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;4435    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>4436    public override Stream OpenForDirectUpdate(Stream stream)4437    {4438      Stream result;4439      if ((stream == null) || !stream.CanWrite) {44404441        result = new MemoryStream();44424443        if (stream != null) {4444          stream.Position = 0;4445          StreamUtils.Copy(stream, result, new byte[4096]);44464447          stream.Close();4448        }4449      }4450      else {4451        result = stream;4452      }44534454      return result;4455    }44564457    /// <summary>4458    /// Disposes this instance.4459    /// </summary>4460    public override void Dispose()4461    {4462      if ( temporaryStream_ != null ) {4463        temporaryStream_.Close();4464      }4465    }44664467    #endregion44684469    #region Instance Fields4470    MemoryStream temporaryStream_;4471    MemoryStream finalStream_;4472    #endregion4473  }44744475  #endregion4476}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 read4193    /// 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      }41994200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());4201      return finalStream_;4202    }42034204    /// <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    }42164217    /// <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) {42284229        result = new MemoryStream();42304231        if (stream != null) {4232          stream.Position = 0;4233          StreamUtils.Copy(stream, result, new byte[4096]);42344235          stream.Close();4236        }4237      } else {4238        result = stream;4239      }42404241      return result;4242    }42434244    /// <summary>4245    /// Disposes this instance.4246    /// </summary>4247    public override void Dispose()4248    {4249      if (temporaryStream_ != null) {4250        temporaryStream_.Close();4251      }4252    }42534254    #endregion42554256    #region Instance Fields4257    MemoryStream temporaryStream_;4258    MemoryStream finalStream_;4259    #endregion4260  }42614262  #endregion4263} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_StreamManipulator.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_StreamManipulator.htm index 071ef33cc..51145b39a 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_StreamManipulator.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_StreamManipulator.htm @@ -18,7 +18,7 @@

Summary

Covered lines:51 Uncovered lines:12 Coverable lines:63 -Total lines:288 +Total lines:241 Line coverage:80.9% Branch coverage:67.6% @@ -41,296 +41,249 @@

#LineLine coverage - 1// StreamManipulator.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839using System;4041namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams42{1using System;23namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams4{5  /// <summary>6  /// This class allows us to retrieve a specified number of bits from7  /// the input buffer, as well as copy big byte blocks.8  ///9  /// It uses an int buffer to store up to 31 bits for direct10  /// 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 must14  /// never peek more than 8 bits more than needed, and you must first15  /// peek bits before you may drop them.  This is not a general purpose16  /// class but optimized for the behaviour of the Inflater.17  ///18  /// authors of the original java version : John Leuner, Jochen Hoenicke19  /// </summary>20  public class StreamManipulator21  {22    /// <summary>23    /// Get the next sequence of bits but don't increase input pointer.  bitCount must be24    /// less or equal 16 and if this call succeeds, you must drop25    /// 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; // ok36        } + 589137        buffer_ |= (uint)((window_[windowStart_++] & 0xff | + 589138                 (window_[windowStart_++] & 0xff) << 8) << bitsInBuffer_); + 589139        bitsInBuffer_ += 16;40      } + 1122441      return (int)(buffer_ & ((1 << bitCount) - 1));42    }  4344  /// <summary>45  /// This class allows us to retrieve a specified number of bits from46  /// the input buffer, as well as copy big byte blocks.47  ///48  /// It uses an int buffer to store up to 31 bits for direct49  /// manipulation.  This guarantees that we can get at least 16 bits,50  /// but we only need at most 15, so this is all safe.51  ///52  /// There are some optimizations in this class, for example, you must53  /// never peek more than 8 bits more than needed, and you must first54  /// peek bits before you may drop them.  This is not a general purpose55  /// class but optimized for the behaviour of the Inflater.56  ///57  /// authors of the original java version : John Leuner, Jochen Hoenicke58  /// </summary>59  public class StreamManipulator60  {61    /// <summary>62    /// Get the next sequence of bits but don't increase input pointer.  bitCount must be63    /// less or equal 16 and if this call succeeds, you must drop64    /// at least n - 8 bits in the next call.65    /// </summary>66    /// <param name="bitCount">The number of bits to peek.</param>67    /// <returns>68    /// the value of the bits, or -1 if not enough bits available.  */69    /// </returns>70    public int PeekBits(int bitCount)71    { - 1166672       if (bitsInBuffer_ < bitCount) { - 631873         if (windowStart_ == windowEnd_) { - 39774          return -1; // ok75        } - 592176        buffer_ |= (uint)((window_[windowStart_++] & 0xff | - 592177                 (window_[windowStart_++] & 0xff) << 8) << bitsInBuffer_); - 592178        bitsInBuffer_ += 16;79      } - 1126980      return (int)(buffer_ & ((1 << bitCount) - 1));81    }8283    /// <summary>84    /// Drops the next n bits from the input.  You should have called PeekBits85    /// with a bigger or equal n before, to make sure that enough bits are in86    /// the bit buffer.87    /// </summary>88    /// <param name="bitCount">The number of bits to drop.</param>89    public void DropBits(int bitCount)90    { - 1126991      buffer_ >>= bitCount; - 1126992      bitsInBuffer_ -= bitCount; - 1126993    }9495    /// <summary>96    /// Gets the next n bits and increases input pointer.  This is equivalent97    /// to <see cref="PeekBits"/> followed by <see cref="DropBits"/>, except for correct error handling.98    /// </summary>99    /// <param name="bitCount">The number of bits to retrieve.</param>100    /// <returns>101    /// the value of the bits, or -1 if not enough bits available.102    /// </returns>103    public int GetBits(int bitCount)104    { - 0105      int bits = PeekBits(bitCount); - 0106       if (bits >= 0) { - 0107        DropBits(bitCount);108      } - 0109      return bits;110    }111112    /// <summary>113    /// Gets the number of bits available in the bit buffer.  This must be114    /// only called when a previous PeekBits() returned -1.115    /// </summary>116    /// <returns>117    /// the number of bits available.118    /// </returns>119    public int AvailableBits {120      get { - 23121        return bitsInBuffer_;122      }123    }124125    /// <summary>126    /// Gets the number of bytes available.127    /// </summary>128    /// <returns>129    /// The number of bytes available.130    /// </returns>131    public int AvailableBytes {132      get { - 2384133        return windowEnd_ - windowStart_ + (bitsInBuffer_ >> 3);134      }135    }136137    /// <summary>138    /// Skips to the next byte boundary.139    /// </summary>140    public void SkipToByteBoundary()44    /// <summary>45    /// Drops the next n bits from the input.  You should have called PeekBits46    /// with a bigger or equal n before, to make sure that enough bits are in47    /// 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    }5556    /// <summary>57    /// Gets the next n bits and increases input pointer.  This is equivalent58    /// 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    }7273    /// <summary>74    /// Gets the number of bits available in the bit buffer.  This must be75    /// 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    }8586    /// <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    }9798    /// <summary>99    /// Skips to the next byte boundary.100    /// </summary>101    public void SkipToByteBoundary()102    { + 303103      buffer_ >>= (bitsInBuffer_ & 7); + 303104      bitsInBuffer_ &= ~7; + 303105    }106107    /// <summary>108    /// Returns true when SetInput can be called109    /// </summary>110    public bool IsNeedingInput {111      get { + 3355112        return windowStart_ == windowEnd_;113      }114    }115116    /// <summary>117    /// Copies bytes from input buffer to output buffer starting118    /// at output[offset].  You have to make sure, that the buffer is119    /// byte aligned.  If not enough bytes are available, copies fewer120    /// 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 starts127    /// </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 zero136    /// </exception>137    /// <exception cref="InvalidOperationException">138    /// Bit buffer isnt byte aligned139    /// </exception>140    public int CopyBytes(byte[] output, int offset, int length)  141    { - 310142      buffer_ >>= (bitsInBuffer_ & 7); - 310143      bitsInBuffer_ &= ~7; - 310144    } + 2376142       if (length < 0) { + 0143        throw new ArgumentOutOfRangeException(nameof(length));144      }  145146    /// <summary>147    /// Returns true when SetInput can be called148    /// </summary>149    public bool IsNeedingInput {150      get { - 3428151        return windowStart_ == windowEnd_;152      }153    }154155    /// <summary>156    /// Copies bytes from input buffer to output buffer starting157    /// at output[offset].  You have to make sure, that the buffer is158    /// byte aligned.  If not enough bytes are available, copies fewer159    /// bytes.160    /// </summary>161    /// <param name="output">162    /// The buffer to copy bytes to.163    /// </param>164    /// <param name="offset">165    /// The offset in the buffer at which copying starts166    /// </param>167    /// <param name="length">168    /// The length to copy, 0 is allowed.169    /// </param>170    /// <returns>171    /// The number of bytes copied, 0 if no bytes were available.172    /// </returns>173    /// <exception cref="ArgumentOutOfRangeException">174    /// Length is less than zero175    /// </exception>176    /// <exception cref="InvalidOperationException">177    /// Bit buffer isnt byte aligned178    /// </exception>179    public int CopyBytes(byte[] output, int offset, int length)180    { - 2434181       if (length < 0) { - 0182        throw new ArgumentOutOfRangeException(nameof(length));183      }184 - 2434185       if ((bitsInBuffer_ & 7) != 0) {186        // bits_in_buffer may only be 0 or a multiple of 8 - 0187        throw new InvalidOperationException("Bit buffer is not byte aligned!");188      }189 - 2434190      int count = 0; - 2667191       while ((bitsInBuffer_ > 0) && (length > 0)) { - 233192        output[offset++] = (byte) buffer_; - 233193        buffer_ >>= 8; - 233194        bitsInBuffer_ -= 8; - 233195        length--; - 233196        count++;197      }198 - 2434199       if (length == 0) { - 1020200        return count;201      }202 - 1414203      int avail = windowEnd_ - windowStart_; - 1414204       if (length > avail) { - 0205        length = avail;206      } - 1414207      System.Array.Copy(window_, windowStart_, output, offset, length); - 1414208      windowStart_ += length;209 - 1414210       if (((windowStart_ - windowEnd_) & 1) != 0) {211        // We always want an even number of bytes in input, see peekBits - 211212        buffer_ = (uint)(window_[windowStart_++] & 0xff); - 211213        bitsInBuffer_ = 8;214      } - 1414215      return count + length;216    }217218    /// <summary>219    /// Resets state and empties internal buffers220    /// </summary>221    public void Reset()222    { - 44223      buffer_ = 0; - 44224      windowStart_ = windowEnd_ = bitsInBuffer_ = 0; - 44225    } + 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    }178179    /// <summary>180    /// Resets state and empties internal buffers181    /// </summary>182    public void Reset()183    { + 41184      buffer_ = 0; + 41185      windowStart_ = windowEnd_ = bitsInBuffer_ = 0; + 41186    }187188    /// <summary>189    /// Add more input for consumption.190    /// Only call when IsNeedingInput returns true191    /// </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;214215      // 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      }  226227    /// <summary>228    /// Add more input for consumption.229    /// Only call when IsNeedingInput returns true230    /// </summary>231    /// <param name="buffer">data to be input</param>232    /// <param name="offset">offset of first byte of input</param>233    /// <param name="count">number of bytes of input to add.</param>234    public void SetInput(byte[] buffer, int offset, int count)235    { - 1460236       if ( buffer == null ) { - 0237        throw new ArgumentNullException(nameof(buffer));238      }239 - 1460240       if ( offset < 0 ) {241#if NETCF_1_0242        throw new ArgumentOutOfRangeException("offset");243#else - 0244        throw new ArgumentOutOfRangeException(nameof(offset), "Cannot be negative");245#endif246      }247 - 1460248       if ( count < 0 ) {249#if NETCF_1_0250        throw new ArgumentOutOfRangeException("count");251#else - 0252        throw new ArgumentOutOfRangeException(nameof(count), "Cannot be negative");253#endif254      }255 - 1460256       if (windowStart_ < windowEnd_) { - 0257        throw new InvalidOperationException("Old input was not completely processed");258      }259 - 1460260      int end = offset + count;261262      // We want to throw an ArrayIndexOutOfBoundsException early.263      // Note the check also handles integer wrap around. - 1460264       if ((offset > end) || (end > buffer.Length) ) { - 0265        throw new ArgumentOutOfRangeException(nameof(count));266      }267 - 1460268       if ((count & 1) != 0) {269        // We always want an even number of bytes in input, see PeekBits - 217270        buffer_ |= (uint)((buffer[offset++] & 0xff) << bitsInBuffer_); - 217271        bitsInBuffer_ += 8;272      }273 - 1460274      window_ = buffer; - 1460275      windowStart_ = offset; - 1460276      windowEnd_ = end; - 1460277    }278279    #region Instance Fields280    private byte[] window_;281    private int windowStart_;282    private int windowEnd_;283284    private uint buffer_;285    private int bitsInBuffer_;286    #endregion287  }288} + 1433227      window_ = buffer; + 1433228      windowStart_ = offset; + 1433229      windowEnd_ = end; + 1433230    }231232    #region Instance Fields233    private byte[] window_;234    private int windowStart_;235    private int windowEnd_;236237    private uint buffer_;238    private int bitsInBuffer_;239    #endregion240  }241} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_StreamUtils.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_StreamUtils.htm index 1e80d849e..dbc5102fb 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_StreamUtils.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_StreamUtils.htm @@ -16,10 +16,10 @@

Summary

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:54 -Coverable lines:79 -Total lines:246 -Line coverage:31.6% +Uncovered lines:53 +Coverable lines:78 +Total lines:208 +Line coverage:32% Branch coverage:34% @@ -40,254 +40,216 @@

#LineLine coverage - 1// StreamUtils.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;37using System.IO;3839namespace ICSharpCode.SharpZipLib.Core40{41  /// <summary>42  /// Provides simple <see cref="Stream"/>" utilities.43  /// </summary>44  public sealed class StreamUtils45  {46    /// <summary>47    /// Read from a <see cref="Stream"/> ensuring all the required data is read.48    /// </summary>49    /// <param name="stream">The stream to read.</param>50    /// <param name="buffer">The buffer to fill.</param>51    /// <seealso cref="ReadFully(Stream,byte[],int,int)"/>52    static public void ReadFully(Stream stream, byte[] buffer)53    { - 26378954      ReadFully(stream, buffer, 0, buffer.Length); - 26378955    }5657    /// <summary>58    /// Read from a <see cref="Stream"/>" ensuring all the required data is read.59    /// </summary>60    /// <param name="stream">The stream to read data from.</param>61    /// <param name="buffer">The buffer to store data in.</param>62    /// <param name="offset">The offset at which to begin storing data.</param>63    /// <param name="count">The number of bytes of data to store.</param>64    /// <exception cref="ArgumentNullException">Required parameter is null</exception>65    /// <exception cref="ArgumentOutOfRangeException"><paramref name="offset"/> and or <paramref name="count"/> are inva66    /// <exception cref="EndOfStreamException">End of stream is encountered before all the data has been read.</exceptio67    static public void ReadFully(Stream stream, byte[] buffer, int offset, int count)1using System;2using System.IO;34namespace ICSharpCode.SharpZipLib.Core5{6  /// <summary>7  /// Provides simple <see cref="Stream"/>" utilities.8  /// </summary>9  public sealed class StreamUtils10  {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    }2122    /// <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 inva31    /// <exception cref="EndOfStreamException">End of stream is encountered before all the data has been read.</exceptio32    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      }4142      // 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    }6061    /// <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    { - 32974569       if ( stream == null ) { - 070        throw new ArgumentNullException(nameof(stream)); + 869       if (source == null) { + 070        throw new ArgumentNullException(nameof(source));  71      }  72 - 32974573       if ( buffer == null ) { - 074        throw new ArgumentNullException(nameof(buffer)); + 873       if (destination == null) { + 074        throw new ArgumentNullException(nameof(destination));  75      }  7677      // Offset can equal length when buffer and count are 0. - 32974578       if ( (offset < 0) || (offset > buffer.Length) ) { - 079        throw new ArgumentOutOfRangeException(nameof(offset));80      }81 - 32974582       if ( (count < 0) || (offset + count > buffer.Length) ) { - 083        throw new ArgumentOutOfRangeException(nameof(count)); + 877       if (buffer == null) { + 078        throw new ArgumentNullException(nameof(buffer));79      }8081      // 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 - 52767886       while ( count > 0 ) { - 19793387        int readCount = stream.Read(buffer, offset, count); - 19793388         if ( readCount <= 0 ) { - 089          throw new EndOfStreamException();90        } - 19793391        offset += readCount; - 19793392        count -= readCount;93      } - 32974594    }9596    /// <summary>97    /// Copy the contents of one <see cref="Stream"/> to another.98    /// </summary>99    /// <param name="source">The stream to source data from.</param>100    /// <param name="destination">The stream to write data to.</param>101    /// <param name="buffer">The buffer to use during copying.</param>102    static public void Copy(Stream source, Stream destination, byte[] buffer)103    { - 8104       if (source == null) { - 0105        throw new ArgumentNullException(nameof(source));106      }107 - 8108       if (destination == null) { - 0109        throw new ArgumentNullException(nameof(destination));110      }111 - 8112       if (buffer == null) { - 0113        throw new ArgumentNullException(nameof(buffer));114      } + 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    }9899    /// <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    }  115116      // Ensure a reasonable size of buffer is used without being prohibitive. - 8117       if (buffer.Length < 128) { - 0118        throw new ArgumentException("Buffer is too small", nameof(buffer));119      }120 - 8121      bool copying = true;122 - 24123       while (copying) { - 16124        int bytesRead = source.Read(buffer, 0, buffer.Length); - 16125         if (bytesRead > 0) { - 8126          destination.Write(buffer, 0, bytesRead); - 8127        }128        else { - 8129          destination.Flush(); - 8130          copying = false;131        }132      } - 8133    }134135    /// <summary>136    /// Copy the contents of one <see cref="Stream"/> to another.137    /// </summary>138    /// <param name="source">The stream to source data from.</param>139    /// <param name="destination">The stream to write data to.</param>140    /// <param name="buffer">The buffer to use during copying.</param>141    /// <param name="progressHandler">The <see cref="ProgressHandler">progress handler delegate</see> to use.</param>142    /// <param name="updateInterval">The minimum <see cref="TimeSpan"/> between progress updates.</param>143    /// <param name="sender">The source for this event.</param>144    /// <param name="name">The name to use with the event.</param>145    /// <remarks>This form is specialised for use within #Zip to support events during archive operations.</remarks>146    static public void Copy(Stream source, Stream destination,147      byte[] buffer, ProgressHandler progressHandler, TimeSpan updateInterval, object sender, string name)148    { - 0149      Copy(source, destination, buffer, progressHandler, updateInterval, sender, name, -1); - 0150    }151152    /// <summary>153    /// Copy the contents of one <see cref="Stream"/> to another.154    /// </summary>155    /// <param name="source">The stream to source data from.</param>156    /// <param name="destination">The stream to write data to.</param>157    /// <param name="buffer">The buffer to use during copying.</param>158    /// <param name="progressHandler">The <see cref="ProgressHandler">progress handler delegate</see> to use.</param>159    /// <param name="updateInterval">The minimum <see cref="TimeSpan"/> between progress updates.</param>160    /// <param name="sender">The source for this event.</param>161    /// <param name="name">The name to use with the event.</param>162    /// <param name="fixedTarget">A predetermined fixed target value to use with progress updates.163    /// If the value is negative the target is calculated by looking at the stream.</param>164    /// <remarks>This form is specialised for use within #Zip to support events during archive operations.</remarks>165    static public void Copy(Stream source, Stream destination,166      byte[] buffer,167      ProgressHandler progressHandler, TimeSpan updateInterval,168      object sender, string name, long fixedTarget)169    { - 0170       if (source == null) { - 0171        throw new ArgumentNullException(nameof(source));172      }173 - 0174       if (destination == null) { - 0175        throw new ArgumentNullException(nameof(destination));176      }177 - 0178       if (buffer == null) { - 0179        throw new ArgumentNullException(nameof(buffer));180      }181182      // Ensure a reasonable size of buffer is used without being prohibitive. - 0183       if (buffer.Length < 128) { - 0184        throw new ArgumentException("Buffer is too small", nameof(buffer));185      }186 - 0187       if (progressHandler == null) { - 0188        throw new ArgumentNullException(nameof(progressHandler));189      }190 - 0191      bool copying = true;192 - 0193      DateTime marker = DateTime.Now; - 0194      long processed = 0; - 0195      long target = 0;196 - 0197       if (fixedTarget >= 0) { - 0198        target = fixedTarget; - 0199      } - 0200       else if (source.CanSeek) { - 0201        target = source.Length - source.Position;202      }203204      // Always fire 0% progress.. - 0205      var args = new ProgressEventArgs(name, processed, target); - 0206      progressHandler(sender, args);207 - 0208      bool progressFired = true;209 - 0210       while (copying) { - 0211        int bytesRead = source.Read(buffer, 0, buffer.Length); - 0212         if (bytesRead > 0) { - 0213          processed += bytesRead; - 0214          progressFired = false; - 0215          destination.Write(buffer, 0, bytesRead); - 0216        }217        else { - 0218          destination.Flush(); - 0219          copying = false;220        }221 - 0222         if (DateTime.Now - marker > updateInterval) { - 0223          progressFired = true; - 0224          marker = DateTime.Now; - 0225          args = new ProgressEventArgs(name, processed, target); - 0226          progressHandler(sender, args);227 - 0228          copying = args.ContinueRunning;229        }230      }231 - 0232       if (!progressFired) { - 0233        args = new ProgressEventArgs(name, processed, target); - 0234        progressHandler(sender, args);235      } - 0236    }237238    /// <summary>239    /// Initialise an instance of <see cref="StreamUtils"></see>240    /// </summary> - 0241    private StreamUtils()242    {243      // Do nothing. - 0244    }245  }246}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      }145146      // 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      }166167      // 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    }199200    /// <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/Documentation/opencover/ICSharpCode.SharpZipLib_TarArchive.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_TarArchive.htm index 9c5a42003..c29f49847 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_TarArchive.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_TarArchive.htm @@ -18,9 +18,9 @@

Summary

Covered lines:46 Uncovered lines:223 Coverable lines:269 -Total lines:895 +Total lines:830 Line coverage:17.1% -Branch coverage:14% +Branch coverage:13.6%

Metrics

@@ -40,7 +40,7 @@

Metrics

SetUserInfo(...)200 CloseArchive()100 ListContents()357.1460 -ExtractContents(...)300 +ExtractContents(...)500 ExtractEntry(...)1400 WriteEntry(...)500 WriteEntryCore(...)1900 @@ -57,903 +57,838 @@

#LineLine coverage - 1// TarArchive.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536// HISTORY37//  2010-01-28      Added IsStreamOwner38//  2012-06-07  Z-1675  RootPath was case and slash direction sensitive; trailing slash caused failure1using System;2using System.IO;3using System.Text;45namespace ICSharpCode.SharpZipLib.Tar6{7  /// <summary>8  /// Used to advise clients of 'events' while processing archives9  /// </summary>10  public delegate void ProgressMessageHandler(TarArchive archive, TarEntry entry, string message);1112  /// <summary>13  /// The TarArchive class implements the concept of a14  /// 'Tape Archive'. A tar archive is a series of entries, each of15  /// which represents a file system object. Each entry in16  /// 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 entries18  /// for the directory's contents. File entries consist of a19  /// header followed by the number of blocks needed to20  /// contain the file's contents. All entries are written on21  /// 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 InputStream25  /// or an OutputStream. Once instantiated TarArchives read/write26  /// 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 the30  /// TarBuffer.CurrentRecord and TarBuffer.CurrentBlock31  /// properties, this would be rather trivial.32  /// </summary>33  public class TarArchive : IDisposable34  {35    /// <summary>36    /// Client hook allowing detailed information to be reported during processing37    /// </summary>38    public event ProgressMessageHandler ProgressMessageEvent;  3940using System;41using System.IO;42using System.Text;4344namespace ICSharpCode.SharpZipLib.Tar45{46  /// <summary>47  /// Used to advise clients of 'events' while processing archives48  /// </summary>49  public delegate void ProgressMessageHandler(TarArchive archive, TarEntry entry, string message);5051  /// <summary>52  /// The TarArchive class implements the concept of a53  /// 'Tape Archive'. A tar archive is a series of entries, each of54  /// which represents a file system object. Each entry in55  /// the archive consists of a header block followed by 0 or more data blocks.56  /// Directory entries consist only of the header block, and are followed by entries57  /// for the directory's contents. File entries consist of a58  /// header followed by the number of blocks needed to59  /// contain the file's contents. All entries are written on60  /// block boundaries. Blocks are 512 bytes long.61  ///62  /// TarArchives are instantiated in either read or write mode,63  /// based upon whether they are instantiated with an InputStream64  /// or an OutputStream. Once instantiated TarArchives read/write65  /// mode can not be changed.66  ///67  /// There is currently no support for random access to tar archives.68  /// However, it seems that subclassing TarArchive, and using the69  /// TarBuffer.CurrentRecord and TarBuffer.CurrentBlock70  /// properties, this would be rather trivial.71  /// </summary>72  public class TarArchive : IDisposable73  {40    /// <summary>41    /// Raises the ProgressMessage event42    /// </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    }5253    #region Constructors54    /// <summary>55    /// Constructor for a default <see cref="TarArchive"/>.56    /// </summary> + 057    protected TarArchive()58    { + 059    }6061    /// <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    /// Client hook allowing detailed information to be reported during processing75    /// Initialise a TarArchive for output.  76    /// </summary>77    public event ProgressMessageHandler ProgressMessageEvent;7879    /// <summary>80    /// Raises the ProgressMessage event81    /// </summary>82    /// <param name="entry">The <see cref="TarEntry">TarEntry</see> for this event</param>83    /// <param name="message">message for this event.  Null is no message</param>84    protected virtual void OnProgressMessageEvent(TarEntry entry, string message)85    { - 086        ProgressMessageHandler handler = ProgressMessageEvent; - 087       if (handler != null) { - 088        handler(this, entry, message);89      } - 090    }9192    #region Constructors93    /// <summary>94    /// Constructor for a default <see cref="TarArchive"/>.95    /// </summary> - 096    protected TarArchive()97    { - 098    }99100    /// <summary>101    /// Initalise a TarArchive for input.102    /// </summary>103    /// <param name="stream">The <see cref="TarInputStream"/> to use for input.</param> - 1104    protected TarArchive(TarInputStream stream)105    { - 1106       if ( stream == null ) { - 0107        throw new ArgumentNullException(nameof(stream));108      }109 - 1110      tarIn = stream; - 1111    }112113    /// <summary>114    /// Initialise a TarArchive for output.115    /// </summary>116    /// <param name="stream">The <see cref="TarOutputStream"/> to use for output.</param> - 1117    protected TarArchive(TarOutputStream stream)118    { - 1119       if ( stream == null ) { - 0120        throw new ArgumentNullException(nameof(stream));121      }122 - 1123      tarOut = stream; - 1124    }125    #endregion126127    #region Static factory methods128    /// <summary>129    /// The InputStream based constructors create a TarArchive for the130    /// purposes of extracting or listing a tar archive. Thus, use131    /// these constructors when you wish to extract files from or list132    /// the contents of an existing tar archive.133    /// </summary>134    /// <param name="inputStream">The stream to retrieve archive data from.</param>135    /// <returns>Returns a new <see cref="TarArchive"/> suitable for reading from.</returns>136    public static TarArchive CreateInputTarArchive(Stream inputStream)137    { - 1138       if ( inputStream == null ) { - 0139        throw new ArgumentNullException(nameof(inputStream));140      }141 - 1142      var tarStream = inputStream as TarInputStream;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    #endregion8788    #region Static factory methods89    /// <summary>90    /// The InputStream based constructors create a TarArchive for the91    /// purposes of extracting or listing a tar archive. Thus, use92    /// these constructors when you wish to extract files from or list93    /// 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;104105      TarArchive result; + 1106       if (tarStream != null) { + 0107        result = new TarArchive(tarStream); + 0108      } else { + 1109        result = CreateInputTarArchive(inputStream, TarBuffer.DefaultBlockFactor);110      } + 1111      return result;112    }113114    /// <summary>115    /// Create TarArchive for reading setting block factor116    /// </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    }132133    /// <summary>134    /// Create a TarArchive for writing to, using the default blocking factor135    /// </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      }  143144        TarArchive result; - 1145       if ( tarStream != null ) { - 0146        result = new TarArchive(tarStream); - 0147      }148      else { - 1149        result = CreateInputTarArchive(inputStream, TarBuffer.DefaultBlockFactor);150      } - 1151        return result;152    }153154    /// <summary>155    /// Create TarArchive for reading setting block factor156    /// </summary>157    /// <param name="inputStream">A stream containing the tar archive contents</param>158    /// <param name="blockFactor">The blocking factor to apply</param>159    /// <returns>Returns a <see cref="TarArchive"/> suitable for reading.</returns>160    public static TarArchive CreateInputTarArchive(Stream inputStream, int blockFactor)161    { - 1162       if ( inputStream == null ) { - 0163        throw new ArgumentNullException(nameof(inputStream));164      }165 - 1166       if ( inputStream is TarInputStream ) { - 0167        throw new ArgumentException("TarInputStream not valid");168      }169 - 1170      return new TarArchive(new TarInputStream(inputStream, blockFactor));171    }172173    /// <summary>174    /// Create a TarArchive for writing to, using the default blocking factor175    /// </summary>176    /// <param name="outputStream">The <see cref="Stream"/> to write to</param>177    /// <returns>Returns a <see cref="TarArchive"/> suitable for writing.</returns>178    public static TarArchive CreateOutputTarArchive(Stream outputStream)179    { - 1180       if ( outputStream == null ) { - 0181        throw new ArgumentNullException(nameof(outputStream));182      }183 - 1184            var tarStream = outputStream as TarOutputStream;185186        TarArchive result; - 1187       if ( tarStream != null ) { - 0188        result = new TarArchive(tarStream); - 0189      }190      else { - 1191        result = CreateOutputTarArchive(outputStream, TarBuffer.DefaultBlockFactor);192      } - 1193        return result;194    }195196    /// <summary>197    /// Create a <see cref="TarArchive">tar archive</see> for writing.198    /// </summary>199    /// <param name="outputStream">The stream to write to</param>200    /// <param name="blockFactor">The blocking factor to use for buffering.</param>201    /// <returns>Returns a <see cref="TarArchive"/> suitable for writing.</returns>202    public static TarArchive CreateOutputTarArchive(Stream outputStream, int blockFactor)203    { - 1204       if ( outputStream == null ) { - 0205        throw new ArgumentNullException(nameof(outputStream));206      }207 - 1208       if ( outputStream is TarOutputStream ) { - 0209        throw new ArgumentException("TarOutputStream is not valid");210      }211 - 1212      return new TarArchive(new TarOutputStream(outputStream, blockFactor));213    }214    #endregion215216    /// <summary>217    /// Set the flag that determines whether existing files are218    /// kept, or overwritten during extraction.219    /// </summary>220    /// <param name="keepExistingFiles">221    /// If true, do not overwrite existing files.222    /// </param>223    public void SetKeepOldFiles(bool keepExistingFiles)224    { - 0225       if ( isDisposed ) { - 0226        throw new ObjectDisposedException("TarArchive");227      }228 - 0229      keepOldFiles = keepExistingFiles; - 0230    } + 1144      var tarStream = outputStream as TarOutputStream;145146      TarArchive result; + 1147       if (tarStream != null) { + 0148        result = new TarArchive(tarStream); + 0149      } else { + 1150        result = CreateOutputTarArchive(outputStream, TarBuffer.DefaultBlockFactor);151      } + 1152      return result;153    }154155    /// <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    #endregion174175    /// <summary>176    /// Set the flag that determines whether existing files are177    /// 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    }190191    /// <summary>192    /// Get/set the ascii file translation flag. If ascii file translation193    /// 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 text195    /// file, it will be translated. The translation converts the local196    /// operating system's concept of line ends into the UNIX line end,197    /// '\n', which is the defacto standard for a TAR archive. This makes198    /// 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      }208209      set { + 0210         if (isDisposed) { + 0211          throw new ObjectDisposedException("TarArchive");212        }213 + 0214        asciiTranslate = value; + 0215      }216217    }218219    /// <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      }  231232    /// <summary>233    /// Get/set the ascii file translation flag. If ascii file translation234    /// is true, then the file is checked to see if it a binary file or not.235    /// If the flag is true and the test indicates it is ascii text236    /// file, it will be translated. The translation converts the local237    /// operating system's concept of line ends into the UNIX line end,238    /// '\n', which is the defacto standard for a TAR archive. This makes239    /// text files compatible with UNIX.240    /// </summary>241    public bool AsciiTranslate242    {243      get { - 0244         if ( isDisposed ) { - 0245          throw new ObjectDisposedException("TarArchive");246        } + 0232      asciiTranslate = translateAsciiFiles; + 0233    }234235    /// <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 PathPrefix238    /// </summary>239    public string PathPrefix {240      get { + 0241         if (isDisposed) { + 0242          throw new ObjectDisposedException("TarArchive");243        }244 + 0245        return pathPrefix;246      }  247 - 0248        return asciiTranslate;249      }250251      set { - 0252         if ( isDisposed ) { - 0253          throw new ObjectDisposedException("TarArchive");254        }248      set { + 0249         if (isDisposed) { + 0250          throw new ObjectDisposedException("TarArchive");251        }252 + 0253        pathPrefix = value; + 0254      }  255 - 0256        asciiTranslate = value; - 0257      }258259    }260261    /// <summary>262    /// Set the ascii file translation flag.263    /// </summary>264    /// <param name= "translateAsciiFiles">265    /// If true, translate ascii text files.266    /// </param>267    [Obsolete("Use the AsciiTranslate property")]268    public void SetAsciiTranslation(bool translateAsciiFiles)269    { - 0270       if ( isDisposed ) { - 0271        throw new ObjectDisposedException("TarArchive");272      }273 - 0274      asciiTranslate = translateAsciiFiles; - 0275    }276277    /// <summary>278    /// PathPrefix is added to entry names as they are written if the value is not null.279    /// A slash character is appended after PathPrefix280    /// </summary>281    public string PathPrefix282    {283      get { - 0284         if ( isDisposed ) { - 0285          throw new ObjectDisposedException("TarArchive");286        }287 - 0288        return pathPrefix;289      }290291      set { - 0292         if ( isDisposed ) { - 0293          throw new ObjectDisposedException("TarArchive");294        }295 - 0296        pathPrefix = value; - 0297      }298299    }300301    /// <summary>302    /// RootPath is removed from entry names if it is found at the303    /// beginning of the name.304    /// </summary>305    public string RootPath306    {307      get { - 0308         if ( isDisposed ) { - 0309          throw new ObjectDisposedException("TarArchive");310        }311 - 0312        return rootPath;313      }314315      set { - 0316         if ( isDisposed ) { - 0317          throw new ObjectDisposedException("TarArchive");318        }319        // Convert to forward slashes for matching. Trim trailing / for correct final path - 0320        rootPath = value.Replace('\\', '/').TrimEnd('/'); - 0321      }322    }323324    /// <summary>325    /// Set user and group information that will be used to fill in the326    /// tar archive's entry headers. This information is based on that available327    /// for the linux operating system, which is not always available on other328    /// operating systems.  TarArchive allows the programmer to specify values329    /// to be used in their place.330    /// <see cref="ApplyUserInfoOverrides"/> is set to true by this call.331    /// </summary>332    /// <param name="userId">333    /// The user id to use in the headers.334    /// </param>335    /// <param name="userName">336    /// The user name to use in the headers.337    /// </param>338    /// <param name="groupId">339    /// The group id to use in the headers.340    /// </param>341    /// <param name="groupName">342    /// The group name to use in the headers.343    /// </param>344    public void SetUserInfo(int userId, string userName, int groupId, string groupName)345    { - 0346       if ( isDisposed ) { - 0347        throw new ObjectDisposedException("TarArchive");348      }349 - 0350      this.userId    = userId; - 0351      this.userName  = userName; - 0352      this.groupId   = groupId; - 0353      this.groupName = groupName; - 0354      applyUserInfoOverrides = true; - 0355    }356357    /// <summary>358    /// Get or set a value indicating if overrides defined by <see cref="SetUserInfo">SetUserInfo</see> should be applie359    /// </summary>360    /// <remarks>If overrides are not applied then the values as set in each header will be used.</remarks>361    public bool ApplyUserInfoOverrides362    {363      get { - 0364         if ( isDisposed ) { - 0365          throw new ObjectDisposedException("TarArchive");366        }367 - 0368        return applyUserInfoOverrides;369      }256    }257258    /// <summary>259    /// RootPath is removed from entry names if it is found at the260    /// 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      }270271      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    }279280    /// <summary>281    /// Set user and group information that will be used to fill in the282    /// tar archive's entry headers. This information is based on that available283    /// for the linux operating system, which is not always available on other284    /// operating systems.  TarArchive allows the programmer to specify values285    /// 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    }312313    /// <summary>314    /// Get or set a value indicating if overrides defined by <see cref="SetUserInfo">SetUserInfo</see> should be applie315    /// </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      }325326      set { + 0327         if (isDisposed) { + 0328          throw new ObjectDisposedException("TarArchive");329        }330 + 0331        applyUserInfoOverrides = value; + 0332      }333    }334335    /// <summary>336    /// Get the archive user id.337    /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail338    /// 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    }352353    /// <summary>354    /// Get the archive user name.355    /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail356    /// 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    }  370371      set { - 0372         if ( isDisposed ) { - 0373          throw new ObjectDisposedException("TarArchive");374        }375 - 0376        applyUserInfoOverrides = value; - 0377      }378    }379380    /// <summary>381    /// Get the archive user id.382    /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail383    /// on how to allow setting values on a per entry basis.384    /// </summary>385    /// <returns>386    /// The current user id.387    /// </returns>388    public int UserId {389      get { - 0390         if ( isDisposed ) { - 0391          throw new ObjectDisposedException("TarArchive");392        }393 - 0394        return userId;395      }396    }397398    /// <summary>399    /// Get the archive user name.400    /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail401    /// on how to allow setting values on a per entry basis.402    /// </summary>403    /// <returns>404    /// The current user name.405    /// </returns>406    public string UserName {407      get { - 0408         if ( isDisposed ) { - 0409          throw new ObjectDisposedException("TarArchive");410        }411 - 0412        return userName;413      }414    }415416    /// <summary>417    /// Get the archive group id.418    /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail419    /// on how to allow setting values on a per entry basis.420    /// </summary>421    /// <returns>422    /// The current group id.423    /// </returns>424    public int GroupId {425      get { - 0426         if ( isDisposed ) { - 0427          throw new ObjectDisposedException("TarArchive");428        }429 - 0430        return groupId;431      }432    }433434    /// <summary>435    /// Get the archive group name.436    /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail437    /// on how to allow setting values on a per entry basis.438    /// </summary>439    /// <returns>440    /// The current group name.441    /// </returns>442    public string GroupName {443      get { - 0444         if ( isDisposed ) { - 0445          throw new ObjectDisposedException("TarArchive");446        }447 - 0448        return groupName;449      }450    }451452    /// <summary>453    /// Get the archive's record size. Tar archives are composed of454    /// a series of RECORDS each containing a number of BLOCKS.455    /// This allowed tar archives to match the IO characteristics of456    /// the physical device being used. Archives are expected457    /// to be properly "blocked".458    /// </summary>459    /// <returns>460    /// The record size this archive is using.461    /// </returns>462    public int RecordSize {463      get { - 1464         if ( isDisposed ) { - 0465          throw new ObjectDisposedException("TarArchive");466        }467 - 1468         if (tarIn != null) { - 0469          return tarIn.RecordSize; - 1470         } else if (tarOut != null) { - 1471          return tarOut.RecordSize;371    /// <summary>372    /// Get the archive group id.373    /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail374    /// 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    }388389    /// <summary>390    /// Get the archive group name.391    /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail392    /// 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    }406407    /// <summary>408    /// Get the archive's record size. Tar archives are composed of409    /// a series of RECORDS each containing a number of BLOCKS.410    /// This allowed tar archives to match the IO characteristics of411    /// the physical device being used. Archives are expected412    /// 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    }431432    /// <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    }445446    /// <summary>447    /// Close the archive.448    /// </summary>449    [Obsolete("Use Close instead")]450    public void CloseArchive()451    { + 0452      Close(); + 0453    }454455    /// <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 list459    /// 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        return TarBuffer.DefaultRecordSize; + 0473        OnProgressMessageEvent(entry, null);  474      }475    } + 1475    }  476  477    /// <summary>478    /// Sets the IsStreamOwner property on the underlying stream.479    /// Set this to false to prevent the Close of the TarArchive from closing the stream.480    /// </summary>481    public bool IsStreamOwner {482      set { - 0483         if (tarIn != null) { - 0484          tarIn.IsStreamOwner = value; - 0485        } else { - 0486          tarOut.IsStreamOwner = value;487        } - 0488      }489    }490491    /// <summary>492    /// Close the archive.493    /// </summary>494    [Obsolete("Use Close instead")]495    public void CloseArchive()496    { - 0497      Close(); - 0498    }499500    /// <summary>501    /// Perform the "list" command for the archive contents.502    ///503    /// NOTE That this method uses the <see cref="ProgressMessageEvent"> progress event</see> to actually list504    /// the contents. If the progress display event is not set, nothing will be listed!505    /// </summary>506    public void ListContents()507    { - 1508       if ( isDisposed ) { - 0509        throw new ObjectDisposedException("TarArchive");510      }511 - 0512      while (true) { - 1513        TarEntry entry = tarIn.GetNextEntry();514 - 1515         if (entry == null) {516          break;517        } - 0518        OnProgressMessageEvent(entry, null);519      } - 1520    }521522    /// <summary>523    /// Perform the "extract" command and extract the contents of the archive.524    /// </summary>525    /// <param name="destinationDirectory">526    /// The destination directory into which to extract.527    /// </param>528    public void ExtractContents(string destinationDirectory)529    { - 0530       if ( isDisposed ) { - 0531        throw new ObjectDisposedException("TarArchive");532      }533 - 0534      while (true) { - 0535        TarEntry entry = tarIn.GetNextEntry();536 - 0537         if (entry == null) {538          break;539        }540 - 0541        ExtractEntry(destinationDirectory, entry);542      } - 0543    }544545    /// <summary>546    /// Extract an entry from the archive. This method assumes that the547    /// tarIn stream has been properly set with a call to GetNextEntry().548    /// </summary>549    /// <param name="destDir">550    /// The destination directory into which to extract.551    /// </param>552    /// <param name="entry">553    /// The TarEntry returned by tarIn.GetNextEntry().554    /// </param>555    void ExtractEntry(string destDir, TarEntry entry)556    { - 0557      OnProgressMessageEvent(entry, null);558 - 0559      string name = entry.Name;560 - 0561       if (Path.IsPathRooted(name)) {562        // NOTE:563        // for UNC names...  \\machine\share\zoom\beet.txt gives \zoom\beet.txt - 0564        name = name.Substring(Path.GetPathRoot(name).Length);565      }566 - 0567      name = name.Replace('/', Path.DirectorySeparatorChar);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    }502503    /// <summary>504    /// Extract an entry from the archive. This method assumes that the505    /// 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      string destFile = Path.Combine(destDir, name);570 - 0571       if (entry.IsDirectory) { - 0572        EnsureDirectoryExists(destFile); - 0573      } else { - 0574        string parentDirectory = Path.GetDirectoryName(destFile); - 0575        EnsureDirectoryExists(parentDirectory);576 - 0577        bool process = true; - 0578        var fileInfo = new FileInfo(destFile); - 0579         if (fileInfo.Exists) { - 0580           if (keepOldFiles) { - 0581            OnProgressMessageEvent(entry, "Destination file already exists"); - 0582            process = false; - 0583           } else if ((fileInfo.Attributes & FileAttributes.ReadOnly) != 0) { - 0584            OnProgressMessageEvent(entry, "Destination file already exists, and is read-only"); - 0585            process = false; + 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         if (process) { - 0590          bool asciiTrans = false;591 - 0592          Stream outputStream = File.Create(destFile); - 0593           if (this.asciiTranslate) { - 0594            asciiTrans = !IsBinary(destFile);595          }596 - 0597          StreamWriter outw = null; - 0598           if (asciiTrans) { - 0599            outw = new StreamWriter(outputStream);600          }601 - 0602          byte[] rdbuf = new byte[32 * 1024];603 - 0604          while (true) { - 0605            int numRead = tarIn.Read(rdbuf, 0, rdbuf.Length);606 - 0607             if (numRead <= 0) {608              break;609            }610 - 0611             if (asciiTrans) { - 0612               for (int off = 0, b = 0; b < numRead; ++b) { - 0613                 if (rdbuf[b] == 10) { - 0614                  string s = Encoding.ASCII.GetString(rdbuf, off, (b - off)); - 0615                  outw.WriteLine(s); - 0616                  off = b + 1;617                }618              } - 0619            } else { - 0620              outputStream.Write(rdbuf, 0, numRead);621            }622          }623 - 0624           if (asciiTrans) { - 0625            outw.Close(); - 0626          } else { - 0627            outputStream.Close();628          }629        }630      } - 0631    }632633    /// <summary>634    /// Write an entry to the archive. This method will call the putNextEntry635    /// and then write the contents of the entry, and finally call closeEntry()636    /// for entries that are files. For directories, it will call putNextEntry(),637    /// and then, if the recurse flag is true, process each entry that is a638    /// child of the directory.639    /// </summary>640    /// <param name="sourceEntry">641    /// The TarEntry representing the entry to write to the archive.642    /// </param>643    /// <param name="recurse">644    /// If true, process the children of directory entries.645    /// </param>646    public void WriteEntry(TarEntry sourceEntry, bool recurse)647    { - 0648       if ( sourceEntry == null ) { - 0649        throw new ArgumentNullException(nameof(sourceEntry));650      }651 - 0652       if ( isDisposed ) { - 0653        throw new ObjectDisposedException("TarArchive");654      }588      } + 0589    }590591    /// <summary>592    /// Write an entry to the archive. This method will call the putNextEntry593    /// 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 a596    /// 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      }613614      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    }626627    /// <summary>628    /// Write an entry to the archive. This method will call the putNextEntry629    /// 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 a632    /// 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);  655656      try657      { - 0658         if ( recurse ) { - 0659          TarHeader.SetValueDefaults(sourceEntry.UserId, sourceEntry.UserName, - 0660                         sourceEntry.GroupId, sourceEntry.GroupName);661        } - 0662        WriteEntryCore(sourceEntry, recurse); - 0663      }664      finally665      { - 0666         if ( recurse ) { - 0667          TarHeader.RestoreSetValues();668        } - 0669      } - 0670    }671672    /// <summary>673    /// Write an entry to the archive. This method will call the putNextEntry674    /// and then write the contents of the entry, and finally call closeEntry()675    /// for entries that are files. For directories, it will call putNextEntry(),676    /// and then, if the recurse flag is true, process each entry that is a677    /// child of the directory.678    /// </summary>679    /// <param name="sourceEntry">680    /// The TarEntry representing the entry to write to the archive.681    /// </param>682    /// <param name="recurse">683    /// If true, process the children of directory entries.684    /// </param>685    void WriteEntryCore(TarEntry sourceEntry, bool recurse)686    { - 0687      string tempFileName = null; - 0688      string entryFilename   = sourceEntry.File;689 - 0690      var entry = (TarEntry)sourceEntry.Clone();691 - 0692       if ( applyUserInfoOverrides ) { - 0693        entry.GroupId = groupId; - 0694        entry.GroupName = groupName; - 0695        entry.UserId = userId; - 0696        entry.UserName = userName; + 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      OnProgressMessageEvent(entry, null); + 0699      tarOut.PutNextEntry(entry);  700 - 0701       if (asciiTranslate && !entry.IsDirectory) {702 - 0703         if (!IsBinary(entryFilename)) { - 0704          tempFileName = Path.GetTempFileName();705 - 0706          using (StreamReader inStream  = File.OpenText(entryFilename)) { - 0707            using (Stream outStream = File.Create(tempFileName)) {708 - 0709              while (true) { - 0710                string line = inStream.ReadLine(); - 0711                 if (line == null) {712                  break;713                } - 0714                byte[] data = Encoding.ASCII.GetBytes(line); - 0715                outStream.Write(data, 0, data.Length); - 0716                outStream.WriteByte((byte)'\n');717              }718 - 0719              outStream.Flush(); - 0720            }721          }722 - 0723          entry.Size = new FileInfo(tempFileName).Length; - 0724          entryFilename = tempFileName;725        }726      }727 - 0728      string newName = null; + 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 - 0730       if (rootPath != null) { - 0731         if (entry.Name.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase)) { - 0732          newName = entry.Name.Substring(rootPath.Length + 1 );733        }734      }735 - 0736       if (pathPrefix != null) { - 0737        newName = (newName == null) ? pathPrefix + "/" + entry.Name : pathPrefix + "/" + newName;738      }739 - 0740       if (newName != null) { - 0741        entry.Name = newName;742      }743 - 0744      tarOut.PutNextEntry(entry);745 - 0746       if (entry.IsDirectory) { - 0747         if (recurse) { - 0748          TarEntry[] list = entry.GetDirectoryEntries(); - 0749           for (int i = 0; i < list.Length; ++i) { - 0750            WriteEntryCore(list[i], recurse);751          }752        } - 0753      }754      else { - 0755        using (Stream inputStream = File.OpenRead(entryFilename)) { - 0756          byte[] localBuffer = new byte[32 * 1024]; - 0757          while (true) { - 0758            int numRead = inputStream.Read(localBuffer, 0, localBuffer.Length);759 - 0760             if (numRead <=0) { - 0761              break;762            }763 - 0764            tarOut.Write(localBuffer, 0, numRead);765          }766        }767 - 0768         if ( !string.IsNullOrEmpty(tempFileName)) { - 0769          File.Delete(tempFileName);770        }771 - 0772        tarOut.CloseEntry();773      } - 0774    }775776        /// <summary>777        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.778        /// </summary>779        public void Dispose()780        { - 2781            Dispose(true); - 2782            GC.SuppressFinalize(this); - 2783        }784785      /// <summary>786    /// Releases the unmanaged resources used by the FileStream and optionally releases the managed resources.787    /// </summary>788    /// <param name="disposing">true to release both managed and unmanaged resources;789    /// false to release only unmanaged resources.</param>790    protected virtual void Dispose(bool disposing)791    { - 2792       if ( !isDisposed ) { - 2793        isDisposed = true; - 2794         if ( disposing ) { - 2795           if ( tarOut != null ) { - 1796            tarOut.Flush(); - 1797            tarOut.Close();798          }799 - 2800           if ( tarIn != null ) { - 1801            tarIn.Close();802          }803        }804      } - 2805        }806807    /// <summary>808    /// Closes the archive and releases any associated resources.809    /// </summary>810    public virtual void Close()811    { - 0812      Dispose(true); - 0813    }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    }738739    /// <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    }760761    /// <summary>762    /// Closes the archive and releases any associated resources.763    /// </summary>764    public virtual void Close()765    { + 0766      Dispose(true); + 0767    }768769    /// <summary>770    /// Ensures that resources are freed and other cleanup operations are performed771    /// when the garbage collector reclaims the <see cref="TarArchive"/>.772    /// </summary>773    ~TarArchive()774    { + 0775      Dispose(false); + 0776    }777778    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    }788789    // 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 binary792    // and that all non text files contain one of these values793    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    }810811    #region Instance Fields812    bool keepOldFiles;813    bool asciiTranslate;  814815    /// <summary>816    /// Ensures that resources are freed and other cleanup operations are performed817    /// when the garbage collector reclaims the <see cref="TarArchive"/>.818    /// </summary>819    ~TarArchive()820    { - 0821      Dispose(false); - 0822    }823824    static void EnsureDirectoryExists(string directoryName)825    { - 0826       if (!Directory.Exists(directoryName)) {827        try { - 0828          Directory.CreateDirectory(directoryName); - 0829        } - 0830        catch (Exception e) { - 0831          throw new TarException("Exception creating directory '" + directoryName + "', " + e.Message, e);832        }833      } - 0834    }835836    // TODO: TarArchive - Is there a better way to test for a text file?837    // It no longer reads entire files into memory but is still a weak test!838    // This assumes that byte values 0-7, 14-31 or 255 are binary839    // and that all non text files contain one of these values840    static bool IsBinary(string filename)841    { - 0842      using (FileStream fs = File.OpenRead(filename))843      { - 0844        int sampleSize = Math.Min(4096, (int)fs.Length); - 0845        byte[] content = new byte[sampleSize];846 - 0847        int bytesRead = fs.Read(content, 0, sampleSize);848 - 0849         for (int i = 0; i < bytesRead; ++i) { - 0850          byte b = content[i]; - 0851           if ( (b < 8) || ((b > 13) && (b < 32)) || (b == 255) ) { - 0852            return true;853          }854        } - 0855      } - 0856      return false; - 0857    }858859    #region Instance Fields860    bool keepOldFiles;861    bool asciiTranslate;862863    int    userId; - 2864    string userName = string.Empty;865    int    groupId; - 2866    string groupName = string.Empty;867868    string rootPath;869    string pathPrefix;870871    bool applyUserInfoOverrides;872873    TarInputStream  tarIn;874    TarOutputStream tarOut;875    bool isDisposed;876    #endregion877  }878}879880881/* The original Java file had this header:882  ** Authored by Timothy Gerard Endres883  ** <mailto:time@gjt.org>  <http://www.trustice.com>884  **885  ** This work has been placed into the public domain.886  ** You may use this work in any way and for any purpose you wish.887  **888  ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,889  ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR890  ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY891  ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR892  ** REDISTRIBUTION OF THIS SOFTWARE.893  **894  */895815    int userId; + 2816    string userName = string.Empty;817    int groupId; + 2818    string groupName = string.Empty;819820    string rootPath;821    string pathPrefix;822823    bool applyUserInfoOverrides;824825    TarInputStream tarIn;826    TarOutputStream tarOut;827    bool isDisposed;828    #endregion829  }830} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_TarBuffer.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_TarBuffer.htm index 85293171d..dc727f8d1 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_TarBuffer.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_TarBuffer.htm @@ -15,12 +15,12 @@

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:97 +Covered lines:96 Uncovered lines:50 -Coverable lines:147 -Total lines:624 -Line coverage:65.9% -Branch coverage:51.2% +Coverable lines:146 +Total lines:551 +Line coverage:65.7% +Branch coverage:50%

Metrics

@@ -38,7 +38,7 @@

Metrics

IsEOFBlock(...)500 IsEndOfArchiveBlock(...)58077.78 SkipBlock()400 -ReadBlock()477.7871.43 +ReadBlock()477.7857.14 ReadRecord()491.6771.43 GetCurrentBlockNum()100 GetCurrentRecordNum()100 @@ -54,632 +54,559 @@

#LineLine coverage - 1// TarBuffer.cs2// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team3//4// This program is free software; you can redistribute it and/or5// modify it under the terms of the GNU General Public License6// as published by the Free Software Foundation; either version 27// of the License, or (at your option) any later version.8//9// This program is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.13//14// You should have received a copy of the GNU General Public License15// along with this program; if not, write to the Free Software16// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.17//18// Linking this library statically or dynamically with other modules is19// making a combined work based on this library.  Thus, the terms and20// conditions of the GNU General Public License cover the whole21// combination.22//23// As a special exception, the copyright holders of this library give you24// permission to link this library with independent modules to produce an25// executable, regardless of the license terms of these independent26// modules, and to copy and distribute the resulting executable under27// terms of your choice, provided that you also meet, for each linked28// independent module, the terms and conditions of the license of that29// module.  An independent module is a module which is not derived from30// or based on this library.  If you modify this library, you may extend31// this exception to your version of the library, but you are not32// obligated to do so.  If you do not wish to do so, delete this33// exception statement from your version.3435using System;36using System.IO;3738namespace ICSharpCode.SharpZipLib.Tar39{4041  /// <summary>42  /// The TarBuffer class implements the tar archive concept43  /// of a buffered input stream. This concept goes back to the44  /// days of blocked tape drives and special io devices. In the45  /// C# universe, the only real function that this class46  /// performs is to ensure that files have the correct "record"47  /// size, or other tars will complain.48  /// <p>49  /// You should never have a need to access this class directly.50  /// TarBuffers are created by Tar IO Streams.51  /// </p>52  /// </summary>53  public class TarBuffer54  {5556/* A quote from GNU tar man file on blocking and records57   A `tar' archive file contains a series of blocks.  Each block58contains `BLOCKSIZE' bytes.  Although this format may be thought of as59being on magnetic tape, other media are often used.6061   Each file archived is represented by a header block which describes62the file, followed by zero or more blocks which give the contents of63the file.  At the end of the archive file there may be a block filled64with binary zeros as an end-of-file marker.  A reasonable system should65write a block of zeros at the end, but must not assume that such a66block exists when reading an archive.6768   The blocks may be "blocked" for physical I/O operations.  Each69record of N blocks is written with a single 'write ()'70operation.  On magnetic tapes, the result of such a write is a single71record.  When writing an archive, the last record of blocks should be72written at the full size, with blocks after the zero block containing73all zeros.  When reading an archive, a reasonable system should74properly handle an archive whose last record is shorter than the rest,75or which contains garbage records after a zero block.76*/1using System;2using System.IO;34namespace ICSharpCode.SharpZipLib.Tar5{6  /// <summary>7  /// The TarBuffer class implements the tar archive concept8  /// of a buffered input stream. This concept goes back to the9  /// days of blocked tape drives and special io devices. In the10  /// C# universe, the only real function that this class11  /// 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 TarBuffer19  {2021    /* A quote from GNU tar man file on blocking and records22       A `tar' archive file contains a series of blocks.  Each block23    contains `BLOCKSIZE' bytes.  Although this format may be thought of as24    being on magnetic tape, other media are often used.2526       Each file archived is represented by a header block which describes27    the file, followed by zero or more blocks which give the contents of28    the file.  At the end of the archive file there may be a block filled29    with binary zeros as an end-of-file marker.  A reasonable system should30    write a block of zeros at the end, but must not assume that such a31    block exists when reading an archive.3233       The blocks may be "blocked" for physical I/O operations.  Each34    record of N blocks is written with a single 'write ()'35    operation.  On magnetic tapes, the result of such a write is a single36    record.  When writing an archive, the last record of blocks should be37    written at the full size, with blocks after the zero block containing38    all zeros.  When reading an archive, a reasonable system should39    properly handle an archive whose last record is shorter than the rest,40    or which contains garbage records after a zero block.41    */4243    #region Constants44    /// <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;4950    /// <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;5758    /// <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    #endregion6667    /// <summary>68    /// Get the record size for this buffer69    /// </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    }  7778    #region Constants79    /// <summary>80    /// The size of a block in a tar archive in bytes.81    /// </summary>82    /// <remarks>This is 512 bytes.</remarks>83    public const int BlockSize = 512;8485    /// <summary>86    /// The number of blocks in a default record.87    /// </summary>88    /// <remarks>89    /// The default value is 20 blocks per record.90    /// </remarks>91    public const int DefaultBlockFactor = 20;9293    /// <summary>94    /// The size in bytes of a default record.95    /// </summary>96    /// <remarks>97    /// The default size is 10KB.98    /// </remarks>99    public const int DefaultRecordSize = BlockSize * DefaultBlockFactor;100    #endregion101102    /// <summary>103    /// Get the record size for this buffer104    /// </summary>105    /// <value>The record size in bytes.106    /// This is equal to the <see cref="BlockFactor"/> multiplied by the <see cref="BlockSize"/></value>107    public int RecordSize108    {109      get { - 2950110        return recordSize;111      }112    }113114    /// <summary>115    /// Get the TAR Buffer's record size.116    /// </summary>117    /// <returns>The record size in bytes.118    /// This is equal to the <see cref="BlockFactor"/> multiplied by the <see cref="BlockSize"/></returns>119    [Obsolete("Use RecordSize property instead")]120    public int GetRecordSize()121    { - 0122      return recordSize;123    }124125    /// <summary>126    /// Get the Blocking factor for the buffer127    /// </summary>128    /// <value>This is the number of blocks in each record.</value>129    public int BlockFactor {130      get { - 7940131        return blockFactor;132      }133    }134135    /// <summary>136    /// Get the TAR Buffer's block factor137    /// </summary>138    /// <returns>The block factor; the number of blocks per record.</returns>139    [Obsolete("Use BlockFactor property instead")]140    public int GetBlockFactor()141    { - 0142      return blockFactor;143    }144145    /// <summary>146    /// Construct a default TarBuffer147    /// </summary> - 1114148    protected TarBuffer()149    { - 1114150    }151152    /// <summary>153    /// Create TarBuffer for reading with default BlockFactor154    /// </summary>155    /// <param name="inputStream">Stream to buffer</param>156    /// <returns>A new <see cref="TarBuffer"/> suitable for input.</returns>157    public static TarBuffer CreateInputTarBuffer(Stream inputStream)158    { - 0159       if ( inputStream == null )160      { - 0161        throw new ArgumentNullException(nameof(inputStream));162      }163 - 0164      return CreateInputTarBuffer(inputStream, DefaultBlockFactor);165    }166167    /// <summary>168    /// Construct TarBuffer for reading inputStream setting BlockFactor169    /// </summary>170    /// <param name="inputStream">Stream to buffer</param>171    /// <param name="blockFactor">Blocking factor to apply</param>172    /// <returns>A new <see cref="TarBuffer"/> suitable for input.</returns>173    public static TarBuffer CreateInputTarBuffer(Stream inputStream, int blockFactor)174    { - 523175       if ( inputStream == null )176      { - 0177        throw new ArgumentNullException(nameof(inputStream));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    }8889    /// <summary>90    /// Get the Blocking factor for the buffer91    /// </summary>92    /// <value>This is the number of blocks in each record.</value>93    public int BlockFactor {94      get { + 419895        return blockFactor;96      }97    }9899    /// <summary>100    /// Get the TAR Buffer's block factor101    /// </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    }108109    /// <summary>110    /// Construct a default TarBuffer111    /// </summary> + 78112    protected TarBuffer()113    { + 78114    }115116    /// <summary>117    /// Create TarBuffer for reading with default BlockFactor118    /// </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    }129130    /// <summary>131    /// Construct TarBuffer for reading inputStream setting BlockFactor132    /// </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    }153154    /// <summary>155    /// Construct TarBuffer for writing with default BlockFactor156    /// </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    }167168    /// <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 - 523180       if ( blockFactor <= 0 )181      {182#if NETCF_1_0183        throw new ArgumentOutOfRangeException("blockFactor");184#else - 0185        throw new ArgumentOutOfRangeException(nameof(blockFactor), "Factor cannot be negative");186#endif187      } + 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 - 523189      var tarBuffer = new TarBuffer(); - 523190      tarBuffer.inputStream  = inputStream; - 523191      tarBuffer.outputStream = null; - 523192      tarBuffer.Initialize(blockFactor);193 - 523194      return tarBuffer;195    }196197    /// <summary>198    /// Construct TarBuffer for writing with default BlockFactor199    /// </summary>200    /// <param name="outputStream">output stream for buffer</param>201    /// <returns>A new <see cref="TarBuffer"/> suitable for output.</returns>202    public static TarBuffer CreateOutputTarBuffer(Stream outputStream)203    { - 0204       if ( outputStream == null )205      { - 0206        throw new ArgumentNullException(nameof(outputStream)); + 73189      return tarBuffer;190    }191192    /// <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      }208 - 0209      return CreateOutputTarBuffer(outputStream, DefaultBlockFactor);210    }211212    /// <summary>213    /// Construct TarBuffer for writing Tar output to streams.214    /// </summary>215    /// <param name="outputStream">Output stream to write to.</param>216    /// <param name="blockFactor">Blocking factor to apply</param>217    /// <returns>A new <see cref="TarBuffer"/> suitable for output.</returns>218    public static TarBuffer CreateOutputTarBuffer(Stream outputStream, int blockFactor)219    { - 591220       if ( outputStream == null )221      { - 0222        throw new ArgumentNullException(nameof(outputStream));223      }224 - 591225       if ( blockFactor <= 0 )226      {227#if NETCF_1_0228        throw new ArgumentOutOfRangeException("blockFactor");229#else - 0230        throw new ArgumentOutOfRangeException(nameof(blockFactor), "Factor cannot be negative");231#endif232      }233 - 591234      var tarBuffer = new TarBuffer(); - 591235      tarBuffer.inputStream  = null; - 591236      tarBuffer.outputStream = outputStream; - 591237      tarBuffer.Initialize(blockFactor); + 73208    }209210    /// <summary>211    /// Determine if an archive block indicates End of Archive. End of212    /// archive is indicated by a block that consists entirely of null bytes.213    /// All remaining blocks for the record should also be null's214    /// However some older tars only do a couple of null blocks (Old GNU tar for one)215    /// and also partial records216    /// </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 - 591239      return tarBuffer;240    }241242    /// <summary>243    /// Initialization common to all constructors.244    /// </summary>245    void Initialize(int archiveBlockFactor)246    { - 1114247      blockFactor  = archiveBlockFactor; - 1114248      recordSize   = archiveBlockFactor * BlockSize; - 1114249      recordBuffer  = new byte[RecordSize];250 - 1114251       if (inputStream != null) { - 523252        currentRecordIndex = -1; - 523253        currentBlockIndex = BlockFactor; - 523254      }255      else { - 591256        currentRecordIndex = 0; - 591257        currentBlockIndex = 0;258      } - 591259    }260261    /// <summary>262    /// Determine if an archive block indicates End of Archive. End of263    /// archive is indicated by a block that consists entirely of null bytes.264    /// All remaining blocks for the record should also be null's265    /// However some older tars only do a couple of null blocks (Old GNU tar for one)266    /// and also partial records267    /// </summary>268    /// <param name = "block">The data block to check.</param>269    /// <returns>Returns true if the block is an EOF block; false otherwise.</returns>270    [Obsolete("Use IsEndOfArchiveBlock instead")]271    public bool IsEOFBlock(byte[] block)239240    /// <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's244    /// However some older tars only do a couple of null blocks (Old GNU tar for one)245    /// and also partial records246    /// </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    }267268    /// <summary>269    /// Skip over a block on the input stream.270    /// </summary>271    public void SkipBlock()  272    { - 0273       if ( block == null ) { - 0274        throw new ArgumentNullException(nameof(block)); + 0273       if (inputStream == null) { + 0274        throw new TarException("no input stream defined");  275      }  276 - 0277       if ( block.Length != BlockSize )278      { - 0279        throw new ArgumentException("block length is invalid");280      }281 - 0282       for (int i = 0; i < BlockSize; ++i) { - 0283         if (block[i] != 0) { - 0284          return false;285        }286      }287 - 0288      return true;289    }290291292    /// <summary>293    /// Determine if an archive block indicates the End of an Archive has been reached.294    /// End of archive is indicated by a block that consists entirely of null bytes.295    /// All remaining blocks for the record should also be null's296    /// However some older tars only do a couple of null blocks (Old GNU tar for one)297    /// and also partial records298    /// </summary>299    /// <param name = "block">The data block to check.</param>300    /// <returns>Returns true if the block is an EOF block; false otherwise.</returns>301    public static bool IsEndOfArchiveBlock(byte[] block)302    { - 522303       if ( block == null ) { - 0304        throw new ArgumentNullException(nameof(block));305      }306 - 522307       if ( block.Length != BlockSize ) { - 0308        throw new ArgumentException("block length is invalid");309      } + 0277       if (currentBlockIndex >= BlockFactor) { + 0278         if (!ReadRecord()) { + 0279          throw new TarException("Failed to read a record");280        }281      }282 + 0283      currentBlockIndex++; + 0284    }285286    /// <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 - 3092311       for ( int i = 0; i < BlockSize; ++i ) { - 1544312         if ( block[i] != 0 ) { - 520313          return false;314        }315      }316 - 2317      return true;318    }319320    /// <summary>321    /// Skip over a block on the input stream.322    /// </summary>323    public void SkipBlock()324    { - 0325       if (inputStream == null) { - 0326        throw new TarException("no input stream defined");327      }328 - 0329       if (currentBlockIndex >= BlockFactor) { - 0330         if (!ReadRecord()) { - 0331          throw new TarException("Failed to read a record");332        }333      }334 - 0335      currentBlockIndex++; - 0336    }337338    /// <summary>339    /// Read a block from the input stream.340    /// </summary>341    /// <returns>342    /// The block of data read.343    /// </returns>344    public byte[] ReadBlock()345    { - 1357346       if (inputStream == null) { - 0347        throw new TarException("TarBuffer.ReadBlock - no input stream defined");348      }349 - 1357350       if (currentBlockIndex >= BlockFactor) { - 521351         if (!ReadRecord()) { - 0352          throw new TarException("Failed to read a record");353        }354      }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);330331        //332        // NOTE333        // We have found EOF, and the record is not full!334        //335        // This is a broken archive. It does not follow the standard336        // blocking algorithm. However, because we are generous, and337        // it requires little effort, we will simply ignore the error338        // and continue as if the entire record were read. This does339        // not appear to break anything upstream. We used to return340        // 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 - 1357356      byte[] result = new byte[BlockSize];357 - 1357358      Array.Copy(recordBuffer, (currentBlockIndex * BlockSize), result, 0, BlockSize ); - 1357359      currentBlockIndex++; - 1357360      return result;361    }362363    /// <summary>364    /// Read a record from data stream.365    /// </summary>366    /// <returns>367    /// false if End-Of-File, else true.368    /// </returns>369    bool ReadRecord()370    { - 521371       if (inputStream == null) { - 0372        throw new TarException("no input stream stream defined");373      }374 - 521375      currentBlockIndex = 0;376 - 521377      int offset = 0; - 521378      int bytesNeeded = RecordSize;379 - 1042380       while (bytesNeeded > 0) { - 521381        long numBytes = inputStream.Read(recordBuffer, offset, bytesNeeded);382383        //384        // NOTE385        // We have found EOF, and the record is not full!386        //387        // This is a broken archive. It does not follow the standard388        // blocking algorithm. However, because we are generous, and389        // it requires little effort, we will simply ignore the error390        // and continue as if the entire record were read. This does391        // not appear to break anything upstream. We used to return392        // false in this case.393        //394        // Thanks to 'Yohann.Roussel@alcatel.fr' for this fix.395        // - 521396         if (numBytes <= 0) {397          break;398        }399 - 521400        offset      += (int)numBytes; - 521401        bytesNeeded -= (int)numBytes;402      }403 - 521404      currentRecordIndex++; - 521405      return true;406    }407408    /// <summary>409    /// Get the current block number, within the current record, zero based.410    /// </summary>411        /// <remarks>Block numbers are zero based values</remarks>412        /// <seealso cref="RecordSize"/>413    public int CurrentBlock414    { - 0415      get { return currentBlockIndex; }416    }417418        /// <summary>419        /// Get/set flag indicating ownership of the underlying stream.420        /// When the flag is true <see cref="Close"></see> will close the underlying stream also.421        /// </summary>422        public bool IsStreamOwner423        { - 0424            get { return isStreamOwner_; } - 4425            set { isStreamOwner_ = value; }426        }427428    /// <summary>429    /// Get the current block number, within the current record, zero based.430    /// </summary>431    /// <returns>432    /// The current zero based block number.433    /// </returns>434    /// <remarks>435    /// The absolute block number = (<see cref="GetCurrentRecordNum">record number</see> * <see cref="BlockFactor">block436    /// </remarks>437    [Obsolete("Use CurrentBlock property instead")]438    public int GetCurrentBlockNum()439    { - 0440      return currentBlockIndex;441    }442443    /// <summary>444    /// Get the current record number.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    }364365    /// <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    }373374    /// <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">block382    /// </remarks>383    [Obsolete("Use CurrentBlock property instead")]384    public int GetCurrentBlockNum()385    { + 0386      return currentBlockIndex;387    }388389    /// <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    }398399    /// <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    }410411    /// <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    }440441    /// <summary>442    /// Write an archive record to the archive, where the record may be443    /// inside of a larger array buffer. The buffer must be "offset plus444    /// record size" long.  445    /// </summary>446    /// <returns>447    /// The current zero based record number.448    /// </returns>449    public int CurrentRecord450    { - 0451      get { return currentRecordIndex; }452    }453454    /// <summary>455    /// Get the current record number.456    /// </summary>457    /// <returns>458    /// The current zero based record number.459    /// </returns>460    [Obsolete("Use CurrentRecord property instead")]461    public int GetCurrentRecordNum()462    { - 0463      return currentRecordIndex;464    }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      }  465466    /// <summary>467    /// Write a block of data to the archive.468    /// </summary>469    /// <param name="block">470    /// The data to write to the archive.471    /// </param>472    public void WriteBlock(byte[] block)473    { - 2018474       if ( block == null ) { - 0475        throw new ArgumentNullException(nameof(block));476      } + 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 - 2018478       if (outputStream == null) { - 0479        throw new TarException("TarBuffer.WriteBlock - no output stream defined");480      }481 - 2018482       if (block.Length != BlockSize) { - 0483        string errorText = string.Format("TarBuffer.WriteBlock - block to write has length '{0}' which is not the block  - 0484          block.Length, BlockSize ); - 0485        throw new TarException(errorText);486      }487 - 2018488       if (currentBlockIndex >= BlockFactor) { - 4489        WriteRecord();490      }491 - 2018492      Array.Copy(block, 0, recordBuffer, (currentBlockIndex * BlockSize), BlockSize); - 2018493      currentBlockIndex++; - 2018494    }495496    /// <summary>497    /// Write an archive record to the archive, where the record may be498    /// inside of a larger array buffer. The buffer must be "offset plus499    /// record size" long.500    /// </summary>501    /// <param name="buffer">502    /// The buffer containing the record data to write.503    /// </param>504    /// <param name="offset">505    /// The offset of the record data within buffer.506    /// </param>507    public void WriteBlock(byte[] buffer, int offset)508    { - 4042509       if ( buffer == null ) { - 0510        throw new ArgumentNullException(nameof(buffer));511      }512 - 4042513       if (outputStream == null) { - 0514        throw new TarException("TarBuffer.WriteBlock - no output stream stream defined");515      } + 4042478      currentBlockIndex++; + 4042479    }480481    /// <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    }496497    /// <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 behaviour501    /// 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 - 4042517       if ( (offset < 0) || (offset >= buffer.Length) )518      { - 0519        throw new ArgumentOutOfRangeException(nameof(offset));520      }521 - 4042522       if ((offset + BlockSize) > buffer.Length) { - 0523        string errorText = string.Format("TarBuffer.WriteBlock - record has length '{0}' with offset '{1}' which is less - 0524          buffer.Length, offset, recordSize); - 0525        throw new TarException(errorText);526      }527 - 4042528       if (currentBlockIndex >= BlockFactor) { - 128529        WriteRecord();530      }531 - 4042532      Array.Copy(buffer, offset, recordBuffer, (currentBlockIndex * BlockSize), BlockSize);533 - 4042534      currentBlockIndex++; - 4042535    }536537    /// <summary>538    /// Write a TarBuffer record to the archive.539    /// </summary>540    void WriteRecord()541    { - 723542       if (outputStream == null) { - 0543        throw new TarException("TarBuffer.WriteRecord no output stream defined");544      }517    /// <summary>518    /// Close the TarBuffer. If this is an output buffer, also flush the519    /// 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    }537538    #region Instance Fields539    Stream inputStream;540    Stream outputStream;541542    byte[] recordBuffer;543    int currentBlockIndex;544    int currentRecordIndex;  545 - 723546      outputStream.Write(recordBuffer, 0, RecordSize); - 723547      outputStream.Flush();548 - 723549      currentBlockIndex = 0; - 723550      currentRecordIndex++; - 723551    }552553    /// <summary>554    /// WriteFinalRecord writes the current record buffer to output any unwritten data is present.555    /// </summary>556        /// <remarks>Any trailing bytes are set to zero which is by definition correct behaviour557        /// for the end of a tar stream.</remarks>558    void WriteFinalRecord()559    { - 591560       if (outputStream == null) { - 0561        throw new TarException("TarBuffer.WriteFinalRecord no output stream defined");562      }563 - 591564       if (currentBlockIndex > 0) { - 591565        int dataBytes = currentBlockIndex * BlockSize; - 591566        Array.Clear(recordBuffer, dataBytes, RecordSize - dataBytes); - 591567        WriteRecord();568      }569 - 591570      outputStream.Flush(); - 591571    }572573    /// <summary>574    /// Close the TarBuffer. If this is an output buffer, also flush the575    /// current block before closing.576    /// </summary>577    public void Close()578    { - 1114579       if (outputStream != null) { - 591580        WriteFinalRecord();581 - 591582                 if (isStreamOwner_) { - 590583                    outputStream.Close();584                } - 591585        outputStream = null; - 591586      } - 523587       else if (inputStream != null) { - 523588                 if (isStreamOwner_) { - 522589                    inputStream.Close();590                } - 523591        inputStream = null;592      } - 523593    }594595    #region Instance Fields596    Stream inputStream;597    Stream outputStream;598599    byte[] recordBuffer;600    int currentBlockIndex;601    int currentRecordIndex;602 - 1114603    int recordSize = DefaultRecordSize; - 1114604    int blockFactor = DefaultBlockFactor; - 1114605        bool isStreamOwner_ = true;606    #endregion607  }608}609610/* The original Java file had this header:611  *612  ** Authored by Timothy Gerard Endres613  ** <mailto:time@gjt.org>  <http://www.trustice.com>614  **615  ** This work has been placed into the public domain.616  ** You may use this work in any way and for any purpose you wish.617  **618  ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,619  ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR620  ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY621  ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR622  ** REDISTRIBUTION OF THIS SOFTWARE.623  **624  */ + 78546    int recordSize = DefaultRecordSize; + 78547    int blockFactor = DefaultBlockFactor; + 78548    bool isStreamOwner_ = true;549    #endregion550  }551} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_TarEntry.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_TarEntry.htm index 7bb78973b..6c370704b 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_TarEntry.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_TarEntry.htm @@ -15,12 +15,12 @@

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:66 -Uncovered lines:56 +Covered lines:61 +Uncovered lines:61 Coverable lines:122 -Total lines:559 -Line coverage:54% -Branch coverage:23.8% +Total lines:496 +Line coverage:50% +Branch coverage:21.4%

Metrics

@@ -33,7 +33,7 @@

Metrics

Clone()1100100 CreateTarEntry(...)1100100 CreateEntryFromFile(...)100 -Equals(...)27566.67 +Equals(...)200 GetHashCode()100 IsDescendent(...)200 SetIds(...)100 @@ -50,567 +50,504 @@

#LineLine coverage - 1// TarEntry.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;37using System.IO;3839namespace ICSharpCode.SharpZipLib.Tar40{41  /// <summary>42  /// This class represents an entry in a Tar archive. It consists43  /// of the entry's header, as well as the entry's File. Entries44  /// can be instantiated in one of three ways, depending on how45  /// they are to be used.46  /// <p>47  /// TarEntries that are created from the header bytes read from48  /// an archive are instantiated with the TarEntry( byte[] )49  /// constructor. These entries will be used when extracting from50  /// or listing the contents of an archive. These entries have their51  /// header filled in using the header bytes. They also set the File52  /// to null, since they reference an archive entry not a file.</p>53  /// <p>54  /// TarEntries that are created from files that are to be written55  /// into an archive are instantiated with the CreateEntryFromFile(string)56  /// pseudo constructor. These entries have their header filled in using57  /// the File's information. They also keep a reference to the File58  /// for convenience when writing entries.</p>59  /// <p>60  /// Finally, TarEntries can be constructed from nothing but a name.61  /// This allows the programmer to construct the entry by hand, for62  /// instance when only an InputStream is available for writing to63  /// the archive, and the header information is constructed from64  /// other information. In this case the header fields are set to65  /// defaults and the File is set to null.</p>66  /// <see cref="TarHeader"/>67  /// </summary>68  public class TarEntry : ICloneable69  {70    #region Constructors71    /// <summary>72    /// Initialise a default instance of <see cref="TarEntry"/>.73    /// </summary> - 59774    private TarEntry()75    { - 59776      header = new TarHeader(); - 59777    }7879    /// <summary>80    /// Construct an entry from an archive's header bytes. File is set81    /// to null.82    /// </summary>83    /// <param name = "headerBuffer">84    /// The header bytes from a tar archive entry.85    /// </param> - 51986    public TarEntry(byte[] headerBuffer)87    { - 51988      header = new TarHeader(); - 51989      header.ParseBuffer(headerBuffer); - 51990    }9192    /// <summary>93    /// Construct a TarEntry using the <paramref name="header">header</paramref> provided94    /// </summary>95    /// <param name="header">Header details for entry</param> - 196    public TarEntry(TarHeader header)97    { - 198       if ( header == null )99      { - 0100        throw new ArgumentNullException(nameof(header));101      }102 - 1103      this.header = (TarHeader)header.Clone(); - 1104    }105    #endregion106107    #region ICloneable Members108    /// <summary>109    /// Clone this tar entry.110    /// </summary>111    /// <returns>Returns a clone of this entry.</returns>112    public object Clone()113    { - 1114      var entry = new TarEntry(); - 1115      entry.file = file; - 1116      entry.header = (TarHeader)header.Clone(); - 1117      entry.Name = Name; - 1118      return entry;119    }120    #endregion121122    /// <summary>123    /// Construct an entry with only a <paramref name="name">name</paramref>.124    /// This allows the programmer to construct the entry's header "by hand".125    /// </summary>126    /// <param name="name">The name to use for the entry</param>127    /// <returns>Returns the newly created <see cref="TarEntry"/></returns>128    public static TarEntry CreateTarEntry(string name)129    { - 596130      var entry = new TarEntry(); - 596131      TarEntry.NameTarHeader(entry.header, name); - 596132      return entry;133    }134135    /// <summary>136    /// Construct an entry for a file. File is set to file, and the137    /// header is constructed from information from the file.138    /// </summary>139    /// <param name = "fileName">The file name that the entry represents.</param>140    /// <returns>Returns the newly created <see cref="TarEntry"/></returns>141    public static TarEntry CreateEntryFromFile(string fileName)142    { - 0143      var entry = new TarEntry(); - 0144      entry.GetFileTarHeader(entry.header, fileName); - 0145      return entry;146    }147148    /// <summary>149    /// Determine if the two entries are equal. Equality is determined150    /// by the header names being equal.151    /// </summary>152    /// <param name="obj">The <see cref="Object"/> to compare with the current Object.</param>153    /// <returns>154    /// True if the entries are equal; false if not.155    /// </returns>156    public override bool Equals(object obj)157    { - 1158      var localEntry = obj as TarEntry;159 - 1160       if ( localEntry != null )161      { - 1162        return Name.Equals(localEntry.Name);163      } - 0164      return false;165    }166167    /// <summary>168    /// Derive a Hash value for the current <see cref="Object"/>169    /// </summary>170    /// <returns>A Hash code for the current <see cref="Object"/></returns>171    public override int GetHashCode()172    { - 0173      return Name.GetHashCode();174    }175176    /// <summary>177    /// Determine if the given entry is a descendant of this entry.178    /// Descendancy is determined by the name of the descendant179    /// starting with this entry's name.180    /// </summary>181    /// <param name = "toTest">182    /// Entry to be checked as a descendent of this.183    /// </param>184    /// <returns>185    /// True if entry is a descendant of this.186    /// </returns>187    public bool IsDescendent(TarEntry toTest)188    { - 0189       if ( toTest == null ) { - 0190        throw new ArgumentNullException(nameof(toTest));191      }192 - 0193      return toTest.Name.StartsWith(Name, StringComparison.Ordinal);194    }195196    /// <summary>197    /// Get this entry's header.198    /// </summary>199    /// <returns>200    /// This entry's TarHeader.201    /// </returns>202    public TarHeader TarHeader203    {204      get { - 2269205        return header;206      }207    }208209    /// <summary>210    /// Get/Set this entry's name.211    /// </summary>212    public string Name213    {214      get { - 1110215        return header.Name;216      }217      set { - 419218        header.Name = value; - 418219      }220    }221222    /// <summary>223    /// Get/set this entry's user id.224    /// </summary>225    public int UserId226    {227      get { - 0228        return header.UserId;229      }230      set { - 1231        header.UserId = value; - 1232      }233    }234235    /// <summary>236    /// Get/set this entry's group id.237    /// </summary>238    public int GroupId239    {240      get { - 2241        return header.GroupId;242      }243      set { - 2244        header.GroupId = value; - 2245      }246    }247248    /// <summary>249    /// Get/set this entry's user name.250    /// </summary>251    public string UserName252    {253      get { - 2254        return header.UserName;255      }256      set { - 3257        header.UserName = value; - 3258      }259    }1using System;2using System.IO;34namespace ICSharpCode.SharpZipLib.Tar5{6  /// <summary>7  /// This class represents an entry in a Tar archive. It consists8  /// of the entry's header, as well as the entry's File. Entries9  /// can be instantiated in one of three ways, depending on how10  /// they are to be used.11  /// <p>12  /// TarEntries that are created from the header bytes read from13  /// an archive are instantiated with the TarEntry( byte[] )14  /// constructor. These entries will be used when extracting from15  /// or listing the contents of an archive. These entries have their16  /// header filled in using the header bytes. They also set the File17  /// 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 written20  /// into an archive are instantiated with the CreateEntryFromFile(string)21  /// pseudo constructor. These entries have their header filled in using22  /// the File's information. They also keep a reference to the File23  /// 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, for27  /// instance when only an InputStream is available for writing to28  /// the archive, and the header information is constructed from29  /// other information. In this case the header fields are set to30  /// defaults and the File is set to null.</p>31  /// <see cref="TarHeader"/>32  /// </summary>33  public class TarEntry : ICloneable34  {35    #region Constructors36    /// <summary>37    /// Initialise a default instance of <see cref="TarEntry"/>.38    /// </summary> + 7939    private TarEntry()40    { + 7941      header = new TarHeader(); + 7942    }4344    /// <summary>45    /// Construct an entry from an archive's header bytes. File is set46    /// 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    }5657    /// <summary>58    /// Construct a TarEntry using the <paramref name="header">header</paramref> provided59    /// </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    #endregion7071    #region ICloneable Members72    /// <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    #endregion8586    /// <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    }9899    /// <summary>100    /// Construct an entry for a file. File is set to file, and the101    /// 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    }111112    /// <summary>113    /// Determine if the two entries are equal. Equality is determined114    /// 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    }129130    /// <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    }138139    /// <summary>140    /// Determine if the given entry is a descendant of this entry.141    /// Descendancy is determined by the name of the descendant142    /// 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    }158159    /// <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    }170171    /// <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    }182183    /// <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    }194195    /// <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    }206207    /// <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    }218219    /// <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    }230231    /// <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    }245246    /// <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 this entry's group name.262    /// Get/Set the modification time for this entry  263    /// </summary>264    public string GroupName265    {266      get { - 3267        return header.GroupName;268      }269      set { - 3270        header.GroupName = value; - 3271      }272    }273274    /// <summary>275    /// Convenience method to set this entry's group and user ids.276    /// </summary>277    /// <param name="userId">278    /// This entry's new user id.279    /// </param>280    /// <param name="groupId">281    /// This entry's new group id.282    /// </param>283    public void SetIds(int userId, int groupId)284    { - 0285      UserId  = userId; - 0286      GroupId = groupId; - 0287    }288289    /// <summary>290    /// Convenience method to set this entry's group and user names.291    /// </summary>292    /// <param name="userName">293    /// This entry's new user name.294    /// </param>295    /// <param name="groupName">296    /// This entry's new group name.297    /// </param>298    public void SetNames(string userName, string groupName)299    { - 0300      UserName  = userName; - 0301      GroupName = groupName; - 0302    }303304    /// <summary>305    /// Get/Set the modification time for this entry306    /// </summary>307    public DateTime ModTime {308      get { - 3309        return header.ModTime;310      }311      set { - 3312        header.ModTime = value; - 2313      }314    }315316    /// <summary>317    /// Get this entry's file.318    /// </summary>319    /// <returns>320    /// This entry's file.321    /// </returns>322    public string File {323      get { - 2324        return file;325      }326    }327328    /// <summary>329    /// Get/set this entry's recorded file size.330    /// </summary>331    public long Size {332      get { - 1109333        return header.Size;334      }335      set { - 70336        header.Size = value; - 69337      }338    }339340    /// <summary>341    /// Return true if this entry represents a directory, false otherwise342    /// </summary>343    /// <returns>344    /// True if this entry is a directory.345    /// </returns>346    public bool IsDirectory {347      get { - 590348         if (file != null) { - 0349          return Directory.Exists(file);350        }351 - 590352         if (header != null) { - 590353           if ((header.TypeFlag == TarHeader.LF_DIR) || Name.EndsWith("/", StringComparison.Ordinal)) { - 0354            return true;355          }356        } - 590357        return false;358      }359    }360361    /// <summary>362    /// Fill in a TarHeader with information from a File.363    /// </summary>364    /// <param name="header">365    /// The TarHeader to fill in.366    /// </param>367    /// <param name="file">368    /// The file from which to get the header information.369    /// </param>370    public void GetFileTarHeader(TarHeader header, string file)371    { - 0372       if ( header == null ) { - 0373        throw new ArgumentNullException(nameof(header));374      }375 - 0376       if ( file == null ) { - 0377        throw new ArgumentNullException(nameof(file));378      }379 - 0380      this.file = file;381382      // bugfix from torhovl from #D forum: - 0383      string name = file;384385#if !NETCF_1_0 && !NETCF_2_0386      // 23-Jan-2004 GnuTar allows device names in path where the name is not local to the current directory - 0387       if (name.IndexOf(Environment.CurrentDirectory, StringComparison.Ordinal) == 0) { - 0388        name = name.Substring(Environment.CurrentDirectory.Length);264    public DateTime ModTime {265      get { + 2266        return header.ModTime;267      }268      set { + 2269        header.ModTime = value; + 1270      }271    }272273    /// <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    }284285    /// <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    }296297    /// <summary>298    /// Return true if this entry represents a directory, false otherwise299    /// </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    }317318    /// <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;338339      // bugfix from torhovl from #D forum: + 0340      string name = file;341342      // 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      }346347      /*348            if (Path.DirectorySeparatorChar == '\\')349            {350              // check if the OS is Windows351              // Strip off drive letters!352              if (name.Length > 2)353              {354                char ch1 = name[0];355                char ch2 = name[1];356357                if (ch2 == ':' && Char.IsLetter(ch1))358                {359                  name = name.Substring(2);360                }361              }362            }363      */364 + 0365      name = name.Replace(Path.DirectorySeparatorChar, '/');366367      // No absolute pathnames368      // 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#endif391392/*393      if (Path.DirectorySeparatorChar == '\\')394      {395        // check if the OS is Windows396        // Strip off drive letters!397        if (name.Length > 2)398        {399          char ch1 = name[0];400          char ch2 = name[1];401402          if (ch2 == ':' && Char.IsLetter(ch1))403          {404            name = name.Substring(2);405          }406        }390 + 0391      header.ModTime = System.IO.File.GetLastWriteTime(file.Replace('/', Path.DirectorySeparatorChar)).ToUniversalTime() + 0392      header.DevMajor = 0; + 0393      header.DevMinor = 0; + 0394    }395396    /// <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*/409 - 0410      name = name.Replace(Path.DirectorySeparatorChar, '/');408 + 0409      string[] list = Directory.GetFileSystemEntries(file); + 0410      TarEntry[] result = new TarEntry[list.Length];  411412      // No absolute pathnames413      // Windows (and Posix?) paths can start with UNC style "\\NetworkDrive\",414      // so we loop on starting /'s. - 0415       while (name.StartsWith("/", StringComparison.Ordinal)) { - 0416        name = name.Substring(1);417      } + 0412       for (int i = 0; i < list.Length; ++i) { + 0413        result[i] = TarEntry.CreateEntryFromFile(list[i]);414      }415 + 0416      return result;417    }  418 - 0419      header.LinkName = String.Empty; - 0420      header.Name     = name;421 - 0422       if (Directory.Exists(file)) { - 0423        header.Mode     = 1003; // Magic number for security access for a UNIX filesystem - 0424        header.TypeFlag = TarHeader.LF_DIR; - 0425         if ( (header.Name.Length == 0) || header.Name[header.Name.Length - 1] != '/') { - 0426          header.Name = header.Name + "/";427        }428 - 0429        header.Size     = 0; - 0430      } else { - 0431        header.Mode     = 33216; // Magic number for security access for a UNIX filesystem - 0432        header.TypeFlag = TarHeader.LF_NORMAL; - 0433        header.Size     = new FileInfo(file.Replace('/', Path.DirectorySeparatorChar)).Length;434      }435 - 0436      header.ModTime = System.IO.File.GetLastWriteTime(file.Replace('/', Path.DirectorySeparatorChar)).ToUniversalTime() - 0437      header.DevMajor = 0; - 0438      header.DevMinor = 0; - 0439    }440441    /// <summary>442    /// Get entries for all files present in this entries directory.443    /// If this entry doesnt represent a directory zero entries are returned.444    /// </summary>445    /// <returns>446    /// An array of TarEntry's for this entry's children.447    /// </returns>448    public TarEntry[] GetDirectoryEntries()449    { - 0450       if ( (file == null) || !Directory.Exists(file)) { - 0451        return new TarEntry[0];452      }453 - 0454      string[]   list   = Directory.GetFileSystemEntries(file); - 0455      TarEntry[] result = new TarEntry[list.Length];456 - 0457       for (int i = 0; i < list.Length; ++i) { - 0458        result[i] = TarEntry.CreateEntryFromFile(list[i]);459      }460 - 0461      return result;462    }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    }429430    /// <summary>431    /// Convenience method that will modify an entry's name directly432    /// 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    }444445    /// <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      }  463464    /// <summary>465    /// Write an entry's header information to a header buffer.466    /// </summary>467    /// <param name = "outBuffer">468    /// The tar entry header buffer to fill in.469    /// </param>470    public void WriteEntryHeader(byte[] outBuffer)471    { - 588472      header.WriteHeader(outBuffer); - 588473    }474475    /// <summary>476    /// Convenience method that will modify an entry's name directly477    /// in place in an entry header buffer byte array.478    /// </summary>479    /// <param name="buffer">480    /// The buffer containing the entry header to modify.481    /// </param>482    /// <param name="newName">483    /// The new name to place into the header buffer.484    /// </param>485    static public void AdjustEntryName(byte[] buffer, string newName)486    { - 0487      TarHeader.GetNameBytes(newName, buffer, 0, TarHeader.NAMELEN); - 0488    } + 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    }483484    #region Instance Fields485    /// <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    /// Fill in a TarHeader given only the entry's name.491    /// The entry's header information.  492    /// </summary>493    /// <param name="header">494    /// The TarHeader to fill in.495    /// </param>496    /// <param name="name">497    /// The tar entry name.498    /// </param>499    static public void NameTarHeader(TarHeader header, string name)500    { - 596501       if ( header == null ) { - 0502        throw new ArgumentNullException(nameof(header));503      }504 - 596505       if ( name == null ) { - 0506        throw new ArgumentNullException(nameof(name));507      }508 - 596509      bool isDir = name.EndsWith("/", StringComparison.Ordinal);510 - 596511      header.Name = name; - 596512       header.Mode = isDir ? 1003 : 33216; - 596513      header.UserId   = 0; - 596514      header.GroupId  = 0; - 596515      header.Size     = 0;516 - 596517      header.ModTime  = DateTime.UtcNow;518 - 596519       header.TypeFlag = isDir ? TarHeader.LF_DIR : TarHeader.LF_NORMAL;520 - 596521      header.LinkName  = String.Empty; - 596522      header.UserName  = String.Empty; - 596523      header.GroupName = String.Empty;524 - 596525      header.DevMajor = 0; - 596526      header.DevMinor = 0; - 596527    }528529    #region Instance Fields530    /// <summary>531    /// The name of the file this entry represents or null if the entry is not based on a file.532    /// </summary>533    string file;534535    /// <summary>536    /// The entry's header information.537    /// </summary>538    TarHeader  header;539    #endregion540  }541}542543544545/* The original Java file had this header:546  *547  ** Authored by Timothy Gerard Endres548  ** <mailto:time@gjt.org>  <http://www.trustice.com>549  **550  ** This work has been placed into the public domain.551  ** You may use this work in any way and for any purpose you wish.552  **553  ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,554  ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR555  ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY556  ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR557  ** REDISTRIBUTION OF THIS SOFTWARE.558  **559  */493    TarHeader header;494    #endregion495  }496} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_TarException.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_TarException.htm index 01d57ce2f..36647d078 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_TarException.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_TarException.htm @@ -18,7 +18,7 @@

Summary

Covered lines:2 Uncovered lines:6 Coverable lines:8 -Total lines:91 +Total lines:48 Line coverage:25% @@ -37,99 +37,56 @@

#LineLine coverage - 1// TarException.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;1using System;2using System.Runtime.Serialization;34namespace ICSharpCode.SharpZipLib.Tar5{6  /// <summary>7  /// TarException represents exceptions specific to Tar classes and code.8  /// </summary>9  [Serializable]10  public class TarException : SharpZipBaseException11  {12    /// <summary>13    /// Deserialization constructor14    /// </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    }2122    /// <summary>23    /// Initialise a new instance of <see cref="TarException" />.24    /// </summary> + 025    public TarException()26    { + 027    }2829    /// <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    }  3738#if !NETCF_1_0 && !NETCF_2_039using System.Runtime.Serialization;40#endif4142namespace ICSharpCode.SharpZipLib.Tar {4344  /// <summary>45  /// TarExceptions are used for exceptions specific to tar classes and code.46  /// </summary>47#if !NETCF_1_0 && !NETCF_2_048  [Serializable]49#endif50  public class TarException : SharpZipBaseException51  {52#if !NETCF_1_0 && !NETCF_2_053    /// <summary>54    /// Deserialization constructor55    /// </summary>56    /// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>57    /// <param name="context"><see cref="StreamingContext"/> for this constructor</param>58    protected TarException(SerializationInfo info, StreamingContext context) - 059      : base(info, context)6061    { - 062    }63#endif6465    /// <summary>66    /// Initialises a new instance of the TarException class.67    /// </summary> - 068    public TarException()69    { - 070    }7172    /// <summary>73    /// Initialises a new instance of the TarException class with a specified message.74    /// </summary>75    /// <param name="message">The message that describes the error.</param>76    public TarException(string message) - 177      : base(message)78    { - 179    }8081    /// <summary>82    ///83    /// </summary>84    /// <param name="message">A message describing the error.</param>85    /// <param name="exception">The exception that is the cause of the current exception.</param>86    public TarException(string message, Exception exception) - 087      : base(message, exception)88    { - 089    }90  }91}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/Documentation/opencover/ICSharpCode.SharpZipLib_TarHeader.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_TarHeader.htm index d71a9c26a..0b6d2fa9a 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_TarHeader.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_TarHeader.htm @@ -15,12 +15,12 @@

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:217 -Uncovered lines:52 -Coverable lines:269 -Total lines:1180 -Line coverage:80.6% -Branch coverage:69.2% +Covered lines:209 +Uncovered lines:63 +Coverable lines:272 +Total lines:1077 +Line coverage:76.8% +Branch coverage:66.9%

Metrics

@@ -30,7 +30,7 @@

Metrics

.ctor()1100100 GetName()100 Clone()1100100 -ParseBuffer(...)296.9766.67 +ParseBuffer(...)463.1642.86 WriteHeader(...)689.6672.73 GetHashCode()100 Equals(...)1683.3366.67 @@ -40,7 +40,7 @@

Metrics

ParseOctal(...)893.3373.33 ParseName(...)773.3369.23 GetNameBytes(...)300 -GetNameBytes(...)683.3381.82 +GetNameBytes(...)683.3372.73 GetNameBytes(...)300 GetNameBytes(...)36060 GetAsciiBytes(...)577.7877.78 @@ -59,1188 +59,1085 @@

#LineLine coverage - 1// TarHeader.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536// HISTORY37//  27-07-2012  Z-1647  Added handling of Tar formats for files over 8GB such as Posix and Pax3839/* The tar format and its POSIX successor PAX have a long history which makes for compatability40   issues when creating and reading files.4142   This is further complicated by a large number of programs with variations on formats43   One common issue is the handling of names longer than 100 characters.44   GNU style long names are currently supported.4546This is the ustar (Posix 1003.1) header.4748struct header49{50  char t_name[100];          //   0 Filename51  char t_mode[8];            // 100 Permissions52  char t_uid[8];             // 108 Numerical User ID53  char t_gid[8];             // 116 Numerical Group ID54  char t_size[12];           // 124 Filesize55  char t_mtime[12];          // 136 st_mtime56  char t_chksum[8];          // 148 Checksum57  char t_typeflag;           // 156 Type of File58  char t_linkname[100];      // 157 Target of Links59  char t_magic[6];           // 257 "ustar" or other...60  char t_version[2];         // 263 Version fixed to 0061  char t_uname[32];          // 265 User Name62  char t_gname[32];          // 297 Group Name63  char t_devmajor[8];        // 329 Major for devices64  char t_devminor[8];        // 337 Minor for devices65  char t_prefix[155];        // 345 Prefix for t_name66  char t_mfill[12];          // 500 Filler up to 51267};1using System;2using System.Text;34namespace ICSharpCode.SharpZipLib.Tar5{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 compatability12  ///    issues when creating and reading files.13  ///14  ///    This is further complicated by a large number of programs with variations on formats15  ///    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 header21  /// {22  ///   char t_name[100];          //   0 Filename23  ///   char t_mode[8];            // 100 Permissions24  ///   char t_uid[8];             // 108 Numerical User ID25  ///   char t_gid[8];             // 116 Numerical Group ID26  ///   char t_size[12];           // 124 Filesize27  ///   char t_mtime[12];          // 136 st_mtime28  ///   char t_chksum[8];          // 148 Checksum29  ///   char t_typeflag;           // 156 Type of File30  ///   char t_linkname[100];      // 157 Target of Links31  ///   char t_magic[6];           // 257 "ustar" or other...32  ///   char t_version[2];         // 263 Version fixed to 0033  ///   char t_uname[32];          // 265 User Name34  ///   char t_gname[32];          // 297 Group Name35  ///   char t_devmajor[8];        // 329 Major for devices36  ///   char t_devminor[8];        // 337 Minor for devices37  ///   char t_prefix[155];        // 345 Prefix for t_name38  ///   char t_mfill[12];          // 500 Filler up to 51239  /// };40  /// </remarks>41  public class TarHeader : ICloneable42  {43    #region Constants44    /// <summary>45    /// The length of the name field in a header buffer.46    /// </summary>47    public const int NAMELEN = 100;4849    /// <summary>50    /// The length of the mode field in a header buffer.51    /// </summary>52    public const int MODELEN = 8;5354    /// <summary>55    /// The length of the user id field in a header buffer.56    /// </summary>57    public const int UIDLEN = 8;5859    /// <summary>60    /// The length of the group id field in a header buffer.61    /// </summary>62    public const int GIDLEN = 8;6364    /// <summary>65    /// The length of the checksum field in a header buffer.66    /// </summary>67    public const int CHKSUMLEN = 8;  6869*/7071using System;72using System.Text;69    /// <summary>70    /// Offset of checksum in a header buffer.71    /// </summary>72    public const int CHKSUMOFS = 148;  7374namespace ICSharpCode.SharpZipLib.Tar75{767778  /// <summary>79  /// This class encapsulates the Tar Entry Header used in Tar Archives.80  /// The class also holds a number of tar constants, used mostly in headers.81  /// </summary>82  public class TarHeader : ICloneable83  {84    #region Constants85    /// <summary>86    /// The length of the name field in a header buffer.87    /// </summary>88    public const int NAMELEN = 100;8990    /// <summary>91    /// The length of the mode field in a header buffer.92    /// </summary>93    public const int MODELEN = 8;9495    /// <summary>96    /// The length of the user id field in a header buffer.97    /// </summary>98    public const int UIDLEN = 8;99100    /// <summary>101    /// The length of the group id field in a header buffer.102    /// </summary>103    public const int GIDLEN = 8;104105    /// <summary>106    /// The length of the checksum field in a header buffer.107    /// </summary>108    public const int CHKSUMLEN = 8;109110    /// <summary>111    /// Offset of checksum in a header buffer.112    /// </summary>113    public const int CHKSUMOFS = 148;114115    /// <summary>116    /// The length of the size field in a header buffer.117    /// </summary>118    public const int SIZELEN = 12;119120    /// <summary>121    /// The length of the magic field in a header buffer.122    /// </summary>123    public const int MAGICLEN = 6;124125    /// <summary>126    /// The length of the version field in a header buffer.127    /// </summary>128    public const int VERSIONLEN = 2;129130    /// <summary>131    /// The length of the modification time field in a header buffer.132    /// </summary>133    public const int MODTIMELEN = 12;134135    /// <summary>136    /// The length of the user name field in a header buffer.137    /// </summary>138    public const int UNAMELEN = 32;139140    /// <summary>141    /// The length of the group name field in a header buffer.142    /// </summary>143    public const int GNAMELEN = 32;144145    /// <summary>146    /// The length of the devices field in a header buffer.147    /// </summary>148    public const int DEVLEN = 8;149150    //151    // LF_ constants represent the "type" of an entry152    //153154    /// <summary>155    ///  The "old way" of indicating a normal file.156    /// </summary>157    public const byte  LF_OLDNORM  = 0;158159    /// <summary>160    /// Normal file type.161    /// </summary>162    public const byte  LF_NORMAL  = (byte) '0';163164    /// <summary>165    /// Link file type.166    /// </summary>167    public const byte  LF_LINK    = (byte) '1';168169    /// <summary>170    /// Symbolic link file type.171    /// </summary>172    public const byte  LF_SYMLINK  = (byte) '2';173174    /// <summary>175    /// Character device file type.176    /// </summary>177    public const byte  LF_CHR    = (byte) '3';178179    /// <summary>180    /// Block device file type.181    /// </summary>182    public const byte  LF_BLK    = (byte) '4';183184    /// <summary>185    /// Directory file type.186    /// </summary>187    public const byte  LF_DIR    = (byte) '5';188189    /// <summary>190    /// FIFO (pipe) file type.191    /// </summary>192    public const byte  LF_FIFO    = (byte) '6';193194    /// <summary>195    /// Contiguous file type.196    /// </summary>197    public const byte  LF_CONTIG  = (byte) '7';198199    /// <summary>200    /// Posix.1 2001 global extended header201    /// </summary>202    public const byte   LF_GHDR    = (byte) 'g';203204    /// <summary>205    /// Posix.1 2001 extended header206    /// </summary>207    public const byte   LF_XHDR    = (byte) 'x';208209    // POSIX allows for upper case ascii type as extensions210211    /// <summary>212    /// Solaris access control list file type213    /// </summary>214    public const byte   LF_ACL            = (byte) 'A';215216    /// <summary>217    /// GNU dir dump file type218    /// This is a dir entry that contains the names of files that were in the219    /// dir at the time the dump was made220    /// </summary>221    public const byte   LF_GNU_DUMPDIR    = (byte) 'D';222223    /// <summary>224    /// Solaris Extended Attribute File225    /// </summary>226    public const byte   LF_EXTATTR        = (byte) 'E' ;227228    /// <summary>229    /// Inode (metadata only) no file content230    /// </summary>231    public const byte   LF_META           = (byte) 'I';232233    /// <summary>234    /// Identifies the next file on the tape as having a long link name235    /// </summary>236    public const byte   LF_GNU_LONGLINK   = (byte) 'K';237238    /// <summary>239    /// Identifies the next file on the tape as having a long name240    /// </summary>241    public const byte   LF_GNU_LONGNAME   = (byte) 'L';74    /// <summary>75    /// The length of the size field in a header buffer.76    /// </summary>77    public const int SIZELEN = 12;7879    /// <summary>80    /// The length of the magic field in a header buffer.81    /// </summary>82    public const int MAGICLEN = 6;8384    /// <summary>85    /// The length of the version field in a header buffer.86    /// </summary>87    public const int VERSIONLEN = 2;8889    /// <summary>90    /// The length of the modification time field in a header buffer.91    /// </summary>92    public const int MODTIMELEN = 12;9394    /// <summary>95    /// The length of the user name field in a header buffer.96    /// </summary>97    public const int UNAMELEN = 32;9899    /// <summary>100    /// The length of the group name field in a header buffer.101    /// </summary>102    public const int GNAMELEN = 32;103104    /// <summary>105    /// The length of the devices field in a header buffer.106    /// </summary>107    public const int DEVLEN = 8;108109    /// <summary>110    /// The length of the name prefix field in a header buffer.111    /// </summary>112    public const int PREFIXLEN = 155;113114    //115    // LF_ constants represent the "type" of an entry116    //117118    /// <summary>119    ///  The "old way" of indicating a normal file.120    /// </summary>121    public const byte LF_OLDNORM = 0;122123    /// <summary>124    /// Normal file type.125    /// </summary>126    public const byte LF_NORMAL = (byte)'0';127128    /// <summary>129    /// Link file type.130    /// </summary>131    public const byte LF_LINK = (byte)'1';132133    /// <summary>134    /// Symbolic link file type.135    /// </summary>136    public const byte LF_SYMLINK = (byte)'2';137138    /// <summary>139    /// Character device file type.140    /// </summary>141    public const byte LF_CHR = (byte)'3';142143    /// <summary>144    /// Block device file type.145    /// </summary>146    public const byte LF_BLK = (byte)'4';147148    /// <summary>149    /// Directory file type.150    /// </summary>151    public const byte LF_DIR = (byte)'5';152153    /// <summary>154    /// FIFO (pipe) file type.155    /// </summary>156    public const byte LF_FIFO = (byte)'6';157158    /// <summary>159    /// Contiguous file type.160    /// </summary>161    public const byte LF_CONTIG = (byte)'7';162163    /// <summary>164    /// Posix.1 2001 global extended header165    /// </summary>166    public const byte LF_GHDR = (byte)'g';167168    /// <summary>169    /// Posix.1 2001 extended header170    /// </summary>171    public const byte LF_XHDR = (byte)'x';172173    // POSIX allows for upper case ascii type as extensions174175    /// <summary>176    /// Solaris access control list file type177    /// </summary>178    public const byte LF_ACL = (byte)'A';179180    /// <summary>181    /// GNU dir dump file type182    /// This is a dir entry that contains the names of files that were in the183    /// dir at the time the dump was made184    /// </summary>185    public const byte LF_GNU_DUMPDIR = (byte)'D';186187    /// <summary>188    /// Solaris Extended Attribute File189    /// </summary>190    public const byte LF_EXTATTR = (byte)'E';191192    /// <summary>193    /// Inode (metadata only) no file content194    /// </summary>195    public const byte LF_META = (byte)'I';196197    /// <summary>198    /// Identifies the next file on the tape as having a long link name199    /// </summary>200    public const byte LF_GNU_LONGLINK = (byte)'K';201202    /// <summary>203    /// Identifies the next file on the tape as having a long name204    /// </summary>205    public const byte LF_GNU_LONGNAME = (byte)'L';206207    /// <summary>208    /// Continuation of a file that began on another volume209    /// </summary>210    public const byte LF_GNU_MULTIVOL = (byte)'M';211212    /// <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';216217    /// <summary>218    /// GNU Sparse file219    /// </summary>220    public const byte LF_GNU_SPARSE = (byte)'S';221222    /// <summary>223    /// GNU Tape/volume header ignore on extraction224    /// </summary>225    public const byte LF_GNU_VOLHDR = (byte)'V';226227    /// <summary>228    /// The magic tag representing a POSIX tar archive.  (includes trailing NULL)229    /// </summary>230    public const string TMAGIC = "ustar ";231232    /// <summary>233    /// The magic tag representing an old GNU tar archive where version is included in magic and overwrites it234    /// </summary>235    public const string GNU_TMAGIC = "ustar  ";236237    const long timeConversionFactor = 10000000L;           // 1 tick == 100 nanoseconds + 1238    readonly static DateTime dateTime1970 = new DateTime(1970, 1, 1, 0, 0, 0, 0);239    #endregion240241    #region Constructors  242  243    /// <summary>244    /// Continuation of a file that began on another volume244    /// Initialise a default TarHeader instance  245    /// </summary>246    public const byte   LF_GNU_MULTIVOL   = (byte) 'M';247248    /// <summary>249    /// For storing filenames that dont fit in the main header (old GNU)250    /// </summary>251    public const byte   LF_GNU_NAMES      = (byte) 'N';252253    /// <summary>254    /// GNU Sparse file255    /// </summary>256    public const byte   LF_GNU_SPARSE     = (byte) 'S';257258    /// <summary>259    /// GNU Tape/volume header ignore on extraction260    /// </summary>261    public const byte   LF_GNU_VOLHDR     = (byte) 'V'; + 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    }260261    #endregion  262263    /// <summary>264    /// The magic tag representing a POSIX tar archive.  (includes trailing NULL)265    /// </summary>266    public const string  TMAGIC    = "ustar ";267268    /// <summary>269    /// The magic tag representing an old GNU tar archive where version is included in magic and overwrites it270    /// </summary>271    public const string  GNU_TMAGIC  = "ustar  ";272273    const long     timeConversionFactor = 10000000L;           // 1 tick == 100 nanoseconds - 1274    readonly static DateTime dateTime1970 = new DateTime(1970, 1, 1, 0, 0, 0, 0);275    #endregion276277    #region Constructors278279    /// <summary>280    /// Initialise a default TarHeader instance281    /// </summary> - 2055282    public TarHeader()283    { - 2055284      Magic = TMAGIC; - 2055285      Version = " ";286 - 2055287      Name     = ""; - 2055288      LinkName = "";289 - 2055290      UserId    = defaultUserId; - 2055291      GroupId   = defaultGroupId; - 2055292      UserName  = defaultUser; - 2055293      GroupName = defaultGroupName; - 2055294      Size      = 0; - 2055295    }263    #region Properties264    /// <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    }277278    /// <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    }287288    /// <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  296297    #endregion298299    #region Properties300    /// <summary>301    /// Get/set the name for this tar entry.302    /// </summary>303    /// <exception cref="ArgumentNullException">Thrown when attempting to set the property to null.</exception>304    public string Name305    { - 4789306      get { return name; }307      set { - 3489308         if ( value == null ) { - 1309          throw new ArgumentNullException(nameof(value));310        } - 3488311        name = value; - 3488312      }313    }314315    /// <summary>316    /// Get the name of this entry.317    /// </summary>318    /// <returns>The entry's name.</returns>319    [Obsolete("Use the Name property instead", true)]320    public string GetName()321    { - 0322      return name;323    }324325    /// <summary>326    /// Get/set the entry's Unix style permission mode.327    /// </summary>328    public int Mode329    { - 1330      get { return mode; } - 1200331      set { mode = value; }332    }333334335    /// <summary>336    /// The entry's user id.337    /// </summary>338    /// <remarks>339    /// This is only directly relevant to unix systems.340    /// The default is zero.341    /// </remarks>342    public int UserId343    { - 1062344      get { return userId; } - 8220345      set { userId = value; }346    }347348349    /// <summary>350    /// Get/set the entry's group id.351    /// </summary>352    /// <remarks>353    /// This is only directly relevant to linux/unix systems.354    /// The default value is zero.355    /// </remarks>356    public int GroupId357    { - 1062358      get { return groupId; } - 8222359      set { groupId = value; }360    }361297    /// <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    }308309310    /// <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    }321322323    /// <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    }336337338    /// <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.</exceptio345    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    }354355356    /// <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    }  362363    /// <summary>364    /// Get/set the entry's size.365    /// </summary>366    /// <exception cref="ArgumentOutOfRangeException">Thrown when setting the size to less than zero.</exception>367    public long Size368    { - 2686369      get { return size; }370      set { - 4179371         if ( value < 0 ) {372#if NETCF_1_0373          throw new ArgumentOutOfRangeException("value");374#else - 1375          throw new ArgumentOutOfRangeException(nameof(value), "Cannot be less than zero");376#endif377        } - 4178378        size = value; - 4178379      }380    }381382383    /// <summary>384    /// Get/set the entry's modification time.385    /// </summary>386    /// <remarks>387    /// The modification time is only accurate to within a second.388    /// </remarks>389    /// <exception cref="ArgumentOutOfRangeException">Thrown when setting the date time to less than 1/1/1970.</exceptio390    public DateTime ModTime391    { - 1059392      get { return modTime; }393      set { - 1640394         if ( value < dateTime1970 )395        {396#if NETCF_1_0397          throw new ArgumentOutOfRangeException("value");398#else - 1399          throw new ArgumentOutOfRangeException(nameof(value), "ModTime cannot be before Jan 1st 1970");400#endif401        } - 1639402        modTime = new DateTime(value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second); - 1639403      }404    }405406407    /// <summary>408    /// Get the entry's checksum.  This is only valid/updated after writing or reading an entry.409    /// </summary>410    public int Checksum411    { - 1091412      get { return checksum; }413    }414415416    /// <summary>417    /// Get value of true if the header checksum is valid, false otherwise.418    /// </summary>419    public bool IsChecksumValid420    { - 521421      get { return isChecksumValid; }422    }423424425    /// <summary>426    /// Get/set the entry's type flag.427    /// </summary>428    public byte TypeFlag429    { - 4581430      get { return typeFlag; } - 4108431      set { typeFlag = value; }432    }433434435    /// <summary>436    /// The entry's link name.437    /// </summary>438    /// <exception cref="ArgumentNullException">Thrown when attempting to set LinkName to null.</exception>439    public string LinkName440    { - 1057441      get { return linkName; }442      set { - 4112443         if ( value == null ) { - 1444          throw new ArgumentNullException(nameof(value));445        } - 4111446        linkName = value; - 4111447      }448    }449450451    /// <summary>452    /// Get/set the entry's magic tag.453    /// </summary>454    /// <exception cref="ArgumentNullException">Thrown when attempting to set Magic to null.</exception>455    public string Magic456    { - 1050457      get { return magic; }458      set { - 3097459         if ( value == null ) { - 1460          throw new ArgumentNullException(nameof(value));363364    /// <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    }370371372    /// <summary>373    /// Get/set the entry's type flag.374    /// </summary>375    public byte TypeFlag { + 334376      get { return typeFlag; } + 166377      set { typeFlag = value; }378    }379380381    /// <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    }394395396    /// <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    }409410411    /// <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      }419420      set { + 87421         if (value == null) { + 1422          throw new ArgumentNullException(nameof(value));423        } + 86424        version = value; + 86425      }426    }427428429    /// <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    }446447448    /// <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        } - 3096462        magic = value; - 3096463      }464    } + 165462      }463    }464  465466467    /// <summary>468    /// The entry's version.469    /// </summary>470    /// <exception cref="ArgumentNullException">Thrown when attempting to set Version to null.</exception>471    public string Version472    {473      get { - 1048474        return version;475      }476477      set { - 3097478         if ( value == null ) { - 1479          throw new ArgumentNullException(nameof(value));480        } - 3096481        version = value; - 3096482      }483    }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    }473474475    /// <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    }482483    #endregion  484485485    #region ICloneable Members  486    /// <summary>487    /// The entry's user name.487    /// Create a new <see cref="TarHeader"/> that is a copy of the current instance.  488    /// </summary>489    public string UserName490    { - 1048491      get { return userName; }492      set { - 4112493         if (value != null) { - 2056494          userName = value.Substring(0, Math.Min(UNAMELEN, value.Length)); - 2056495        }496        else {497#if NETCF_1_0 || NETCF_2_0498          string currentUser = "PocketPC";499#else - 2056500          string currentUser = Environment.UserName;501#endif - 2056502           if (currentUser.Length > UNAMELEN) { - 0503            currentUser = currentUser.Substring(0, UNAMELEN);504          } - 2056505          userName = currentUser;506        } - 2056507      }508    }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    #endregion495496    /// <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;  509510511    /// <summary>512    /// Get/set the entry's group name.513    /// </summary>514    /// <remarks>515    /// This is only directly relevant to unix systems.516    /// </remarks>517    public string GroupName518    { - 1047519      get { return groupName; }520      set { - 4112521         if ( value == null ) { - 1522          groupName = "None"; - 1523        }524        else { - 4111525          groupName = value;526        } - 4111527      }528    }529 + 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;  530531    /// <summary>532    /// Get/set the entry's major device number.533    /// </summary>534    public int DevMajor535    { - 38536      get { return devMajor; } - 3276537      set { devMajor = value; }538    }539540541    /// <summary>542    /// Get/set the entry's minor device number.543    /// </summary>544    public int DevMinor545    { - 36546      get { return devMinor; } - 3276547      set { devMinor = value; }548    } + 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;  549550    #endregion551552    #region ICloneable Members553    /// <summary>554    /// Create a new <see cref="TarHeader"/> that is a copy of the current instance.555    /// </summary>556    /// <returns>A new <see cref="Object"/> that is a copy of the current instance.</returns>557    public object Clone()558    { - 2559      return MemberwiseClone();560    }561    #endregion + 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    /// Parse TarHeader information from a header buffer.564    /// 'Write' header information to buffer provided, updating the <see cref="Checksum">check sum</see>.  565    /// </summary>566    /// <param name = "header">567    /// The tar entry header buffer to get information from.568    /// </param>569    public void ParseBuffer(byte[] header)570    { - 1039571       if ( header == null )572      { - 0573        throw new ArgumentNullException(nameof(header));574      }575 - 1039576      int offset = 0;577 - 1039578      name = ParseName(header, offset, NAMELEN).ToString(); - 1039579      offset += NAMELEN;580 - 1039581      mode = (int)ParseOctal(header, offset, MODELEN); - 1039582      offset += MODELEN;583 - 1039584      UserId = (int)ParseOctal(header, offset, UIDLEN); - 1039585      offset += UIDLEN;586 - 1039587      GroupId = (int)ParseOctal(header, offset, GIDLEN); - 1039588      offset += GIDLEN;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 - 1039590      Size = ParseBinaryOrOctal(header, offset, SIZELEN); - 1039591      offset += SIZELEN;592 - 1039593      ModTime = GetDateTimeFromCTime(ParseOctal(header, offset, MODTIMELEN)); - 1039594      offset += MODTIMELEN; + 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 - 1039596      checksum = (int)ParseOctal(header, offset, CHKSUMLEN); - 1039597      offset += CHKSUMLEN;598 - 1039599      TypeFlag = header[ offset++ ]; + 70596       if ((TypeFlag == LF_CHR) || (TypeFlag == LF_BLK)) { + 0597        offset = GetOctalBytes(DevMajor, outBuffer, offset, DEVLEN); + 0598        offset = GetOctalBytes(DevMinor, outBuffer, offset, DEVLEN);599      }  600 - 1039601      LinkName = ParseName(header, offset, NAMELEN).ToString(); - 1039602      offset += NAMELEN;603 - 1039604      Magic = ParseName(header, offset, MAGICLEN).ToString(); - 1039605      offset += MAGICLEN; + 12880601       for (; offset < outBuffer.Length;) { + 12810602        outBuffer[offset++] = 0;603      }604 + 70605      checksum = ComputeCheckSum(outBuffer);  606 - 1039607      Version = ParseName(header, offset, VERSIONLEN).ToString(); - 1039608      offset += VERSIONLEN;609 - 1039610      UserName = ParseName(header, offset, UNAMELEN).ToString(); - 1039611      offset += UNAMELEN;612 - 1039613      GroupName = ParseName(header, offset, GNAMELEN).ToString(); - 1039614      offset += GNAMELEN;615 - 1039616      DevMajor = (int)ParseOctal(header, offset, DEVLEN); - 1039617      offset += DEVLEN;618 - 1039619      DevMinor = (int)ParseOctal(header, offset, DEVLEN);620621      // Fields past this point not currently parsed or used...622 - 1039623      isChecksumValid = Checksum == TarHeader.MakeCheckSum(header); - 1039624    }625626    /// <summary>627    /// 'Write' header information to buffer provided, updating the <see cref="Checksum">check sum</see>.628    /// </summary>629    /// <param name="outBuffer">output buffer for header information</param>630    public void WriteHeader(byte[] outBuffer)631    { - 1005632       if ( outBuffer == null )633      { - 0634        throw new ArgumentNullException(nameof(outBuffer));635      }636 - 1005637      int offset = 0;638 - 1005639      offset = GetNameBytes(Name, outBuffer, offset, NAMELEN); - 1005640      offset = GetOctalBytes(mode, outBuffer, offset, MODELEN); - 1005641      offset = GetOctalBytes(UserId, outBuffer, offset, UIDLEN); - 1005642      offset = GetOctalBytes(GroupId, outBuffer, offset, GIDLEN);643 - 1005644      offset = GetBinaryOrOctalBytes(Size, outBuffer, offset, SIZELEN); - 1005645      offset = GetOctalBytes(GetCTime(ModTime), outBuffer, offset, MODTIMELEN);646 - 1005647      int csOffset = offset; - 18090648       for (int c = 0; c < CHKSUMLEN; ++c)649      { - 8040650        outBuffer[offset++] = (byte)' ';651      }652 - 1005653      outBuffer[offset++] = TypeFlag;654 - 1005655      offset = GetNameBytes(LinkName, outBuffer, offset, NAMELEN); - 1005656      offset = GetAsciiBytes(Magic, 0, outBuffer, offset, MAGICLEN); - 1005657      offset = GetNameBytes(Version, outBuffer, offset, VERSIONLEN); - 1005658      offset = GetNameBytes(UserName, outBuffer, offset, UNAMELEN); - 1005659      offset = GetNameBytes(GroupName, outBuffer, offset, GNAMELEN);660 - 1005661       if ((TypeFlag == LF_CHR) || (TypeFlag == LF_BLK))662      { - 0663        offset = GetOctalBytes(DevMajor, outBuffer, offset, DEVLEN); - 0664        offset = GetOctalBytes(DevMinor, outBuffer, offset, DEVLEN);665      } + 70607      GetCheckSumOctalBytes(checksum, outBuffer, csOffset, CHKSUMLEN); + 70608      isChecksumValid = true; + 70609    }610611    /// <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    }619620    /// <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;628629      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    }651652    /// <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 - 184920667       for ( ; offset < outBuffer.Length; )668      { - 183915669        outBuffer[offset++] = 0;670      }671 - 1005672      checksum = ComputeCheckSum(outBuffer);673 - 1005674      GetCheckSumOctalBytes(checksum, outBuffer, csOffset, CHKSUMLEN); - 1005675      isChecksumValid = true; - 1005676    }677678    /// <summary>679    /// Get a hash code for the current object.680    /// </summary>681    /// <returns>A hash code for the current object.</returns>682    public override int GetHashCode()683    { - 0684      return Name.GetHashCode();685    }686687    /// <summary>688    /// Determines if this instance is equal to the specified object.689    /// </summary>690    /// <param name="obj">The object to compare with.</param>691    /// <returns>true if the objects are equal, false otherwise.</returns>692    public override bool Equals(object obj)693    { - 30694      var localHeader = obj as TarHeader;695696        bool result; - 30697       if ( localHeader != null )698      { - 30699        result = (name == localHeader.name) - 30700          && (mode == localHeader.mode) - 30701          && (UserId == localHeader.UserId) - 30702          && (GroupId == localHeader.GroupId) - 30703          && (Size == localHeader.Size) - 30704          && (ModTime == localHeader.ModTime) - 30705          && (Checksum == localHeader.Checksum) - 30706          && (TypeFlag == localHeader.TypeFlag) - 30707          && (LinkName == localHeader.LinkName) - 30708          && (Magic == localHeader.Magic) - 30709          && (Version == localHeader.Version) - 30710          && (UserName == localHeader.UserName) - 30711          && (GroupName == localHeader.GroupName) - 30712          && (DevMajor == localHeader.DevMajor) - 30713          && (DevMinor == localHeader.DevMinor); - 30714      }715      else716      { - 0717        result = false;718      } - 30719        return result;720    }667    static internal void RestoreSetValues()668    { + 0669      defaultUserId = userIdAsSet; + 0670      defaultUser = userNameAsSet; + 0671      defaultGroupId = groupIdAsSet; + 0672      defaultGroupName = groupNameAsSet; + 0673    }674675    // 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    }689690    /// <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        }  721722    /// <summary>723    /// Set defaults for values used when constructing a TarHeader instance.724    /// </summary>725    /// <param name="userId">Value to apply as a default for userId.</param>726    /// <param name="userName">Value to apply as a default for userName.</param>727    /// <param name="groupId">Value to apply as a default for groupId.</param>728    /// <param name="groupName">Value to apply as a default for groupName.</param>729    static internal void SetValueDefaults(int userId, string userName, int groupId, string groupName)730    { - 0731      defaultUserId = userIdAsSet = userId; - 0732      defaultUser = userNameAsSet = userName; - 0733      defaultGroupId = groupIdAsSet = groupId; - 0734      defaultGroupName = groupNameAsSet = groupName; - 0735    }736737    static internal void RestoreSetValues()738    { - 0739      defaultUserId = userIdAsSet; - 0740      defaultUser = userNameAsSet; - 0741      defaultGroupId = groupIdAsSet; - 0742      defaultGroupName = groupNameAsSet; - 0743    }744745    // Return value that may be stored in octal or binary. Length must exceed 8.746    //747    static private long ParseBinaryOrOctal(byte[] header, int offset, int length) { - 1039748       if (header[offset] >= 0x80) {749        // File sizes over 8GB are stored in 8 right-justified bytes of binary indicated by setting the high-order bit o - 0750        long result = 0; - 0751         for (int pos = length - 8; pos < length; pos++) { - 0752          result = result << 8 | header[offset + pos];753        } - 0754        return result;755      } - 1039756      return ParseOctal(header, offset, length);757    } + 60722        stillPadding = false;723 + 60724        result = (result << 3) + (header[i] - '0');725      }726 + 18727      return result;728    }729730    /// <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      }  758759    /// <summary>760    /// Parse an octal string from a header buffer.761    /// </summary>762    /// <param name = "header">The header buffer from which to parse.</param>763    /// <param name = "offset">The offset into the buffer from which to parse.</param>764    /// <param name = "length">The number of header bytes to parse.</param>765    /// <returns>The long equivalent of the octal string.</returns>766    static public long ParseOctal(byte[] header, int offset, int length)767    { - 8312768       if ( header == null ) { - 0769        throw new ArgumentNullException(nameof(header)); + 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 - 8312772      long result = 0; - 8312773      bool stillPadding = true; + 9772      return result;773    }  774 - 8312775      int end = offset + length; - 118348776       for (int i = offset; i < end ; ++i) { - 59174777         if (header[i] == 0) {778          break;779        }780 - 50862781         if (header[i] == (byte)' ' || header[i] == '0') { - 38655782           if (stillPadding) {783            continue;784          }785 - 4314786           if (header[i] == (byte)' ') {787            break;788          }789        }790 - 16521791        stillPadding = false;792 - 16521793        result = (result << 3) + (header[i] - '0');794      }795 - 8312796      return result;797    }798799    /// <summary>800    /// Parse a name from a header buffer.801    /// </summary>802    /// <param name="header">803    /// The header buffer from which to parse.804    /// </param>805    /// <param name="offset">806    /// The offset into the buffer from which to parse.807    /// </param>808    /// <param name="length">809    /// The number of header bytes to parse.810    /// </param>811    /// <returns>812    /// The name parsed.813    /// </returns>814    static public StringBuilder ParseName(byte[] header, int offset, int length)815    { - 6652816       if ( header == null ) { - 0817        throw new ArgumentNullException(nameof(header));818      }819 - 6652820       if ( offset < 0 ) {821#if NETCF_1_0822        throw new ArgumentOutOfRangeException("offset");823#else - 0824        throw new ArgumentOutOfRangeException(nameof(offset), "Cannot be less than zero");825#endif826      }827 - 6652828       if ( length < 0 )829      {830#if NETCF_1_0831        throw new ArgumentOutOfRangeException("length");832#else - 0833        throw new ArgumentOutOfRangeException(nameof(length), "Cannot be less than zero");834#endif835      }836 - 6652837       if ( offset + length > header.Length )838      { - 0839        throw new ArgumentException("Exceeds header size", nameof(length));840      }841 - 6652842      var result = new StringBuilder(length);843 - 395960844       for (int i = offset; i < offset + length; ++i) { - 196940845         if (header[i] == 0) {846          break;847        } - 191328848        result.Append((char)header[i]);849      }850 - 6652851      return result;852    }775    /// <summary>776    /// Add <paramref name="name">name</paramref> to the buffer as a collection of bytes777    /// </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    }796797    /// <summary>798    /// Add <paramref name="name">name</paramref> to the buffer as a collection of bytes799    /// </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      }815816      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    }828829    /// <summary>830    /// Add an entry name to the buffer831    /// </summary>832    /// <param name="name">833    /// The name to add834    /// </param>835    /// <param name="buffer">836    /// The buffer to add to837    /// </param>838    /// <param name="offset">839    /// The offset into the buffer from which to start adding840    /// </param>841    /// <param name="length">842    /// The number of header bytes to add843    /// </param>844    /// <returns>845    /// The index of the next free byte in the buffer846    /// </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      }  853854    /// <summary>855    /// Add <paramref name="name">name</paramref> to the buffer as a collection of bytes856    /// </summary>857    /// <param name="name">The name to add</param>858    /// <param name="nameOffset">The offset of the first character</param>859    /// <param name="buffer">The buffer to add to</param>860    /// <param name="bufferOffset">The index of the first byte to add</param>861    /// <param name="length">The number of characters/bytes to add</param>862    /// <returns>The next free index in the <paramref name="buffer"/></returns>863    public static int GetNameBytes(StringBuilder name, int nameOffset, byte[] buffer, int bufferOffset, int length)864    { - 0865       if ( name == null ) { - 0866        throw new ArgumentNullException(nameof(name));867      }868 - 0869       if ( buffer == null ) { - 0870        throw new ArgumentNullException(nameof(buffer));871      }872 - 0873      return GetNameBytes(name.ToString(), nameOffset, buffer, bufferOffset, length);874    } + 0854       if (buffer == null) { + 0855        throw new ArgumentNullException(nameof(buffer));856      }857 + 0858      return GetNameBytes(name.ToString(), 0, buffer, offset, length);859    }860861    /// <summary>862    /// Add an entry name to the buffer863    /// </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      }  875876    /// <summary>877    /// Add <paramref name="name">name</paramref> to the buffer as a collection of bytes878    /// </summary>879    /// <param name="name">The name to add</param>880    /// <param name="nameOffset">The offset of the first character</param>881    /// <param name="buffer">The buffer to add to</param>882    /// <param name="bufferOffset">The index of the first byte to add</param>883    /// <param name="length">The number of characters/bytes to add</param>884    /// <returns>The next free index in the <paramref name="buffer"/></returns>885    public static int GetNameBytes(string name, int nameOffset, byte[] buffer, int bufferOffset, int length)886    { - 5025887       if ( name == null )888      { - 0889        throw new ArgumentNullException(nameof(name));890      }891 - 5025892       if ( buffer == null )893      { - 0894        throw new ArgumentNullException(nameof(buffer));895      }896897      int i;898 - 116878899       for (i = 0 ; i < length - 1 && nameOffset + i < name.Length; ++i) { - 53414900        buffer[bufferOffset + i] = (byte)name[nameOffset + i];901      }902 - 432857903       for (; i < length ; ++i) { - 213916904        buffer[bufferOffset + i] = 0;905      }906 - 5025907      return bufferOffset + length;908    }909910    /// <summary>911    /// Add an entry name to the buffer912    /// </summary>913    /// <param name="name">914    /// The name to add915    /// </param>916    /// <param name="buffer">917    /// The buffer to add to918    /// </param>919    /// <param name="offset">920    /// The offset into the buffer from which to start adding921    /// </param>922    /// <param name="length">923    /// The number of header bytes to add924    /// </param>925    /// <returns>926    /// The index of the next free byte in the buffer927    /// </returns>928    public static int GetNameBytes(StringBuilder name, byte[] buffer, int offset, int length)929    {930 - 0931       if ( name == null ) { - 0932        throw new ArgumentNullException(nameof(name));933      }934 - 0935       if ( buffer == null ) { - 0936        throw new ArgumentNullException(nameof(buffer));937      }938 - 0939      return GetNameBytes(name.ToString(), 0, buffer, offset, length);940    }941942    /// <summary>943    /// Add an entry name to the buffer944    /// </summary>945    /// <param name="name">The name to add</param>946    /// <param name="buffer">The buffer to add to</param>947    /// <param name="offset">The offset into the buffer from which to start adding</param>948    /// <param name="length">The number of header bytes to add</param>949    /// <returns>The index of the next free byte in the buffer</returns>950    public static int GetNameBytes(string name, byte[] buffer, int offset, int length)951    {952 - 5025953       if ( name == null ) { - 0954        throw new ArgumentNullException(nameof(name));955      }956 - 5025957       if ( buffer == null )958      { - 0959        throw new ArgumentNullException(nameof(buffer));960      }961 - 5025962      return GetNameBytes(name, 0, buffer, offset, length);963    }964965    /// <summary>966    /// Add a string to a buffer as a collection of ascii bytes.967    /// </summary>968    /// <param name="toAdd">The string to add</param>969    /// <param name="nameOffset">The offset of the first character to add.</param>970    /// <param name="buffer">The buffer to add to.</param>971    /// <param name="bufferOffset">The offset to start adding at.</param>972    /// <param name="length">The number of ascii characters to add.</param>973    /// <returns>The next free index in the buffer.</returns>974    public static int GetAsciiBytes(string toAdd, int nameOffset, byte[] buffer, int bufferOffset, int length )975    { - 1422976       if ( toAdd == null ) { - 0977        throw new ArgumentNullException(nameof(toAdd));978      }979 - 1422980       if ( buffer == null ) { - 0981        throw new ArgumentNullException(nameof(buffer));982      }983 - 269462984       for (int i = 0 ; i < length && nameOffset + i < toAdd.Length; ++i)985      { - 133309986        buffer[bufferOffset + i] = (byte)toAdd[nameOffset + i];987      } - 1422988      return bufferOffset + length;989    } + 350876       if (buffer == null) { + 0877        throw new ArgumentNullException(nameof(buffer));878      }879 + 350880      return GetNameBytes(name, 0, buffer, offset, length);881    }882883    /// <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    }907908    /// <summary>909    /// Put an octal representation of a value into a buffer910    /// </summary>911    /// <param name = "value">912    /// the value to be converted to octal913    /// </param>914    /// <param name = "buffer">915    /// buffer to store the octal string916    /// </param>917    /// <param name = "offset">918    /// The offset into the buffer where the value starts919    /// </param>920    /// <param name = "length">921    /// The length of the octal string to create922    /// </param>923    /// <returns>924    /// The offset of the character next byte after the octal string925    /// </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;933934      // 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    }951952    /// <summary>953    /// Put an octal or binary representation of a value into a buffer954    /// </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    }973974    /// <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, a982    /// null, then a space -- rather than digits, a space, then a null.983    /// The final space is already there, from checksumming984    /// </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    /// Put an octal representation of a value into a buffer993    /// </summary>994    /// <param name = "value">995    /// the value to be converted to octal996    /// </param>997    /// <param name = "buffer">998    /// buffer to store the octal string999    /// </param>1000    /// <param name = "offset">1001    /// The offset into the buffer where the value starts1002    /// </param>1003    /// <param name = "length">1004    /// The length of the octal string to create1005    /// </param>1006    /// <returns>1007    /// The offset of the character next byte after the octal string1008    /// </returns>1009    public static int GetOctalBytes(long value, byte[] buffer, int offset, int length)1010    { - 60301011       if ( buffer == null ) { - 01012        throw new ArgumentNullException(nameof(buffer));1013      }1014 - 60301015      int localIndex = length - 1;10161017      // Either a space or null is valid here.  We use NULL as per GNUTar - 60301018      buffer[offset + localIndex] = 0; - 60301019      --localIndex;1020 - 60301021       if (value > 0) { - 375761022         for ( long v = value; (localIndex >= 0) && (v > 0); --localIndex ) { - 161201023          buffer[offset + localIndex] = (byte)((byte)'0' + (byte)(v & 7)); - 161201024          v >>= 3;1025        }1026      }992    /// Compute the checksum for a tar entry header.993    /// The checksum field must be all spaces prior to this happening994    /// </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    }10051006    /// <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 - 722801028       for ( ; localIndex >= 0; --localIndex ) { - 331251029        buffer[offset + localIndex] = (byte)'0';1030      }1031 - 60301032      return offset + length;1033    }10341035    /// <summary>1036    /// Put an octal or binary representation of a value into a buffer1037    /// </summary>1038    /// <param name = "value">Value to be convert to octal</param>1039    /// <param name = "buffer">The buffer to update</param>1040    /// <param name = "offset">The offset into the buffer to store the value</param>1041    /// <param name = "length">The length of the octal string. Must be 12.</param>1042    /// <returns>Index of next byte</returns>1043    private static int GetBinaryOrOctalBytes(long value, byte[] buffer, int offset, int length)1044    { - 10051045       if (value > 0x1FFFFFFFF) {  // Octal 77777777777 (11 digits)1046        // Put value as binary, right-justified into the buffer. Set high order bit of left-most byte. - 01047         for (int pos = length - 1; pos > 0; pos--) { - 01048          buffer[offset + pos] = (byte)value; - 01049          value = value >> 8;1050        } - 01051        buffer[offset] = 0x80; - 01052        return offset + length;1053      } - 10051054      return GetOctalBytes(value, buffer, offset, length);1055    }10561057    /// <summary>1058    /// Add the checksum integer to header buffer.1059    /// </summary>1060    /// <param name = "value"></param>1061    /// <param name = "buffer">The header buffer to set the checksum for</param>1062    /// <param name = "offset">The offset into the buffer for the checksum</param>1063    /// <param name = "length">The number of header bytes to update.1064    /// It's formatted differently from the other fields: it has 6 digits, a1065    /// null, then a space -- rather than digits, a space, then a null.1066    /// The final space is already there, from checksumming1067    /// </param>1068    /// <returns>The modified buffer offset</returns>1069    static void GetCheckSumOctalBytes(long value, byte[] buffer, int offset, int length)1070    { - 10051071      GetOctalBytes(value, buffer, offset, length - 1); - 10051072    }10731074    /// <summary>1075    /// Compute the checksum for a tar entry header.1076    /// The checksum field must be all spaces prior to this happening1077    /// </summary>1078    /// <param name = "buffer">The tar entry's header buffer.</param>1079    /// <returns>The computed checksum.</returns>1080    static int ComputeCheckSum(byte[] buffer)1081    { - 10051082      int sum = 0; - 10311301083       for (int i = 0; i < buffer.Length; ++i) { - 5145601084        sum += buffer[i];1085      } - 10051086      return sum;1087    }10881089    /// <summary>1090    /// Make a checksum for a tar entry ignoring the checksum contents.1091    /// </summary>1092    /// <param name = "buffer">The tar entry's header buffer.</param>1093    /// <returns>The checksum for the buffer</returns>1094    static int MakeCheckSum(byte[] buffer)1095    { - 10391096      int sum = 0; - 3096221097       for ( int i = 0; i < CHKSUMOFS; ++i )1098      { - 1537721099        sum += buffer[i];1100      }1101 - 187021102       for ( int i = 0; i < CHKSUMLEN; ++i)1103      { - 83121104        sum += (byte)' ';1105      }1106 - 7418461107       for (int i = CHKSUMOFS + CHKSUMLEN; i < buffer.Length; ++i)1108      { - 3698841109        sum += buffer[i];1110      } - 10391111      return sum;1112    }11131114    static int GetCTime(DateTime dateTime)1115    { - 10051116      return unchecked((int)((dateTime.Ticks - dateTime1970.Ticks) / timeConversionFactor));1117    }11181119    static DateTime GetDateTimeFromCTime(long ticks)1120    {1121      DateTime result;11221123      try { - 10391124        result = new DateTime(dateTime1970.Ticks + ticks * timeConversionFactor); - 10391125      } - 01126      catch(ArgumentOutOfRangeException) { - 01127        result = dateTime1970; - 01128      } - 10391129      return result;1130    }11311132    #region Instance Fields1133    string name;1134    int mode;1135    int userId;1136    int groupId;1137    long size;1138    DateTime modTime;1139    int checksum;1140    bool isChecksumValid;1141    byte typeFlag;1142    string linkName;1143    string magic;1144    string version;1145    string userName;1146    string groupName;1147    int devMajor;1148    int devMinor;1149    #endregion11501151    #region Class Fields1152    // Values used during recursive operations.1153    static internal int userIdAsSet;1154    static internal int groupIdAsSet;1155    static internal string userNameAsSet; - 11156    static internal string groupNameAsSet = "None";11571158    static internal int defaultUserId;1159    static internal int defaultGroupId; - 11160    static internal string defaultGroupName = "None";1161    static internal string defaultUser;1162    #endregion1163  }1164}11651166/* The original Java file had this header:1167 *1168** Authored by Timothy Gerard Endres1169** <mailto:time@gjt.org>  <http://www.trustice.com>1170**1171** This work has been placed into the public domain.1172** You may use this work in any way and for any purpose you wish.1173**1174** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,1175** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR1176** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY1177** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR1178** REDISTRIBUTION OF THIS SOFTWARE.1179**1180*/1028    static int GetCTime(DateTime dateTime)1029    { + 701030      return unchecked((int)((dateTime.Ticks - dateTime1970.Ticks) / timeConversionFactor));1031    }10321033    static DateTime GetDateTimeFromCTime(long ticks)1034    {1035      DateTime result;10361037      try { + 31038        result = new DateTime(dateTime1970.Ticks + ticks * timeConversionFactor); + 31039      } catch (ArgumentOutOfRangeException) { + 01040        result = dateTime1970; + 01041      } + 31042      return result;1043    }10441045    #region Instance Fields1046    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    #endregion10631064    #region Class Fields1065    // 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";10701071    static internal int defaultUserId;1072    static internal int defaultGroupId; + 11073    static internal string defaultGroupName = "None";1074    static internal string defaultUser;1075    #endregion1076  }1077} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_TarInputStream.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_TarInputStream.htm index 824634b27..2c6cec30a 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_TarInputStream.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_TarInputStream.htm @@ -15,12 +15,12 @@

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:78 -Uncovered lines:77 -Coverable lines:155 -Total lines:693 -Line coverage:50.3% -Branch coverage:51.5% +Covered lines:40 +Uncovered lines:118 +Coverable lines:158 +Total lines:626 +Line coverage:25.3% +Branch coverage:22%

Metrics

@@ -35,16 +35,16 @@

Metrics

Write(...)100 WriteByte(...)100 ReadByte()200 -Read(...)1058.9752.63 +Read(...)1000 Close()1100100 SetEntryFactory(...)100 GetRecordSize()100 Skip(...)400 Mark(...)100 Reset()100 -GetNextEntry()1865.0868.57 +GetNextEntry()2042.8641.03 CopyEntryContents(...)200 -SkipToNextEntry()28066.67 +SkipToNextEntry()200 CreateEntry(...)100 CreateEntryFromFile(...)100 CreateEntry(...)100 @@ -55,701 +55,634 @@

#LineLine coverage - 1// TarInputStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.1using System;2using System.IO;3using System.Text;45namespace ICSharpCode.SharpZipLib.Tar6{7  /// <summary>8  /// The TarInputStream reads a UNIX tar archive as an InputStream.9  /// methods are provided to position at each successive entry in10  /// the archive, and the read each entry as a normal input stream11  /// using read().12  /// </summary>13  public class TarInputStream : Stream14  {15    #region Constructors16    /// <summary>17    /// Construct a TarInputStream with default block factor18    /// </summary>19    /// <param name="inputStream">stream to source data from</param>20    public TarInputStream(Stream inputStream) + 421      : this(inputStream, TarBuffer.DefaultBlockFactor)22    { + 423    }2425    /// <summary>26    /// Construct a TarInputStream with user specified block factor27    /// </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    }  3536using System;37using System.IO;38using System.Text;3940namespace ICSharpCode.SharpZipLib.Tar41{4243  /// <summary>44  /// The TarInputStream reads a UNIX tar archive as an InputStream.45  /// methods are provided to position at each successive entry in46  /// the archive, and the read each entry as a normal input stream47  /// using read().48  /// </summary>49  public class TarInputStream : Stream50  {51    #region Constructors52    /// <summary>53    /// Construct a TarInputStream with default block factor54    /// </summary>55    /// <param name="inputStream">stream to source data from</param>56    public TarInputStream(Stream inputStream) - 52257      : this(inputStream, TarBuffer.DefaultBlockFactor)58    { - 52259    }6061    /// <summary>62    /// Construct a TarInputStream with user specified block factor63    /// </summary>64    /// <param name="inputStream">stream to source data from</param>65    /// <param name="blockFactor">block factor to apply to archive</param> - 52366    public TarInputStream(Stream inputStream, int blockFactor)67    { - 52368      this.inputStream = inputStream; - 52369      tarBuffer      = TarBuffer.CreateInputTarBuffer(inputStream, blockFactor); - 52370    }7172    #endregion7374        /// <summary>75        /// Get/set flag indicating ownership of the underlying stream.76        /// When the flag is true <see cref="Close"></see> will close the underlying stream also.77        /// </summary>78        public bool IsStreamOwner79        { - 080            get { return tarBuffer.IsStreamOwner; } - 281            set { tarBuffer.IsStreamOwner = value; }82        }8384    #region Stream Overrides85    /// <summary>86    /// Gets a value indicating whether the current stream supports reading87    /// </summary>88    public override bool CanRead89    {90      get { - 091        return inputStream.CanRead;92      }93    }9495    /// <summary>96    /// Gets a value indicating whether the current stream supports seeking97    /// This property always returns false.98    /// </summary>99    public override bool CanSeek {100      get { - 0101        return false;102      }103    }104105    /// <summary>106    /// Gets a value indicating if the stream supports writing.107    /// This property always returns false.108    /// </summary>109    public override bool CanWrite {110      get { - 0111        return false;112      }113    }114115    /// <summary>116    /// The length in bytes of the stream117    /// </summary>118    public override long Length {119      get { - 0120        return inputStream.Length;121      }122    }123124    /// <summary>125    /// Gets or sets the position within the stream.126    /// Setting the Position is not supported and throws a NotSupportedExceptionNotSupportedException127    /// </summary>128    /// <exception cref="NotSupportedException">Any attempt to set position</exception>129    public override long Position {130      get { - 0131        return inputStream.Position;132      }133      set { - 0134        throw new NotSupportedException("TarInputStream Seek not supported");135      }136    }137138    /// <summary>139    /// Flushes the baseInputStream140    /// </summary>141    public override void Flush()142    { - 0143      inputStream.Flush(); - 0144    }145146    /// <summary>147    /// Set the streams position.  This operation is not supported and will throw a NotSupportedException148    /// </summary>149    /// <param name="offset">The offset relative to the origin to seek to.</param>150    /// <param name="origin">The <see cref="SeekOrigin"/> to start seeking from.</param>151    /// <returns>The new position in the stream.</returns>152    /// <exception cref="NotSupportedException">Any access</exception>153    public override long Seek(long offset, SeekOrigin origin)154    { - 0155      throw new NotSupportedException("TarInputStream Seek not supported");156    }157158    /// <summary>159    /// Sets the length of the stream160    /// This operation is not supported and will throw a NotSupportedException161    /// </summary>162    /// <param name="value">The new stream length.</param>163    /// <exception cref="NotSupportedException">Any access</exception>164    public override void SetLength(long value)165    { - 0166      throw new NotSupportedException("TarInputStream SetLength not supported");36    #endregion3738    /// <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    }4647    #region Stream Overrides48    /// <summary>49    /// Gets a value indicating whether the current stream supports reading50    /// </summary>51    public override bool CanRead {52      get { + 053        return inputStream.CanRead;54      }55    }5657    /// <summary>58    /// Gets a value indicating whether the current stream supports seeking59    /// This property always returns false.60    /// </summary>61    public override bool CanSeek {62      get { + 063        return false;64      }65    }6667    /// <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    }7677    /// <summary>78    /// The length in bytes of the stream79    /// </summary>80    public override long Length {81      get { + 082        return inputStream.Length;83      }84    }8586    /// <summary>87    /// Gets or sets the position within the stream.88    /// Setting the Position is not supported and throws a NotSupportedExceptionNotSupportedException89    /// </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    }99100    /// <summary>101    /// Flushes the baseInputStream102    /// </summary>103    public override void Flush()104    { + 0105      inputStream.Flush(); + 0106    }107108    /// <summary>109    /// Set the streams position.  This operation is not supported and will throw a NotSupportedException110    /// </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    }119120    /// <summary>121    /// Sets the length of the stream122    /// This operation is not supported and will throw a NotSupportedException123    /// </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    }130131    /// <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 NotSupportedException134    /// </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    }143144    /// <summary>145    /// Writes a byte to the current position in the file stream.146    /// This operation is not supported and will throw a NotSupportedException147    /// </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    /// Writes a block of bytes to this stream using data from a buffer.171    /// This operation is not supported and will throw a NotSupportedException172    /// </summary>173    /// <param name="buffer">The buffer containing bytes to write.</param>174    /// <param name="offset">The offset in the buffer of the frist byte to write.</param>175    /// <param name="count">The number of bytes to write.</param>176    /// <exception cref="NotSupportedException">Any access</exception>177    public override void Write(byte[] buffer, int offset, int count)178    { - 0179      throw new NotSupportedException("TarInputStream Write not supported");180    }181182    /// <summary>183    /// Writes a byte to the current position in the file stream.184    /// This operation is not supported and will throw a NotSupportedException185    /// </summary>186    /// <param name="value">The byte value to write.</param>187    /// <exception cref="NotSupportedException">Any access</exception>188    public override void WriteByte(byte value)189    { - 0190      throw new NotSupportedException("TarInputStream WriteByte not supported");191    }192    /// <summary>193    /// Reads a byte from the current tar archive entry.194    /// </summary>195    /// <returns>A byte cast to an int; -1 if the at the end of the stream.</returns>196    public override int ReadByte()197    { - 0198      byte[] oneByteBuffer = new byte[1]; - 0199      int num = Read(oneByteBuffer, 0, 1); - 0200       if (num <= 0)201      {202                // return -1 to indicate that no byte was read. - 0203        return -1;204      } - 0205      return oneByteBuffer[0];206    }170    /// Reads bytes from the current tar archive entry.171    ///172    /// This method is aware of the boundaries of the current173    /// entry in the archive and will deal with them appropriately174    /// </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;  207208    /// <summary>209    /// Reads bytes from the current tar archive entry.210    ///211    /// This method is aware of the boundaries of the current212    /// entry in the archive and will deal with them appropriately213    /// </summary>214    /// <param name="buffer">215    /// The buffer into which to place bytes read.216    /// </param>217    /// <param name="offset">218    /// The offset at which to place bytes read.219    /// </param>220    /// <param name="count">221    /// The number of bytes to read.222    /// </param>223    /// <returns>224    /// The number of bytes read, or 0 at end of stream/EOF.225    /// </returns>226    public override int Read(byte[] buffer, int offset, int count)227    { - 418228       if ( buffer == null )229      { - 0230        throw new ArgumentNullException(nameof(buffer));231      }232 - 418233      int totalRead = 0;234 - 418235       if (entryOffset >= entrySize)236      { - 0237        return 0;238      }239 - 418240      long numToRead = count;241 - 418242       if ((numToRead + entryOffset) > entrySize)243      { - 0244        numToRead = entrySize - entryOffset;245      }246 - 418247       if (readBuffer != null)248      { - 0249         int sz = (numToRead > readBuffer.Length) ? readBuffer.Length : (int)numToRead;250 - 0251        Array.Copy(readBuffer, 0, buffer, offset, sz); + 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 - 0253         if (sz >= readBuffer.Length)254        { - 0255          readBuffer = null; - 0256        }257        else258        { - 0259          int newLen = readBuffer.Length - sz; - 0260          byte[] newBuf = new byte[newLen]; - 0261          Array.Copy(readBuffer, sz, newBuf, 0, newLen); - 0262          readBuffer = newBuf;263        }264 - 0265        totalRead += sz; - 0266        numToRead -= sz; - 0267        offset += sz;268      }269 - 836270       while (numToRead > 0)271      { - 418272        byte[] rec = tarBuffer.ReadBlock(); - 418273         if (rec == null)274        {275          // Unexpected EOF! - 0276          throw new TarException("unexpected EOF with " + numToRead + " bytes unread");277        }278 - 418279        var sz     = (int)numToRead; - 418280        int recLen = rec.Length;281 - 418282         if (recLen > sz)283        { - 416284          Array.Copy(rec, 0, buffer, offset, sz); - 416285          readBuffer = new byte[recLen - sz]; - 416286          Array.Copy(rec, sz, readBuffer, 0, recLen - sz); - 416287        }288        else289        { - 2290          sz = recLen; - 2291          Array.Copy(rec, 0, buffer, offset, recLen);292        }293 - 418294        totalRead += sz; - 418295        numToRead -= sz; - 418296        offset += sz;297      }298 - 418299      entryOffset += totalRead;300 - 418301      return totalRead;302    }303304    /// <summary>305    /// Closes this stream. Calls the TarBuffer's close() method.306    /// The underlying stream is closed by the TarBuffer.307    /// </summary>308    public override void Close()309    { - 523310      tarBuffer.Close(); - 523311    }312313    #endregion314315    /// <summary>316    /// Set the entry factory for this instance.317    /// </summary>318    /// <param name="factory">The factory for creating new entries</param>319    public void SetEntryFactory(IEntryFactory factory)320    { - 0321      entryFactory = factory; - 0322    }323324    /// <summary>325    /// Get the record size being used by this stream's TarBuffer.326    /// </summary>327    public int RecordSize328    { - 0329      get { return tarBuffer.RecordSize; }330    }331332    /// <summary>333    /// Get the record size being used by this stream's TarBuffer.334    /// </summary>335    /// <returns>336    /// TarBuffer record size.337    /// </returns>338    [Obsolete("Use RecordSize property instead")]339    public int GetRecordSize()340    { - 0341      return tarBuffer.RecordSize;342    }343344    /// <summary>345    /// Get the available data that can be read from the current346    /// entry in the archive. This does not indicate how much data347    /// is left in the entire archive, only in the current entry.348    /// This value is determined from the entry's size header field349    /// and the amount of data already read from the current entry.350    /// </summary>351    /// <returns>352    /// The number of available bytes for the current entry.353    /// </returns>354    public long Available {355      get { - 0356        return entrySize - entryOffset;357      }358    }359360    /// <summary>361    /// Skip bytes in the input buffer. This skips bytes in the362    /// current entry's data, not the entire archive, and will363    /// stop at the end of the current entry's data if the number364    /// to skip extends beyond that point.365    /// </summary>366    /// <param name="skipCount">367    /// The number of bytes to skip.368    /// </param>369    public void Skip(long skipCount)370    {371      // TODO: REVIEW efficiency of TarInputStream.Skip372      // This is horribly inefficient, but it ensures that we373      // properly skip over bytes via the TarBuffer...374      // - 0375      byte[] skipBuf = new byte[8 * 1024];376 - 0377       for (long num = skipCount; num > 0;) { - 0378         int toRead = num > skipBuf.Length ? skipBuf.Length : (int)num; - 0379        int numRead = Read(skipBuf, 0, toRead);380 - 0381         if (numRead == -1) {382          break;383        }384 - 0385        num -= numRead;386      } - 0387    }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    }261262    #endregion263264    /// <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    }272273    /// <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    }279280    /// <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    }291292    /// <summary>293    /// Get the available data that can be read from the current294    /// entry in the archive. This does not indicate how much data295    /// is left in the entire archive, only in the current entry.296    /// This value is determined from the entry's size header field297    /// 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    }307308    /// <summary>309    /// Skip bytes in the input buffer. This skips bytes in the310    /// current entry's data, not the entire archive, and will311    /// stop at the end of the current entry's data if the number312    /// 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.Skip320      // This is horribly inefficient, but it ensures that we321      // 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    }336337    /// <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    }346347    /// <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    }356357    /// <summary>358    /// Since we do not support marking just yet, we do nothing.359    /// </summary>360    public void Reset()361    { + 0362    }363364    /// <summary>365    /// Get the next entry in this tar archive. This will skip366    /// over any remaining data in the current entry, if there367    /// is one, and place the input stream at the header of the368    /// next entry, and read the header and instantiate a new369    /// TarEntry from the header bytes and return that entry.370    /// If there are no more entries in the archive, null will371    /// be returned to indicate that the end of the archive has372    /// 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();  388389    /// <summary>390    /// Return a value of true if marking is supported; false otherwise.391    /// </summary>392    /// <remarks>Currently marking is not supported, the return value is always false.</remarks>393    public bool IsMarkSupported {394      get { - 0395        return false;396      }397    }398399    /// <summary>400    /// Since we do not support marking just yet, we do nothing.401    /// </summary>402    /// <param name ="markLimit">403    /// The limit to mark.404    /// </param>405    public void Mark(int markLimit)406    { - 0407    }408409    /// <summary>410    /// Since we do not support marking just yet, we do nothing.411    /// </summary>412    public void Reset()413    { - 0414    }415416    /// <summary>417    /// Get the next entry in this tar archive. This will skip418    /// over any remaining data in the current entry, if there419    /// is one, and place the input stream at the header of the420    /// next entry, and read the header and instantiate a new421    /// TarEntry from the header bytes and return that entry.422    /// If there are no more entries in the archive, null will423    /// be returned to indicate that the end of the archive has424    /// been reached.425    /// </summary>426    /// <returns>427    /// The next TarEntry in the archive, or null.428    /// </returns>429    public TarEntry GetNextEntry()430    { - 522431       if (hasHitEOF) { - 0432        return null;433      }434 - 522435       if (currentEntry != null) { - 1436        SkipToNextEntry();437      }438 - 522439      byte[] headerBuf = tarBuffer.ReadBlock();440 - 522441       if (headerBuf == null) { - 0442        hasHitEOF = true; - 522443      } else hasHitEOF |= TarBuffer.IsEndOfArchiveBlock(headerBuf);444 - 522445       if (hasHitEOF) { - 2446        currentEntry = null; - 2447      } else {448        try { - 520449          var header = new TarHeader(); - 520450          header.ParseBuffer(headerBuf); - 520451           if ( !header.IsChecksumValid )452          { - 1453            throw new TarException("Header checksum is invalid");454          } - 519455          this.entryOffset = 0; - 519456          this.entrySize = header.Size;457 - 519458          StringBuilder longName = null;459 - 519460           if (header.TypeFlag == TarHeader.LF_GNU_LONGNAME) { + 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)numToRead417 + 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 header429                                    // 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 header433                                    // 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          }458459          // Magic was checked here for 'ustar' but there are multiple valid possibilities460          // so this is not done anymore.  461 - 417462            byte[] nameBuffer = new byte[TarBuffer.BlockSize]; - 417463            long numToRead = this.entrySize;464 - 417465            longName = new StringBuilder();466 - 835467             while (numToRead > 0) { - 418468               int numRead = this.Read(nameBuffer, 0, (numToRead > nameBuffer.Length ? nameBuffer.Length : (int)numToRead469 - 418470               if (numRead == -1) { - 0471                throw new InvalidHeaderException("Failed to read long name entry");472              }473 - 418474              longName.Append(TarHeader.ParseName(nameBuffer, 0, numRead).ToString()); - 418475              numToRead -= numRead;476            } + 1462          entryOffset = 0;463464          // 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 - 417478            SkipToNextEntry(); - 417479            headerBuf = this.tarBuffer.ReadBlock(); - 519480           } else if (header.TypeFlag == TarHeader.LF_GHDR) {  // POSIX global extended header481            // Ignore things we dont understand completely for now - 0482            SkipToNextEntry(); - 0483            headerBuf = this.tarBuffer.ReadBlock(); - 102484           } else if (header.TypeFlag == TarHeader.LF_XHDR) {  // POSIX extended header485            // Ignore things we dont understand completely for now - 0486            SkipToNextEntry(); - 0487            headerBuf = this.tarBuffer.ReadBlock(); - 102488           } else if (header.TypeFlag == TarHeader.LF_GNU_VOLHDR) {489            // TODO: could show volume name when verbose - 0490            SkipToNextEntry(); - 0491            headerBuf = this.tarBuffer.ReadBlock(); - 102492           } else if (header.TypeFlag != TarHeader.LF_NORMAL && - 102493                 header.TypeFlag != TarHeader.LF_OLDNORM && - 102494                 header.TypeFlag != TarHeader.LF_DIR) {495            // Ignore things we dont understand completely for now - 0496            SkipToNextEntry(); - 0497            headerBuf = tarBuffer.ReadBlock();498          }499 - 519500           if (entryFactory == null) { - 519501            currentEntry = new TarEntry(headerBuf); - 519502             if (longName != null) { - 417503              currentEntry.Name = longName.ToString();504            } - 417505          } else { - 0506            currentEntry = entryFactory.CreateEntry(headerBuf);507          }478    /// <summary>479    /// Copies the contents of the current tar archive entry directly into480    /// 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    }497498    void SkipToNextEntry()499    { + 0500      long numToSkip = entrySize - entryOffset;501 + 0502       if (numToSkip > 0) { + 0503        Skip(numToSkip);504      }505 + 0506      readBuffer = null; + 0507    }  508509          // Magic was checked here for 'ustar' but there are multiple valid possibilities510          // so this is not done anymore.511 - 519512          entryOffset = 0;513514          // TODO: Review How do we resolve this discrepancy?! - 519515          entrySize = this.currentEntry.Size; - 519516        } catch (InvalidHeaderException ex) { - 0517          entrySize = 0; - 0518          entryOffset = 0; - 0519          currentEntry = null; - 0520          string errorText = string.Format("Bad header in record {0} block {1} {2}", - 0521            tarBuffer.CurrentRecord, tarBuffer.CurrentBlock, ex.Message); - 0522          throw new InvalidHeaderException(errorText);523        }524      } - 521525      return currentEntry;526    }527528    /// <summary>529    /// Copies the contents of the current tar archive entry directly into530    /// an output stream.531    /// </summary>532    /// <param name="outputStream">533    /// The OutputStream into which to write the entry's data.534    /// </param>535    public void CopyEntryContents(Stream outputStream)536    { - 0537      byte[] tempBuffer = new byte[32 * 1024];538 - 0539      while (true) { - 0540        int numRead = Read(tempBuffer, 0, tempBuffer.Length); - 0541         if (numRead <= 0) {542          break;543        } - 0544        outputStream.Write(tempBuffer, 0, numRead);545      } - 0546    }509    /// <summary>510    /// This interface is provided, along with the method <see cref="SetEntryFactory"/>, to allow511    /// the programmer to have their own <see cref="TarEntry"/> subclass instantiated for the512    /// entries return from <see cref="GetNextEntry"/>.513    /// </summary>514    public interface IEntryFactory515    {516      /// <summary>517      /// Create an entry based on name alone518      /// </summary>519      /// <param name="name">520      /// Name of the new EntryPointNotFoundException to create521      /// </param>522      /// <returns>created TarEntry or descendant class</returns>523      TarEntry CreateEntry(string name);524525      /// <summary>526      /// Create an instance based on an actual file527      /// </summary>528      /// <param name="fileName">529      /// Name of file to represent in the entry530      /// </param>531      /// <returns>532      /// Created TarEntry or descendant class533      /// </returns>534      TarEntry CreateEntryFromFile(string fileName);535536      /// <summary>537      /// Create a tar entry based on the header information passed538      /// </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 class544      /// </returns>545      TarEntry CreateEntry(byte[] headerBuffer);546    }  547548    void SkipToNextEntry()549    { - 418550      long numToSkip = entrySize - entryOffset;551 - 418552       if (numToSkip > 0)553      { - 0554        Skip(numToSkip);555      }556 - 418557      readBuffer = null; - 418558    }559560    /// <summary>561    /// This interface is provided, along with the method <see cref="SetEntryFactory"/>, to allow562    /// the programmer to have their own <see cref="TarEntry"/> subclass instantiated for the563    /// entries return from <see cref="GetNextEntry"/>.564    /// </summary>565    public interface IEntryFactory566    {567      /// <summary>568      /// Create an entry based on name alone569      /// </summary>570      /// <param name="name">571      /// Name of the new EntryPointNotFoundException to create572      /// </param>573      /// <returns>created TarEntry or descendant class</returns>574      TarEntry CreateEntry(string name);575576      /// <summary>577      /// Create an instance based on an actual file578      /// </summary>579      /// <param name="fileName">580      /// Name of file to represent in the entry581      /// </param>582      /// <returns>583      /// Created TarEntry or descendant class584      /// </returns>585      TarEntry CreateEntryFromFile(string fileName);586587      /// <summary>588      /// Create a tar entry based on the header information passed589      /// </summary>590      /// <param name="headerBuffer">591      /// Buffer containing header information to create an an entry from.592      /// </param>593      /// <returns>594      /// Created TarEntry or descendant class595      /// </returns>596      TarEntry CreateEntry(byte[] headerBuffer);597    }598599    /// <summary>600    /// Standard entry factory class creating instances of the class TarEntry601    /// </summary>602    public class EntryFactoryAdapter : IEntryFactory603    {604      /// <summary>605      /// Create a <see cref="TarEntry"/> based on named606      /// </summary>607      /// <param name="name">The name to use for the entry</param>608      /// <returns>A new <see cref="TarEntry"/></returns>609      public TarEntry CreateEntry(string name)610      { - 0611        return TarEntry.CreateTarEntry(name);612      }613614      /// <summary>615      /// Create a tar entry with details obtained from <paramref name="fileName">file</paramref>616      /// </summary>617      /// <param name="fileName">The name of the file to retrieve details from.</param>618      /// <returns>A new <see cref="TarEntry"/></returns>619      public TarEntry CreateEntryFromFile(string fileName)620      { - 0621        return TarEntry.CreateEntryFromFile(fileName);622      }623624      /// <summary>625      /// Create an entry based on details in <paramref name="headerBuffer">header</paramref>626      /// </summary>627      /// <param name="headerBuffer">The buffer containing entry details.</param>628      /// <returns>A new <see cref="TarEntry"/></returns>629      public TarEntry CreateEntry(byte[] headerBuffer)630      { - 0631        return new TarEntry(headerBuffer);632      }633    }634635    #region Instance Fields636    /// <summary>637    /// Flag set when last block has been read638    /// </summary>639    protected bool hasHitEOF;640641    /// <summary>642    /// Size of this entry as recorded in header643    /// </summary>644    protected long entrySize;645646    /// <summary>647    /// Number of bytes read for this entry so far648    /// </summary>649    protected long entryOffset;650651    /// <summary>652    /// Buffer used with calls to <code>Read()</code>653    /// </summary>654    protected byte[] readBuffer;655656    /// <summary>657    /// Working buffer658    /// </summary>659    protected TarBuffer tarBuffer;660661    /// <summary>662    /// Current entry being read663    /// </summary>664    TarEntry  currentEntry;665666    /// <summary>667    /// Factory used to create TarEntry or descendant class instance668    /// </summary>669    protected IEntryFactory entryFactory;670671    /// <summary>672    /// Stream used as the source of input data.673    /// </summary>674    readonly Stream inputStream;675    #endregion676  }677}678679/* The original Java file had this header:680  ** Authored by Timothy Gerard Endres681  ** <mailto:time@gjt.org>  <http://www.trustice.com>682  **683  ** This work has been placed into the public domain.684  ** You may use this work in any way and for any purpose you wish.685  **686  ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,687  ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR688  ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY689  ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR690  ** REDISTRIBUTION OF THIS SOFTWARE.691  **692  */693548    /// <summary>549    /// Standard entry factory class creating instances of the class TarEntry550    /// </summary>551    public class EntryFactoryAdapter : IEntryFactory552    {553      /// <summary>554      /// Create a <see cref="TarEntry"/> based on named555      /// </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      }562563      /// <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      }572573      /// <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    }583584    #region Instance Fields585    /// <summary>586    /// Flag set when last block has been read587    /// </summary>588    protected bool hasHitEOF;589590    /// <summary>591    /// Size of this entry as recorded in header592    /// </summary>593    protected long entrySize;594595    /// <summary>596    /// Number of bytes read for this entry so far597    /// </summary>598    protected long entryOffset;599600    /// <summary>601    /// Buffer used with calls to <code>Read()</code>602    /// </summary>603    protected byte[] readBuffer;604605    /// <summary>606    /// Working buffer607    /// </summary>608    protected TarBuffer tarBuffer;609610    /// <summary>611    /// Current entry being read612    /// </summary>613    TarEntry currentEntry;614615    /// <summary>616    /// Factory used to create TarEntry or descendant class instance617    /// </summary>618    protected IEntryFactory entryFactory;619620    /// <summary>621    /// Stream used as the source of input data.622    /// </summary>623    readonly Stream inputStream;624    #endregion625  }626} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_TarOutputStream.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_TarOutputStream.htm index cdb6ee68e..7cf123c3a 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_TarOutputStream.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_TarOutputStream.htm @@ -15,12 +15,12 @@

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:81 -Uncovered lines:36 -Coverable lines:117 -Total lines:527 -Line coverage:69.2% -Branch coverage:66.6% +Covered lines:64 +Uncovered lines:54 +Coverable lines:118 +Total lines:442 +Line coverage:54.2% +Branch coverage:58.3%

Metrics

@@ -37,7 +37,7 @@

Metrics

Finish()2100100 Close()210066.67 GetRecordSize()100 -PutNextEntry(...)59677.78 +PutNextEntry(...)526.9244.44 CloseEntry()377.7860 WriteByte(...)1100100 Write(...)1059.4668.42 @@ -49,535 +49,450 @@

#LineLine coverage - 1// TarOutputStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536// HISTORY37//  2012-06-04  Z-1419  Last char of file name was dropped if path length > 1003839using System;40using System.IO;4142namespace ICSharpCode.SharpZipLib.Tar43{4445  /// <summary>46  /// The TarOutputStream writes a UNIX tar archive as an OutputStream.47  /// Methods are provided to put entries, and then write their contents48  /// by writing to this stream using write().49  /// </summary>50  /// public51  public class TarOutputStream : Stream52  {53    #region Constructors54    /// <summary>55    /// Construct TarOutputStream using default block factor56    /// </summary>57    /// <param name="outputStream">stream to write to</param>58    public TarOutputStream(Stream outputStream) - 52159      : this(outputStream, TarBuffer.DefaultBlockFactor)60    { - 52161    }6263    /// <summary>64    /// Construct TarOutputStream with user specified block factor65    /// </summary>66    /// <param name="outputStream">stream to write to</param>67    /// <param name="blockFactor">blocking factor</param> - 59168    public TarOutputStream(Stream outputStream, int blockFactor)69    { - 59170       if ( outputStream == null )71      { - 072        throw new ArgumentNullException(nameof(outputStream));73      }74 - 59175      this.outputStream = outputStream; - 59176      buffer = TarBuffer.CreateOutputTarBuffer(outputStream, blockFactor);77 - 59178      assemblyBuffer = new byte[TarBuffer.BlockSize]; - 59179      blockBuffer  = new byte[TarBuffer.BlockSize]; - 59180    }81    #endregion8283        /// <summary>84        /// Get/set flag indicating ownership of the underlying stream.85        /// When the flag is true <see cref="Close"></see> will close the underlying stream also.86        /// </summary>87        public bool IsStreamOwner88        { - 089            get { return buffer.IsStreamOwner; } - 290            set { buffer.IsStreamOwner = value; }91        }9293    /// <summary>94    /// true if the stream supports reading; otherwise, false.95    /// </summary>96    public override bool CanRead97    {98      get99      { - 0100        return outputStream.CanRead;101      }102    }103104    /// <summary>105    /// true if the stream supports seeking; otherwise, false.106    /// </summary>107    public override bool CanSeek108    {109      get110      { - 0111        return outputStream.CanSeek;112      }113    }114115    /// <summary>116    /// true if stream supports writing; otherwise, false.117    /// </summary>118    public override bool CanWrite119    {120      get121      { - 0122        return outputStream.CanWrite;123      }124    }125126    /// <summary>127    /// length of stream in bytes128    /// </summary>129    public override long Length130    {131      get132      { - 0133        return outputStream.Length;134      }135    }136137    /// <summary>138    /// gets or sets the position within the current stream.139    /// </summary>140    public override long Position1using System;2using System.IO;34namespace ICSharpCode.SharpZipLib.Tar5{6  /// <summary>7  /// The TarOutputStream writes a UNIX tar archive as an OutputStream.8  /// Methods are provided to put entries, and then write their contents9  /// by writing to this stream using write().10  /// </summary>11  /// public12  public class TarOutputStream : Stream13  {14    #region Constructors15    /// <summary>16    /// Construct TarOutputStream using default block factor17    /// </summary>18    /// <param name="outputStream">stream to write to</param>19    public TarOutputStream(Stream outputStream) + 320      : this(outputStream, TarBuffer.DefaultBlockFactor)21    { + 322    }2324    /// <summary>25    /// Construct TarOutputStream with user specified block factor26    /// </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    #endregion4243    /// <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    }5152    /// <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    }6061    /// <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    }6970    /// <summary>71    /// true if stream supports writing; otherwise, false.72    /// </summary>73    public override bool CanWrite {74      get { + 075        return outputStream.CanWrite;76      }77    }7879    /// <summary>80    /// length of stream in bytes81    /// </summary>82    public override long Length {83      get { + 084        return outputStream.Length;85      }86    }8788    /// <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    }99100    /// <summary>101    /// set the position within the current stream102    /// </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    }110111    /// <summary>112    /// Set the length of the current stream113    /// </summary>114    /// <param name="value">The new stream length.</param>115    public override void SetLength(long value)116    { + 0117      outputStream.SetLength(value); + 0118    }119120    /// <summary>121    /// Read a byte from the stream and advance the position within the stream122    /// 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    }129130    /// <summary>131    /// read bytes from the current stream and advance the position within the132    /// 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    {142      get143      { - 0144        return outputStream.Position;145      }146      set147      { - 0148        outputStream.Position = value; - 0149      }150    }151152    /// <summary>153    /// set the position within the current stream154    /// </summary>155    /// <param name="offset">The offset relative to the <paramref name="origin"/> to seek to</param>156    /// <param name="origin">The <see cref="SeekOrigin"/> to seek from.</param>157    /// <returns>The new position in the stream.</returns>158    public override long Seek(long offset, SeekOrigin origin)159    { - 0160      return outputStream.Seek(offset, origin);161    }162163    /// <summary>164    /// Set the length of the current stream165    /// </summary>166    /// <param name="value">The new stream length.</param>167    public override void SetLength(long value)168    { - 0169      outputStream.SetLength(value); - 0170    }171172    /// <summary>173    /// Read a byte from the stream and advance the position within the stream174    /// by one byte or returns -1 if at the end of the stream.175    /// </summary>176    /// <returns>The byte value or -1 if at end of stream</returns>177    public override int ReadByte()178    { - 0179      return outputStream.ReadByte();180    }181182    /// <summary>183    /// read bytes from the current stream and advance the position within the184    /// stream by the number of bytes read.185    /// </summary>186    /// <param name="buffer">The buffer to store read bytes in.</param>187    /// <param name="offset">The index into the buffer to being storing bytes at.</param>188    /// <param name="count">The desired number of bytes to read.</param>189    /// <returns>The total number of bytes read, or zero if at the end of the stream.190    /// The number of bytes may be less than the <paramref name="count">count</paramref>191    /// requested if data is not avialable.</returns>192    public override int Read(byte[] buffer, int offset, int count)193    { - 0194      return outputStream.Read(buffer, offset, count);195    }196197    /// <summary>198    /// All buffered data is written to destination199    /// </summary>200    public override void Flush()201    { - 1202      outputStream.Flush(); - 1203    }204205    /// <summary>206    /// Ends the TAR archive without closing the underlying OutputStream.207    /// The result is that the EOF block of nulls is written.208    /// </summary>209    public void Finish()210    { - 591211       if ( IsEntryOpen )212      { - 5213        CloseEntry();214      } - 591215      WriteEofBlock(); - 591216    }217218    /// <summary>219    /// Ends the TAR archive and closes the underlying OutputStream.220    /// </summary>221    /// <remarks>This means that Finish() is called followed by calling the222    /// TarBuffer's Close().</remarks>223    public override void Close()224    { - 591225       if ( !isClosed )226      { - 591227        isClosed = true; - 591228        Finish(); - 591229        buffer.Close();230      } - 591231    }232233    /// <summary>234    /// Get the record size being used by this stream's TarBuffer.235    /// </summary>236    public int RecordSize237    { - 1238      get { return buffer.RecordSize; }239    } + 0142      return outputStream.Read(buffer, offset, count);143    }144145    /// <summary>146    /// All buffered data is written to destination147    /// </summary>148    public override void Flush()149    { + 1150      outputStream.Flush(); + 1151    }152153    /// <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    }164165    /// <summary>166    /// Ends the TAR archive and closes the underlying OutputStream.167    /// </summary>168    /// <remarks>This means that Finish() is called followed by calling the169    /// TarBuffer's Close().</remarks>170    public override void Close()171    { + 73172       if (!isClosed) { + 73173        isClosed = true; + 73174        Finish(); + 73175        buffer.Close();176      } + 73177    }178179    /// <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    }185186    /// <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    }197198    /// <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); }203204    }205206    /// <summary>207    /// Put an entry on the output stream. This writes the entry's208    /// header and positions the output stream for writing209    /// the contents of the entry. Once this method is called, the210    /// stream is ready for calls to write() to write the entry's211    /// contents. Once the contents are written, closeEntry()212    /// <B>MUST</B> be called to ensure that all buffered data213    /// 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 char235 + 0236        longHeader.WriteHeader(blockBuffer); + 0237        buffer.WriteBlock(blockBuffer);  // Add special long filename header block238 + 0239        int nameCharIndex = 0;  240241    /// <summary>242    /// Get the record size being used by this stream's TarBuffer.243    /// </summary>244    /// <returns>245    /// The TarBuffer record size.246    /// </returns>247    [Obsolete("Use RecordSize property instead")]248    public int GetRecordSize()249    { - 0250      return buffer.RecordSize;251    }252253    /// <summary>254    /// Get a value indicating wether an entry is open, requiring more data to be written.255    /// </summary>256    bool IsEntryOpen257    { - 591258      get { return (currBytes < currSize); }259260    }261262    /// <summary>263    /// Put an entry on the output stream. This writes the entry's264    /// header and positions the output stream for writing265    /// the contents of the entry. Once this method is called, the266    /// stream is ready for calls to write() to write the entry's267    /// contents. Once the contents are written, closeEntry()268    /// <B>MUST</B> be called to ensure that all buffered data269    /// is completely written to the output stream.270    /// </summary>271    /// <param name="entry">272    /// The TarEntry to be written to the archive.273    /// </param>274    public void PutNextEntry(TarEntry entry)275    { - 588276       if ( entry == null ) { - 0277        throw new ArgumentNullException(nameof(entry));278      }279 - 588280       if (entry.TarHeader.Name.Length >= TarHeader.NAMELEN) { - 417281        var longHeader = new TarHeader(); - 417282        longHeader.TypeFlag = TarHeader.LF_GNU_LONGNAME; - 417283        longHeader.Name = longHeader.Name + "././@LongLink"; - 417284        longHeader.UserId = 0; - 417285        longHeader.GroupId = 0; - 417286        longHeader.GroupName = ""; - 417287        longHeader.UserName = ""; - 417288        longHeader.LinkName = ""; - 417289                longHeader.Size = entry.TarHeader.Name.Length + 1;  // Plus one to avoid dropping last char290 - 417291        longHeader.WriteHeader(blockBuffer); - 417292        buffer.WriteBlock(blockBuffer);  // Add special long filename header block293 - 417294        int nameCharIndex = 0;295 - 834296         while (nameCharIndex < entry.TarHeader.Name.Length) { - 417297          Array.Clear(blockBuffer, 0, blockBuffer.Length); - 417298          TarHeader.GetAsciiBytes(entry.TarHeader.Name, nameCharIndex, this.blockBuffer, 0, TarBuffer.BlockSize); - 417299          nameCharIndex += TarBuffer.BlockSize; - 417300          buffer.WriteBlock(blockBuffer);301        }302      }303 - 588304      entry.WriteEntryHeader(blockBuffer); - 588305      buffer.WriteBlock(blockBuffer);306 - 588307      currBytes = 0;308 - 588309       currSize = entry.IsDirectory ? 0 : entry.Size; - 588310    }311312    /// <summary>313    /// Close an entry. This method MUST be called for all file314    /// entries that contain data. The reason is that we must315    /// buffer data written to the stream in order to satisfy316    /// the buffer's block based writes. Thus, there may be317    /// data fragments still being assembled that must be written318    /// to the output stream before this entry is closed and the319    /// next entry written.320    /// </summary>321    public void CloseEntry()322    { - 5323       if (assemblyBufferLength > 0) { - 5324        Array.Clear(assemblyBuffer, assemblyBufferLength, assemblyBuffer.Length - assemblyBufferLength);325 - 5326        buffer.WriteBlock(assemblyBuffer);327 - 5328        currBytes += assemblyBufferLength; - 5329        assemblyBufferLength = 0;330      }331 - 5332       if (currBytes < currSize) { - 0333        string errorText = string.Format( - 0334          "Entry closed at '{0}' before the '{1}' bytes specified in the header were written", - 0335          currBytes, currSize); - 0336        throw new TarException(errorText); + 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    }256257    /// <summary>258    /// Close an entry. This method MUST be called for all file259    /// entries that contain data. The reason is that we must260    /// buffer data written to the stream in order to satisfy261    /// the buffer's block based writes. Thus, there may be262    /// data fragments still being assembled that must be written263    /// to the output stream before this entry is closed and the264    /// 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    }284285    /// <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    }296297    /// <summary>298    /// Writes bytes to the current tar archive entry. This method299    /// is aware of the current entry and will throw an exception if300    /// you attempt to write bytes past the length specified for the301    /// current entry. The method is also (painfully) aware of the302    /// record buffering required by TarBuffer, and manages buffers303    /// that are not a multiple of recordsize in length, including304    /// 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      } - 5338    }339340    /// <summary>341    /// Writes a byte to the current tar archive entry.342    /// This method simply calls Write(byte[], int, int).343    /// </summary>344    /// <param name="value">345    /// The byte to be written.346    /// </param>347    public override void WriteByte(byte value)348    { - 45349      Write(new byte[] { value }, 0, 1); - 45350    }351352    /// <summary>353    /// Writes bytes to the current tar archive entry. This method354    /// is aware of the current entry and will throw an exception if355    /// you attempt to write bytes past the length specified for the356    /// current entry. The method is also (painfully) aware of the357    /// record buffering required by TarBuffer, and manages buffers358    /// that are not a multiple of recordsize in length, including359    /// assembling records from small buffers.360    /// </summary>361    /// <param name = "buffer">362    /// The buffer to write to the archive.363    /// </param>364    /// <param name = "offset">365    /// The offset in the buffer from which to get bytes.366    /// </param>367    /// <param name = "count">368    /// The number of bytes to write.369    /// </param>370    public override void Write(byte[] buffer, int offset, int count)371    { - 4087372       if ( buffer == null ) { - 0373        throw new ArgumentNullException(nameof(buffer));374      }375 - 4087376       if ( offset < 0 )377      {378#if NETCF_1_0379        throw new ArgumentOutOfRangeException("offset");380#else - 0381        throw new ArgumentOutOfRangeException(nameof(offset), "Cannot be negative");382#endif383      }384 - 4087385       if ( buffer.Length - offset < count )386      { - 0387        throw new ArgumentException("offset and count combination is invalid");388      }338339      //340      // We have to deal with assembly!!!341      // The programmer can be writing little 32 byte chunks for all342      // we know, and we must assemble complete blocks for writing.343      // TODO  REVIEW Maybe this should be in TarBuffer? Could that help to344      //        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      }368369      //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 - 4087390       if ( count < 0 )391      {392#if NETCF_1_0393        throw new ArgumentOutOfRangeException("count");394#else - 0395        throw new ArgumentOutOfRangeException(nameof(count), "Cannot be negative");396#endif397      }398 - 4087399       if ( (currBytes + count) > currSize ) { - 0400        string errorText = string.Format("request to write '{0}' bytes exceeds size in header of '{1}' bytes", - 0401          count, this.currSize);402#if NETCF_1_0403        throw new ArgumentOutOfRangeException("count");404#else - 0405        throw new ArgumentOutOfRangeException(nameof(count), errorText);406#endif407      }408409      //410      // We have to deal with assembly!!!411      // The programmer can be writing little 32 byte chunks for all412      // we know, and we must assemble complete blocks for writing.413      // TODO  REVIEW Maybe this should be in TarBuffer? Could that help to414      //        eliminate some of the buffer copying.415      // - 4087416       if (assemblyBufferLength > 0) { - 40417         if ((assemblyBufferLength + count ) >= blockBuffer.Length) { - 0418          int aLen = blockBuffer.Length - assemblyBufferLength;419 - 0420          Array.Copy(assemblyBuffer, 0, blockBuffer, 0, assemblyBufferLength); - 0421          Array.Copy(buffer, offset, blockBuffer, assemblyBufferLength, aLen);422 - 0423          this.buffer.WriteBlock(blockBuffer);424 - 0425          currBytes += blockBuffer.Length;426 - 0427          offset    += aLen; - 0428          count -= aLen;429 - 0430          assemblyBufferLength = 0; - 0431        } else { - 40432          Array.Copy(buffer, offset, assemblyBuffer, assemblyBufferLength, count); - 40433          offset += count; - 40434          assemblyBufferLength += count; - 40435          count -= count;436        }437      }438439      //440      // When we get here we have EITHER:441      //   o An empty "assembly" buffer.442      //   o No bytes to write (count == 0)443      // - 8129444       while (count > 0) { - 4047445         if (count < blockBuffer.Length) { - 5446          Array.Copy(buffer, offset, assemblyBuffer, assemblyBufferLength, count); - 5447          assemblyBufferLength += count; - 5448          break;449        }450 - 4042451        this.buffer.WriteBlock(buffer, offset);452 - 4042453        int bufferLength = blockBuffer.Length; - 4042454        currBytes += bufferLength; - 4042455        count -= bufferLength; - 4042456        offset += bufferLength;457      } - 4082458    }459460    /// <summary>461    /// Write an EOF (end of archive) block to the tar archive.462    /// An EOF block consists of all zeros.463    /// </summary>464    void WriteEofBlock()465    { - 591466      Array.Clear(blockBuffer, 0, blockBuffer.Length); - 591467      buffer.WriteBlock(blockBuffer); - 591468    }469470    #region Instance Fields471    /// <summary>472    /// bytes written for this entry so far473    /// </summary>474    long currBytes;475476    /// <summary>477    /// current 'Assembly' buffer length478    /// </summary>479    int assemblyBufferLength;480481    /// <summary>482    /// Flag indicating wether this instance has been closed or not.483    /// </summary>484    bool isClosed;485486    /// <summary>487    /// Size for the current entry488    /// </summary>489    protected long currSize;490491    /// <summary>492    /// single block working buffer493    /// </summary>494    protected byte[] blockBuffer;495496    /// <summary>497    /// 'Assembly' buffer used to assemble data before writing498    /// </summary>499    protected byte[] assemblyBuffer;500501    /// <summary>502    /// TarBuffer used to provide correct blocking factor503    /// </summary>504    protected TarBuffer buffer;505506    /// <summary>507    /// the destination stream for the archive contents508    /// </summary>509    protected Stream outputStream;510    #endregion511  }512}513514/* The original Java file had this header:515  ** Authored by Timothy Gerard Endres516  ** <mailto:time@gjt.org>  <http://www.trustice.com>517  **518  ** This work has been placed into the public domain.519  ** You may use this work in any way and for any purpose you wish.520  **521  ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,522  ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR523  ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY524  ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR525  ** REDISTRIBUTION OF THIS SOFTWARE.526  **527  */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    }399400    #region Instance Fields401    /// <summary>402    /// bytes written for this entry so far403    /// </summary>404    long currBytes;405406    /// <summary>407    /// current 'Assembly' buffer length408    /// </summary>409    int assemblyBufferLength;410411    /// <summary>412    /// Flag indicating wether this instance has been closed or not.413    /// </summary>414    bool isClosed;415416    /// <summary>417    /// Size for the current entry418    /// </summary>419    protected long currSize;420421    /// <summary>422    /// single block working buffer423    /// </summary>424    protected byte[] blockBuffer;425426    /// <summary>427    /// 'Assembly' buffer used to assemble data before writing428    /// </summary>429    protected byte[] assemblyBuffer;430431    /// <summary>432    /// TarBuffer used to provide correct blocking factor433    /// </summary>434    protected TarBuffer buffer;435436    /// <summary>437    /// the destination stream for the archive contents438    /// </summary>439    protected Stream outputStream;440    #endregion441  }442} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_TestStatus.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_TestStatus.htm index 9200bde14..dca53c13e 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_TestStatus.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_TestStatus.htm @@ -18,7 +18,7 @@

Summary

Covered lines:7 Uncovered lines:13 Coverable lines:20 -Total lines:4476 +Total lines:4263 Line coverage:35% @@ -38,4484 +38,4271 @@

#LineLine coverage - 1// ZipFile.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  2009-12-22  Z-1649  Added AES support41//  2010-03-02  Z-1650  Fixed updating ODT archives in memory. Exposed exceptions in updating.42//  2010-05-25  Z-1663  Fixed exception when testing local header compressed size of -143//  2012-11-29  Z-1684  Fixed ZipFile.Add(string fileName, string entryName) losing the file TimeStamp4445using System;46using System.Collections;47using System.IO;48using System.Text;49using System.Globalization;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;1213namespace ICSharpCode.SharpZipLib.Zip14{15  #region Keys Required Event Args16  /// <summary>17  /// Arguments used with KeysRequiredEvent18  /// </summary>19  public class KeysRequiredEventArgs : EventArgs20  {21    #region Constructors22    /// <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    }3031    /// <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    }4142    #endregion43    #region Properties44    /// <summary>45    /// Gets the name of the file for which keys are required.46    /// </summary>47    public string FileName {48      get { return fileName; }49    }  5051#if !NETCF_1_052using System.Security.Cryptography;53using ICSharpCode.SharpZipLib.Encryption;54#endif5556using ICSharpCode.SharpZipLib.Core;57using ICSharpCode.SharpZipLib.Checksums;58using ICSharpCode.SharpZipLib.Zip.Compression.Streams;59using ICSharpCode.SharpZipLib.Zip.Compression;6061namespace ICSharpCode.SharpZipLib.Zip62{63  #region Keys Required Event Args64  /// <summary>65  /// Arguments used with KeysRequiredEvent66  /// </summary>67  public class KeysRequiredEventArgs : EventArgs68  {69    #region Constructors70    /// <summary>71    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>72    /// </summary>73    /// <param name="name">The name of the file for which keys are required.</param>74    public KeysRequiredEventArgs(string name)75    {76      fileName = name;77    }7879    /// <summary>80    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>81    /// </summary>82    /// <param name="name">The name of the file for which keys are required.</param>83    /// <param name="keyValue">The current key value.</param>84    public KeysRequiredEventArgs(string name, byte[] keyValue)85    {86      fileName = name;87      key = keyValue;88    }8990    #endregion91    #region Properties92    /// <summary>93    /// Gets the name of the file for which keys are required.94    /// </summary>95    public string FileName96    {97      get { return fileName; }98    }99100    /// <summary>101    /// Gets or sets the key value102    /// </summary>103    public byte[] Key104    {105      get { return key; }106      set { key = value; }107    }108    #endregion109110    #region Instance Fields111    string fileName;112    byte[] key;113    #endregion114  }115  #endregion116117  #region Test Definitions118  /// <summary>119  /// The strategy to apply to testing.120  /// </summary>121  public enum TestStrategy122  {123    /// <summary>124    /// Find the first error only.125    /// </summary>126    FindFirstError,51    /// <summary>52    /// Gets or sets the key value53    /// </summary>54    public byte[] Key {55      get { return key; }56      set { key = value; }57    }58    #endregion5960    #region Instance Fields61    string fileName;62    byte[] key;63    #endregion64  }65  #endregion6667  #region Test Definitions68  /// <summary>69  /// The strategy to apply to testing.70  /// </summary>71  public enum TestStrategy72  {73    /// <summary>74    /// Find the first error only.75    /// </summary>76    FindFirstError,77    /// <summary>78    /// Find all possible errors.79    /// </summary>80    FindAllErrors,81  }8283  /// <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 TestOperation88  {89    /// <summary>90    /// Setting up testing.91    /// </summary>92    Initialising,9394    /// <summary>95    /// Testing an individual entries header96    /// </summary>97    EntryHeader,9899    /// <summary>100    /// Testing an individual entries data101    /// </summary>102    EntryData,103104    /// <summary>105    /// Testing an individual entry has completed.106    /// </summary>107    EntryComplete,108109    /// <summary>110    /// Running miscellaneous tests111    /// </summary>112    MiscellaneousTests,113114    /// <summary>115    /// Testing is complete116    /// </summary>117    Complete,118  }119120  /// <summary>121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.122  /// </summary>123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>124  public class TestStatus125  {126    #region Constructors  127    /// <summary>128    /// Find all possible errors.128    /// Initialise a new instance of <see cref="TestStatus"/>  129    /// </summary>130    FindAllErrors,131  }132133  /// <summary>134  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.135  /// </summary>136  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>137  public enum TestOperation138  {130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param> + 96131    public TestStatus(ZipFile file)132    { + 96133      file_ = file; + 96134    }135    #endregion136137    #region Properties138  139    /// <summary>140    /// Setting up testing.140    /// Get the current <see cref="TestOperation"/> in progress.  141    /// </summary>142    Initialising,143144    /// <summary>145    /// Testing an individual entries header146    /// </summary>147    EntryHeader,148149    /// <summary>150    /// Testing an individual entries data151    /// </summary>152    EntryData,153154    /// <summary>155    /// Testing an individual entry has completed.156    /// </summary>157    EntryComplete,158159    /// <summary>160    /// Running miscellaneous tests161    /// </summary>162    MiscellaneousTests,163164    /// <summary>165    /// Testing is complete166    /// </summary>167    Complete,168  }169170  /// <summary>171  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.172  /// </summary>173  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>174  public class TestStatus175  {176    #region Constructors177    /// <summary>178    /// Initialise a new instance of <see cref="TestStatus"/>179    /// </summary>180    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param> - 96181    public TestStatus(ZipFile file)182    { - 96183      file_ = file; - 96184    }185    #endregion186187    #region Properties142    public TestOperation Operation { + 0143      get { return operation_; }144    }145146    /// <summary>147    /// Get the <see cref="ZipFile"/> this status is applicable to.148    /// </summary>149    public ZipFile File { + 0150      get { return file_; }151    }152153    /// <summary>154    /// Get the current/last entry tested.155    /// </summary>156    public ZipEntry Entry { + 0157      get { return entry_; }158    }159160    /// <summary>161    /// Get the number of errors detected so far.162    /// </summary>163    public int ErrorCount { + 96164      get { return errorCount_; }165    }166167    /// <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    }173174    /// <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    #endregion181182    #region Internal API183    internal void AddError()184    { + 1185      errorCount_++; + 1186      entryValid_ = false; + 1187    }  188189    /// <summary>190    /// Get the current <see cref="TestOperation"/> in progress.191    /// </summary>192    public TestOperation Operation193    { - 0194      get { return operation_; }195    }196197    /// <summary>198    /// Get the <see cref="ZipFile"/> this status is applicable to.199    /// </summary>200    public ZipFile File201    { - 0202      get { return file_; }203    }204205    /// <summary>206    /// Get the current/last entry tested.207    /// </summary>208    public ZipEntry Entry209    { - 0210      get { return entry_; }211    }212213    /// <summary>214    /// Get the number of errors detected so far.215    /// </summary>216    public int ErrorCount217    { - 96218      get { return errorCount_; }219    }220221    /// <summary>222    /// Get the number of bytes tested so far for the current entry.223    /// </summary>224    public long BytesTested225    { - 0226      get { return bytesTested_; }227    }228229    /// <summary>230    /// Get a value indicating wether the last entry test was valid.231    /// </summary>232    public bool EntryValid233    { - 0234      get { return entryValid_; }235    }236    #endregion237238    #region Internal API239    internal void AddError()240    { - 1241      errorCount_++; - 1242      entryValid_ = false; - 1243    }244245    internal void SetOperation(TestOperation operation)246    { - 0247      operation_ = operation; - 0248    }249250    internal void SetEntry(ZipEntry entry)251    { - 0252      entry_ = entry; - 0253      entryValid_ = true; - 0254      bytesTested_ = 0; - 0255    }256257    internal void SetBytesTested(long value)258    { - 0259      bytesTested_ = value; - 0260    }261    #endregion262263    #region Instance Fields264    ZipFile file_;265    ZipEntry entry_;266    bool entryValid_;267    int errorCount_;268    long bytesTested_;269    TestOperation operation_;270    #endregion271  }272273  /// <summary>274  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if275  /// </summary>276  /// <remarks>If the message is non-null an error has occured.  If the message is null277  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>278  public delegate void ZipTestResultHandler(TestStatus status, string message);279  #endregion280281  #region Update Definitions282  /// <summary>283  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.284  /// </summary>285  public enum FileUpdateMode286  {287    /// <summary>288    /// Perform all updates on temporary files ensuring that the original file is saved.289    /// </summary>290    Safe,291    /// <summary>292    /// Update the archive directly, which is faster but less safe.293    /// </summary>294    Direct,295  }296  #endregion189    internal void SetOperation(TestOperation operation)190    { + 0191      operation_ = operation; + 0192    }193194    internal void SetEntry(ZipEntry entry)195    { + 0196      entry_ = entry; + 0197      entryValid_ = true; + 0198      bytesTested_ = 0; + 0199    }200201    internal void SetBytesTested(long value)202    { + 0203      bytesTested_ = value; + 0204    }205    #endregion206207    #region Instance Fields208    ZipFile file_;209    ZipEntry entry_;210    bool entryValid_;211    int errorCount_;212    long bytesTested_;213    TestOperation operation_;214    #endregion215  }216217  /// <summary>218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if219  /// </summary>220  /// <remarks>If the message is non-null an error has occured.  If the message is null221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>222  public delegate void ZipTestResultHandler(TestStatus status, string message);223  #endregion224225  #region Update Definitions226  /// <summary>227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.228  /// </summary>229  public enum FileUpdateMode230  {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  #endregion241242  #region ZipFile Class243  /// <summary>244  /// This class represents a Zip archive.  You can ask for the contained245  /// entries, or get an input stream for a file entry.  The entry is246  /// 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 arbitrary251  /// entries in different threads.252  /// <br/>253  /// <br/>Author of the original java version : Jochen Hoenicke254  /// </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 MainClass265  /// {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, IDisposable287  {288    #region KeyHandling289290    /// <summary>291    /// Delegate for handling keys/password setting during compresion/decompression.292    /// </summary>293    public delegate void KeysRequiredEventHandler(294      object sender,295      KeysRequiredEventArgs e296    );  297298  #region ZipFile Class299  /// <summary>300  /// This class represents a Zip archive.  You can ask for the contained301  /// entries, or get an input stream for a file entry.  The entry is302  /// automatically decompressed.303  ///304  /// You can also update the archive adding or deleting entries.305  ///306  /// This class is thread safe for input:  You can open input streams for arbitrary307  /// entries in different threads.308  /// <br/>309  /// <br/>Author of the original java version : Jochen Hoenicke310  /// </summary>311  /// <example>312  /// <code>313  /// using System;314  /// using System.Text;315  /// using System.Collections;316  /// using System.IO;317  ///318  /// using ICSharpCode.SharpZipLib.Zip;319  ///320  /// class MainClass321  /// {322  ///   static public void Main(string[] args)323  ///   {324  ///     using (ZipFile zFile = new ZipFile(args[0])) {325  ///       Console.WriteLine("Listing of : " + zFile.Name);326  ///       Console.WriteLine("");327  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");328  ///       Console.WriteLine("--------  --------  --------  ------  ---------");329  ///       foreach (ZipEntry e in zFile) {330  ///         if ( e.IsFile ) {331  ///           DateTime d = e.DateTime;332  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,333  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),334  ///             e.Name);335  ///         }336  ///       }337  ///     }338  ///   }339  /// }340  /// </code>341  /// </example>342  public class ZipFile : IEnumerable, IDisposable343  {344    #region KeyHandling345346    /// <summary>347    /// Delegate for handling keys/password setting during compresion/decompression.348    /// </summary>349    public delegate void KeysRequiredEventHandler(350      object sender,351      KeysRequiredEventArgs e352    );353354    /// <summary>355    /// Event handler for handling encryption keys.356    /// </summary>357    public KeysRequiredEventHandler KeysRequired;358359    /// <summary>360    /// Handles getting of encryption keys when required.361    /// </summary>362    /// <param name="fileName">The file for which encryption keys are required.</param>363    void OnKeysRequired(string fileName)364    {365      if (KeysRequired != null) {366        var krea = new KeysRequiredEventArgs(fileName, key);367        KeysRequired(this, krea);368        key = krea.Key;369      }370    }371372    /// <summary>373    /// Get/set the encryption key value.374    /// </summary>375    byte[] Key376    {377      get { return key; }378      set { key = value; }379    }380381#if !NETCF_1_0382    /// <summary>383    /// Password to be used for encrypting/decrypting files.384    /// </summary>385    /// <remarks>Set to null if no password is required.</remarks>386    public string Password387    {388      set389      {390        if ( string.IsNullOrEmpty(value)) {391          key = null;392        }393        else {394          rawPassword_ = value;395          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));396        }298    /// <summary>299    /// Event handler for handling encryption keys.300    /// </summary>301    public KeysRequiredEventHandler KeysRequired;302303    /// <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    }315316    /// <summary>317    /// Get/set the encryption key value.318    /// </summary>319    byte[] Key {320      get { return key; }321      set { key = value; }322    }323324    /// <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    }338339    /// <summary>340    /// Get a value indicating wether encryption keys are currently available.341    /// </summary>342    bool HaveKeys {343      get { return key != null; }344    }345    #endregion346347    #region Constructors348    /// <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 occurs355    /// </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      }364365      name_ = name;366367      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);368      isStreamOwner = true;369370      try {371        ReadEntries();372      } catch {373        DisposeInternal(true);374        throw;375      }376    }377378    /// <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      }394395      if (!file.CanSeek) {396        throw new ArgumentException("Stream is not seekable", nameof(file));  397      }398    }399#endif400401    /// <summary>402    /// Get a value indicating wether encryption keys are currently available.403    /// </summary>404    bool HaveKeys405    {406      get { return key != null; }407    }408    #endregion409410    #region Constructors398399      baseStream_ = file;400      name_ = file.Name;401      isStreamOwner = true;402403      try {404        ReadEntries();405      } catch {406        DisposeInternal(true);407        throw;408      }409    }410  411    /// <summary>412    /// Opens a Zip file with the given name for reading.412    /// Opens a Zip file reading the given <see cref="Stream"/>.  413    /// </summary>414    /// <param name="name">The name of the file to open.</param>415    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>416    /// <exception cref="IOException">417    /// An i/o error occurs418    /// </exception>419    /// <exception cref="ZipException">420    /// The file doesn't contain a valid zip archive.421    /// </exception>422    public ZipFile(string name)423    {424      if ( name == null ) {425        throw new ArgumentNullException(nameof(name));426      }427428      name_ = name;429430      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);431      isStreamOwner = true;414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>415    /// <exception cref="IOException">416    /// An i/o error occurs417    /// </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      }  432433      try {434        ReadEntries();433      if (!stream.CanSeek) {434        throw new ArgumentException("Stream is not seekable", nameof(stream));  435      }436      catch {437        DisposeInternal(true);438        throw;439      }440    }441442    /// <summary>443    /// Opens a Zip file reading the given <see cref="FileStream"/>.444    /// </summary>445    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>446    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>447    /// <exception cref="IOException">448    /// An i/o error occurs.449    /// </exception>450    /// <exception cref="ZipException">451    /// The file doesn't contain a valid zip archive.452    /// </exception>453    public ZipFile(FileStream file)454    {455      if ( file == null ) {456        throw new ArgumentNullException(nameof(file));457      }458459      if ( !file.CanSeek ) {460        throw new ArgumentException("Stream is not seekable", nameof(file));461      }462463      baseStream_  = file;464      name_ = file.Name;465      isStreamOwner = true;466467      try {468        ReadEntries();469      }470      catch {471        DisposeInternal(true);472        throw;473      }474    }475476    /// <summary>477    /// Opens a Zip file reading the given <see cref="Stream"/>.478    /// </summary>479    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>480    /// <exception cref="IOException">481    /// An i/o error occurs482    /// </exception>483    /// <exception cref="ZipException">484    /// The stream doesn't contain a valid zip archive.<br/>485    /// </exception>486    /// <exception cref="ArgumentException">487    /// The <see cref="Stream">stream</see> doesnt support seeking.488    /// </exception>489    /// <exception cref="ArgumentNullException">490    /// The <see cref="Stream">stream</see> argument is null.491    /// </exception>492    public ZipFile(Stream stream)493    {494      if ( stream == null ) {495        throw new ArgumentNullException(nameof(stream));496      }497498      if ( !stream.CanSeek ) {499        throw new ArgumentException("Stream is not seekable", nameof(stream));500      }501502      baseStream_  = stream;503      isStreamOwner = true;504505      if ( baseStream_.Length > 0 ) {506        try {507          ReadEntries();508        }509        catch {510          DisposeInternal(true);511          throw;512        }513      } else {514        entries_ = new ZipEntry[0];515        isNewArchive_ = true;516      }517    }518519    /// <summary>520    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.521    /// </summary>522    internal ZipFile()523    {524      entries_ = new ZipEntry[0];525      isNewArchive_ = true;526    }527528    #endregion529530    #region Destructors and Closing531    /// <summary>532    /// Finalize this instance.533    /// </summary>534    ~ZipFile()535    {536      Dispose(false);537    }538436437      baseStream_ = stream;438      isStreamOwner = true;439440      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    }452453    /// <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    }461462    #endregion463464    #region Destructors and Closing465    /// <summary>466    /// Finalize this instance.467    /// </summary>468    ~ZipFile()469    {470      Dispose(false);471    }472473    /// <summary>474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying475    /// 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    }485486    #endregion487488    #region Creators489    /// <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      }500501      FileStream fs = File.Create(fileName);502503      var result = new ZipFile();504      result.name_ = fileName;505      result.baseStream_ = fs;506      result.isStreamOwner = true;507      return result;508    }509510    /// <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      }522523      if (!outStream.CanWrite) {524        throw new ArgumentException("Stream is not writeable", nameof(outStream));525      }526527      if (!outStream.CanSeek) {528        throw new ArgumentException("Stream is not seekable", nameof(outStream));529      }530531      var result = new ZipFile();532      result.baseStream_ = outStream;533      return result;534    }535536    #endregion537538    #region Properties  539    /// <summary>540    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying541    /// Once closed, no further instance methods should be called.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    /// <exception cref="System.IO.IOException">544    /// An i/o error occurs.545    /// </exception>546    public void Close()547    {548      DisposeInternal(true);549      GC.SuppressFinalize(this);550    }551552    #endregion553554    #region Creators555    /// <summary>556    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.557    /// </summary>558    /// <param name="fileName">The name of the archive to create.</param>559    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>560    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>561    public static ZipFile Create(string fileName)562    {563      if ( fileName == null ) {564        throw new ArgumentNullException(nameof(fileName));565      }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    }550551    /// <summary>552    /// Get a value indicating wether553    /// this archive is embedded in another file or not.554    /// </summary>555    public bool IsEmbeddedArchive {556      // Not strictly correct in all circumstances currently557      get { return offsetOfFirstEntry > 0; }558    }559560    /// <summary>561    /// Get a value indicating that this archive is a new one.562    /// </summary>563    public bool IsNewArchive {564      get { return isNewArchive_; }565    }  566567      FileStream fs = File.Create(fileName);568569      var result = new ZipFile();570      result.name_ = fileName;571      result.baseStream_ = fs;572      result.isStreamOwner = true;573      return result;574    }575576    /// <summary>577    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.578    /// </summary>579    /// <param name="outStream">The stream providing data storage.</param>580    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>581    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>582    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>583    public static ZipFile Create(Stream outStream)584    {585      if ( outStream == null ) {586        throw new ArgumentNullException(nameof(outStream));587      }588589      if ( !outStream.CanWrite ) {590        throw new ArgumentException("Stream is not writeable", nameof(outStream));567    /// <summary>568    /// Gets the comment for the zip file.569    /// </summary>570    public string ZipFileComment {571      get { return comment_; }572    }573574    /// <summary>575    /// Gets the name of this zip file.576    /// </summary>577    public string Name {578      get { return name_; }579    }580581    /// <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      }592593      if ( !outStream.CanSeek ) {594        throw new ArgumentException("Stream is not seekable", nameof(outStream));595      }596597      var result = new ZipFile();598      result.baseStream_ = outStream;599      return result;600    }601602    #endregion603604    #region Properties605    /// <summary>606    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.607    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.608    /// </summary>609    /// <remarks>610    /// The default value is true in all cases.611    /// </remarks>612    public bool IsStreamOwner613    {614      get { return isStreamOwner; }615      set { isStreamOwner = value; }616    }617618    /// <summary>619    /// Get a value indicating wether620    /// this archive is embedded in another file or not.621    /// </summary>622    public bool IsEmbeddedArchive623    {624      // Not strictly correct in all circumstances currently625      get { return offsetOfFirstEntry > 0; }626    }627628    /// <summary>629    /// Get a value indicating that this archive is a new one.630    /// </summary>631    public bool IsNewArchive632    {633      get { return isNewArchive_; }634    }635636    /// <summary>637    /// Gets the comment for the zip file.638    /// </summary>639    public string ZipFileComment640    {641      get { return comment_; }642    }643644    /// <summary>645    /// Gets the name of this zip file.646    /// </summary>647    public string Name648    {649      get { return name_; }650    }651652    /// <summary>653    /// Gets the number of entries in this zip file.654    /// </summary>655    /// <exception cref="InvalidOperationException">656    /// The Zip file has been closed.657    /// </exception>658    [Obsolete("Use the Count property instead")]659    public int Size660    {661      get662      {663        return entries_.Length;664      }665    }666667    /// <summary>668    /// Get the number of entries contained in this <see cref="ZipFile"/>.669    /// </summary>670    public long Count671    {672      get673      {674        return entries_.Length;675      }676    }677678    /// <summary>679    /// Indexer property for ZipEntries680    /// </summary>681    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]682    public ZipEntry this[int index]683    {684      get {685        return (ZipEntry) entries_[index].Clone();686      }687    }688689    #endregion690691    #region Input Handling692    /// <summary>693    /// Gets an enumerator for the Zip entries in this Zip file.694    /// </summary>695    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>696    /// <exception cref="ObjectDisposedException">697    /// The Zip file has been closed.698    /// </exception>699    public IEnumerator GetEnumerator()700    {701      if (isDisposed_) {702        throw new ObjectDisposedException("ZipFile");703      }704705      return new ZipEntryEnumerator(entries_);706    }707708    /// <summary>709    /// Return the index of the entry with a matching name710    /// </summary>711    /// <param name="name">Entry name to find</param>712    /// <param name="ignoreCase">If true the comparison is case insensitive</param>713    /// <returns>The index position of the matching entry or -1 if not found</returns>714    /// <exception cref="ObjectDisposedException">715    /// The Zip file has been closed.716    /// </exception>717    public int FindEntry(string name, bool ignoreCase)718    {719      if (isDisposed_) {720        throw new ObjectDisposedException("ZipFile");721      }722723      // TODO: This will be slow as the next ice age for huge archives!724      for (int i = 0; i < entries_.Length; i++) {725        if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) {726          return i;727        }728      }729      return -1;730    }731732    /// <summary>733    /// Searches for a zip entry in this archive with the given name.734    /// String comparisons are case insensitive735    /// </summary>736    /// <param name="name">737    /// The name to find. May contain directory components separated by slashes ('/').738    /// </param>739    /// <returns>740    /// A clone of the zip entry, or null if no entry with that name exists.741    /// </returns>742    /// <exception cref="ObjectDisposedException">743    /// The Zip file has been closed.744    /// </exception>745    public ZipEntry GetEntry(string name)746    {747      if (isDisposed_) {748        throw new ObjectDisposedException("ZipFile");749      }750751      int index = FindEntry(name, true);752      return (index >= 0) ? (ZipEntry) entries_[index].Clone() : null;753    }754755    /// <summary>756    /// Gets an input stream for reading the given zip entry data in an uncompressed form.757    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().758    /// </summary>759    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>760    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>761    /// <exception cref="ObjectDisposedException">762    /// The ZipFile has already been closed763    /// </exception>764    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">765    /// The compression method for the entry is unknown766    /// </exception>767    /// <exception cref="IndexOutOfRangeException">768    /// The entry is not found in the ZipFile769    /// </exception>770    public Stream GetInputStream(ZipEntry entry)771    {772      if ( entry == null ) {773        throw new ArgumentNullException(nameof(entry));774      }775776      if ( isDisposed_ ) {777        throw new ObjectDisposedException("ZipFile");778      }779780      long index = entry.ZipFileIndex;781      if ( (index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name) ) {782        index = FindEntry(entry.Name, true);783        if (index < 0) {784          throw new ZipException("Entry cannot be found");785        }786      }787      return GetInputStream(index);788    }789790    /// <summary>791    /// Creates an input stream reading a zip entry792    /// </summary>793    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>794    /// <returns>795    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>796    /// </returns>797    /// <exception cref="ObjectDisposedException">798    /// The ZipFile has already been closed799    /// </exception>800    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">801    /// The compression method for the entry is unknown802    /// </exception>803    /// <exception cref="IndexOutOfRangeException">804    /// The entry is not found in the ZipFile805    /// </exception>806    public Stream GetInputStream(long entryIndex)807    {808      if ( isDisposed_ ) {809        throw new ObjectDisposedException("ZipFile");810      }592    }593594    /// <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    }602603    /// <summary>604    /// Indexer property for ZipEntries605    /// </summary>606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]607    public ZipEntry this[int index] {608      get {609        return (ZipEntry)entries_[index].Clone();610      }611    }612613    #endregion614615    #region Input Handling616    /// <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      }628629      return new ZipEntryEnumerator(entries_);630    }631632    /// <summary>633    /// Return the index of the entry with a matching name634    /// </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      }646647      // 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    }655656    /// <summary>657    /// Searches for a zip entry in this archive with the given name.658    /// String comparisons are case insensitive659    /// </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      }674675      int index = FindEntry(name, true);676      return (index >= 0) ? (ZipEntry)entries_[index].Clone() : null;677    }678679    /// <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 closed687    /// </exception>688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">689    /// The compression method for the entry is unknown690    /// </exception>691    /// <exception cref="IndexOutOfRangeException">692    /// The entry is not found in the ZipFile693    /// </exception>694    public Stream GetInputStream(ZipEntry entry)695    {696      if (entry == null) {697        throw new ArgumentNullException(nameof(entry));698      }699700      if (isDisposed_) {701        throw new ObjectDisposedException("ZipFile");702      }703704      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    }713714    /// <summary>715    /// Creates an input stream reading a zip entry716    /// </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 closed723    /// </exception>724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">725    /// The compression method for the entry is unknown726    /// </exception>727    /// <exception cref="IndexOutOfRangeException">728    /// The entry is not found in the ZipFile729    /// </exception>730    public Stream GetInputStream(long entryIndex)731    {732      if (isDisposed_) {733        throw new ObjectDisposedException("ZipFile");734      }735736      long start = LocateEntry(entries_[entryIndex]);737      CompressionMethod method = entries_[entryIndex].CompressionMethod;738      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);739740      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      }746747      switch (method) {748        case CompressionMethod.Stored:749          // read as is.750          break;751752        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;756757        default:758          throw new ZipException("Unsupported compression method " + method);759      }760761      return result;762    }763764    #endregion765766    #region Archive Testing767    /// <summary>768    /// Test an archive for integrity/validity769    /// </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    }777778    /// <summary>779    /// Test an archive for integrity/validity780    /// </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      }791792      var status = new TestStatus(this);793794      if (resultHandler != null) {795        resultHandler(status, null);796      }797798      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;799800      bool testing = true;801802      try {803        int entryIndex = 0;804805        while (testing && (entryIndex < Count)) {806          if (resultHandler != null) {807            status.SetEntry(this[entryIndex]);808            status.SetOperation(TestOperation.EntryHeader);809            resultHandler(status, null);810          }  811812      long start = LocateEntry(entries_[entryIndex]);813      CompressionMethod method = entries_[entryIndex].CompressionMethod;814      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);815816      if (entries_[entryIndex].IsCrypted == true) {817#if NETCF_1_0818        throw new ZipException("decryption not supported for Compact Framework 1.0");819#else820        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]);821        if (result == null) {822          throw new ZipException("Unable to decrypt this entry");823        }824#endif825      }826827      switch (method) {828        case CompressionMethod.Stored:829          // read as is.830          break;831832        case CompressionMethod.Deflated:833          // No need to worry about ownership and closing as underlying stream close does nothing.834          result = new InflaterInputStream(result, new Inflater(true));835          break;836837        default:838          throw new ZipException("Unsupported compression method " + method);839      }812          try {813            TestLocalHeader(this[entryIndex], test);814          } catch (ZipException ex) {815            status.AddError();816817            if (resultHandler != null) {818              resultHandler(status,819                string.Format("Exception during test - '{0}'", ex.Message));820            }821822            testing &= strategy != TestStrategy.FindFirstError;823          }824825          if (testing && testData && this[entryIndex].IsFile) {826            if (resultHandler != null) {827              status.SetOperation(TestOperation.EntryData);828              resultHandler(status, null);829            }830831            var crc = new Crc32();832833            using (Stream entryStream = this.GetInputStream(this[entryIndex])) {834835              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);  840841      return result;842    }843844    #endregion845846    #region Archive Testing847    /// <summary>848    /// Test an archive for integrity/validity849    /// </summary>850    /// <param name="testData">Perform low level data Crc check</param>851    /// <returns>true if all tests pass, false otherwise</returns>852    /// <remarks>Testing will terminate on the first error found.</remarks>853    public bool TestArchive(bool testData)854    {855      return TestArchive(testData, TestStrategy.FindFirstError, null);856    }857858    /// <summary>859    /// Test an archive for integrity/validity860    /// </summary>861    /// <param name="testData">Perform low level data Crc check</param>862    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>863    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>864    /// <returns>true if all tests pass, false otherwise</returns>865    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>866    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)867    {868      if (isDisposed_) {869        throw new ObjectDisposedException("ZipFile");870      }871872      var status = new TestStatus(this);873874      if ( resultHandler != null ) {875        resultHandler(status, null);876      }877878      HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;879880      bool testing = true;841                if (resultHandler != null) {842                  totalBytes += bytesRead;843                  status.SetBytesTested(totalBytes);844                  resultHandler(status, null);845                }846              }847            }848849            if (this[entryIndex].Crc != crc.Value) {850              status.AddError();851852              if (resultHandler != null) {853                resultHandler(status, "CRC mismatch");854              }855856              testing &= strategy != TestStrategy.FindFirstError;857            }858859            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              }866867              if (this[entryIndex].CompressedSize != data.CompressedSize) {868                status.AddError();869              }870871              if (this[entryIndex].Size != data.Size) {872                status.AddError();873              }874            }875          }876877          if (resultHandler != null) {878            status.SetOperation(TestOperation.EntryComplete);879            resultHandler(status, null);880          }  881882      try {883        int entryIndex = 0;882          entryIndex += 1;883        }  884885        while ( testing && (entryIndex < Count) ) {886          if ( resultHandler != null ) {887            status.SetEntry(this[entryIndex]);888            status.SetOperation(TestOperation.EntryHeader);889            resultHandler(status, null);890          }891892          try  {893            TestLocalHeader(this[entryIndex], test);894          }895          catch(ZipException ex) {896            status.AddError();897898            if ( resultHandler != null ) {899              resultHandler(status,900                string.Format("Exception during test - '{0}'", ex.Message));901            }902903            testing &= strategy != TestStrategy.FindFirstError;904          }885        if (resultHandler != null) {886          status.SetOperation(TestOperation.MiscellaneousTests);887          resultHandler(status, null);888        }889890        // TODO: the 'Corrina Johns' test where local headers are missing from891        // the central directory.  They are therefore invisible to many archivers.892      } catch (Exception ex) {893        status.AddError();894895        if (resultHandler != null) {896          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));897        }898      }899900      if (resultHandler != null) {901        status.SetOperation(TestOperation.Complete);902        status.SetEntry(null);903        resultHandler(status, null);904      }  905906          if ( testing && testData && this[entryIndex].IsFile ) {907            if ( resultHandler != null ) {908              status.SetOperation(TestOperation.EntryData);909              resultHandler(status, null);910            }911912                        var crc = new Crc32();913914                        using (Stream entryStream = this.GetInputStream(this[entryIndex]))915                        {916917                            byte[] buffer = new byte[4096];918                            long totalBytes = 0;919                            int bytesRead;920                            while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0)921                            {922                                crc.Update(buffer, 0, bytesRead);923924                                if (resultHandler != null)925                                {926                                    totalBytes += bytesRead;927                                    status.SetBytesTested(totalBytes);928                                    resultHandler(status, null);929                                }930                            }931                        }932933            if (this[entryIndex].Crc != crc.Value) {934              status.AddError();935936              if ( resultHandler != null ) {937                resultHandler(status, "CRC mismatch");938              }939940              testing &= strategy != TestStrategy.FindFirstError;941            }942943            if (( this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0 ) {944              var helper = new ZipHelperStream(baseStream_);945              var data = new DescriptorData();946              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);947              if (this[entryIndex].Crc != data.Crc) {948                status.AddError();949              }950951              if (this[entryIndex].CompressedSize != data.CompressedSize) {952                status.AddError();953              }954955              if (this[entryIndex].Size != data.Size) {956                status.AddError();957              }958            }959          }960961          if ( resultHandler != null ) {962            status.SetOperation(TestOperation.EntryComplete);963            resultHandler(status, null);964          }965966          entryIndex += 1;967        }968969        if ( resultHandler != null ) {970          status.SetOperation(TestOperation.MiscellaneousTests);971          resultHandler(status, null);972        }973974        // TODO: the 'Corrina Johns' test where local headers are missing from975        // the central directory.  They are therefore invisible to many archivers.976      }977      catch (Exception ex) {978        status.AddError();906      return (status.ErrorCount == 0);907    }908909    [Flags]910    enum HeaderTest911    {912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted913      Header = 0x02,     // Check that this header contents are valid914    }915916    /// <summary>917    /// Test a local header against that provided from the central directory918    /// </summary>919    /// <param name="entry">920    /// The entry to test against921    /// </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;929930        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        }934935        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();945946        byte[] nameData = new byte[storedNameLength];947        StreamUtils.ReadFully(baseStream_, nameData);948949        byte[] extraData = new byte[extraDataLength];950        StreamUtils.ReadFully(baseStream_, extraData);951952        var localExtraData = new ZipExtraData(extraData);953954        // Extra data / zip64 checks955        if (localExtraData.Find(1)) {956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64957          // and size or compressedSize = MaxValue, due to rogue creators.958959          size = localExtraData.ReadLong();960          compressedSize = localExtraData.ReadLong();961962          if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) {963            // These may be valid if patched later964            if ((size != -1) && (size != entry.Size)) {965              throw new ZipException("Size invalid for descriptor");966            }967968            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        }  979980        if ( resultHandler != null ) {981          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));982        }983      }984985      if ( resultHandler != null ) {986        status.SetOperation(TestOperation.Complete);987        status.SetEntry(null);988        resultHandler(status, null);989      }980        if (testData) {981          if (entry.IsFile) {982            if (!entry.IsCompressionMethodSupported()) {983              throw new ZipException("Compression method not supported");984            }985986            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})", extract989            }  990991      return (status.ErrorCount == 0);992    }993994    [Flags]995    enum HeaderTest996    {997      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted998      Header  = 0x02,     // Check that this header contents are valid999    }10001001    /// <summary>1002    /// Test a local header against that provided from the central directory1003    /// </summary>1004    /// <param name="entry">1005    /// The entry to test against1006    /// </param>1007    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>1008    /// <returns>The offset of the entries data in the file</returns>1009    long TestLocalHeader(ZipEntry entry, HeaderTest tests)1010    {1011      lock(baseStream_)1012      {1013        bool testHeader = (tests & HeaderTest.Header) != 0;1014        bool testData = (tests & HeaderTest.Extract) != 0;10151016        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);1017        if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {1018          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)1019        }10201021        var extractVersion = ( short ) (ReadLEUshort() & 0x00ff);1022        var localFlags = ( short )ReadLEUshort();1023        var compressionMethod = ( short )ReadLEUshort();1024        var fileTime = ( short )ReadLEUshort();1025        var fileDate = ( short )ReadLEUshort();1026        uint crcValue = ReadLEUint();1027        long compressedSize = ReadLEUint();1028        long size = ReadLEUint();1029        int storedNameLength = ReadLEUshort();1030        int extraDataLength = ReadLEUshort();10311032        byte[] nameData = new byte[storedNameLength];1033        StreamUtils.ReadFully(baseStream_, nameData);10341035        byte[] extraData = new byte[extraDataLength];1036        StreamUtils.ReadFully(baseStream_, extraData);991            if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enhance992              throw new ZipException("The library does not support the zip version required to extract this entry");993            }994          }995        }996997        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})", extractVersi1015          }10161017          // Local entry flags dont have reserved bit set on.1018          if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.R1019            throw new ZipException("Reserved bit flags cannot be set.");1020          }10211022          // Encryption requires extract version >= 201023          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          }10261027          // 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            }10321033            if (extractVersion < 50) {1034              throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({01035            }1036          }  10371038        var localExtraData = new ZipExtraData(extraData);10391040        // Extra data / zip64 checks1041        if (localExtraData.Find(1))1042        {1043          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip641044          // and size or compressedSize = MaxValue, due to rogue creators.10451046          size = localExtraData.ReadLong();1047          compressedSize = localExtraData.ReadLong();10481049                    if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0)1050                    {1051                        // These may be valid if patched later1052                        if ( (size != -1) && (size != entry.Size)) {1053                            throw new ZipException("Size invalid for descriptor");1054                        }10551056                        if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {1057                            throw new ZipException("Compressed size invalid for descriptor");1058                        }1059                    }1060                }1061        else1062        {1063          // No zip64 extra data but entry requires it.1064          if ((extractVersion >= ZipConstants.VersionZip64) &&1065            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue)))1066          {1067            throw new ZipException("Required Zip64 extended information missing");1038          // Patched entries require extract version >= 271039          if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) {1040            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));1041          }10421043          // Central header flags match local entry flags.1044          if (localFlags != entry.Flags) {1045            throw new ZipException("Central header/local header flags mismatch");1046          }10471048          // Central header compression method matches local entry1049          if (entry.CompressionMethod != (CompressionMethod)compressionMethod) {1050            throw new ZipException("Central header/local header compression method mismatch");1051          }10521053          if (entry.Version != extractVersion) {1054            throw new ZipException("Extract version mismatch");1055          }10561057          // Strong encryption and extract version match1058          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          }10631064          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        }10701071        if ( testData ) {1072          if ( entry.IsFile ) {1073            if ( !entry.IsCompressionMethodSupported() ) {1074              throw new ZipException("Compression method not supported");1075            }10761077            if ( (extractVersion > ZipConstants.VersionMadeBy)1078              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)) ) {1079              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract1080            }10811082            if ( (localFlags & ( int )(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enha1083              throw new ZipException("The library does not support the zip version required to extract this entry");1084            }1085          }1086        }10871088                if (testHeader)1089                {1090                    if ((extractVersion <= 63) &&  // Ignore later versions as we dont know about them..1091                        (extractVersion != 10) &&1092                        (extractVersion != 11) &&1093                        (extractVersion != 20) &&1094                        (extractVersion != 21) &&1095                        (extractVersion != 25) &&1096                        (extractVersion != 27) &&1097                        (extractVersion != 45) &&1098                        (extractVersion != 46) &&1099                        (extractVersion != 50) &&1100                        (extractVersion != 51) &&1101                        (extractVersion != 52) &&1102                        (extractVersion != 61) &&1103                        (extractVersion != 62) &&1104                        (extractVersion != 63)1105                        )1106                    {1107                        throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", 1108                    }11091110                    // Local entry flags dont have reserved bit set on.1111                    if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | General1112                    {1113                        throw new ZipException("Reserved bit flags cannot be set.");1114                    }11151116                    // Encryption requires extract version >= 201117                    if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20))1118                    {1119                        throw new ZipException(string.Format("Version required to extract this entry is too low for encr1120                    }11211122                    // Strong encryption requires encryption flag to be set and extract version >= 50.1123                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1124                    {1125                        if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0)1126                        {1127                            throw new ZipException("Strong encryption flag set but encryption flag is not set");1128                        }10691070          if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {1071            if (crcValue != (uint)entry.Crc) {1072              throw new ZipException("Central header/local header crc mismatch");1073            }1074          }10751076          // Crc valid for empty entry.1077          // This will also apply to streamed entries where size isnt known and the header cant be patched1078          if ((size == 0) && (compressedSize == 0)) {1079            if (crcValue != 0) {1080              throw new ZipException("Invalid CRC for empty entry");1081            }1082          }10831084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str1085          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably1086          if (entry.Name.Length > storedNameLength) {1087            throw new ZipException("File name length mismatch");1088          }10891090          // Name data has already been read convert it and compare.1091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);10921093          // Central directory and local entry name match1094          if (localName != entry.Name) {1095            throw new ZipException("Central header and local header file name mismatch");1096          }10971098          // Directories have zero actual size but can have compressed size1099          if (entry.IsDirectory) {1100            if (size > 0) {1101              throw new ZipException("Directory cannot have size");1102            }11031104            // 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 bytes1112              // 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 bytes1114              throw new ZipException("Directory compressed size invalid");1115            }1116          }11171118          if (!ZipNameTransform.IsValidName(localName, true)) {1119            throw new ZipException("Name is invalid");1120          }1121        }11221123        // Tests that apply to both data and header.11241125        // 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)) {  11291130                        if (extractVersion < 50)1131                        {1132                            throw new ZipException(string.Format("Version required to extract this entry is too low for 1133                        }1134                    }11351136                    // Patched entries require extract version >= 271137                    if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27))1138                    {1139                        throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractV1140                    }11411142                    // Central header flags match local entry flags.1143                    if (localFlags != entry.Flags)1144                    {1145                        throw new ZipException("Central header/local header flags mismatch");1146                    }11471148                    // Central header compression method matches local entry1149                    if (entry.CompressionMethod != (CompressionMethod)compressionMethod)1150                    {1151                        throw new ZipException("Central header/local header compression method mismatch");1152                    }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          }11361137          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        }11441145        int extraLength = storedNameLength + extraDataLength;1146        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;1147      }1148    }11491150    #endregion11511152    #region Updating  11531154                    if (entry.Version != extractVersion)1155                    {1156                        throw new ZipException("Extract version mismatch");1157                    }11581159                    // Strong encryption and extract version match1160                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1161                    {1162                        if (extractVersion < 62)1163                        {1164                            throw new ZipException("Strong encryption flag set but version not high enough");1165                        }1166                    }11671168                    if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0)1169                    {1170                        if ((fileTime != 0) || (fileDate != 0))1171                        {1172                            throw new ZipException("Header masked set but date/time values non-zero");1173                        }1174                    }11751176                    if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0)1177                    {1178                        if (crcValue != (uint)entry.Crc)1179                        {1180                            throw new ZipException("Central header/local header crc mismatch");1181                        }1182                    }11831184                    // Crc valid for empty entry.1185                    // This will also apply to streamed entries where size isnt known and the header cant be patched1186                    if ((size == 0) && (compressedSize == 0))1187                    {1188                        if (crcValue != 0)1189                        {1190                            throw new ZipException("Invalid CRC for empty entry");1191                        }1192                    }11931194                    // TODO: make test more correct...  can't compare lengths as was done originally as this can fail fo1195                    // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntr1196                    if (entry.Name.Length > storedNameLength)1197                    {1198                        throw new ZipException("File name length mismatch");1199                    }12001201                    // Name data has already been read convert it and compare.1202                    string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);12031204                    // Central directory and local entry name match1205                    if (localName != entry.Name)1206                    {1207                        throw new ZipException("Central header and local header file name mismatch");1208                    }12091210                    // Directories have zero actual size but can have compressed size1211                    if (entry.IsDirectory)1212                    {1213                        if (size > 0)1214                        {1215                            throw new ZipException("Directory cannot have size");1216                        }12171218                        // There may be other cases where the compressed size can be greater than this?1219                        // If so until details are known we will be strict.1220                        if (entry.IsCrypted)1221                        {1222                            if (compressedSize > ZipConstants.CryptoHeaderSize + 2)1223                            {1224                                throw new ZipException("Directory compressed size invalid");1225                            }1226                        }1227                        else if (compressedSize > 2)1228                        {1229                            // When not compressed the directory size can validly be 2 bytes1230                            // if the true size wasnt known when data was originally being written.1231                            // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes1232                            throw new ZipException("Directory compressed size invalid");1233                        }1234                    }12351236                    if (!ZipNameTransform.IsValidName(localName, true))1237                    {1238                        throw new ZipException("Name is invalid");1239                    }1240                }12411242        // Tests that apply to both data and header.1154    const int DefaultBufferSize = 4096;11551156    /// <summary>1157    /// The kind of update to apply.1158    /// </summary>1159    enum UpdateCommand1160    {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    }11651166    #region Properties1167    /// <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      }11741175      set {1176        updateEntryFactory_.NameTransform = value;1177      }1178    }11791180    /// <summary>1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1182    /// during updates.1183    /// </summary>1184    public IEntryFactory EntryFactory {1185      get {1186        return updateEntryFactory_;1187      }11881189      set {1190        if (value == null) {1191          updateEntryFactory_ = new ZipEntryFactory();1192        } else {1193          updateEntryFactory_ = value;1194        }1195      }1196    }11971198    /// <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        }12071208        if (bufferSize_ != value) {1209          bufferSize_ = value;1210          copyBuffer_ = null;1211        }1212      }1213    }12141215    /// <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    }12211222    /// <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    }12291230    #endregion12311232    #region Immediate updating1233    //    TBD: Direct form of updating1234    //1235    //    public void Update(IEntryMatcher deleteMatcher)1236    //    {1237    //    }1238    //1239    //    public void Update(IScanner addScanner)1240    //    {1241    //    }1242    #endregion  12431244        // Size can be verified only if it is known in the local header.1245        // it will always be known in the central header.1246        if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||1247          ((size > 0) || (compressedSize > 0))) {12481249          if (size != entry.Size) {1250            throw new ZipException(1251              string.Format("Size mismatch between central header({0}) and local header({1})",1252                entry.Size, size));1253          }12541255          if (compressedSize != entry.CompressedSize &&1256            compressedSize != 0xFFFFFFFF && compressedSize != -1) {1257            throw new ZipException(1258              string.Format("Compressed size mismatch between central header({0}) and local header({1})",1259              entry.CompressedSize, compressedSize));1260          }1261        }1244    #region Deferred Updating1245    /// <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.</p1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1250    /// <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      }12581259      if (dataSource == null) {1260        throw new ArgumentNullException(nameof(dataSource));1261      }  12621263        int extraLength = storedNameLength + extraDataLength;1264        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;1263      if (isDisposed_) {1264        throw new ObjectDisposedException("ZipFile");  1265      }1266    }12671268    #endregion12691270    #region Updating12711272    const int DefaultBufferSize = 4096;12661267      if (IsEmbeddedArchive) {1268        throw new ZipException("Cannot update embedded/SFX archives");1269      }12701271      archiveStorage_ = archiveStorage;1272      updateDataSource_ = dataSource;  12731274    /// <summary>1275    /// The kind of update to apply.1276    /// </summary>1277    enum UpdateCommand1278    {1279      Copy,       // Copy original file contents.1280      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.1281      Add,        // Add a new file to the archive.1282    }1274      // NOTE: the baseStream_ may not currently support writing or seeking.12751276      updateIndex_ = new Hashtable();12771278      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      }  12831284    #region Properties1285    /// <summary>1286    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.1287    /// </summary>1288    public INameTransform NameTransform1289    {1290      get {1291        return updateEntryFactory_.NameTransform;1292      }12931294      set {1295        updateEntryFactory_.NameTransform = value;1296      }1297    }12981299    /// <summary>1300    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1301    /// during updates.1302    /// </summary>1303    public IEntryFactory EntryFactory1304    {1305      get {1306        return updateEntryFactory_;1307      }13081309      set {1310        if (value == null) {1311          updateEntryFactory_ = new ZipEntryFactory();1312        }1313        else {1314          updateEntryFactory_ = value;1315        }1316      }1317    }13181319    /// <summary>1320    /// Get /set the buffer size to be used when updating this zip file.1321    /// </summary>1322    public int BufferSize1323    {1324      get { return bufferSize_; }1325      set {1326        if ( value < 1024 ) {1327#if NETCF_1_01328          throw new ArgumentOutOfRangeException("value");1329#else1330          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");1331#endif1332        }13331334        if ( bufferSize_ != value ) {1335          bufferSize_ = value;1336          copyBuffer_ = null;1337        }1338      }1339    }1284      // We must sort by offset before using offset's calculated sizes1285      updates_.Sort(new UpdateComparer());12861287      int idx = 0;1288      foreach (ZipUpdate update in updates_) {1289        //If last entry, there is no next entry offset to use1290        if (idx == updates_.Count - 1)1291          break;12921293        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;1294        idx++;1295      }1296      updateCount_ = updates_.Count;12971298      contentsEdited_ = false;1299      commentEdited_ = false;1300      newComment_ = null;1301    }13021303    /// <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    }13111312    /// <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    }13261327    /// <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      }13381339      CheckUpdating();  13401341    /// <summary>1342    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.1343    /// </summary>1344    public bool IsUpdating1345    {1346      get { return updates_ != null; }1347    }13481349    /// <summary>1350    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.1351    /// </summary>1352    public UseZip64 UseZip641353    {1354      get { return useZip64_; }1355      set { useZip64_ = value; }1356    }13571358    #endregion13591360    #region Immediate updating1361//    TBD: Direct form of updating1362//1363//    public void Update(IEntryMatcher deleteMatcher)1364//    {1365//    }1366//1367//    public void Update(IScanner addScanner)1368//    {1369//    }1370    #endregion13711372    #region Deferred Updating1373    /// <summary>1374    /// Begin updating this <see cref="ZipFile"/> archive.1375    /// </summary>1376    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p1377    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1341      try {1342        updateIndex_.Clear();1343        updateIndex_ = null;13441345        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        }13581359      } finally {1360        PostUpdateCleanup();1361      }1362    }13631364    /// <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    }13731374    /// <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    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>1380    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1381    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)1382    {1383      if ( archiveStorage == null ) {1384        throw new ArgumentNullException(nameof(archiveStorage));1385      }1379    public void SetComment(string comment)1380    {1381      if (isDisposed_) {1382        throw new ObjectDisposedException("ZipFile");1383      }13841385      CheckUpdating();  13861387      if ( dataSource == null ) {1388        throw new ArgumentNullException(nameof(dataSource));1389      }13901391      if ( isDisposed_ ) {1392        throw new ObjectDisposedException("ZipFile");1393      }13941395      if ( IsEmbeddedArchive ) {1396        throw new ZipException ("Cannot update embedded/SFX archives");1397      }1387      newComment_ = new ZipString(comment);13881389      if (newComment_.RawLength > 0xffff) {1390        newComment_ = null;1391        throw new ZipException("Comment length exceeds maximum - 65535");1392      }13931394      // We dont take account of the original and current comment appearing to be the same1395      // as encoding may be different.1396      commentEdited_ = true;1397    }  13981399      archiveStorage_ = archiveStorage;1400      updateDataSource_ = dataSource;14011402      // NOTE: the baseStream_ may not currently support writing or seeking.14031404      updateIndex_ = new Hashtable();14051406      updates_ = new ArrayList(entries_.Length);1407      foreach(ZipEntry entry in entries_) {1408        int index = updates_.Add(new ZipUpdate(entry));1409        updateIndex_.Add(entry.Name, index);1410      }14111412      // We must sort by offset before using offset's calculated sizes1413      updates_.Sort(new UpdateComparer());14141415      int idx = 0;1416      foreach (ZipUpdate update in updates_) {1417        //If last entry, there is no next entry offset to use1418        if (idx == updates_.Count - 1)1419          break;14201421        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset;1422        idx++;1423      }1424      updateCount_ = updates_.Count;14251426      contentsEdited_ = false;1427      commentEdited_ = false;1428      newComment_ = null;1429    }14301431    /// <summary>1432    /// Begin updating to this <see cref="ZipFile"/> archive.1433    /// </summary>1434    /// <param name="archiveStorage">The storage to use during the update.</param>1435    public void BeginUpdate(IArchiveStorage archiveStorage)1436    {1437      BeginUpdate(archiveStorage, new DynamicDiskDataSource());1438    }14391440    /// <summary>1441    /// Begin updating this <see cref="ZipFile"/> archive.1442    /// </summary>1443    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>1444    /// <seealso cref="CommitUpdate"></seealso>1445    /// <seealso cref="AbortUpdate"></seealso>1446    public void BeginUpdate()1447    {1448      if ( Name == null ) {1449        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource());1450      }1451      else {1452        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());1453      }1399    #endregion14001401    #region Adding Entries14021403    void AddUpdate(ZipUpdate update)1404    {1405      contentsEdited_ = true;14061407      int index = FindExistingUpdate(update.Entry.Name);14081409      if (index >= 0) {1410        if (updates_[index] == null) {1411          updateCount_ += 1;1412        }14131414        // 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    }14221423    /// <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      }14371438      if (isDisposed_) {1439        throw new ObjectDisposedException("ZipFile");1440      }14411442      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1443        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1444      }14451446      CheckUpdating();1447      contentsEdited_ = true;14481449      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1450      entry.IsUnicodeText = useUnicodeText;1451      entry.CompressionMethod = compressionMethod;14521453      AddUpdate(new ZipUpdate(fileName, entry));  1454    }  1455  1456    /// <summary>1457    /// Commit current updates, updating this archive.1457    /// Add a new entry to the archive.  1458    /// </summary>1459    /// <seealso cref="BeginUpdate()"></seealso>1460    /// <seealso cref="AbortUpdate"></seealso>1461    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1462    public void CommitUpdate()1463    {1464      if ( isDisposed_ ) {1465        throw new ObjectDisposedException("ZipFile");1466      }14671468      CheckUpdating();14691470      try {1471        updateIndex_.Clear();1472        updateIndex_=null;14731474        if( contentsEdited_ ) {1475          RunUpdates();1476        }1477        else if( commentEdited_ ) {1478          UpdateCommentOnly();1479        }1480        else {1481          // Create an empty archive if none existed originally.1482          if( entries_.Length==0 ) {1483            byte[] theComment=(newComment_!=null)?newComment_.RawComment:ZipConstants.ConvertToArray(comment_);1484            using( ZipHelperStream zhs=new ZipHelperStream(baseStream_) ) {1485              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);1486            }1487          }1488        }14891459    /// <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      }14681469      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1470        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1471      }14721473      CheckUpdating();1474      contentsEdited_ = true;14751476      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1477      entry.CompressionMethod = compressionMethod;1478      AddUpdate(new ZipUpdate(fileName, entry));1479    }14801481    /// <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      finally {1492        PostUpdateCleanup();1493      }14911492      CheckUpdating();1493      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));  1494    }  1495  1496    /// <summary>1497    /// Abort updating leaving the archive unchanged.1497    /// Add a file to the archive.  1498    /// </summary>1499    /// <seealso cref="BeginUpdate()"></seealso>1500    /// <seealso cref="CommitUpdate"></seealso>1501    public void AbortUpdate()1502    {1503      PostUpdateCleanup();1504    }15051506    /// <summary>1507    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.1508    /// </summary>1509    /// <param name="comment">The comment to record.</param>1510    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1511    public void SetComment(string comment)1512    {1513      if ( isDisposed_ ) {1514        throw new ObjectDisposedException("ZipFile");1515      }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      }15071508      if (entryName == null) {1509        throw new ArgumentNullException(nameof(entryName));1510      }15111512      CheckUpdating();1513      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));1514    }1515  15161517      CheckUpdating();15181519      newComment_ = new ZipString(comment);15201521      if ( newComment_.RawLength  > 0xffff ) {1522        newComment_ = null;1523        throw new ZipException("Comment length exceeds maximum - 65535");1524      }15251526      // We dont take account of the original and current comment appearing to be the same1527      // as encoding may be different.1528      commentEdited_ = true;1529    }15301531    #endregion15321533    #region Adding Entries15341535    void AddUpdate(ZipUpdate update)1536    {1537      contentsEdited_ = true;15381539      int index = FindExistingUpdate(update.Entry.Name);15401541      if (index >= 0) {1542        if ( updates_[index] == null ) {1543          updateCount_ += 1;1544        }15451546        // Direct replacement is faster than delete and add.1547        updates_[index] = update;1548      }1549      else {1550        index = updates_.Add(update);1551        updateCount_ += 1;1552        updateIndex_.Add(update.Entry.Name, index);1553      }1554    }15551556    /// <summary>1557    /// Add a new entry to the archive.1558    /// </summary>1559    /// <param name="fileName">The name of the file to add.</param>1560    /// <param name="compressionMethod">The compression method to use.</param>1561    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>1562    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1563    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1564    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>1565    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText )1566    {1567      if (fileName == null) {1568        throw new ArgumentNullException(nameof(fileName));1569      }15701571      if ( isDisposed_ ) {1572        throw new ObjectDisposedException("ZipFile");1573      }15741575      if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) {1576        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1577      }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      }15271528      if (entryName == null) {1529        throw new ArgumentNullException(nameof(entryName));1530      }15311532      CheckUpdating();1533      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));1534    }15351536    /// <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      }15471548      if (entryName == null) {1549        throw new ArgumentNullException(nameof(entryName));1550      }15511552      CheckUpdating();15531554      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1555      entry.CompressionMethod = compressionMethod;15561557      AddUpdate(new ZipUpdate(dataSource, entry));1558    }15591560    /// <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 useUnicode1568    {1569      if (dataSource == null) {1570        throw new ArgumentNullException(nameof(dataSource));1571      }15721573      if (entryName == null) {1574        throw new ArgumentNullException(nameof(entryName));1575      }15761577      CheckUpdating();  15781579      CheckUpdating();1580      contentsEdited_ = true;15811582      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1583      entry.IsUnicodeText = useUnicodeText;1584      entry.CompressionMethod = compressionMethod;1579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1580      entry.IsUnicodeText = useUnicodeText;1581      entry.CompressionMethod = compressionMethod;15821583      AddUpdate(new ZipUpdate(dataSource, entry));1584    }  15851586      AddUpdate(new ZipUpdate(fileName, entry));1587    }15881589    /// <summary>1590    /// Add a new entry to the archive.1591    /// </summary>1592    /// <param name="fileName">The name of the file to add.</param>1593    /// <param name="compressionMethod">The compression method to use.</param>1594    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>1595    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>1596    public void Add(string fileName, CompressionMethod compressionMethod)1597    {1598      if ( fileName == null ) {1599        throw new ArgumentNullException(nameof(fileName));1600      }16011602      if ( !ZipEntry.IsCompressionMethodSupported(compressionMethod) ) {1603        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1604      }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      }15961597      CheckUpdating();15981599      if ((entry.Size != 0) || (entry.CompressedSize != 0)) {1600        throw new ZipException("Entry cannot have any data");1601      }16021603      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));1604    }  16051606      CheckUpdating();1607      contentsEdited_ = true;16081609      ZipEntry entry = EntryFactory.MakeFileEntry(fileName);1610      entry.CompressionMethod = compressionMethod;1611      AddUpdate(new ZipUpdate(fileName, entry));1612    }16131614    /// <summary>1615    /// Add a file to the archive.1616    /// </summary>1617    /// <param name="fileName">The name of the file to add.</param>1618    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1619    public void Add(string fileName)1620    {1621      if ( fileName == null ) {1622        throw new ArgumentNullException(nameof(fileName));1623      }16241625      CheckUpdating();1626      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName)));1627    }16281629    /// <summary>1630    /// Add a file to the archive.1631    /// </summary>1632    /// <param name="fileName">The name of the file to add.</param>1633    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>1634    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1635    public void Add(string fileName, string entryName)1636    {1637      if (fileName == null) {1638        throw new ArgumentNullException(nameof(fileName));1639      }16401641      if ( entryName == null ) {1642        throw new ArgumentNullException(nameof(entryName));1643      }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      }16151616      CheckUpdating();16171618      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);1619      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));1620    }16211622    #endregion16231624    #region Modifying Entries1625    /* 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          }16331634          if ( updated == null ) {1635            throw new ArgumentNullException("updated");1636          }16371638          CheckUpdating();1639          contentsEdited_ = true;1640          updates_.Add(new ZipUpdate(original, updated));1641        }1642    */1643    #endregion  16441645      CheckUpdating();1646      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true)));1647    }164816491650    /// <summary>1651    /// Add a file entry with data.1652    /// </summary>1653    /// <param name="dataSource">The source of the data for this entry.</param>1654    /// <param name="entryName">The name to give to the entry.</param>1655    public void Add(IStaticDataSource dataSource, string entryName)1656    {1657      if ( dataSource == null ) {1658        throw new ArgumentNullException(nameof(dataSource));1659      }16601661      if ( entryName == null ) {1662        throw new ArgumentNullException(nameof(entryName));1663      }16641665      CheckUpdating();1666      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false)));1667    }16681669    /// <summary>1670    /// Add a file entry with data.1671    /// </summary>1672    /// <param name="dataSource">The source of the data for this entry.</param>1673    /// <param name="entryName">The name to give to the entry.</param>1674    /// <param name="compressionMethod">The compression method to use.</param>1675    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)1676    {1677      if ( dataSource == null ) {1678        throw new ArgumentNullException(nameof(dataSource));1679      }16801681      if ( entryName == null ) {1682        throw new ArgumentNullException(nameof(entryName));1683      }16841685      CheckUpdating();16861687      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1688      entry.CompressionMethod = compressionMethod;16891690      AddUpdate(new ZipUpdate(dataSource, entry));1691    }16921693    /// <summary>1694    /// Add a file entry with data.1695    /// </summary>1696    /// <param name="dataSource">The source of the data for this entry.</param>1697    /// <param name="entryName">The name to give to the entry.</param>1698    /// <param name="compressionMethod">The compression method to use.</param>1699    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>1700    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode1701    {1702      if (dataSource == null) {1703        throw new ArgumentNullException(nameof(dataSource));1704      }17051706      if ( entryName == null ) {1707        throw new ArgumentNullException(nameof(entryName));1708      }17091710      CheckUpdating();17111712      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false);1713      entry.IsUnicodeText = useUnicodeText;1714      entry.CompressionMethod = compressionMethod;17151716      AddUpdate(new ZipUpdate(dataSource, entry));1717    }17181719    /// <summary>1720    /// Add a <see cref="ZipEntry"/> that contains no data.1721    /// </summary>1722    /// <param name="entry">The entry to add.</param>1723    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>1724    public void Add(ZipEntry entry)1725    {1726      if ( entry == null ) {1727        throw new ArgumentNullException(nameof(entry));1728      }17291730      CheckUpdating();1645    #region Deleting Entries1646    /// <summary>1647    /// Delete an entry by name1648    /// </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      }16561657      CheckUpdating();16581659      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    }16711672    /// <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      }16811682      CheckUpdating();16831684      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    }16931694    #endregion16951696    #region Update Support16971698    #region Writing Values/Headers1699    void WriteLEShort(int value)1700    {1701      baseStream_.WriteByte((byte)(value & 0xff));1702      baseStream_.WriteByte((byte)((value >> 8) & 0xff));1703    }17041705    /// <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    }17131714    /// <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    }17221723    /// <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    }  17311732      if ( (entry.Size != 0) || (entry.CompressedSize != 0) ) {1733        throw new ZipException("Entry cannot have any data");1734      }17351736      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));1737    }17381739    /// <summary>1740    /// Add a directory entry to the archive.1741    /// </summary>1742    /// <param name="directoryName">The directory to add.</param>1743    public void AddDirectory(string directoryName)1744    {1745      if ( directoryName == null ) {1746        throw new ArgumentNullException(nameof(directoryName));1747      }17481749      CheckUpdating();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    }17401741    void WriteLEUlong(ulong value)1742    {1743      WriteLEUint((uint)(value & 0xffffffff));1744      WriteLEUint((uint)(value >> 32));1745    }17461747    void WriteLocalEntryHeader(ZipUpdate update)1748    {1749      ZipEntry entry = update.OutEntry;  17501751      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName);1752      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry));1753    }17541755    #endregion17561757    #region Modifying Entries1758/* Modify not yet ready for public consumption.1759   Direct modification of an entry should not overwrite original data before its read.1760   Safe mode is trivial in this sense.1761    public void Modify(ZipEntry original, ZipEntry updated)1762    {1763      if ( original == null ) {1764        throw new ArgumentNullException("original");1765      }1751      // TODO: Local offset will require adjusting for multi-disk zip files.1752      entry.Offset = baseStream_.Position;17531754      // 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        }  17661767      if ( updated == null ) {1768        throw new ArgumentNullException("updated");1769      }17701771      CheckUpdating();1772      contentsEdited_ = true;1773      updates_.Add(new ZipUpdate(original, updated));1774    }1775*/1776    #endregion17771778    #region Deleting Entries1779    /// <summary>1780    /// Delete an entry by name1781    /// </summary>1782    /// <param name="fileName">The filename to delete</param>1783    /// <returns>True if the entry was found and deleted; false otherwise.</returns>1784    public bool Delete(string fileName)1785    {1786      if ( fileName == null ) {1787        throw new ArgumentNullException(nameof(fileName));1788      }17891790      CheckUpdating();17911792      bool result = false;1793      int index = FindExistingUpdate(fileName);1794      if ( (index >= 0) && (updates_[index] != null) ) {1795        result = true;1796        contentsEdited_ = true;1797        updates_[index] = null;1798        updateCount_ -= 1;1799      }1800      else {1801        throw new ZipException("Cannot find entry to delete");1802      }1803      return result;1804    }18051806    /// <summary>1807    /// Delete a <see cref="ZipEntry"/> from the archive.1808    /// </summary>1809    /// <param name="entry">The entry to delete.</param>1810    public void Delete(ZipEntry entry)1811    {1812      if ( entry == null ) {1813        throw new ArgumentNullException(nameof(entry));1814      }18151816      CheckUpdating();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        }17751776        switch (useZip64_) {1777          case UseZip64.Dynamic:1778            if (entry.Size < 0) {1779              entry.ForceZip64();1780            }1781            break;17821783          case UseZip64.On:1784            entry.ForceZip64();1785            break;17861787          case UseZip64.Off:1788            // Do nothing.  The entry itself may be using Zip64 independantly.1789            break;1790        }1791      }17921793      // Write the local file header1794      WriteLEInt(ZipConstants.LocalHeaderSignature);17951796      WriteLEShort(entry.Version);1797      WriteLEShort(entry.Flags);17981799      WriteLEShort((byte)entry.CompressionMethod);1800      WriteLEInt((int)entry.DosTime);18011802      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      }18091810      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        }  18171818      int index = FindExistingUpdate(entry);1819      if ( index >= 0 ) {1820        contentsEdited_ = true;1821        updates_[index] = null;1822        updateCount_ -= 1;1823      }1824      else {1825        throw new ZipException("Cannot find entry to delete");1818        WriteLEInt((int)entry.CompressedSize);1819        WriteLEInt((int)entry.Size);1820      }18211822      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);18231824      if (name.Length > 0xFFFF) {1825        throw new ZipException("Entry name too long.");  1826      }1827    }18281829    #endregion18301831    #region Update Support18271828      var ed = new ZipExtraData(entry.ExtraData);18291830      if (entry.LocalHeaderRequiresZip64) {1831        ed.StartNewEntry();  18321833    #region Writing Values/Headers1834    void WriteLEShort(int value)1835    {1836      baseStream_.WriteByte(( byte )(value & 0xff));1837      baseStream_.WriteByte(( byte )((value >> 8) & 0xff));1838    }18391840    /// <summary>1841    /// Write an unsigned short in little endian byte order.1842    /// </summary>1843    void WriteLEUshort(ushort value)1844    {1845      baseStream_.WriteByte(( byte )(value & 0xff));1846      baseStream_.WriteByte(( byte )(value >> 8));1847    }18481849    /// <summary>1850    /// Write an int in little endian byte order.1851    /// </summary>1852    void WriteLEInt(int value)1853    {1854      WriteLEShort(value & 0xffff);1855      WriteLEShort(value >> 16);1856    }18571858    /// <summary>1859    /// Write an unsigned int in little endian byte order.1860    /// </summary>1861    void WriteLEUint(uint value)1862    {1863      WriteLEUshort((ushort)(value & 0xffff));1864      WriteLEUshort((ushort)(value >> 16));1865    }18661867    /// <summary>1868    /// Write a long in little endian byte order.1869    /// </summary>1870    void WriteLeLong(long value)1871    {1872      WriteLEInt(( int )(value & 0xffffffff));1873      WriteLEInt(( int )(value >> 32));1874    }18751876    void WriteLEUlong(ulong value)1877    {1878      WriteLEUint(( uint )(value & 0xffffffff));1879      WriteLEUint(( uint )(value >> 32));1880    }18811882    void WriteLocalEntryHeader(ZipUpdate update)1883    {1884      ZipEntry entry = update.OutEntry;18851886      // TODO: Local offset will require adjusting for multi-disk zip files.1887      entry.Offset = baseStream_.Position;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      }18411842      entry.ExtraData = ed.GetEntryData();18431844      WriteLEShort(name.Length);1845      WriteLEShort(entry.ExtraData.Length);18461847      if (name.Length > 0) {1848        baseStream_.Write(name, 0, name.Length);1849      }18501851      if (entry.LocalHeaderRequiresZip64) {1852        if (!ed.Find(1)) {1853          throw new ZipException("Internal error cannot find extra data");1854        }18551856        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1857      }18581859      if (entry.ExtraData.Length > 0) {1860        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);1861      }1862    }18631864    int WriteCentralDirectoryHeader(ZipEntry entry)1865    {1866      if (entry.CompressedSize < 0) {1867        throw new ZipException("Attempt to write central directory entry with unknown csize");1868      }18691870      if (entry.Size < 0) {1871        throw new ZipException("Attempt to write central directory entry with unknown size");1872      }18731874      if (entry.Crc < 0) {1875        throw new ZipException("Attempt to write central directory entry with unknown crc");1876      }18771878      // Write the central file header1879      WriteLEInt(ZipConstants.CentralHeaderSignature);18801881      // Version made by1882      WriteLEShort(ZipConstants.VersionMadeBy);18831884      // Version required to extract1885      WriteLEShort(entry.Version);18861887      WriteLEShort(entry.Flags);  18881889      // TODO: Need to clear any entry flags that dont make sense or throw an exception here.1890      if (update.Command != UpdateCommand.Copy) {1891        if (entry.CompressionMethod == CompressionMethod.Deflated) {1892          if (entry.Size == 0) {1893            // No need to compress - no data.1894            entry.CompressedSize = entry.Size;1895            entry.Crc = 0;1896            entry.CompressionMethod = CompressionMethod.Stored;1897          }1898        }1899        else if (entry.CompressionMethod == CompressionMethod.Stored) {1900          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;1901        }19021903        if (HaveKeys) {1904          entry.IsCrypted = true;1905          if (entry.Crc < 0) {1906            entry.Flags |= (int)GeneralBitFlags.Descriptor;1907          }1908        }1909        else {1910          entry.IsCrypted = false;1911        }1889      unchecked {1890        WriteLEShort((byte)entry.CompressionMethod);1891        WriteLEInt((int)entry.DosTime);1892        WriteLEInt((int)entry.Crc);1893      }18941895      if ((entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff)) {1896        WriteLEInt(-1);1897      } else {1898        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));1899      }19001901      if ((entry.IsZip64Forced()) || (entry.Size >= 0xffffffff)) {1902        WriteLEInt(-1);1903      } else {1904        WriteLEInt((int)entry.Size);1905      }19061907      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);19081909      if (name.Length > 0xFFFF) {1910        throw new ZipException("Entry name is too long.");1911      }  19121913        switch (useZip64_) {1914          case UseZip64.Dynamic:1915            if (entry.Size < 0) {1916              entry.ForceZip64();1917            }1918            break;19191920          case UseZip64.On:1921            entry.ForceZip64();1922            break;19231924          case UseZip64.Off:1925            // Do nothing.  The entry itself may be using Zip64 independantly.1926            break;1913      WriteLEShort(name.Length);19141915      // Central header extra data is different to local header version so regenerate.1916      var ed = new ZipExtraData(entry.ExtraData);19171918      if (entry.CentralHeaderRequiresZip64) {1919        ed.StartNewEntry();19201921        if ((entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On)) {1922          ed.AddLeLong(entry.Size);1923        }19241925        if ((entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On)) {1926          ed.AddLeLong(entry.CompressedSize);  1927        }1928      }19291930      // Write the local file header1931      WriteLEInt(ZipConstants.LocalHeaderSignature);19281929        if (entry.Offset >= 0xffffffff) {1930          ed.AddLeLong(entry.Offset);1931        }  19321933      WriteLEShort(entry.Version);1934      WriteLEShort(entry.Flags);19351936      WriteLEShort((byte)entry.CompressionMethod);1937      WriteLEInt(( int )entry.DosTime);19381939      if ( !entry.HasCrc ) {1940        // Note patch address for updating CRC later.1941        update.CrcPatchOffset = baseStream_.Position;1942        WriteLEInt(( int )0);1943      }1944      else {1945        WriteLEInt(unchecked(( int )entry.Crc));1946      }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      }19391940      byte[] centralExtraData = ed.GetEntryData();19411942      WriteLEShort(centralExtraData.Length);1943      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);19441945      WriteLEShort(0);    // disk number1946      WriteLEShort(0);    // internal file attributes  19471948      if (entry.LocalHeaderRequiresZip64) {1949        WriteLEInt(-1);1950        WriteLEInt(-1);1951      }1952      else {1953        if ( (entry.CompressedSize < 0) || (entry.Size < 0) ) {1954          update.SizePatchOffset = baseStream_.Position;1955        }19561957        WriteLEInt(( int )entry.CompressedSize);1958        WriteLEInt(( int )entry.Size);1959      }19601961      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);19621963      if ( name.Length > 0xFFFF ) {1964        throw new ZipException("Entry name too long.");1965      }19661967      var ed = new ZipExtraData(entry.ExtraData);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      }19581959      if (entry.Offset >= 0xffffffff) {1960        WriteLEUint(0xffffffff);1961      } else {1962        WriteLEUint((uint)(int)entry.Offset);1963      }19641965      if (name.Length > 0) {1966        baseStream_.Write(name, 0, name.Length);1967      }  19681969      if ( entry.LocalHeaderRequiresZip64 ) {1970        ed.StartNewEntry();19711972        // Local entry header always includes size and compressed size.1973        // NOTE the order of these fields is reversed when compared to the normal headers!1974        ed.AddLeLong(entry.Size);1975        ed.AddLeLong(entry.CompressedSize);1976        ed.AddNewEntry(1);1969      if (centralExtraData.Length > 0) {1970        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);1971      }19721973      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];19741975      if (rawComment.Length > 0) {1976        baseStream_.Write(rawComment, 0, rawComment.Length);  1977      }1978      else {1979        ed.Delete(1);1980      }19811982      entry.ExtraData = ed.GetEntryData();19831984      WriteLEShort(name.Length);1985      WriteLEShort(entry.ExtraData.Length);19861987      if ( name.Length > 0 ) {1988        baseStream_.Write(name, 0, name.Length);1989      }19901991      if ( entry.LocalHeaderRequiresZip64 ) {1992        if ( !ed.Find(1) ) {1993          throw new ZipException("Internal error cannot find extra data");1994        }19951996        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1997      }19981999      if ( entry.ExtraData.Length > 0 ) {2000        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);2001      }2002    }20032004    int WriteCentralDirectoryHeader(ZipEntry entry)2005    {2006      if ( entry.CompressedSize < 0 ) {2007        throw new ZipException("Attempt to write central directory entry with unknown csize");2008      }20092010      if ( entry.Size < 0 ) {2011        throw new ZipException("Attempt to write central directory entry with unknown size");2012      }20132014      if ( entry.Crc < 0 ) {2015        throw new ZipException("Attempt to write central directory entry with unknown crc");2016      }20172018      // Write the central file header2019      WriteLEInt(ZipConstants.CentralHeaderSignature);20202021      // Version made by2022      WriteLEShort(ZipConstants.VersionMadeBy);20232024      // Version required to extract2025      WriteLEShort(entry.Version);19781979      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;1980    }1981    #endregion19821983    void PostUpdateCleanup()1984    {1985      updateDataSource_ = null;1986      updates_ = null;1987      updateIndex_ = null;19881989      if (archiveStorage_ != null) {1990        archiveStorage_.Dispose();1991        archiveStorage_ = null;1992      }1993    }19941995    string GetTransformedFileName(string name)1996    {1997      INameTransform transform = NameTransform;1998      return (transform != null) ?1999        transform.TransformFile(name) :2000        name;2001    }20022003    string GetTransformedDirectoryName(string name)2004    {2005      INameTransform transform = NameTransform;2006      return (transform != null) ?2007        transform.TransformDirectory(name) :2008        name;2009    }20102011    /// <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    }20222023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2024    {2025      int bytesToCopy = GetDescriptorSize(update);  20262027      WriteLEShort(entry.Flags);20282029      unchecked {2030        WriteLEShort((byte)entry.CompressionMethod);2031        WriteLEInt((int)entry.DosTime);2032        WriteLEInt((int)entry.Crc);2033      }20342035      if ( (entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff) ) {2036        WriteLEInt(-1);2037      }2038      else {2039        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));2040      }20412042      if ( (entry.IsZip64Forced()) || (entry.Size >= 0xffffffff) ) {2043        WriteLEInt(-1);2044      }2045      else {2046        WriteLEInt((int)entry.Size);2047      }20482049      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);2027      if (bytesToCopy > 0) {2028        byte[] buffer = GetBuffer();20292030        while (bytesToCopy > 0) {2031          int readSize = Math.Min(buffer.Length, bytesToCopy);20322033          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    }20432044    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      }  20502051      if ( name.Length > 0xFFFF ) {2052        throw new ZipException("Entry name is too long.");2053      }2051      // NOTE: Compressed size is updated elsewhere.2052      var crc = new Crc32();2053      byte[] buffer = GetBuffer();  20542055      WriteLEShort(name.Length);20562057      // Central header extra data is different to local header version so regenerate.2058      var ed = new ZipExtraData(entry.ExtraData);20592060      if ( entry.CentralHeaderRequiresZip64 ) {2061        ed.StartNewEntry();20622063        if ( (entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On) )2064        {2065          ed.AddLeLong(entry.Size);2066        }20672068        if ( (entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On) )2069        {2070          ed.AddLeLong(entry.CompressedSize);2071        }20722073        if ( entry.Offset >= 0xffffffff ) {2074          ed.AddLeLong(entry.Offset);2075        }20762077        // Number of disk on which this file starts isnt supported and is never written here.2078        ed.AddNewEntry(1);2079      }2080      else {2081        // Should have already be done when local header was added.2082        ed.Delete(1);2083      }20842085      byte[] centralExtraData = ed.GetEntryData();2055      long targetBytes = bytesToCopy;2056      long totalBytesRead = 0;20572058      int bytesRead;2059      do {2060        int readSize = buffer.Length;20612062        if (bytesToCopy < readSize) {2063          readSize = (int)bytesToCopy;2064        }20652066        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));20772078      if (totalBytesRead != targetBytes) {2079        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2080      }20812082      if (updateCrc) {2083        update.OutEntry.Crc = crc.Value;2084      }2085    }  20862087      WriteLEShort(centralExtraData.Length);2088      WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);20892090      WriteLEShort(0);  // disk number2091      WriteLEShort(0);  // internal file attributes20922093      // External file attributes...2094      if ( entry.ExternalFileAttributes != -1 ) {2095        WriteLEInt(entry.ExternalFileAttributes);2096      }2097      else {2098        if ( entry.IsDirectory ) {2099          WriteLEUint(16);2100        }2101        else {2102          WriteLEUint(0);2103        }2104      }21052106      if ( entry.Offset >= 0xffffffff ) {2107        WriteLEUint(0xffffffff);2108      }2109      else {2110        WriteLEUint((uint)(int)entry.Offset);2111      }21122113      if ( name.Length > 0 ) {2114        baseStream_.Write(name, 0, name.Length);2115      }21162117      if ( centralExtraData.Length > 0 ) {2118        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);2119      }21202121      byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];21222123      if ( rawComment.Length > 0 ) {2124        baseStream_.Write(rawComment, 0, rawComment.Length);2125      }21262127      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;2128    }2129    #endregion21302131    void PostUpdateCleanup()2132    {2133            updateDataSource_ = null;2134            updates_ = null;2135            updateIndex_ = null;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    }21032104    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2105    {2106      int bytesToCopy = GetDescriptorSize(update);21072108      while (bytesToCopy > 0) {2109        var readSize = (int)bytesToCopy;2110        byte[] buffer = GetBuffer();21112112        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    }21252126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2127    {2128      long bytesToCopy = update.Entry.CompressedSize;21292130      // NOTE: Compressed size is updated elsewhere.2131      var crc = new Crc32();2132      byte[] buffer = GetBuffer();21332134      long targetBytes = bytesToCopy;2135      long totalBytesRead = 0;  21362137            if (archiveStorage_ != null)2138            {2139        archiveStorage_.Dispose();2140        archiveStorage_=null;2141      }2142    }21432144    string GetTransformedFileName(string name)2145    {2146            INameTransform transform = NameTransform;2147      return (transform != null) ?2148        transform.TransformFile(name) :2149        name;2150    }21512152    string GetTransformedDirectoryName(string name)2153    {2154            INameTransform transform = NameTransform;2155            return (transform != null) ?2156        transform.TransformDirectory(name) :2157        name;2158    }21592160    /// <summary>2161    /// Get a raw memory buffer.2162    /// </summary>2163    /// <returns>Returns a raw memory buffer.</returns>2164    byte[] GetBuffer()2165    {2166      if ( copyBuffer_ == null ) {2167        copyBuffer_ = new byte[bufferSize_];2137      int bytesRead;2138      do {2139        int readSize = buffer.Length;21402141        if (bytesToCopy < readSize) {2142          readSize = (int)bytesToCopy;2143        }21442145        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);21532154          destinationPosition += bytesRead;2155          sourcePosition += bytesRead;2156          bytesToCopy -= bytesRead;2157          totalBytesRead += bytesRead;2158        }2159      }2160      while ((bytesRead > 0) && (bytesToCopy > 0));21612162      if (totalBytesRead != targetBytes) {2163        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2164      }21652166      if (updateCrc) {2167        update.OutEntry.Crc = crc.Value;  2168      }2169      return copyBuffer_;2170    }21712172    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2173    {2174      int bytesToCopy = GetDescriptorSize(update);2169    }21702171    int FindExistingUpdate(ZipEntry entry)2172    {2173      int result = -1;2174      string convertedName = GetTransformedFileName(entry.Name);  21752176      if ( bytesToCopy > 0 ) {2177        byte[] buffer = GetBuffer();21782179        while ( bytesToCopy > 0 ) {2180          int readSize = Math.Min(buffer.Length, bytesToCopy);21812182          int bytesRead = source.Read(buffer, 0, readSize);2183          if ( bytesRead > 0 ) {2184            dest.Write(buffer, 0, bytesRead);2185            bytesToCopy -= bytesRead;2186          }2187          else {2188            throw new ZipException("Unxpected end of stream");2189          }2190        }2191      }2192    }21932194    void CopyBytes(ZipUpdate update, Stream destination, Stream source,2195      long bytesToCopy, bool updateCrc)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 useful2181            // 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    }21942195    int FindExistingUpdate(string fileName)  2196    {2197      if ( destination == source ) {2198        throw new InvalidOperationException("Destination and source are the same");2199      }2197      int result = -1;21982199      string convertedName = GetTransformedFileName(fileName);  22002201      // NOTE: Compressed size is updated elsewhere.2202      var crc = new Crc32();2203      byte[] buffer = GetBuffer();2201      if (updateIndex_.ContainsKey(convertedName)) {2202        result = (int)updateIndex_[convertedName];2203      }  22042205      long targetBytes = bytesToCopy;2206      long totalBytesRead = 0;22072208      int bytesRead;2209      do {2210        int readSize = buffer.Length;22112212        if ( bytesToCopy < readSize ) {2213          readSize = (int)bytesToCopy;2214        }22152216        bytesRead = source.Read(buffer, 0, readSize);2217        if ( bytesRead > 0 ) {2218          if ( updateCrc ) {2219            crc.Update(buffer, 0, bytesRead);2220          }2221          destination.Write(buffer, 0, bytesRead);2222          bytesToCopy -= bytesRead;2223          totalBytesRead += bytesRead;2224        }2225      }2226      while ( (bytesRead > 0) && (bytesToCopy > 0) );22272228      if ( totalBytesRead != targetBytes ) {2229        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2230      }22312232      if ( updateCrc ) {2233        update.OutEntry.Crc = crc.Value;2234      }2235    }22362237    /// <summary>2238    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.2239    /// </summary>2240    /// <param name="update">The update to get the size for.</param>2241    /// <returns>The descriptor size, zero if there isnt one.</returns>2242    int GetDescriptorSize(ZipUpdate update)2243    {2244      int result = 0;2245      if ( (update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {2246        result = ZipConstants.DataDescriptorSize - 4;2247        if ( update.Entry.LocalHeaderRequiresZip64 ) {2248          result = ZipConstants.Zip64DataDescriptorSize - 4;2249        }2250      }2251      return result;2252    }2205      /*2206            // This is slow like the coming of the next ice age but takes less storage and may be useful2207            // 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       */22162217      return result;2218    }22192220    /// <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_;22282229      if (entry.IsCrypted == true) {2230        result = CreateAndInitEncryptionStream(result, entry);2231      }22322233      switch (entry.CompressionMethod) {2234        case CompressionMethod.Stored:2235          result = new UncompressedStream(result);2236          break;22372238        case CompressionMethod.Deflated:2239          var dos = new DeflaterOutputStream(result, new Deflater(9, true));2240          dos.IsStreamOwner = false;2241          result = dos;2242          break;22432244        default:2245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2246      }2247      return result;2248    }22492250    void AddEntry(ZipFile workFile, ZipUpdate update)2251    {2252      Stream source = null;  22532254    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2255    {2256      int bytesToCopy = GetDescriptorSize(update);22572258      while ( bytesToCopy > 0 ) {2259        var readSize = (int)bytesToCopy;2260        byte[] buffer = GetBuffer();2254      if (update.Entry.IsFile) {2255        source = update.GetSource();22562257        if (source == null) {2258          source = updateDataSource_.GetSource(update.Entry, update.Filename);2259        }2260      }  22612262        stream.Position = sourcePosition;2263        int bytesRead = stream.Read(buffer, 0, readSize);2264        if ( bytesRead > 0 ) {2265          stream.Position = destinationPosition;2266          stream.Write(buffer, 0, bytesRead);2267          bytesToCopy -= bytesRead;2268          destinationPosition += bytesRead;2269          sourcePosition += bytesRead;2270        }2271        else {2272          throw new ZipException("Unxpected end of stream");2273        }2274      }2275    }22762277    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2278    {2279      long bytesToCopy = update.Entry.CompressedSize;22802281      // NOTE: Compressed size is updated elsewhere.2282      var crc = new Crc32();2283      byte[] buffer = GetBuffer();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          }22732274          workFile.WriteLocalEntryHeader(update);22752276          long dataStart = workFile.baseStream_.Position;22772278          using (Stream output = workFile.GetOutputStream(update.OutEntry)) {2279            CopyBytes(update, output, source, sourceStreamLength, true);2280          }22812282          long dataEnd = workFile.baseStream_.Position;2283          update.OutEntry.CompressedSize = dataEnd - dataStart;  22842285      long targetBytes = bytesToCopy;2286      long totalBytesRead = 0;22872288      int bytesRead;2289      do2290      {2291        int readSize = buffer.Length;22922293        if ( bytesToCopy < readSize ) {2294          readSize = (int)bytesToCopy;2295        }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      }22942295    }  22962297        stream.Position = sourcePosition;2298        bytesRead = stream.Read(buffer, 0, readSize);2299        if ( bytesRead > 0 ) {2300          if ( updateCrc ) {2301            crc.Update(buffer, 0, bytesRead);2302          }2303          stream.Position = destinationPosition;2304          stream.Write(buffer, 0, bytesRead);23052306          destinationPosition += bytesRead;2307          sourcePosition += bytesRead;2308          bytesToCopy -= bytesRead;2309          totalBytesRead += bytesRead;2310        }2311      }2312      while ( (bytesRead > 0) && (bytesToCopy > 0) );23132314      if ( totalBytesRead != targetBytes ) {2315        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2316      }23172318      if ( updateCrc ) {2319        update.OutEntry.Crc = crc.Value;2320      }2321    }23222323    int FindExistingUpdate(ZipEntry entry)2324    {2325      int result = -1;2326      string convertedName = GetTransformedFileName(entry.Name);23272328      if (updateIndex_.ContainsKey(convertedName)) {2329        result = (int)updateIndex_[convertedName];2330      }2331/*2332      // This is slow like the coming of the next ice age but takes less storage and may be useful2333      // for CF?2334      for (int index = 0; index < updates_.Count; ++index)2335      {2336        ZipUpdate zu = ( ZipUpdate )updates_[index];2337        if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&2338          (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {2339          result = index;2340          break;2341        }2342      }2343 */2344      return result;2345    }23462347    int FindExistingUpdate(string fileName)2348    {2349      int result = -1;23502351      string convertedName = GetTransformedFileName(fileName);23522353      if (updateIndex_.ContainsKey(convertedName)) {2354        result = (int)updateIndex_[convertedName];2355      }23562357/*2358      // This is slow like the coming of the next ice age but takes less storage and may be useful2359      // for CF?2360      for ( int index = 0; index < updates_.Count; ++index ) {2361        if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,2362          true, CultureInfo.InvariantCulture) == 0 ) {2363          result = index;2364          break;2365        }2366      }2367 */23682369      return result;2370    }23712372    /// <summary>2373    /// Get an output stream for the specified <see cref="ZipEntry"/>2374    /// </summary>2375    /// <param name="entry">The entry to get an output stream for.</param>2376    /// <returns>The output stream obtained for the entry.</returns>2377    Stream GetOutputStream(ZipEntry entry)2378    {2379      Stream result = baseStream_;2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)2298    {2299      workFile.WriteLocalEntryHeader(update);2300      long dataStart = workFile.baseStream_.Position;23012302      // 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      }23102311      long dataEnd = workFile.baseStream_.Position;2312      update.Entry.CompressedSize = dataEnd - dataStart;2313    }23142315    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2316    {2317      bool skipOver = false || update.Entry.Offset == destinationPosition;23182319      if (!skipOver) {2320        baseStream_.Position = destinationPosition;2321        workFile.WriteLocalEntryHeader(update);2322        destinationPosition = baseStream_.Position;2323      }23242325      long sourcePosition = 0;23262327      const int NameLengthOffset = 26;23282329      // TODO: Add base for SFX friendly handling2330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;23312332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23332334      // 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();23382339      sourcePosition = baseStream_.Position + nameLength + extraLength;23402341      if (skipOver) {2342        if (update.OffsetBasedSize != -1)2343          destinationPosition += update.OffsetBasedSize;2344        else2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2346          // WinZip produces a warning on these entries:2347          // "caution: value of lrec.csize (compressed size) changed from ..."2348          destinationPosition +=2349            (sourcePosition - entryDataOffset) + NameLengthOffset + // Header size2350            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    }23582359    void CopyEntry(ZipFile workFile, ZipUpdate update)2360    {2361      workFile.WriteLocalEntryHeader(update);23622363      if (update.Entry.CompressedSize > 0) {2364        const int NameLengthOffset = 26;23652366        long entryDataOffset = update.Entry.Offset + NameLengthOffset;23672368        // TODO: This wont work for SFX files!2369        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23702371        uint nameLength = ReadLEUshort();2372        uint extraLength = ReadLEUshort();23732374        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);23752376        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2377      }2378      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);2379    }  23802381      if ( entry.IsCrypted == true ) {2382#if NETCF_1_02383        throw new ZipException("Encryption not supported for Compact Framework 1.0");2384#else2385        result = CreateAndInitEncryptionStream(result, entry);2386#endif2387      }23882389      switch ( entry.CompressionMethod ) {2390        case CompressionMethod.Stored:2391          result = new UncompressedStream(result);2392          break;23932394        case CompressionMethod.Deflated:2395          var dos = new DeflaterOutputStream(result, new Deflater(9, true));2396          dos.IsStreamOwner = false;2397          result = dos;2398          break;23992400        default:2401          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2402      }2403      return result;2404    }24052406    void AddEntry(ZipFile workFile, ZipUpdate update)2407    {2408      Stream source = null;24092410      if ( update.Entry.IsFile ) {2411        source = update.GetSource();24122413        if ( source == null ) {2414          source = updateDataSource_.GetSource(update.Entry, update.Filename);2415        }2416      }24172418      if ( source != null ) {2419        using ( source ) {2420          long sourceStreamLength = source.Length;2421          if ( update.OutEntry.Size < 0 ) {2422            update.OutEntry.Size = sourceStreamLength;2423          }2424          else {2425            // Check for errant entries.2426            if ( update.OutEntry.Size != sourceStreamLength ) {2427              throw new ZipException("Entry size/stream size mismatch");2428            }2429          }24302431          workFile.WriteLocalEntryHeader(update);24322433          long dataStart = workFile.baseStream_.Position;24342435          using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {2436            CopyBytes(update, output, source, sourceStreamLength, true);2437          }24382439          long dataEnd = workFile.baseStream_.Position;2440          update.OutEntry.CompressedSize = dataEnd - dataStart;24412442          if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor)2443          {2444            var helper = new ZipHelperStream(workFile.baseStream_);2445            helper.WriteDataDescriptor(update.OutEntry);2446          }2447        }2381    void Reopen(Stream source)2382    {2383      if (source == null) {2384        throw new ZipException("Failed to reopen archive - no source");2385      }23862387      isNewArchive_ = false;2388      baseStream_ = source;2389      ReadEntries();2390    }23912392    void Reopen()2393    {2394      if (Name == null) {2395        throw new InvalidOperationException("Name is not known cannot Reopen");2396      }23972398      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));2399    }24002401    void UpdateCommentOnly()2402    {2403      long baseLength = baseStream_.Length;24042405      ZipHelperStream updateFile = null;24062407      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {2408        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);2409        updateFile = new ZipHelperStream(copyStream);2410        updateFile.IsStreamOwner = true;24112412        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 doesnt2418          // 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.24212422          // 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      }24312432      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        }24392440        const int CentralHeaderCommentSizeOffset = 16;2441        updateFile.Position += CentralHeaderCommentSizeOffset;24422443        byte[] rawComment = newComment_.RawComment;24442445        updateFile.WriteLEShort(rawComment.Length);2446        updateFile.Write(rawComment, 0, rawComment.Length);2447        updateFile.SetLength(updateFile.Position);  2448      }2449      else {2450        workFile.WriteLocalEntryHeader(update);2451        update.OutEntry.CompressedSize = 0;2452      }24532454    }24552456    void ModifyEntry(ZipFile workFile, ZipUpdate update)2457    {2458      workFile.WriteLocalEntryHeader(update);2459      long dataStart = workFile.baseStream_.Position;24602461      // TODO: This is slow if the changes don't effect the data!!2462      if ( update.Entry.IsFile && (update.Filename != null) ) {2463        using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) {2464          using ( Stream source = this.GetInputStream(update.Entry) ) {2465            CopyBytes(update, output, source, source.Length, true);2466          }2467        }2468      }24692470      long dataEnd = workFile.baseStream_.Position;2471      update.Entry.CompressedSize = dataEnd - dataStart;2472    }24732474    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2475    {2476      bool skipOver = false || update.Entry.Offset == destinationPosition;24492450      if (archiveStorage_.UpdateMode == FileUpdateMode.Safe) {2451        Reopen(archiveStorage_.ConvertTemporaryToFinal());2452      } else {2453        ReadEntries();2454      }2455    }24562457    /// <summary>2458    /// Class used to sort updates.2459    /// </summary>2460    class UpdateComparer : IComparer2461    {2462      /// <summary>2463      /// Compares two objects and returns a value indicating whether one is2464      /// 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;24752476        int result;  24772478      if ( !skipOver ) {2479        baseStream_.Position = destinationPosition;2480        workFile.WriteLocalEntryHeader(update);2481        destinationPosition = baseStream_.Position;2482      }24832484      long sourcePosition = 0;24852486      const int NameLengthOffset = 26;24872488      // TODO: Add base for SFX friendly handling2489      long entryDataOffset = update.Entry.Offset + NameLengthOffset;24902491      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);24922493      // Clumsy way of handling retrieving the original name and extra data length for now.2494      // TODO: Stop re-reading name and data length in CopyEntryDirect.2495      uint nameLength = ReadLEUshort();2496      uint extraLength = ReadLEUshort();24972498      sourcePosition = baseStream_.Position + nameLength + extraLength;24992500      if (skipOver) {2501        if (update.OffsetBasedSize != -1)2502          destinationPosition += update.OffsetBasedSize;2503        else2504          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2505          // WinZip produces a warning on these entries:2506          // "caution: value of lrec.csize (compressed size) changed from ..."2507          destinationPosition +=2508            (sourcePosition - entryDataOffset) + NameLengthOffset +  // Header size2509            update.Entry.CompressedSize + GetDescriptorSize(update);2510      }2511      else {2512        if ( update.Entry.CompressedSize > 0 ) {2513          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition );2514        }2515        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);2516      }2517    }25182519    void CopyEntry(ZipFile workFile, ZipUpdate update)2520    {2521      workFile.WriteLocalEntryHeader(update);25222523      if ( update.Entry.CompressedSize > 0 ) {2524        const int NameLengthOffset = 26;25252526        long entryDataOffset = update.Entry.Offset + NameLengthOffset;25272528        // TODO: This wont work for SFX files!2529        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);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;24892490          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    }25052506    void RunUpdates()2507    {2508      long sizeEntries = 0;2509      long endOfStream = 0;2510      bool directUpdate = false;2511      long destinationPosition = 0; // NOT SFX friendly25122513      ZipFile workFile;25142515      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;25232524        // 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;  25302531        uint nameLength = ReadLEUshort();2532        uint extraLength = ReadLEUshort();25332534        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);2531        if (key != null) {2532          workFile.key = (byte[])key.Clone();2533        }2534      }  25352536        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2537      }2538      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);2539    }25402541    void Reopen(Stream source)2542    {2543      if ( source == null ) {2544        throw new ZipException("Failed to reopen archive - no source");2545      }25462547      isNewArchive_ = false;2548      baseStream_ = source;2549      ReadEntries();2550    }25512552    void Reopen()2553    {2554      if (Name == null) {2555        throw new InvalidOperationException("Name is not known cannot Reopen");2556      }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;25472548              case UpdateCommand.Modify:2549                // TODO: Direct modifying of an entry will take some legwork.2550                ModifyEntry(workFile, update);2551                break;25522553              case UpdateCommand.Add:2554                if (!IsNewArchive && directUpdate) {2555                  workFile.baseStream_.Position = destinationPosition;2556                }  25572558      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read));2559    }25602561    void UpdateCommentOnly()2562    {2563      long baseLength = baseStream_.Length;25642565      ZipHelperStream updateFile = null;25662567      if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {2568        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);2569        updateFile = new ZipHelperStream(copyStream);2570        updateFile.IsStreamOwner = true;2558                AddEntry(workFile, update);25592560                if (directUpdate) {2561                  destinationPosition = workFile.baseStream_.Position;2562                }2563                break;2564            }2565          }2566        }25672568        if (!IsNewArchive && directUpdate) {2569          workFile.baseStream_.Position = destinationPosition;2570        }  25712572        baseStream_.Close();2573        baseStream_ = null;2574      }2575      else {2576        if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {2577          // TODO: archiveStorage wasnt originally intended for this use.2578          // Need to revisit this to tidy up handling as archive storage currently doesnt2579          // handle the original stream well.2580          // The problem is when using an existing zip archive with an in memory archive storage.2581          // The open stream wont support writing but the memory storage should open the same file not an in memory one.25822583          // Need to tidy up the archive storage interface and contract basically.2584          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_);2585          updateFile = new ZipHelperStream(baseStream_);2586        }2587        else {2588          baseStream_.Close();2589          baseStream_ = null;2590          updateFile = new ZipHelperStream(Name);2591        }2592      }25932594      using ( updateFile ) {2595        long locatedCentralDirOffset =2596          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,2597                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);2598        if ( locatedCentralDirOffset < 0 ) {2599          throw new ZipException("Cannot find central directory");2600        }26012602        const int CentralHeaderCommentSizeOffset = 16;2603        updateFile.Position += CentralHeaderCommentSizeOffset;26042605        byte[] rawComment = newComment_.RawComment;26062607        updateFile.WriteLEShort(rawComment.Length);2608        updateFile.Write(rawComment, 0, rawComment.Length);2609        updateFile.SetLength(updateFile.Position);2610      }26112612      if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {2613        Reopen(archiveStorage_.ConvertTemporaryToFinal());2614      }2615      else {2616        ReadEntries();2617      }2618    }26192620    /// <summary>2621    /// Class used to sort updates.2622    /// </summary>2623    class UpdateComparer : IComparer2624    {2625      /// <summary>2626      /// Compares two objects and returns a value indicating whether one is2627      /// less than, equal to or greater than the other.2628      /// </summary>2629      /// <param name="x">First object to compare</param>2630      /// <param name="y">Second object to compare.</param>2631      /// <returns>Compare result.</returns>2632      public int Compare(2633        object x,2634        object y)2635      {2636        var zx = x as ZipUpdate;2637        var zy = y as ZipUpdate;26382639        int result;26402641        if (zx == null) {2642          if (zy == null) {2643            result = 0;2644          }2645          else {2646            result = -1;2647          }2648        }2649        else if (zy == null) {2650          result = 1;2651        }2652        else {2653          int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1;2654          int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;26552656          result = xCmdValue - yCmdValue;2657          if (result == 0) {2658            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset;2659            if (offsetDiff < 0) {2660              result = -1;2661            }2662            else if (offsetDiff == 0) {2663              result = 0;2664            }2665            else {2666              result = 1;2667            }2668          }2669        }2670        return result;2671      }2672    }26732674    void RunUpdates()2675    {2676      long sizeEntries = 0;2677      long endOfStream = 0;2678      bool directUpdate = false;2679      long destinationPosition = 0; // NOT SFX friendly26802681      ZipFile workFile;2572        long centralDirOffset = workFile.baseStream_.Position;25732574        foreach (ZipUpdate update in updates_) {2575          if (update != null) {2576            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2577          }2578        }25792580        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        }25842585        endOfStream = workFile.baseStream_.Position;25862587        // 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            }25962597            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      }26162617      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    }26272628    void CheckUpdating()2629    {2630      if (updates_ == null) {2631        throw new InvalidOperationException("BeginUpdate has not been called");2632      }2633    }26342635    #endregion26362637    #region ZipUpdate class2638    /// <summary>2639    /// Represents a pending update to a Zip file.2640    /// </summary>2641    class ZipUpdate2642    {2643      #region Constructors2644      public ZipUpdate(string fileName, ZipEntry entry)2645      {2646        command_ = UpdateCommand.Add;2647        entry_ = entry;2648        filename_ = fileName;2649      }26502651      [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      }26592660      [Obsolete]2661      public ZipUpdate(string fileName, string entryName)2662        : this(fileName, entryName, CompressionMethod.Deflated)2663      {2664        // Do nothing.2665      }26662667      [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      }26752676      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2677      {2678        command_ = UpdateCommand.Add;2679        entry_ = entry;2680        dataSource_ = dataSource;2681      }  26822683      if ( IsNewArchive ) {2684        workFile = this;2685        workFile.baseStream_.Position = 0;2686        directUpdate = true;2687      }2688      else if ( archiveStorage_.UpdateMode == FileUpdateMode.Direct ) {2689        workFile = this;2690        workFile.baseStream_.Position = 0;2691        directUpdate = true;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      }  26922693        // Sort the updates by offset within copies/modifies, then adds.2694        // This ensures that data required by copies will not be overwritten.2695        updates_.Sort(new UpdateComparer());2696      }2697      else {2698        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());2699        workFile.UseZip64 = UseZip64;27002701        if (key != null) {2702          workFile.key = (byte[])key.Clone();2703        }2704      }27052706      try {2707        foreach ( ZipUpdate update in updates_ ) {2708          if (update != null) {2709            switch (update.Command) {2710              case UpdateCommand.Copy:2711                if (directUpdate) {2712                  CopyEntryDirect(workFile, update, ref destinationPosition);2713                }2714                else {2715                  CopyEntry(workFile, update);2716                }2717                break;2693      public ZipUpdate(UpdateCommand command, ZipEntry entry)2694      {2695        command_ = command;2696        entry_ = (ZipEntry)entry.Clone();2697      }269826992700      /// <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      #endregion27102711      /// <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      }  27182719              case UpdateCommand.Modify:2720                // TODO: Direct modifying of an entry will take some legwork.2721                ModifyEntry(workFile, update);2722                break;27232724              case UpdateCommand.Add:2725                if (!IsNewArchive && directUpdate) {2726                  workFile.baseStream_.Position = destinationPosition;2727                }27282729                AddEntry(workFile, update);27302731                if (directUpdate) {2732                  destinationPosition = workFile.baseStream_.Position;2733                }2734                break;2735            }2736          }2737        }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          }27272728          return outEntry_;2729        }2730      }27312732      /// <summary>2733      /// Get the command for this update.2734      /// </summary>2735      public UpdateCommand Command {2736        get { return command_; }2737      }  27382739        if ( !IsNewArchive && directUpdate ) {2740          workFile.baseStream_.Position = destinationPosition;2741        }27422743        long centralDirOffset = workFile.baseStream_.Position;27442745        foreach ( ZipUpdate update in updates_ ) {2746          if (update != null) {2747            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2748          }2749        }27502751        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);2752        using ( ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_) ) {2753          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment);2754        }27552756        endOfStream = workFile.baseStream_.Position;27572758        // And now patch entries...2759        foreach ( ZipUpdate update in updates_ ) {2760          if (update != null)2761          {2762            // If the size of the entry is zero leave the crc as 0 as well.2763            // The calculated crc will be all bits on...2764            if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) {2765              workFile.baseStream_.Position = update.CrcPatchOffset;2766              workFile.WriteLEInt((int)update.OutEntry.Crc);2767            }27682769            if (update.SizePatchOffset > 0) {2770              workFile.baseStream_.Position = update.SizePatchOffset;2771              if (update.OutEntry.LocalHeaderRequiresZip64) {2772                workFile.WriteLeLong(update.OutEntry.Size);2773                workFile.WriteLeLong(update.OutEntry.CompressedSize);2774              }2775              else {2776                workFile.WriteLEInt((int)update.OutEntry.CompressedSize);2777                workFile.WriteLEInt((int)update.OutEntry.Size);2778              }2779            }2780          }2781        }2782      }2783      catch {2784        workFile.Close();2785        if (!directUpdate && (workFile.Name != null)) {2786          File.Delete(workFile.Name);2787        }2788        throw;2789      }27902791      if (directUpdate) {2792        workFile.baseStream_.SetLength(endOfStream);2793        workFile.baseStream_.Flush();2794        isNewArchive_ = false;2795        ReadEntries();2796      }2797      else {2798        baseStream_.Close();2799        Reopen(archiveStorage_.ConvertTemporaryToFinal());2800      }2801    }28022803    void CheckUpdating()2804    {2805      if ( updates_ == null ) {2806        throw new InvalidOperationException("BeginUpdate has not been called");2807      }2808    }28092810    #endregion28112812    #region ZipUpdate class2813    /// <summary>2814    /// Represents a pending update to a Zip file.2815    /// </summary>2816    class ZipUpdate2817    {2818      #region Constructors2819      public ZipUpdate(string fileName, ZipEntry entry)2820      {2821        command_ = UpdateCommand.Add;2822        entry_ = entry;2823        filename_ = fileName;2824      }28252826      [Obsolete]2827      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)2828      {2829        command_ = UpdateCommand.Add;2830        entry_ = new ZipEntry(entryName);2831        entry_.CompressionMethod = compressionMethod;2832        filename_ = fileName;2833      }28342835      [Obsolete]2836      public ZipUpdate(string fileName, string entryName)2837        : this(fileName, entryName, CompressionMethod.Deflated)2838      {2839        // Do nothing.2840      }28412842      [Obsolete]2843      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)2844      {2845        command_ = UpdateCommand.Add;2846        entry_ = new ZipEntry(entryName);2847        entry_.CompressionMethod = compressionMethod;2848        dataSource_ = dataSource;2849      }28502851      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2852      {2853        command_ = UpdateCommand.Add;2854        entry_ = entry;2855        dataSource_ = dataSource;2856      }28572858      public ZipUpdate(ZipEntry original, ZipEntry updated)2859      {2860        throw new ZipException("Modify not currently supported");2861      /*2862        command_ = UpdateCommand.Modify;2863        entry_ = ( ZipEntry )original.Clone();2864        outEntry_ = ( ZipEntry )updated.Clone();2865      */2866      }28672868      public ZipUpdate(UpdateCommand command, ZipEntry entry)2869      {2870        command_ = command;2871        entry_ = ( ZipEntry )entry.Clone();2872      }28732739      /// <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      }27452746      /// <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      }27532754      /// <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      }27612762      /// <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      }27702771      public Stream GetSource()2772      {2773        Stream result = null;2774        if (dataSource_ != null) {2775          result = dataSource_.GetSource();2776        }27772778        return result;2779      }27802781      #region Instance Fields2782      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      #endregion2791    }27922793    #endregion2794    #endregion27952796    #region Disposing27972798    #region IDisposable Members2799    void IDisposable.Dispose()2800    {2801      Close();2802    }2803    #endregion28042805    void DisposeInternal(bool disposing)2806    {2807      if (!isDisposed_) {2808        isDisposed_ = true;2809        entries_ = new ZipEntry[0];28102811        if (IsStreamOwner && (baseStream_ != null)) {2812          lock (baseStream_) {2813            baseStream_.Close();2814          }2815        }28162817        PostUpdateCleanup();2818      }2819    }28202821    /// <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    }28302831    #endregion28322833    #region Internal routines2834    #region Reading2835    /// <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 prematurely2841    /// </exception>2842    ushort ReadLEUshort()2843    {2844      int data1 = baseStream_.ReadByte();28452846      if (data1 < 0) {2847        throw new EndOfStreamException("End of stream");2848      }28492850      int data2 = baseStream_.ReadByte();28512852      if (data2 < 0) {2853        throw new EndOfStreamException("End of stream");2854      }285528562857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));2858    }28592860    /// <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 prematurely2869    /// </exception>2870    uint ReadLEUint()2871    {2872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));2873    }  28742875      /// <summary>2876      /// Copy an existing entry.2877      /// </summary>2878      /// <param name="entry">The existing entry to copy.</param>2879      public ZipUpdate(ZipEntry entry)2880        : this(UpdateCommand.Copy, entry)2881      {2882        // Do nothing.2883      }2884      #endregion28852886      /// <summary>2887      /// Get the <see cref="ZipEntry"/> for this update.2888      /// </summary>2889      /// <remarks>This is the source or original entry.</remarks>2890      public ZipEntry Entry2891      {2892        get { return entry_; }2893      }28942895      /// <summary>2896      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.2897      /// </summary>2898      public ZipEntry OutEntry2899      {2900        get {2901          if ( outEntry_ == null ) {2902            outEntry_ = (ZipEntry)entry_.Clone();2903          }29042905          return outEntry_;2906        }2907      }2875    ulong ReadLEUlong()2876    {2877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);2878    }28792880    #endregion2881    // 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    }28882889    /// <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 found2897    /// </exception>2898    void ReadEntries()2899    {2900      // Search for the End Of Central Directory.  When a zip comment is2901      // present the directory will start earlier2902      //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 files2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then2906      // this could be invalid.2907      // Could also speed this up by reading memory in larger blocks.  29082909      /// <summary>2910      /// Get the command for this update.2911      /// </summary>2912      public UpdateCommand Command2913      {2914        get { return command_; }2915      }29162917      /// <summary>2918      /// Get the filename if any for this update.  Null if none exists.2919      /// </summary>2920      public string Filename2921      {2922        get { return filename_; }2923      }29242925      /// <summary>2926      /// Get/set the location of the size patch for this update.2927      /// </summary>2928      public long SizePatchOffset2929      {2930        get { return sizePatchOffset_; }2931        set { sizePatchOffset_ = value; }2932      }29332934      /// <summary>2935      /// Get /set the location of the crc patch for this update.2936      /// </summary>2937      public long CrcPatchOffset2938      {2939        get { return crcPatchOffset_; }2940        set { crcPatchOffset_ = value; }2941      }29422943      /// <summary>2944      /// Get/set the size calculated by offset.2945      /// Specifically, the difference between this and next entry's starting offset.2946      /// </summary>2947      public long OffsetBasedSize2948      {2949        get { return _offsetBasedSize; }2950        set { _offsetBasedSize = value; }2951      }29522953      public Stream GetSource()2954      {2955        Stream result = null;2956        if ( dataSource_ != null ) {2957          result = dataSource_.GetSource();2958        }29592960        return result;2961      }29622963      #region Instance Fields2964      ZipEntry entry_;2965      ZipEntry outEntry_;2966      UpdateCommand command_;2967      IStaticDataSource dataSource_;2968      string filename_;2969      long sizePatchOffset_ = -1;2970      long crcPatchOffset_ = -1;2971      long _offsetBasedSize = -1;2972      #endregion2973    }29742975    #endregion2976    #endregion29772978    #region Disposing29792980    #region IDisposable Members2981    void IDisposable.Dispose()2982    {2983      Close();2984    }2985    #endregion29862987    void DisposeInternal(bool disposing)2988    {2989      if ( !isDisposed_ ) {2990        isDisposed_ = true;2991        entries_ = new ZipEntry[0];29922993        if ( IsStreamOwner && (baseStream_ != null) ) {2994          lock(baseStream_) {2995            baseStream_.Close();2996          }2997        }2909      if (baseStream_.CanSeek == false) {2910        throw new ZipException("ZipFile stream must be seekable");2911      }29122913      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,2914        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);29152916      if (locatedEndOfCentralDir < 0) {2917        throw new ZipException("Cannot find central directory");2918      }29192920      // Read end of central directory record2921      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();29282929      if (commentSize > 0) {2930        byte[] comment = new byte[commentSize];29312932        StreamUtils.ReadFully(baseStream_, comment);2933        comment_ = ZipConstants.ConvertToString(comment);2934      } else {2935        comment_ = string.Empty;2936      }29372938      bool isZip64 = false;29392940      // 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;29482949        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 2950        if (offset < 0) {2951          throw new ZipException("Cannot find Zip64 locator");2952        }29532954        // number of the disk with the start of the zip64 end of central directory 4 bytes2955        // relative offset of the zip64 end of central directory record 8 bytes2956        // total number of disks 4 bytes2957        ReadLEUint(); // startDisk64 is not currently used2958        ulong offset64 = ReadLEUlong();2959        uint totalDisks = ReadLEUint();29602961        baseStream_.Position = (long)offset64;2962        long sig64 = ReadLEUint();29632964        if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature) {2965          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));2966        }29672968        // 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();29782979        // NOTE: zip64 extensible data sector (variable size) is ignored.2980      }29812982      entries_ = new ZipEntry[entriesForThisDisk];29832984      // SFX/embedded support, find the offset of the first entry vis the start of the stream2985      // 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 offsets2988      // 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      }29962997      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);  29982999        PostUpdateCleanup();3000      }3001    }30023003    /// <summary>3004    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.3005    /// </summary>3006    /// <param name="disposing">true to release both managed and unmanaged resources;3007    /// false to release only unmanaged resources.</param>3008    protected virtual void Dispose(bool disposing)3009    {3010      DisposeInternal(disposing);3011    }30123013    #endregion30143015    #region Internal routines3016    #region Reading3017    /// <summary>3018    /// Read an unsigned short in little endian byte order.3019    /// </summary>3020    /// <returns>Returns the value read.</returns>3021    /// <exception cref="EndOfStreamException">3022    /// The stream ends prematurely3023    /// </exception>3024    ushort ReadLEUshort()3025    {3026      int data1 = baseStream_.ReadByte();30273028      if ( data1 < 0 ) {3029        throw new EndOfStreamException("End of stream");3030      }30313032      int data2 = baseStream_.ReadByte();30333034      if ( data2 < 0 ) {3035        throw new EndOfStreamException("End of stream");3036      }303730383039      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));3040    }30413042    /// <summary>3043    /// Read a uint in little endian byte order.3044    /// </summary>3045    /// <returns>Returns the value read.</returns>3046    /// <exception cref="IOException">3047    /// An i/o error occurs.3048    /// </exception>3049    /// <exception cref="System.IO.EndOfStreamException">3050    /// The file ends prematurely3051    /// </exception>3052    uint ReadLEUint()3053    {3054      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));3055    }30563057    ulong ReadLEUlong()3058    {3059      return ReadLEUint() | ((ulong)ReadLEUint() << 32);3060    }30613062    #endregion3063    // NOTE this returns the offset of the first byte after the signature.3064    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)3065    {3066      using ( ZipHelperStream les = new ZipHelperStream(baseStream_) ) {3067        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);3068      }3069    }30703071    /// <summary>3072    /// Search for and read the central directory of a zip file filling the entries array.3073    /// </summary>3074    /// <exception cref="System.IO.IOException">3075    /// An i/o error occurs.3076    /// </exception>3077    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3078    /// The central directory is malformed or cannot be found3079    /// </exception>3080    void ReadEntries()3081    {3082      // Search for the End Of Central Directory.  When a zip comment is3083      // present the directory will start earlier3084      //3085      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.3086      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files3087      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then3088      // this could be invalid.3089      // Could also speed this up by reading memory in larger blocks.2999      for (ulong i = 0; i < entriesForThisDisk; i++) {3000        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {3001          throw new ZipException("Wrong Central Directory signature");3002        }30033004        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();30153016        int diskStartNo = ReadLEUshort();  // Not currently used3017        int internalAttributes = ReadLEUshort();  // Not currently used30183019        uint externalAttributes = ReadLEUint();3020        long offset = ReadLEUint();30213022        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];30233024        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);3025        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);30263027        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;30363037        if ((bitFlags & 8) == 0) {3038          entry.CryptoCheckValue = (byte)(crc >> 24);3039        } else {3040          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3041        }30423043        if (extraLen > 0) {3044          byte[] extra = new byte[extraLen];3045          StreamUtils.ReadFully(baseStream_, extra);3046          entry.ExtraData = extra;3047        }30483049        entry.ProcessExtraData(false);30503051        if (commentLen > 0) {3052          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);3053          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3054        }30553056        entries_[i] = entry;3057      }3058    }30593060    /// <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 prematurely3068    /// </exception>3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3070    /// The local header signature is invalid, the entry and central header file name lengths are different3071    /// or the local and entry compression methods dont match3072    /// </exception>3073    long LocateEntry(ZipEntry entry)3074    {3075      return TestLocalHeader(entry, HeaderTest.Extract);3076    }30773078    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3079    {3080      CryptoStream result = null;30813082      if ((entry.Version < ZipConstants.VersionStrongEncryption)3083        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3084        var classicManaged = new PkzipClassicManaged();30853086        OnKeysRequired(entry.Name);3087        if (HaveKeys == false) {3088          throw new ZipException("No password available for encrypted stream");3089        }  30903091      if (baseStream_.CanSeek == false) {3092        throw new ZipException("ZipFile stream must be seekable");3093      }30943095      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,3096        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);30973098      if (locatedEndOfCentralDir < 0) {3099        throw new ZipException("Cannot find central directory");3100      }31013102      // Read end of central directory record3103      ushort thisDiskNumber           = ReadLEUshort();3104      ushort startCentralDirDisk      = ReadLEUshort();3105      ulong entriesForThisDisk        = ReadLEUshort();3106      ulong entriesForWholeCentralDir = ReadLEUshort();3107      ulong centralDirSize            = ReadLEUint();3108      long offsetOfCentralDir         = ReadLEUint();3109      uint commentSize                = ReadLEUshort();31103111      if ( commentSize > 0 ) {3112        byte[] comment = new byte[commentSize];31133114        StreamUtils.ReadFully(baseStream_, comment);3115        comment_ = ZipConstants.ConvertToString(comment);3116      }3117      else {3118        comment_ = string.Empty;3119      }31203121      bool isZip64 = false;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 bytes31093110          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      }31193120      return result;3121    }  31223123      // Check if zip64 header information is required.3124      if ( (thisDiskNumber == 0xffff) ||3125        (startCentralDirDisk == 0xffff) ||3126        (entriesForThisDisk == 0xffff) ||3127        (entriesForWholeCentralDir == 0xffff) ||3128        (centralDirSize == 0xffffffff) ||3129        (offsetOfCentralDir == 0xffffffff) ) {3130        isZip64 = true;31313132        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 3133        if ( offset < 0 ) {3134          throw new ZipException("Cannot find Zip64 locator");3135        }31363137        // number of the disk with the start of the zip64 end of central directory 4 bytes3138        // relative offset of the zip64 end of central directory record 8 bytes3139        // total number of disks 4 bytes3140        ReadLEUint(); // startDisk64 is not currently used3141        ulong offset64 = ReadLEUlong();3142        uint totalDisks = ReadLEUint();31433144        baseStream_.Position = (long)offset64;3145        long sig64 = ReadLEUint();31463147        if ( sig64 != ZipConstants.Zip64CentralFileHeaderSignature ) {3148          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));3149        }31503151        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.3152        ulong recordSize = ReadLEUlong();3153        int versionMadeBy = ReadLEUshort();3154        int versionToExtract = ReadLEUshort();3155        uint thisDisk = ReadLEUint();3156        uint centralDirDisk = ReadLEUint();3157        entriesForThisDisk = ReadLEUlong();3158        entriesForWholeCentralDir = ReadLEUlong();3159        centralDirSize = ReadLEUlong();3160        offsetOfCentralDir = (long)ReadLEUlong();31613162        // NOTE: zip64 extensible data sector (variable size) is ignored.3163      }31643165      entries_ = new ZipEntry[entriesForThisDisk];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();31293130        OnKeysRequired(entry.Name);3131        if (HaveKeys == false) {3132          throw new ZipException("No password available for encrypted stream");3133        }31343135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3136        // which doesnt do this.3137        result = new CryptoStream(new UncompressedStream(baseStream),3138          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);31393140        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    }31483149    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    }31573158    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    }  31663167      // SFX/embedded support, find the offset of the first entry vis the start of the stream3168      // This applies to Zip files that are appended to the end of an SFX stub.3169      // Or are appended as a resource to an executable.3170      // Zip files created by some archivers have the offsets altered to reflect the true offsets3171      // and so dont require any adjustment here...3172      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?3173      if ( !isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize)) ) {3174        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);3175        if (offsetOfFirstEntry <= 0) {3176          throw new ZipException("Invalid embedded zip archive");3177        }3178      }31793180      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);31813182      for (ulong i = 0; i < entriesForThisDisk; i++) {3183        if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {3184          throw new ZipException("Wrong Central Directory signature");3185        }3167    #endregion31683169    #region Instance Fields3170    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_;31803181    // Default is dynamic which is not backwards compatible and can cause problems3182    // 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;  31863187        int versionMadeBy      = ReadLEUshort();3188        int versionToExtract   = ReadLEUshort();3189        int bitFlags           = ReadLEUshort();3190        int method             = ReadLEUshort();3191        uint dostime           = ReadLEUint();3192        uint crc               = ReadLEUint();3193        var csize             = (long)ReadLEUint();3194        var size              = (long)ReadLEUint();3195        int nameLen            = ReadLEUshort();3196        int extraLen           = ReadLEUshort();3197        int commentLen         = ReadLEUshort();31983199        int diskStartNo        = ReadLEUshort();  // Not currently used3200        int internalAttributes = ReadLEUshort();  // Not currently used3187    #region Zip Update Instance Fields3188    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    #endregion3200    #endregion  32013202        uint externalAttributes = ReadLEUint();3203        long offset             = ReadLEUint();32043205        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];32063207        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);3208        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);32093210        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);3211        entry.Crc = crc & 0xffffffffL;3212        entry.Size = size & 0xffffffffL;3213        entry.CompressedSize = csize & 0xffffffffL;3214        entry.Flags = bitFlags;3215        entry.DosTime = (uint)dostime;3216        entry.ZipFileIndex = (long)i;3217        entry.Offset = offset;3218        entry.ExternalFileAttributes = (int)externalAttributes;32193220        if ((bitFlags & 8) == 0) {3221          entry.CryptoCheckValue = (byte)(crc >> 24);3222        }3223        else {3224          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3225        }32263227        if (extraLen > 0) {3228          byte[] extra = new byte[extraLen];3229          StreamUtils.ReadFully(baseStream_, extra);3230          entry.ExtraData = extra;3231        }32323233        entry.ProcessExtraData(false);32343235        if (commentLen > 0) {3236          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);3237          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3238        }32393240        entries_[i] = entry;3241      }3242    }32433244    /// <summary>3245    /// Locate the data for a given entry.3246    /// </summary>3247    /// <returns>3248    /// The start offset of the data.3249    /// </returns>3250    /// <exception cref="System.IO.EndOfStreamException">3251    /// The stream ends prematurely3252    /// </exception>3253    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3254    /// The local header signature is invalid, the entry and central header file name lengths are different3255    /// or the local and entry compression methods dont match3256    /// </exception>3257    long LocateEntry(ZipEntry entry)3258    {3259      return TestLocalHeader(entry, HeaderTest.Extract);3260    }32613262#if !NETCF_1_03263    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3264    {3265      CryptoStream result = null;32663267      if ( (entry.Version < ZipConstants.VersionStrongEncryption)3268        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3269        var classicManaged = new PkzipClassicManaged();32703271        OnKeysRequired(entry.Name);3272        if (HaveKeys == false) {3273          throw new ZipException("No password available for encrypted stream");3274        }3202    #region Support Classes3203    /// <summary>3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3205    /// </summary>3206    class ZipString3207    {3208      #region Constructors3209      /// <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      }32183219      /// <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      #endregion32283229      /// <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      }32363237      /// <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      }32463247      /// <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      }32563257      /// <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      }32683269      void MakeTextAvailable()3270      {3271        if (comment_ == null) {3272          comment_ = ZipConstants.ConvertToString(rawComment_);3273        }3274      }  32753276        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);3277        CheckClassicPassword(result, entry);3278      }3279      else {3280#if !NET_1_1 && !NETCF_2_03281        if (entry.Version == ZipConstants.VERSION_AES) {3282          //3283          OnKeysRequired(entry.Name);3284          if (HaveKeys == false) {3285            throw new ZipException("No password available for AES encrypted stream");3286          }3287          int saltLen = entry.AESSaltLen;3288          byte[] saltBytes = new byte[saltLen];3289          int saltIn = baseStream.Read(saltBytes, 0, saltLen);3290          if (saltIn != saltLen)3291            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);3292          //3293          byte[] pwdVerifyRead = new byte[2];3294          baseStream.Read(pwdVerifyRead, 0, 2);3295          int blockSize = entry.AESKeySize / 8;  // bits to bytes32963297          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);3298          byte[] pwdVerifyCalc = decryptor.PwdVerifier;3299          if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])3300            throw new Exception("Invalid password for AES");3301          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);3302        }3303        else3304#endif3305        {3306          throw new ZipException("Decryption method not supported");3307        }3308      }33093310      return result;3311    }33123313    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)3314    {3315      CryptoStream result = null;3316      if ( (entry.Version < ZipConstants.VersionStrongEncryption)3317        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {3318        var classicManaged = new PkzipClassicManaged();3276      void MakeBytesAvailable()3277      {3278        if (rawComment_ == null) {3279          rawComment_ = ZipConstants.ConvertToArray(comment_);3280        }3281      }32823283      /// <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      }32933294      #region Instance Fields3295      string comment_;3296      byte[] rawComment_;3297      bool isSourceString_;3298      #endregion3299    }33003301    /// <summary>3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3303    /// </summary>3304    class ZipEntryEnumerator : IEnumerator3305    {3306      #region Constructors3307      public ZipEntryEnumerator(ZipEntry[] entries)3308      {3309        array = entries;3310      }33113312      #endregion3313      #region IEnumerator Members3314      public object Current {3315        get {3316          return array[index];3317        }3318      }  33193320        OnKeysRequired(entry.Name);3321        if (HaveKeys == false) {3322          throw new ZipException("No password available for encrypted stream");3323        }3320      public void Reset()3321      {3322        index = -1;3323      }  33243325        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3326        // which doesnt do this.3327        result = new CryptoStream(new UncompressedStream(baseStream),3328          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);33293330        if ( (entry.Crc < 0) || (entry.Flags & 8) != 0) {3331          WriteEncryptionHeader(result, entry.DosTime << 16);3332        }3333        else {3334          WriteEncryptionHeader(result, entry.Crc);3335        }3336      }3337      return result;3338    }33393340    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)3325      public bool MoveNext()3326      {3327        return (++index < array.Length);3328      }3329      #endregion3330      #region Instance Fields3331      ZipEntry[] array;3332      int index = -1;3333      #endregion3334    }33353336    /// <summary>3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3338    /// to and flush, but cannot read, seek or do anything else to.3339    /// </summary>3340    class UncompressedStream : Stream  3341    {3342      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];3343      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);3344      if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {3345        throw new ZipException("Invalid password");3342      #region Constructors3343      public UncompressedStream(Stream baseStream)3344      {3345        baseStream_ = baseStream;  3346      }3347    }3348#endif33473348      #endregion  33493350    static void WriteEncryptionHeader(Stream stream, long crcValue)3351    {3352      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];3353      var rnd = new Random();3354      rnd.NextBytes(cryptBuffer);3355      cryptBuffer[11] = (byte)(crcValue >> 24);3356      stream.Write(cryptBuffer, 0, cryptBuffer.Length);3357    }33583359    #endregion33603361    #region Instance Fields3362    bool       isDisposed_;3363    string     name_;3364    string     comment_;3365    string     rawPassword_;3366    Stream     baseStream_;3367    bool       isStreamOwner;3368    long       offsetOfFirstEntry;3369    ZipEntry[] entries_;3370    byte[] key;3371    bool isNewArchive_;33723373    // Default is dynamic which is not backwards compatible and can cause problems3374    // with XP's built in compression which cant read Zip64 archives.3375    // However it does avoid the situation were a large file is added and cannot be completed correctly.3376    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed.3377    UseZip64 useZip64_ = UseZip64.Dynamic ;33783379    #region Zip Update Instance Fields3380    ArrayList updates_;3381    long updateCount_; // Count is managed manually as updates_ can contain nulls!3382    Hashtable updateIndex_;3383    IArchiveStorage archiveStorage_;3384    IDynamicDataSource updateDataSource_;3385    bool contentsEdited_;3386    int bufferSize_ = DefaultBufferSize;3387    byte[] copyBuffer_;3388    ZipString newComment_;3389    bool commentEdited_;3390    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();3391    #endregion3392    #endregion33933394    #region Support Classes3395    /// <summary>3396    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3397    /// </summary>3398    class ZipString3399    {3400      #region Constructors3401      /// <summary>3402      /// Initialise a <see cref="ZipString"/> with a string.3403      /// </summary>3404      /// <param name="comment">The textual string form.</param>3405      public ZipString(string comment)3406      {3407        comment_ = comment;3408        isSourceString_ = true;3409      }34103411      /// <summary>3412      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.3413      /// </summary>3414      /// <param name="rawString"></param>3415      public ZipString(byte[] rawString)3416      {3417        rawComment_ = rawString;3418      }3419      #endregion34203421      /// <summary>3422      /// Get a value indicating the original source of data for this instance.3423      /// True if the source was a string; false if the source was binary data.3424      /// </summary>3425      public bool IsSourceString3426      {3427        get { return isSourceString_; }3428      }34293430      /// <summary>3431      /// Get the length of the comment when represented as raw bytes.3432      /// </summary>3433      public int RawLength3434      {3435        get {3436          MakeBytesAvailable();3437          return rawComment_.Length;3438        }3439      }34403441      /// <summary>3442      /// Get the comment in its 'raw' form as plain bytes.3443      /// </summary>3444      public byte[] RawComment3445      {3446        get {3447          MakeBytesAvailable();3448          return (byte[])rawComment_.Clone();3449        }3450      }34513452      /// <summary>3453      /// Reset the comment to its initial state.3454      /// </summary>3455      public void Reset()3456      {3457        if ( isSourceString_ ) {3458          rawComment_ = null;3459        }3460        else {3461          comment_ = null;3462        }3463      }34643465      void MakeTextAvailable()3466      {3467        if ( comment_ == null ) {3468          comment_ = ZipConstants.ConvertToString(rawComment_);3469        }3470      }34713472      void MakeBytesAvailable()3473      {3474        if ( rawComment_ == null ) {3475          rawComment_ = ZipConstants.ConvertToArray(comment_);3476        }3477      }34783479      /// <summary>3480      /// Implicit conversion of comment to a string.3481      /// </summary>3482      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>3483      /// <returns>The textual equivalent for the input value.</returns>3484      static public implicit operator string(ZipString zipString)3485      {3486        zipString.MakeTextAvailable();3487        return zipString.comment_;3488      }34893490      #region Instance Fields3491      string comment_;3492      byte[] rawComment_;3493      bool isSourceString_;3494      #endregion3495    }34963497    /// <summary>3498    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3499    /// </summary>3500    class ZipEntryEnumerator : IEnumerator3501    {3502      #region Constructors3503      public ZipEntryEnumerator(ZipEntry[] entries)3504      {3505        array = entries;3506      }35073508      #endregion3509      #region IEnumerator Members3510      public object Current3511      {3512        get {3513          return array[index];3514        }3515      }35163517      public void Reset()3518      {3519        index = -1;3520      }35213522      public bool MoveNext()3523      {3524        return (++index < array.Length);3525      }3526      #endregion3527      #region Instance Fields3528      ZipEntry[] array;3529      int index = -1;3530      #endregion3531    }35323533    /// <summary>3534    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3535    /// to and flush, but cannot read, seek or do anything else to.3536    /// </summary>3537    class UncompressedStream : Stream3538    {3539      #region Constructors3540      public UncompressedStream(Stream baseStream)3541      {3542        baseStream_ = baseStream;3543      }35443545      #endregion35463547      /// <summary>3548      /// Close this stream instance.3549      /// </summary>3550      public override void Close()3551      {3552        // Do nothing3553      }35543555      /// <summary>3556      /// Gets a value indicating whether the current stream supports reading.3557      /// </summary>3558      public override bool CanRead3559      {3560        get {3561          return false;3562        }3563      }35643565      /// <summary>3566      /// Write any buffered data to underlying storage.3567      /// </summary>3568      public override void Flush()3569      {3570        baseStream_.Flush();3571      }35723573      /// <summary>3574      /// Gets a value indicating whether the current stream supports writing.3575      /// </summary>3576      public override bool CanWrite3577      {3578        get {3579          return baseStream_.CanWrite;3580        }3581      }35823583      /// <summary>3584      /// Gets a value indicating whether the current stream supports seeking.3585      /// </summary>3586      public override bool CanSeek3587      {3588        get {3589          return false;3590        }3591      }35923593      /// <summary>3594      /// Get the length in bytes of the stream.3595      /// </summary>3596      public override long Length3597      {3598        get {3599          return 0;3600        }3601      }36023603      /// <summary>3604      /// Gets or sets the position within the current stream.3605      /// </summary>3606      public override long Position3607      {3608        get  {3609          return baseStream_.Position;3610        }3611                set {3612                    throw new NotImplementedException();3613                }3614            }36153616            /// <summary>3617            /// Reads a sequence of bytes from the current stream and advances the position within the stream by the num3618            /// </summary>3619            /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte3620            /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from t3621            /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3622            /// <returns>3623            /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if t3624            /// </returns>3625            /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer lengt3626            /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </ex3627            /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3628            /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3629            /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3630            /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3631            public override int Read(byte[] buffer, int offset, int count)3632      {3633        return 0;3634      }36353636      /// <summary>3637      /// Sets the position within the current stream.3638      /// </summary>3639      /// <param name="offset">A byte offset relative to the origin parameter.</param>3640      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3641      /// <returns>3642      /// The new position within the current stream.3643      /// </returns>3644      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3645      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3646      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3647      public override long Seek(long offset, SeekOrigin origin)3648      {3649        return 0;3650      }36513652      /// <summary>3653      /// Sets the length of the current stream.3654      /// </summary>3655      /// <param name="value">The desired length of the current stream in bytes.</param>3656      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3350      /// <summary>3351      /// Close this stream instance.3352      /// </summary>3353      public override void Close()3354      {3355        // Do nothing3356      }33573358      /// <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      }33663367      /// <summary>3368      /// Write any buffered data to underlying storage.3369      /// </summary>3370      public override void Flush()3371      {3372        baseStream_.Flush();3373      }33743375      /// <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      }33833384      /// <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      }33923393      /// <summary>3394      /// Get the length in bytes of the stream.3395      /// </summary>3396      public override long Length {3397        get {3398          return 0;3399        }3400      }34013402      /// <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      }34133414      /// <summary>3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3416      /// </summary>3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3419      /// <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 ma3422      /// </returns>3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3425      /// <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      }34333434      /// <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 is3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3445      public override long Seek(long offset, SeekOrigin origin)3446      {3447        return 0;3448      }34493450      /// <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 as3455      /// <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. </exceptio3457      public override void SetLength(long value)3458      {3459      }34603461      /// <summary>3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3463      /// </summary>3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3466      /// <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. </exceptio3470      /// <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      }34773478      readonly34793480      #region Instance Fields3481      Stream baseStream_;3482      #endregion3483    }34843485    /// <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 : Stream3490    {3491      #region Constructors3492      /// <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;35023503        // Although this is the only time the zipfile is used3504        // keeping a reference here prevents premature closure of3505        // this zip file and thus the baseStream_.35063507        // Code like this will cause apparently random failures depending3508        // 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      #endregion35193520      /// <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        }35303531        lock (baseStream_) {3532          baseStream_.Seek(readPos_++, SeekOrigin.Begin);3533          return baseStream_.ReadByte();3534        }3535      }35363537      /// <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      }35473548      /// <summary>3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3550      /// </summary>3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3553      /// <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 ma3556      /// </returns>3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3559      /// <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 Seek3573          // (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      }35843585      /// <summary>3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3587      /// </summary>3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3590      /// <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. </exceptio3594      /// <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      }36013602      /// <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 as3607      /// <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. </exceptio3609      public override void SetLength(long value)3610      {3611        throw new NotSupportedException();3612      }36133614      /// <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 is3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3625      public override long Seek(long offset, SeekOrigin origin)3626      {3627        long newPos = readPos_;36283629        switch (origin) {3630          case SeekOrigin.Begin:3631            newPos = start_ + offset;3632            break;36333634          case SeekOrigin.Current:3635            newPos = readPos_ + offset;3636            break;36373638          case SeekOrigin.End:3639            newPos = end_ + offset;3640            break;3641        }36423643        if (newPos < start_) {3644          throw new ArgumentException("Negative position is invalid");3645        }36463647        if (newPos >= end_) {3648          throw new IOException("Cannot seek past end");3649        }3650        readPos_ = newPos;3651        return readPos_;3652      }36533654      /// <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      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3659      public override void SetLength(long value)3660      {3658      public override void Flush()3659      {3660        // Nothing to do.  3661      }  3662  3663      /// <summary>3664      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3664      /// Gets or sets the position within the current stream.  3665      /// </summary>3666      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3667      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3668      /// <param name="count">The number of bytes to be written to the current stream.</param>3669      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3670      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3671      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3672      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3673      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3674      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3675      public override void Write(byte[] buffer, int offset, int count)3676      {3677        baseStream_.Write(buffer, offset, count);3678      }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. </exceptio3671      public override long Position {3672        get { return readPos_ - start_; }3673        set {3674          long newPos = start_ + value;36753676          if (newPos < start_) {3677            throw new ArgumentException("Negative position is invalid");3678          }  36793680      readonly36813682      #region Instance Fields3683      Stream baseStream_;3684      #endregion3685    }3680          if (newPos >= end_) {3681            throw new InvalidOperationException("Cannot seek past end");3682          }3683          readPos_ = newPos;3684        }3685      }  36863687    /// <summary>3688    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>3689    /// whose data is only a part or subsection of a file.3690    /// </summary>3691    class PartialInputStream : Stream3692    {3693      #region Constructors3694      /// <summary>3695      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.3696      /// </summary>3697      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>3698      /// <param name="start">The start of the partial data.</param>3699      /// <param name="length">The length of the partial data.</param>3700      public PartialInputStream(ZipFile zipFile, long start, long length)3701      {3702        start_ = start;3703        length_ = length;37043705        // Although this is the only time the zipfile is used3706        // keeping a reference here prevents premature closure of3707        // this zip file and thus the baseStream_.37083709        // Code like this will cause apparently random failures depending3710        // on the size of the files and when garbage is collected.3711        //3712        // ZipFile z = new ZipFile (stream);3713        // Stream reader = z.GetInputStream(0);3714        // uses reader here....3715        zipFile_ = zipFile;3716        baseStream_ = zipFile_.baseStream_;3717        readPos_ = start;3718        end_ = start + length;3719      }3720      #endregion37213722      /// <summary>3723      /// Read a byte from this stream.3724      /// </summary>3725      /// <returns>Returns the byte read or -1 on end of stream.</returns>3726      public override int ReadByte()3727      {3728        if (readPos_ >= end_) {3729           // -1 is the correct value at end of stream.3730          return -1;3731        }37323733        lock( baseStream_ ) {3734          baseStream_.Seek(readPos_++, SeekOrigin.Begin);3735          return baseStream_.ReadByte();3736        }3737      }37383739      /// <summary>3740      /// Close this <see cref="PartialInputStream">partial input stream</see>.3741      /// </summary>3742      /// <remarks>3743      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.3744      /// </remarks>3745      public override void Close()3746      {3747        // Do nothing at all!3748      }37493750      /// <summary>3751      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3752      /// </summary>3753      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3754      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3755      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3756      /// <returns>3757      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma3758      /// </returns>3759      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3760      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3761      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3762      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3763      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3764      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3765      public override int Read(byte[] buffer, int offset, int count)3766      {3767        lock(baseStream_) {3768          if (count > end_ - readPos_) {3769            count = (int) (end_ - readPos_);3770            if (count == 0) {3771              return 0;3772            }3773          }37743775          baseStream_.Seek(readPos_, SeekOrigin.Begin);3776          int readCount = baseStream_.Read(buffer, offset, count);3777          if (readCount > 0) {3778            readPos_ += readCount;3779          }3780          return readCount;3781        }3782      }37833784      /// <summary>3785      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3786      /// </summary>3787      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3788      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3789      /// <param name="count">The number of bytes to be written to the current stream.</param>3790      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3791      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3792      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3793      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3794      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3795      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3796      public override void Write(byte[] buffer, int offset, int count)3797      {3798        throw new NotSupportedException();3799      }38003801      /// <summary>3802      /// When overridden in a derived class, sets the length of the current stream.3803      /// </summary>3804      /// <param name="value">The desired length of the current stream in bytes.</param>3805      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3806      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3807      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3808      public override void SetLength(long value)3809      {3810        throw new NotSupportedException();3811      }38123813      /// <summary>3814      /// When overridden in a derived class, sets the position within the current stream.3815      /// </summary>3816      /// <param name="offset">A byte offset relative to the origin parameter.</param>3817      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3818      /// <returns>3819      /// The new position within the current stream.3820      /// </returns>3821      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3822      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3823      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3824      public override long Seek(long offset, SeekOrigin origin)3825      {3826        long newPos = readPos_;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. </excep3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3694      public override long Length {3695        get { return length_; }3696      }36973698      /// <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      }37063707      /// <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      }37153716      /// <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      }37243725      /// <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 Fields3734      ZipFile zipFile_;3735      Stream baseStream_;3736      long start_;3737      long length_;3738      long readPos_;3739      long end_;3740      #endregion3741    }3742    #endregion3743  }37443745  #endregion37463747  #region DataSources3748  /// <summary>3749  /// Provides a static way to obtain a source of data for an entry.3750  /// </summary>3751  public interface IStaticDataSource3752  {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  }37603761  /// <summary>3762  /// Represents a source of data that can dynamically provide3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3764  /// </summary>3765  public interface IDynamicDataSource3766  {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  }37763777  /// <summary>3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3779  /// </summary>3780  public class StaticDiskDataSource : IStaticDataSource3781  {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    }37903791    #region IDataSource Members37923793    /// <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    }38013802    readonly38033804    #endregion3805    #region Instance Fields3806    string fileName_;3807    #endregion3808  }380938103811  /// <summary>3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.3813  /// </summary>3814  public class DynamicDiskDataSource : IDynamicDataSource3815  {38163817    #region IDataSource Members3818    /// <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;  38273828        switch ( origin )3829        {3830          case SeekOrigin.Begin:3831            newPos = start_ + offset;3832            break;38333834          case SeekOrigin.Current:3835            newPos = readPos_ + offset;3836            break;3828      if (name != null) {3829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);3830      }38313832      return result;3833    }38343835    #endregion3836  }  38373838          case SeekOrigin.End:3839            newPos = end_ + offset;3840            break;3841        }38423843        if ( newPos < start_ ) {3844          throw new ArgumentException("Negative position is invalid");3845        }38463847        if ( newPos >= end_ ) {3848          throw new IOException("Cannot seek past end");3849        }3850        readPos_ = newPos;3851        return readPos_;3852      }38533854      /// <summary>3855      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.3856      /// </summary>3857      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3858      public override void Flush()3859      {3860        // Nothing to do.3861      }38623863      /// <summary>3864      /// Gets or sets the position within the current stream.3865      /// </summary>3866      /// <value></value>3867      /// <returns>The current position within the stream.</returns>3868      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3869      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>3870      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3871      public override long Position {3872        get { return readPos_ - start_; }3873        set {3874          long newPos = start_ + value;38753876          if ( newPos < start_ ) {3877            throw new ArgumentException("Negative position is invalid");3878          }3838  #endregion38393840  #region Archive Storage3841  /// <summary>3842  /// Defines facilities for data storage when updating Zip Archives.3843  /// </summary>3844  public interface IArchiveStorage3845  {3846    /// <summary>3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.3848    /// </summary>3849    FileUpdateMode UpdateMode { get; }38503851    /// <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();38573858    /// <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();38643865    /// <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);38713872    /// <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);  38793880          if ( newPos >= end_ ) {3881            throw new InvalidOperationException("Cannot seek past end");3882          }3883          readPos_ = newPos;3884        }3885      }38863887      /// <summary>3888      /// Gets the length in bytes of the stream.3889      /// </summary>3890      /// <value></value>3891      /// <returns>A long value representing the length of the stream in bytes.</returns>3892      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep3893      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3894      public override long Length {3895        get { return length_; }3896      }38973898      /// <summary>3899      /// Gets a value indicating whether the current stream supports writing.3900      /// </summary>3901      /// <value>false</value>3902      /// <returns>true if the stream supports writing; otherwise, false.</returns>3903      public override bool CanWrite {3904        get { return false; }3905      }39063907      /// <summary>3908      /// Gets a value indicating whether the current stream supports seeking.3909      /// </summary>3910      /// <value>true</value>3911      /// <returns>true if the stream supports seeking; otherwise, false.</returns>3912      public override bool CanSeek {3913        get { return true; }3914      }39153916      /// <summary>3917      /// Gets a value indicating whether the current stream supports reading.3918      /// </summary>3919      /// <value>true.</value>3920      /// <returns>true if the stream supports reading; otherwise, false.</returns>3921      public override bool CanRead {3922        get { return true; }3923      }39243925#if !NET_1_0 && !NET_1_1 && !NETCF_1_03926      /// <summary>3927      /// Gets a value that determines whether the current stream can time out.3928      /// </summary>3929      /// <value></value>3930      /// <returns>A value that determines whether the current stream can time out.</returns>3931      public override bool CanTimeout {3932        get { return baseStream_.CanTimeout; }3933      }3934#endif3935      #region Instance Fields3936      ZipFile zipFile_;3937      Stream baseStream_;3938      long start_;3939      long length_;3940      long readPos_;3941      long end_;3942      #endregion3943    }3944    #endregion3945  }39463947  #endregion39483949  #region DataSources3950  /// <summary>3951  /// Provides a static way to obtain a source of data for an entry.3952  /// </summary>3953  public interface IStaticDataSource3954  {3955    /// <summary>3956    /// Get a source of data by creating a new stream.3957    /// </summary>3958    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3959    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3960    Stream GetSource();3961  }39623963  /// <summary>3964  /// Represents a source of data that can dynamically provide3965  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3966  /// </summary>3967  public interface IDynamicDataSource3968  {3969    /// <summary>3970    /// Get a data source.3971    /// </summary>3972    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>3973    /// <param name="name">The name for data if known.</param>3974    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3975    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3976    Stream GetSource(ZipEntry entry, string name);3977  }39783979  /// <summary>3980  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3981  /// </summary>3982  public class StaticDiskDataSource : IStaticDataSource3983  {3984    /// <summary>3985    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>3986    /// </summary>3987    /// <param name="fileName">The name of the file to obtain data from.</param>3988    public StaticDiskDataSource(string fileName)3989    {3990      fileName_ = fileName;3991    }39923993    #region IDataSource Members39943995    /// <summary>3996    /// Get a <see cref="Stream"/> providing data.3997    /// </summary>3998    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>3999    public Stream GetSource()4000    {4001      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4002    }3880    /// <summary>3881    /// Dispose of this instance.3882    /// </summary>3883    void Dispose();3884  }38853886  /// <summary>3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.3888  /// </summary>3889  abstract public class BaseArchiveStorage : IArchiveStorage3890  {3891    #region Constructors3892    /// <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    #endregion39013902    #region IArchiveStorage Members39033904    /// <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();39103911    /// <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 read3915    /// the final storage for the archive.</returns>3916    /// <seealso cref="GetTemporaryOutput"/>3917    public abstract Stream ConvertTemporaryToFinal();39183919    /// <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);39253926    /// <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);39323933    /// <summary>3934    /// Disposes this instance.3935    /// </summary>3936    public abstract void Dispose();39373938    /// <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    }39473948    #endregion39493950    #region Instance Fields3951    FileUpdateMode updateMode_;3952    #endregion3953  }39543955  /// <summary>3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.3957  /// </summary>3958  public class DiskArchiveStorage : BaseArchiveStorage3959  {3960    #region Constructors3961    /// <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      }39723973      fileName_ = file.Name;3974    }39753976    /// <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    #endregion39853986    #region IArchiveStorage Members39873988    /// <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      }  40034004    readonly40054006    #endregion4007    #region Instance Fields4008    string fileName_;4009    #endregion4010  }401140124013  /// <summary>4014  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.4015  /// </summary>4016  public class DynamicDiskDataSource : IDynamicDataSource4017  {40184019    #region IDataSource Members4020    /// <summary>4021    /// Get a <see cref="Stream"/> providing data for an entry.4022    /// </summary>4023    /// <param name="entry">The entry to provide data for.</param>4024    /// <param name="name">The file name for data if known.</param>4025    /// <returns>Returns a stream providing data; or null if not available</returns>4026    public Stream GetSource(ZipEntry entry, string name)4027    {4028      Stream result = null;4004      return temporaryStream_;4005    }40064007    /// <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 read4011    /// 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      }40174018      Stream result = null;40194020      string moveTempName = GetTempFileName(fileName_, false);4021      bool newFileCreated = false;40224023      try {4024        temporaryStream_.Close();4025        File.Move(fileName_, moveTempName);4026        File.Move(temporaryName_, fileName_);4027        newFileCreated = true;4028        File.Delete(moveTempName);  40294030      if ( name != null ) {4031        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);4032      }4030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4031      } catch (Exception) {4032        result = null;  40334034      return result;4035    }40364037    #endregion4038  }4034        // Try to roll back changes...4035        if (!newFileCreated) {4036          File.Move(moveTempName, fileName_);4037          File.Delete(temporaryName_);4038        }  40394040  #endregion40414042  #region Archive Storage4043  /// <summary>4044  /// Defines facilities for data storage when updating Zip Archives.4045  /// </summary>4046  public interface IArchiveStorage4047  {4048    /// <summary>4049    /// Get the <see cref="FileUpdateMode"/> to apply during updates.4050    /// </summary>4051    FileUpdateMode UpdateMode { get; }40524053    /// <summary>4054    /// Get an empty <see cref="Stream"/> that can be used for temporary output.4055    /// </summary>4056    /// <returns>Returns a temporary output <see cref="Stream"/></returns>4057    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4058    Stream GetTemporaryOutput();40594060    /// <summary>4061    /// Convert a temporary output stream to a final stream.4062    /// </summary>4063    /// <returns>The resulting final <see cref="Stream"/></returns>4064    /// <seealso cref="GetTemporaryOutput"/>4065    Stream ConvertTemporaryToFinal();40664067    /// <summary>4068    /// Make a temporary copy of the original stream.4069    /// </summary>4070    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4071    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4072    Stream MakeTemporaryCopy(Stream stream);40734074    /// <summary>4075    /// Return a stream suitable for performing direct updates on the original source.4076    /// </summary>4077    /// <param name="stream">The current stream.</param>4078    /// <returns>Returns a stream suitable for direct updating.</returns>4079    /// <remarks>This may be the current stream passed.</remarks>4080    Stream OpenForDirectUpdate(Stream stream);40814082    /// <summary>4083    /// Dispose of this instance.4084    /// </summary>4085    void Dispose();4086  }4040        throw;4041      }40424043      return result;4044    }40454046    /// <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();40544055      temporaryName_ = GetTempFileName(fileName_, true);4056      File.Copy(fileName_, temporaryName_, true);40574058      temporaryStream_ = new FileStream(temporaryName_,4059        FileMode.Open,4060        FileAccess.ReadWrite);4061      return temporaryStream_;4062    }40634064    /// <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        }40774078        result = new FileStream(fileName_,4079            FileMode.Open,4080            FileAccess.ReadWrite);4081      } else {4082        result = stream;4083      }40844085      return result;4086    }  40874088  /// <summary>4089  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.4090  /// </summary>4091  abstract public class BaseArchiveStorage : IArchiveStorage4092  {4093    #region Constructors4094    /// <summary>4095    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.4096    /// </summary>4097    /// <param name="updateMode">The update mode.</param>4098    protected BaseArchiveStorage(FileUpdateMode updateMode)4099    {4100      updateMode_ = updateMode;4101    }4102    #endregion41034104    #region IArchiveStorage Members41054106    /// <summary>4107    /// Gets a temporary output <see cref="Stream"/>4108    /// </summary>4109    /// <returns>Returns the temporary output stream.</returns>4110    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4111    public abstract Stream GetTemporaryOutput();41124113    /// <summary>4114    /// Converts the temporary <see cref="Stream"/> to its final form.4115    /// </summary>4116    /// <returns>Returns a <see cref="Stream"/> that can be used to read4117    /// the final storage for the archive.</returns>4118    /// <seealso cref="GetTemporaryOutput"/>4119    public abstract Stream ConvertTemporaryToFinal();41204121    /// <summary>4122    /// Make a temporary copy of a <see cref="Stream"/>.4123    /// </summary>4124    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>4125    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4126    public abstract Stream MakeTemporaryCopy(Stream stream);41274128    /// <summary>4129    /// Return a stream suitable for performing direct updates on the original source.4130    /// </summary>4131    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>4132    /// <returns>Returns a stream suitable for direct updating.</returns>4133    public abstract Stream OpenForDirectUpdate(Stream stream);41344135    /// <summary>4136    /// Disposes this instance.4137    /// </summary>4138    public abstract void Dispose();41394140    /// <summary>4141    /// Gets the update mode applicable.4142    /// </summary>4143    /// <value>The update mode.</value>4144    public FileUpdateMode UpdateMode4145    {4146      get {4147        return updateMode_;4148      }4149    }41504151    #endregion41524153    #region Instance Fields4154    FileUpdateMode updateMode_;4155    #endregion4156  }41574158  /// <summary>4159  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.4160  /// </summary>4161  public class DiskArchiveStorage : BaseArchiveStorage4162  {4163    #region Constructors4164    /// <summary>4165    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4166    /// </summary>4167    /// <param name="file">The file.</param>4168    /// <param name="updateMode">The update mode.</param>4169    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)4170      : base(updateMode)4171    {4172      if ( file.Name == null ) {4173        throw new ZipException("Cant handle non file archives");4174      }41754176      fileName_ = file.Name;4177    }4088    /// <summary>4089    /// Disposes this instance.4090    /// </summary>4091    public override void Dispose()4092    {4093      if (temporaryStream_ != null) {4094        temporaryStream_.Close();4095      }4096    }40974098    #endregion40994100    #region Internal routines4101    static string GetTempFileName(string original, bool makeTempFile)4102    {4103      string result = null;41044105      if (original == null) {4106        result = Path.GetTempFileName();4107      } else {4108        int counter = 0;4109        int suffixSeed = DateTime.Now.Second;41104111        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    #endregion41334134    #region Instance Fields4135    Stream temporaryStream_;4136    string fileName_;4137    string temporaryName_;4138    #endregion4139  }41404141  /// <summary>4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4143  /// </summary>4144  public class MemoryArchiveStorage : BaseArchiveStorage4145  {4146    #region Constructors4147    /// <summary>4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4149    /// </summary>4150    public MemoryArchiveStorage()4151      : base(FileUpdateMode.Direct)4152    {4153    }41544155    /// <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    }41644165    #endregion41664167    #region Properties4168    /// <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    }41744175    #endregion41764177    #region IArchiveStorage Members  4178  4179    /// <summary>4180    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4180    /// Gets the temporary output <see cref="Stream"/>  4181    /// </summary>4182    /// <param name="file">The file.</param>4183    public DiskArchiveStorage(ZipFile file)4184      : this(file, FileUpdateMode.Safe)4185    {4186    }4187    #endregion4182    /// <returns>Returns the temporary output stream.</returns>4183    public override Stream GetTemporaryOutput()4184    {4185      temporaryStream_ = new MemoryStream();4186      return temporaryStream_;4187    }  41884189    #region IArchiveStorage Members41904191    /// <summary>4192    /// Gets a temporary output <see cref="Stream"/> for performing updates on.4193    /// </summary>4194    /// <returns>Returns the temporary output stream.</returns>4195    public override Stream GetTemporaryOutput()4196    {4197      if ( temporaryName_ != null ) {4198        temporaryName_ = GetTempFileName(temporaryName_, true);4199        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4200      }4201      else {4202        // Determine where to place files based on internal strategy.4203        // Currently this is always done in system temp directory.4204        temporaryName_ = Path.GetTempFileName();4205        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4206      }42074208      return temporaryStream_;4209    }42104211    /// <summary>4212    /// Converts a temporary <see cref="Stream"/> to its final form.4213    /// </summary>4214    /// <returns>Returns a <see cref="Stream"/> that can be used to read4215    /// the final storage for the archive.</returns>4216    public override Stream ConvertTemporaryToFinal()4217    {4218      if ( temporaryStream_ == null ) {4219        throw new ZipException("No temporary stream has been created");4220      }42214222      Stream result = null;42234224      string moveTempName = GetTempFileName(fileName_, false);4225      bool newFileCreated = false;42264227      try  {4228        temporaryStream_.Close();4229        File.Move(fileName_, moveTempName);4230        File.Move(temporaryName_, fileName_);4231        newFileCreated = true;4232        File.Delete(moveTempName);42334234        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4235      }4236      catch(Exception) {4237        result  = null;42384239        // Try to roll back changes...4240        if ( !newFileCreated ) {4241          File.Move(moveTempName, fileName_);4242          File.Delete(temporaryName_);4243        }42444245        throw;4246      }42474248      return result;4249    }42504251    /// <summary>4252    /// Make a temporary copy of a stream.4253    /// </summary>4254    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4255    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4256    public override Stream MakeTemporaryCopy(Stream stream)4257    {4258      stream.Close();42594260      temporaryName_ = GetTempFileName(fileName_, true);4261      File.Copy(fileName_, temporaryName_, true);42624263      temporaryStream_ = new FileStream(temporaryName_,4264        FileMode.Open,4265        FileAccess.ReadWrite);4266      return temporaryStream_;4267    }42684269    /// <summary>4270    /// Return a stream suitable for performing direct updates on the original source.4271    /// </summary>4272    /// <param name="stream">The current stream.</param>4273    /// <returns>Returns a stream suitable for direct updating.</returns>4274    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>4275    public override Stream OpenForDirectUpdate(Stream stream)4276    {4277      Stream result;4278      if ((stream == null) || !stream.CanWrite)4279      {4280        if (stream != null) {4281          stream.Close();4282        }42834284        result = new FileStream(fileName_,4285            FileMode.Open,4286            FileAccess.ReadWrite);4287      }4288      else4289      {4290        result = stream;4291      }42924293      return result;4294    }42954296    /// <summary>4297    /// Disposes this instance.4298    /// </summary>4299    public override void Dispose()4300    {4301      if ( temporaryStream_ != null ) {4302        temporaryStream_.Close();4303      }4304    }43054306    #endregion43074308    #region Internal routines4309    static string GetTempFileName(string original, bool makeTempFile)4310    {4311      string result = null;43124313      if ( original == null ) {4314        result = Path.GetTempFileName();4315      }4316      else {4317        int counter = 0;4318        int suffixSeed = DateTime.Now.Second;43194320        while ( result == null ) {4321          counter += 1;4322          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);4323          if ( !File.Exists(newName) ) {4324            if ( makeTempFile) {4325              try  {4326                // Try and create the file.4327                using ( FileStream stream = File.Create(newName) ) {4328                }4329                result = newName;4330              }4331              catch {4332                suffixSeed = DateTime.Now.Second;4333              }4334            }4335            else {4336              result = newName;4337            }4338          }4339        }4340      }4341      return result;4342    }4343    #endregion43444345    #region Instance Fields4346    Stream temporaryStream_;4347    string fileName_;4348    string temporaryName_;4349    #endregion4350  }43514352  /// <summary>4353  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4354  /// </summary>4355  public class MemoryArchiveStorage : BaseArchiveStorage4356  {4357    #region Constructors4358    /// <summary>4359    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4360    /// </summary>4361    public MemoryArchiveStorage()4362      : base(FileUpdateMode.Direct)4363    {4364    }43654366    /// <summary>4367    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4368    /// </summary>4369    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>4370    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>4371    public MemoryArchiveStorage(FileUpdateMode updateMode)4372      : base(updateMode)4373    {4374    }43754376    #endregion43774378    #region Properties4379    /// <summary>4380    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.4381    /// </summary>4382    public MemoryStream FinalStream4383    {4384      get { return finalStream_; }4385    }43864387    #endregion43884389    #region IArchiveStorage Members43904391    /// <summary>4392    /// Gets the temporary output <see cref="Stream"/>4393    /// </summary>4394    /// <returns>Returns the temporary output stream.</returns>4395    public override Stream GetTemporaryOutput()4396    {4397      temporaryStream_ = new MemoryStream();4398      return temporaryStream_;4399    }44004401    /// <summary>4402    /// Converts the temporary <see cref="Stream"/> to its final form.4403    /// </summary>4404    /// <returns>Returns a <see cref="Stream"/> that can be used to read4405    /// the final storage for the archive.</returns>4406    public override Stream ConvertTemporaryToFinal()4407    {4408      if ( temporaryStream_ == null ) {4409        throw new ZipException("No temporary stream has been created");4410      }44114412      finalStream_ = new MemoryStream(temporaryStream_.ToArray());4413      return finalStream_;4414    }44154416    /// <summary>4417    /// Make a temporary copy of the original stream.4418    /// </summary>4419    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4420    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4421    public override Stream MakeTemporaryCopy(Stream stream)4422    {4423      temporaryStream_ = new MemoryStream();4424      stream.Position = 0;4425      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);4426      return temporaryStream_;4427    }44284429    /// <summary>4430    /// Return a stream suitable for performing direct updates on the original source.4431    /// </summary>4432    /// <param name="stream">The original source stream</param>4433    /// <returns>Returns a stream suitable for direct updating.</returns>4434    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;4435    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>4436    public override Stream OpenForDirectUpdate(Stream stream)4437    {4438      Stream result;4439      if ((stream == null) || !stream.CanWrite) {44404441        result = new MemoryStream();44424443        if (stream != null) {4444          stream.Position = 0;4445          StreamUtils.Copy(stream, result, new byte[4096]);44464447          stream.Close();4448        }4449      }4450      else {4451        result = stream;4452      }44534454      return result;4455    }44564457    /// <summary>4458    /// Disposes this instance.4459    /// </summary>4460    public override void Dispose()4461    {4462      if ( temporaryStream_ != null ) {4463        temporaryStream_.Close();4464      }4465    }44664467    #endregion44684469    #region Instance Fields4470    MemoryStream temporaryStream_;4471    MemoryStream finalStream_;4472    #endregion4473  }44744475  #endregion4476}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 read4193    /// 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      }41994200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());4201      return finalStream_;4202    }42034204    /// <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    }42164217    /// <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) {42284229        result = new MemoryStream();42304231        if (stream != null) {4232          stream.Position = 0;4233          StreamUtils.Copy(stream, result, new byte[4096]);42344235          stream.Close();4236        }4237      } else {4238        result = stream;4239      }42404241      return result;4242    }42434244    /// <summary>4245    /// Disposes this instance.4246    /// </summary>4247    public override void Dispose()4248    {4249      if (temporaryStream_ != null) {4250        temporaryStream_.Close();4251      }4252    }42534254    #endregion42554256    #region Instance Fields4257    MemoryStream temporaryStream_;4258    MemoryStream finalStream_;4259    #endregion4260  }42614262  #endregion4263} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_WindowsNameTransform.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_WindowsNameTransform.htm index 621b42840..ff2ab33ca 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_WindowsNameTransform.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_WindowsNameTransform.htm @@ -15,12 +15,12 @@

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:56 -Uncovered lines:21 +Covered lines:42 +Uncovered lines:35 Coverable lines:77 -Total lines:272 -Line coverage:72.7% -Branch coverage:71.4% +Total lines:226 +Line coverage:54.5% +Branch coverage:42.8%

Metrics

@@ -33,7 +33,7 @@

Metrics

TransformFile(...)477.7871.43 IsValidName(...)300 .cctor()1100100 -MakeValidName(...)1183.3376.19 +MakeValidName(...)115052.38

File(s)

@@ -41,280 +41,234 @@

#LineLine coverage - 1// WindowsNameTransform.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536using System;37using System.IO;38using System.Text;3940using ICSharpCode.SharpZipLib.Core;4142namespace ICSharpCode.SharpZipLib.Zip43{44  /// <summary>45  /// WindowsNameTransform transforms <see cref="ZipFile"/> names to windows compatible ones.46  /// </summary>47  public class WindowsNameTransform : INameTransform48  {49    /// <summary>50    /// Initialises a new instance of <see cref="WindowsNameTransform"/>51    /// </summary>52    /// <param name="baseDirectory"></param> - 153    public WindowsNameTransform(string baseDirectory)54    { - 155       if ( baseDirectory == null ) { - 056        throw new ArgumentNullException(nameof(baseDirectory), "Directory name is invalid");57      }58 - 159      BaseDirectory = baseDirectory; - 160    }6162    /// <summary>63    /// Initialise a default instance of <see cref="WindowsNameTransform"/>64    /// </summary> - 665    public WindowsNameTransform()66    {67      // Do nothing. - 668    }6970    /// <summary>71    /// Gets or sets a value containing the target directory to prefix values with.72    /// </summary>73    public string BaseDirectory74    { - 075      get { return _baseDirectory; }76      set { - 277         if ( value == null ) { - 078          throw new ArgumentNullException(nameof(value));79        }80 - 281        _baseDirectory = Path.GetFullPath(value); - 282      }83    }8485    /// <summary>86    /// Gets or sets a value indicating wether paths on incoming values should be removed.87    /// </summary>88    public bool TrimIncomingPaths89    { - 090      get { return _trimIncomingPaths; } - 691      set { _trimIncomingPaths = value; }92    }9394    /// <summary>95    /// Transform a Zip directory name to a windows directory name.96    /// </summary>97    /// <param name="name">The directory name to transform.</param>98    /// <returns>The transformed name.</returns>99    public string TransformDirectory(string name)100    { - 7101      name = TransformFile(name); - 6102       if (name.Length > 0) { - 6103         while (name.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) { - 0104          name = name.Remove(name.Length - 1, 1);105        } - 6106      }107      else { - 0108        throw new ZipException("Cannot have an empty directory name");109      } - 6110      return name;111    }1using System;2using System.IO;3using System.Text;4using ICSharpCode.SharpZipLib.Core;56namespace ICSharpCode.SharpZipLib.Zip7{8  /// <summary>9  /// WindowsNameTransform transforms <see cref="ZipFile"/> names to windows compatible ones.10  /// </summary>11  public class WindowsNameTransform : INameTransform12  {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    }2526    /// <summary>27    /// Initialise a default instance of <see cref="WindowsNameTransform"/>28    /// </summary> + 229    public WindowsNameTransform()30    {31      // Do nothing. + 232    }3334    /// <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    }4748    /// <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    }5556    /// <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    }7374    /// <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        }8788        // 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    }9899    /// <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        ;  112113    /// <summary>114    /// Transform a Zip format file name to a windows style one.115    /// </summary>116    /// <param name="name">The file name to transform.</param>117    /// <returns>The transformed name.</returns>118    public string TransformFile(string name)119    { - 12120       if (name != null) { - 12121        name = MakeValidName(name, _replacementChar); + 0113      return result;114    }115116    /// <summary>117    /// Initialise static class information.118    /// </summary>119    static WindowsNameTransform()120    {121      char[] invalidPathChars;  122 - 11123         if ( _trimIncomingPaths ) { - 0124          name = Path.GetFileName(name);125        }126127        // This may exceed windows length restrictions.128        // Combine will throw a PathTooLongException in that case. - 11129         if ( _baseDirectory != null ) { - 2130          name = Path.Combine(_baseDirectory, name);131        } - 2132      }133      else { - 0134        name = string.Empty;135      } - 11136      return name;137    }138139    /// <summary>140    /// Test a name to see if it is a valid name for a windows filename as extracted from a Zip archive.141    /// </summary>142    /// <param name="name">The name to test.</param>143    /// <returns>Returns true if the name is a valid zip name; false otherwise.</returns>144    /// <remarks>The filename isnt a true windows path in some fundamental ways like no absolute paths, no rooted paths 145    public static bool IsValidName(string name)146    { - 0147      bool result = - 0148        (name != null) && - 0149        (name.Length <= MaxPath) && - 0150        (string.Compare(name, MakeValidName(name, '_'), StringComparison.Ordinal) == 0) - 0151        ;152 - 0153      return result;154    }155156    /// <summary>157    /// Initialise static class information.158    /// </summary>159    static WindowsNameTransform()160    {161      char[] invalidPathChars;162163#if NET_1_0 || NET_1_1 || NETCF_1_0164      invalidPathChars = Path.InvalidPathChars;165#else - 1166      invalidPathChars = Path.GetInvalidPathChars();167#endif - 1168      int howMany = invalidPathChars.Length + 3;169 - 1170      InvalidEntryChars = new char[howMany]; - 1171      Array.Copy(invalidPathChars, 0, InvalidEntryChars, 0, invalidPathChars.Length); - 1172      InvalidEntryChars[howMany - 1] = '*'; - 1173      InvalidEntryChars[howMany - 2] = '?'; - 1174      InvalidEntryChars[howMany - 3] = ':'; - 1175    }176177    /// <summary>178    /// Force a name to be valid by replacing invalid characters with a fixed value179    /// </summary>180    /// <param name="name">The name to make valid</param>181    /// <param name="replacement">The replacement character to use for any invalid characters.</param>182    /// <returns>Returns a valid name</returns>183    public static string MakeValidName(string name, char replacement)184    { - 12185       if ( name == null ) { - 0186        throw new ArgumentNullException(nameof(name));187      }188 - 12189      name = WindowsPathUtils.DropPathRoot(name.Replace("/", Path.DirectorySeparatorChar.ToString()));190191      // Drop any leading slashes. - 12192       while ( (name.Length > 0) && (name[0] == Path.DirectorySeparatorChar)) { - 0193        name = name.Remove(0, 1);194      }195196      // Drop any trailing slashes. - 14197       while ( (name.Length > 0) && (name[name.Length - 1] == Path.DirectorySeparatorChar)) { - 2198        name = name.Remove(name.Length - 1, 1);199      }200201      // Convert consecutive \\ characters to \ - 12202      int index = name.IndexOf(string.Format("{0}{0}", Path.DirectorySeparatorChar), StringComparison.Ordinal); - 23203       while (index >= 0) { - 11204        name = name.Remove(index, 1); - 11205        index = name.IndexOf(Path.DirectorySeparatorChar);206      }207208      // Convert any invalid characters using the replacement one. - 12209      index = name.IndexOfAny(InvalidEntryChars); - 12210       if (index >= 0) { - 2211        var builder = new StringBuilder(name);212 - 4213         while (index >= 0 ) { - 2214          builder[index] = replacement; + 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    }132133    /// <summary>134    /// Force a name to be valid by replacing invalid characters with a fixed value135    /// </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()));146147      // Drop any leading slashes. + 3148       while ((name.Length > 0) && (name[0] == Path.DirectorySeparatorChar)) { + 0149        name = name.Remove(0, 1);150      }151152      // Drop any trailing slashes. + 4153       while ((name.Length > 0) && (name[name.Length - 1] == Path.DirectorySeparatorChar)) { + 1154        name = name.Remove(name.Length - 1, 1);155      }156157      // 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      }163164      // 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      }180181      // 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    }189190    /// <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    }209210    /// <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.</remar214    const int MaxPath = 260;  215 - 2216           if (index >= name.Length) { - 0217            index = -1; - 0218          }219          else { - 2220            index = name.IndexOfAny(InvalidEntryChars, index + 1);221          }222        } - 2223        name = builder.ToString();224      }225226      // Check for names greater than MaxPath characters.227      // TODO: Were is CLR version of MaxPath defined?  Can't find it in Environment. - 12228       if ( name.Length > MaxPath ) { - 1229        throw new PathTooLongException();230      }231 - 11232      return name;233    }234235    /// <summary>236    /// Gets or set the character to replace invalid characters during transformations.237    /// </summary>238    public char Replacement239    { - 0240      get { return _replacementChar; }241      set { - 388242         for ( int i = 0; i < InvalidEntryChars.Length; ++i ) { - 192243           if ( InvalidEntryChars[i] == value ) { - 3244            throw new ArgumentException("invalid path character");245          }246        }247 - 2248         if ((value == Path.DirectorySeparatorChar) || (value == Path.AltDirectorySeparatorChar)) { - 2249          throw new ArgumentException("invalid replacement character");250        }251 - 0252        _replacementChar = value; - 0253      }254    }255256    /// <summary>257    ///  The maximum windows path name permitted.258    /// </summary>259    /// <remarks>This may not valid for all windows systems - CE?, etc but I cant find the equivalent in the CLR.</remar260    const int MaxPath = 260;261262    #region Instance Fields263    string _baseDirectory;264    bool _trimIncomingPaths; - 7265    char _replacementChar = '_';266    #endregion267268    #region Class Fields269    static readonly char[] InvalidEntryChars;270    #endregion271  }272}216    #region Instance Fields217    string _baseDirectory;218    bool _trimIncomingPaths; + 3219    char _replacementChar = '_';220    #endregion221222    #region Class Fields223    static readonly char[] InvalidEntryChars;224    #endregion225  }226} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_WindowsPathUtils.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_WindowsPathUtils.htm index e21aab081..28022755e 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_WindowsPathUtils.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_WindowsPathUtils.htm @@ -16,10 +16,10 @@

Summary

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:4 -Coverable lines:23 -Total lines:94 -Line coverage:82.6% +Uncovered lines:3 +Coverable lines:22 +Total lines:57 +Line coverage:86.3% Branch coverage:76.6% @@ -36,102 +36,65 @@

#LineLine coverage - 1// WindowsPathUtils.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.3536namespace ICSharpCode.SharpZipLib.Core37{38  /// <summary>39  /// WindowsPathUtils provides simple utilities for handling windows paths.40  /// </summary>41  public abstract class WindowsPathUtils42  {43    /// <summary>44    /// Initializes a new instance of the <see cref="WindowsPathUtils"/> class.45    /// </summary> - 046    internal WindowsPathUtils()47    { - 048    }4950    /// <summary>51    /// Remove any path root present in the path52    /// </summary>53    /// <param name="path">A <see cref="string"/> containing path information.</param>54    /// <returns>The path with the root removed if it was present; path otherwise.</returns>55    /// <remarks>Unlike the <see cref="System.IO.Path"/> class the path isnt otherwise checked for validity.</remarks>56    public static string DropPathRoot(string path)57    { - 6594858      string result = path;59 - 6594860       if ( !string.IsNullOrEmpty(path)) { - 6594861         if ((path[0] == '\\') || (path[0] == '/')) {62          // UNC name ? - 663           if ((path.Length > 1) && ((path[1] == '\\') || (path[1] == '/'))) { - 164            int index = 2; - 165            int elements = 2;6667            // Scan for two separate elements \\machine\share\restofpath - 1168             while ((index <= path.Length) && - 1169              (((path[index] != '\\') && (path[index] != '/')) || (--elements > 0))) { - 1070              index++;71            }72 - 173            index++;74 - 175             if (index < path.Length) { - 176              result = path.Substring(index); - 177            }78            else { - 079              result = "";80            }81          } - 082        } - 6594283         else if ((path.Length > 1) && (path[1] == ':')) { - 1884          int dropCount = 2; - 1885           if ((path.Length > 2) && ((path[2] == '\\') || (path[2] == '/'))) { - 1686            dropCount = 3;87          } - 1888          result = result.Remove(0, dropCount);89        }90      } - 6594891      return result;92    }93  }94}1namespace ICSharpCode.SharpZipLib.Core2{3  /// <summary>4  /// WindowsPathUtils provides simple utilities for handling windows paths.5  /// </summary>6  public abstract class WindowsPathUtils7  {8    /// <summary>9    /// Initializes a new instance of the <see cref="WindowsPathUtils"/> class.10    /// </summary> + 011    internal WindowsPathUtils()12    { + 013    }1415    /// <summary>16    /// Remove any path root present in the path17    /// </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;3132            // 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/Documentation/opencover/ICSharpCode.SharpZipLib_ZipAESStream.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipAESStream.htm index 3b050f522..a93ed1462 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipAESStream.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipAESStream.htm @@ -16,9 +16,9 @@

Summary

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:51 -Coverable lines:51 -Total lines:170 +Uncovered lines:50 +Coverable lines:50 +Total lines:134 Line coverage:0% Branch coverage:0% @@ -37,178 +37,142 @@

#LineLine coverage - 1//2// ZipAESStream.cs3//4// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team5//6// This program is free software; you can redistribute it and/or7// modify it under the terms of the GNU General Public License8// as published by the Free Software Foundation; either version 29// of the License, or (at your option) any later version.10//11// This program is distributed in the hope that it will be useful,12// but WITHOUT ANY WARRANTY; without even the implied warranty of13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the14// GNU General Public License for more details.15//16// You should have received a copy of the GNU General Public License17// along with this program; if not, write to the Free Software18// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.19//20// Linking this library statically or dynamically with other modules is21// making a combined work based on this library.  Thus, the terms and22// conditions of the GNU General Public License cover the whole23// combination.24//25// As a special exception, the copyright holders of this library give you26// permission to link this library with independent modules to produce an27// executable, regardless of the license terms of these independent28// modules, and to copy and distribute the resulting executable under29// terms of your choice, provided that you also meet, for each linked30// independent module, the terms and conditions of the license of that31// module.  An independent module is a module which is not derived from32// or based on this library.  If you modify this library, you may extend33// this exception to your version of the library, but you are not34// obligated to do so.  If you do not wish to do so, delete this35// exception statement from your version.36//3738#if !NET_1_1 && !NETCF_2_03940using System;41using System.IO;42using System.Security.Cryptography;1using System;2using System.IO;3using System.Security.Cryptography;45namespace ICSharpCode.SharpZipLib.Encryption6{7  /// <summary>8  /// Encrypts and decrypts AES ZIP9  /// </summary>10  /// <remarks>11  /// Based on information from http://www.winzip.com/aes_info.htm12  /// and http://www.gladman.me.uk/cryptography_technology/fileencrypt/13  /// </remarks>14  internal class ZipAESStream : CryptoStream15  {1617    /// <summary>18    /// Constructor19    /// </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;3233      // 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    }4041    // The final n bytes of the AES stream contain the Auth Code.42    private const int AUTH_CODE_LENGTH = 10;  4344namespace ICSharpCode.SharpZipLib.Encryption {4546  // Based on information from http://www.winzip.com/aes_info.htm47  // and http://www.gladman.me.uk/cryptography_technology/fileencrypt/4849  /// <summary>50  /// Encrypts and decrypts AES ZIP51  /// </summary>52  internal class ZipAESStream : CryptoStream {5354    /// <summary>55    /// Constructor44    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;5253    /// <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    /// <param name="stream">The stream on which to perform the cryptographic transformation.</param>58    /// <param name="transform">Instance of ZipAESTransform</param>59    /// <param name="mode">Read or Write</param>60    public ZipAESStream(Stream stream, ZipAESTransform transform, CryptoStreamMode mode) - 061      : base(stream, transform, mode) {62 - 063      _stream = stream; - 064      _transform = transform; - 065      _slideBuffer = new byte[1024];66 - 067      _blockAndAuth = CRYPTO_BLOCK_SIZE + AUTH_CODE_LENGTH;6869      // mode:70      //  CryptoStreamMode.Read means we read from "stream" and pass decrypted to our Read() method.71      //  Write bypasses this stream and uses the Transform directly. - 072       if (mode != CryptoStreamMode.Read) { - 073        throw new Exception("ZipAESStream only for read");74      } - 075    }7677    // The final n bytes of the AES stream contain the Auth Code.78    private const int AUTH_CODE_LENGTH = 10;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;6364        // 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;  7980    private Stream _stream;81    private ZipAESTransform _transform;82    private byte[] _slideBuffer;83    private int _slideBufStartPos;84    private int _slideBufFreePos;85    // Blocksize is always 16 here, even for AES-256 which has transform.InputBlockSize of 32.86    private const int CRYPTO_BLOCK_SIZE = 16;87    private int _blockAndAuth;8889    /// <summary>90    /// Reads a sequence of bytes from the current CryptoStream into buffer,91    /// and advances the position within the stream by the number of bytes read.92    /// </summary>93    public override int Read(byte[] buffer, int offset, int count) { - 094      int nBytes = 0; - 095       while (nBytes < count) {96        // Calculate buffer quantities vs read-ahead size, and check for sufficient free space - 097        int byteCount = _slideBufFreePos - _slideBufStartPos;9899        // Need to handle final block and Auth Code specially, but don't know total data length.100        // Maintain a read-ahead equal to the length of (crypto block + Auth Code).101        // When that runs out we can detect these final sections. - 0102        int lengthToRead = _blockAndAuth - byteCount; - 0103         if (_slideBuffer.Length - _slideBufFreePos < lengthToRead) {104          // Shift the data to the beginning of the buffer - 0105          int iTo = 0; - 0106           for (int iFrom = _slideBufStartPos; iFrom < _slideBufFreePos; iFrom++, iTo++) { - 0107            _slideBuffer[iTo] = _slideBuffer[iFrom];108          } - 0109          _slideBufFreePos -= _slideBufStartPos;    // Note the -= - 0110          _slideBufStartPos = 0;111        } - 0112        int obtained = _stream.Read(_slideBuffer, _slideBufFreePos, lengthToRead); - 0113        _slideBufFreePos += obtained;114115        // Recalculate how much data we now have - 0116        byteCount = _slideBufFreePos - _slideBufStartPos; - 0117         if (byteCount >= _blockAndAuth) {118          // At least a 16 byte block and an auth code remains. - 0119          _transform.TransformBlock(_slideBuffer, - 0120                        _slideBufStartPos, - 0121                        CRYPTO_BLOCK_SIZE, - 0122                        buffer, - 0123                        offset); - 0124          nBytes += CRYPTO_BLOCK_SIZE; - 0125          offset += CRYPTO_BLOCK_SIZE; - 0126          _slideBufStartPos += CRYPTO_BLOCK_SIZE; - 0127        } else {128          // Last round. - 0129           if (byteCount > AUTH_CODE_LENGTH) {130            // At least one byte of data plus auth code - 0131            int finalBlock = byteCount - AUTH_CODE_LENGTH; - 0132            _transform.TransformBlock(_slideBuffer, - 0133                          _slideBufStartPos, - 0134                          finalBlock, - 0135                          buffer, - 0136                          offset);137 - 0138            nBytes += finalBlock; - 0139            _slideBufStartPos += finalBlock; - 0140          } - 0141           else if (byteCount < AUTH_CODE_LENGTH) - 0142            throw new Exception("Internal error missed auth code");  // Coding bug143          // Final block done. Check Auth code. - 0144          byte[] calcAuthCode = _transform.GetAuthCode(); - 0145           for (int i = 0; i < AUTH_CODE_LENGTH; i++) { - 0146             if (calcAuthCode[i] != _slideBuffer[_slideBufStartPos + i]) { - 0147              throw new Exception("AES Authentication Code does not match. This is a super-CRC check on the data in the  - 0148                + "The file may be damaged.");149            }150          }151 - 0152          break;  // Reached the auth code153        }154      } - 0155      return nBytes;156    }157158    /// <summary>159    /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the num160    /// </summary>161    /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream. </para162    /// <param name="offset">The byte offset in buffer at which to begin copying bytes to the current stream. </param>163    /// <param name="count">The number of bytes to be written to the current stream. </param>164    public override void Write(byte[] buffer, int offset, int count) {165      // ZipAESStream is used for reading but not for writing. Writing uses the ZipAESTransform directly. - 0166      throw new NotImplementedException();167    }168  }169}170#endif80        // 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 bug107                                        // 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 code117        }118      } + 0119      return nBytes;120    }121122    /// <summary>123    /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the num124    /// </summary>125    /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream. </para126    /// <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/Documentation/opencover/ICSharpCode.SharpZipLib_ZipAESTransform.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipAESTransform.htm index 9e359af8e..d02a5f950 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipAESTransform.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipAESTransform.htm @@ -18,7 +18,7 @@

Summary

Covered lines:0 Uncovered lines:47 Coverable lines:47 -Total lines:219 +Total lines:183 Line coverage:0% Branch coverage:0% @@ -39,227 +39,191 @@

#LineLine coverage - 1//2// ZipAESTransform.cs3//4// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team5//6// This program is free software; you can redistribute it and/or7// modify it under the terms of the GNU General Public License8// as published by the Free Software Foundation; either version 29// of the License, or (at your option) any later version.10//11// This program is distributed in the hope that it will be useful,12// but WITHOUT ANY WARRANTY; without even the implied warranty of13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the14// GNU General Public License for more details.15//16// You should have received a copy of the GNU General Public License17// along with this program; if not, write to the Free Software18// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.19//20// Linking this library statically or dynamically with other modules is21// making a combined work based on this library.  Thus, the terms and22// conditions of the GNU General Public License cover the whole23// combination.24//25// As a special exception, the copyright holders of this library give you26// permission to link this library with independent modules to produce an27// executable, regardless of the license terms of these independent28// modules, and to copy and distribute the resulting executable under29// terms of your choice, provided that you also meet, for each linked30// independent module, the terms and conditions of the license of that31// module.  An independent module is a module which is not derived from32// or based on this library.  If you modify this library, you may extend33// this exception to your version of the library, but you are not34// obligated to do so.  If you do not wish to do so, delete this35// exception statement from your version.36//3738#if !NET_1_1 && !NETCF_2_039// Framework version 2.0 required for Rfc2898DeriveBytes4041using System;42using System.Security.Cryptography;1using System;2using System.Security.Cryptography;34namespace ICSharpCode.SharpZipLib.Encryption5{6  /// <summary>7  /// Transforms stream using AES in CTR mode8  /// </summary>9  internal class ZipAESTransform : ICryptoTransform10  {11    private const int PWD_VER_LENGTH = 2;1213    // WinZip use iteration count of 1000 for PBKDF2 key generation14    private const int KEY_ROUNDS = 1000;1516    // 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 encryption18    // block but use only the first 16 bytes of it, and discard the second half.19    private const int ENCRYPT_BLOCK = 16;2021    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;2930    private bool _writeMode;3132    /// <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    {  4344namespace ICSharpCode.SharpZipLib.Encryption {4546  /// <summary>47  /// Transforms stream using AES in CTR mode48  /// </summary>49  internal class ZipAESTransform : ICryptoTransform {5051    private const int PWD_VER_LENGTH = 2; + 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;  5253    // WinZip use iteration count of 1000 for PBKDF2 key generation54    private const int KEY_ROUNDS = 1000;5556    // For 128-bit AES (16 bytes) the encryption is implemented as expected.57    // For 256-bit AES (32 bytes) WinZip do full 256 bit AES of the nonce to create the encryption58    // block but use only the first 16 bytes of it, and discard the second half.59    private const int ENCRYPT_BLOCK = 16;6061    private int _blockSize;62    private readonly ICryptoTransform _encryptor;63    private readonly byte[] _counterNonce;64    private byte[] _encryptBuffer;65    private int _encrPos;66    private byte[] _pwdVerifier;67    private HMACSHA1 _hmacsha1;68    private bool _finalised;6970    private bool _writeMode;7172    /// <summary>73    /// Constructor.74    /// </summary>75    /// <param name="key">Password string</param>76    /// <param name="saltBytes">Random bytes, length depends on encryption strength.77    /// 128 bits = 8 bytes, 192 bits = 12 bytes, 256 bits = 16 bytes.</param>78    /// <param name="blockSize">The encryption strength, in bytes eg 16 for 128 bits.</param>79    /// <param name="writeMode">True when creating a zip, false when reading. For the AuthCode.</param>80    /// - 081    public ZipAESTransform(string key, byte[] saltBytes, int blockSize, bool writeMode) {82 - 083       if (blockSize != 16 && blockSize != 32)  // 24 valid for AES but not supported by Winzip - 084        throw new Exception("Invalid blocksize " + blockSize + ". Must be 16 or 32."); - 085       if (saltBytes.Length != blockSize / 2) - 086        throw new Exception("Invalid salt len. Must be " + blockSize / 2 + " for blocksize " + blockSize);87      // initialise the encryption buffer and buffer pos - 088      _blockSize = blockSize; - 089      _encryptBuffer = new byte[_blockSize]; - 090      _encrPos = ENCRYPT_BLOCK;9192      // Performs the equivalent of derive_key in Dr Brian Gladman's pwd2key.c - 093      var pdb = new Rfc2898DeriveBytes(key, saltBytes, KEY_ROUNDS); - 094      var rm = new RijndaelManaged(); - 095      rm.Mode = CipherMode.ECB;      // No feedback from cipher for CTR mode - 096      _counterNonce = new byte[_blockSize]; - 097      byte[] byteKey1 = pdb.GetBytes(_blockSize); - 098      byte[] byteKey2 = pdb.GetBytes(_blockSize); - 099      _encryptor = rm.CreateEncryptor(byteKey1, byteKey2); - 0100      _pwdVerifier = pdb.GetBytes(PWD_VER_LENGTH);101      // - 0102      _hmacsha1 = new HMACSHA1(byteKey2); - 0103      _writeMode = writeMode; - 0104    }105106    /// <summary>107    /// Implement the ICryptoTransform method.108    /// </summary>109    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset53      // 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    }6667    /// <summary>68    /// Implement the ICryptoTransform method.69    /// </summary>70    public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset71    {7273      // 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    }101102    /// <summary>103    /// Returns the 2 byte password verifier104    /// </summary>105    public byte[] PwdVerifier {106      get { + 0107        return _pwdVerifier;108      }109    }  110111      // Pass the data stream to the hash algorithm for generating the Auth Code.112      // This does not change the inputBuffer. Do this before decryption for read mode. - 0113       if (!_writeMode) { - 0114        _hmacsha1.TransformBlock(inputBuffer, inputOffset, inputCount, inputBuffer, inputOffset);115      }116      // Encrypt with AES in CTR mode. Regards to Dr Brian Gladman for this. - 0117      int ix = 0; - 0118       while (ix < inputCount) { - 0119         if (_encrPos == ENCRYPT_BLOCK) {120          /* increment encryption nonce   */ - 0121          int j = 0; - 0122           while (++_counterNonce[j] == 0) { - 0123            ++j;124          }125          /* encrypt the nonce to form next xor buffer    */ - 0126          _encryptor.TransformBlock(_counterNonce, 0, _blockSize, _encryptBuffer, 0); - 0127          _encrPos = 0;128        } - 0129        outputBuffer[ix + outputOffset] = (byte)(inputBuffer[ix + inputOffset] ^ _encryptBuffer[_encrPos++]);130        // - 0131        ix++;132      } - 0133       if (_writeMode) {134        // This does not change the buffer. - 0135        _hmacsha1.TransformBlock(outputBuffer, outputOffset, inputCount, outputBuffer, outputOffset);136      } - 0137      return inputCount;138    }139140    /// <summary>141    /// Returns the 2 byte password verifier142    /// </summary>143    public byte[] PwdVerifier {144      get { - 0145        return _pwdVerifier;146      }147    }148149    /// <summary>150    /// Returns the 10 byte AUTH CODE to be checked or appended immediately following the AES data stream.151    /// </summary>152    public byte[] GetAuthCode() {153      // We usually don't get advance notice of final block. Hash requres a TransformFinal. - 0154       if (!_finalised) { - 0155        byte[] dummy = new byte[0]; - 0156        _hmacsha1.TransformFinalBlock(dummy, 0, 0); - 0157        _finalised = true;158      } - 0159      return _hmacsha1.Hash;160    }161162    #region ICryptoTransform Members163164    /// <summary>165    /// Not implemented.166    /// </summary>167    public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) {168 - 0169      throw new NotImplementedException("ZipAESTransform.TransformFinalBlock");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    }124125    #region ICryptoTransform Members126127    /// <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    }135136    /// <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    }144145    /// <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    }153154    /// <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    }162163    /// <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    /// Gets the size of the input data blocks in bytes.173    /// Cleanup internal state.  174    /// </summary>175    public int InputBlockSize {176      get { - 0177        return _blockSize;178      }179    }180181    /// <summary>182    /// Gets the size of the output data blocks in bytes.183    /// </summary>184    public int OutputBlockSize {185      get { - 0186        return _blockSize;187      }188    }189190    /// <summary>191    /// Gets a value indicating whether multiple blocks can be transformed.192    /// </summary>193    public bool CanTransformMultipleBlocks {194      get { - 0195        return true;196      }197    }198199    /// <summary>200    /// Gets a value indicating whether the current transform can be reused.201    /// </summary>202    public bool CanReuseTransform {203      get { - 0204        return true;205      }206    }207208    /// <summary>209    /// Cleanup internal state.210    /// </summary>211    public void Dispose() { - 0212      _encryptor.Dispose(); - 0213    }214215    #endregion216217  }218}219#endif175    public void Dispose()176    { + 0177      _encryptor.Dispose(); + 0178    }179180    #endregion181182  }183} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipConstants.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipConstants.htm index d0efd1e5e..7992a5341 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipConstants.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipConstants.htm @@ -18,7 +18,7 @@

Summary

Covered lines:29 Uncovered lines:8 Coverable lines:37 -Total lines:647 +Total lines:591 Line coverage:78.3% Branch coverage:63.3% @@ -42,655 +42,599 @@

#LineLine coverage - 1// ZipConstants.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.1using System;2using System.Text;3using System.Threading;45namespace ICSharpCode.SharpZipLib.Zip6{7  #region Enumerations89  /// <summary>10  /// Determines how entries are tested to see if they should use Zip64 extensions or not.11  /// </summary>12  public enum UseZip6413  {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  }2829  /// <summary>30  /// The kind of compression used for an entry in an archive31  /// </summary>32  public enum CompressionMethod33  {34    /// <summary>35    /// A direct copy of the file contents is held in the archive36    /// </summary>37    Stored = 0,  3839// HISTORY40//  22-12-2009  DavidPierson  Added AES support4142using System;43using System.Text;44using System.Threading;4546#if NETCF_1_0 || NETCF_2_047using System.Globalization;48#endif39    /// <summary>40    /// Common Zip compression method using a sliding dictionary41    /// of up to 32KB and secondary compression from Huffman/Shannon-Fano trees42    /// </summary>43    Deflated = 8,4445    /// <summary>46    /// An extension to deflate with a 64KB window. Not supported by #Zip currently47    /// </summary>48    Deflate64 = 9,  4950namespace ICSharpCode.SharpZipLib.Zip51{5253  #region Enumerations50    /// <summary>51    /// BZip2 compression. Not supported by #Zip.52    /// </summary>53    BZip2 = 11,  5455  /// <summary>56  /// Determines how entries are tested to see if they should use Zip64 extensions or not.57  /// </summary>58  public enum UseZip6459  {60    /// <summary>61    /// Zip64 will not be forced on entries during processing.62    /// </summary>63    /// <remarks>An entry can have this overridden if required <see cref="ZipEntry.ForceZip64"></see></remarks>64    Off,65    /// <summary>66    /// Zip64 should always be used.67    /// </summary>68    On,69    /// <summary>70    /// #ZipLib will determine use based on entry values when added to archive.71    /// </summary>72    Dynamic,73  }7475  /// <summary>76  /// The kind of compression used for an entry in an archive77  /// </summary>78  public enum CompressionMethod79  {80    /// <summary>81    /// A direct copy of the file contents is held in the archive82    /// </summary>83    Stored     = 0,8485    /// <summary>86    /// Common Zip compression method using a sliding dictionary87    /// of up to 32KB and secondary compression from Huffman/Shannon-Fano trees88    /// </summary>89    Deflated   = 8,9055    /// <summary>56    /// WinZip special for AES encryption, Now supported by #Zip.57    /// </summary>58    WinZipAES = 99,5960  }6162  /// <summary>63  /// Identifies the encryption algorithm used for an entry64  /// </summary>65  public enum EncryptionAlgorithm66  {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    /// An extension to deflate with a 64KB window. Not supported by #Zip currently92    /// AES 128 has been used for encryption.  93    /// </summary>94    Deflate64  = 9,9596    /// <summary>97    /// BZip2 compression. Not supported by #Zip.98    /// </summary>99    BZip2      = 11,100101    /// <summary>102    /// WinZip special for AES encryption, Now supported by #Zip.103    /// </summary>104    WinZipAES  = 99,105106  }107108  /// <summary>109  /// Identifies the encryption algorithm used for an entry110  /// </summary>111  public enum EncryptionAlgorithm112  {113    /// <summary>114    /// No encryption has been used.115    /// </summary>116    None           = 0,117    /// <summary>118    /// Encrypted using PKZIP 2.0 or 'classic' encryption.119    /// </summary>120    PkzipClassic   = 1,121    /// <summary>122    /// DES encryption has been used.123    /// </summary>124    Des            = 0x6601,125    /// <summary>126    /// RC2 encryption has been used for encryption.127    /// </summary>128    RC2            = 0x6602,129    /// <summary>130    /// Triple DES encryption with 168 bit keys has been used for this entry.131    /// </summary>132    TripleDes168   = 0x6603,133    /// <summary>134    /// Triple DES with 112 bit keys has been used for this entry.135    /// </summary>136    TripleDes112   = 0x6609,137    /// <summary>138    /// AES 128 has been used for encryption.139    /// </summary>140    Aes128         = 0x660e,141    /// <summary>142    /// AES 192 has been used for encryption.143    /// </summary>144    Aes192         = 0x660f,145    /// <summary>146    /// AES 256 has been used for encryption.147    /// </summary>148    Aes256         = 0x6610,149    /// <summary>150    /// RC2 corrected has been used for encryption.151    /// </summary>152    RC2Corrected   = 0x6702,153    /// <summary>154    /// Blowfish has been used for encryption.155    /// </summary>156    Blowfish = 0x6720,157    /// <summary>158    /// Twofish has been used for encryption.159    /// </summary>160    Twofish = 0x6721,161    /// <summary>162    /// RC4 has been used for encryption.163    /// </summary>164    RC4            = 0x6801,165    /// <summary>166    /// An unknown algorithm has been used for encryption.167    /// </summary>168    Unknown        = 0xffff169  }170171  /// <summary>172  /// Defines the contents of the general bit flags field for an archive entry.173  /// </summary>174  [Flags]175  public enum GeneralBitFlags176  {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 = 0xffff123  }124125  /// <summary>126  /// Defines the contents of the general bit flags field for an archive entry.127  /// </summary>128  [Flags]129  public enum GeneralBitFlags130  {131    /// <summary>132    /// Bit 0 if set indicates that the file is encrypted133    /// </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 data141    /// </summary>142    Descriptor = 0x0008,143    /// <summary>144    /// Bit 4 is reserved for use with method 8 for enhanced deflation145    /// </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 unused158    /// </summary>159    Unused7 = 0x0080,160    /// <summary>161    /// Bit 8 is currently unused162    /// </summary>163    Unused8 = 0x0100,164    /// <summary>165    /// Bit 9 is currently unused166    /// </summary>167    Unused9 = 0x0200,168    /// <summary>169    /// Bit 10 is currently unused170    /// </summary>171    Unused10 = 0x0400,172    /// <summary>173    /// Bit 11 if set indicates the filename and174    /// comment fields for this file must be encoded using UTF-8.175    /// </summary>176    UnicodeText = 0x0800,  177    /// <summary>178    /// Bit 0 if set indicates that the file is encrypted178    /// Bit 12 is documented as being reserved by PKware for enhanced compression.  179    /// </summary>180    Encrypted = 0x0001,180    EnhancedCompress = 0x1000,  181    /// <summary>182    /// Bits 1 and 2 - Two bits defining the compression method (only for Method 6 Imploding and 8,9 Deflating)183    /// </summary>184    Method = 0x0006,185    /// <summary>186    /// Bit 3 if set indicates a trailing data desciptor is appended to the entry data187    /// </summary>188    Descriptor = 0x0008,182    /// Bit 13 if set indicates that values in the local header are masked to hide183    /// 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 4 is reserved for use with method 8 for enhanced deflation190    /// Bit 14 is documented as being reserved for use by PKware  191    /// </summary>192    ReservedPKware4 = 0x0010,192    ReservedPkware14 = 0x4000,  193    /// <summary>194    /// Bit 5 if set indicates the file contains Pkzip compressed patched data.195    /// Requires version 2.7 or greater.196    /// </summary>197    Patched = 0x0020,198    /// <summary>199    /// Bit 6 if set indicates strong encryption has been used for this entry.200    /// </summary>201    StrongEncryption = 0x0040,202    /// <summary>203    /// Bit 7 is currently unused204    /// </summary>205    Unused7 = 0x0080,206    /// <summary>207    /// Bit 8 is currently unused208    /// </summary>209    Unused8 = 0x0100,210    /// <summary>211    /// Bit 9 is currently unused212    /// </summary>213    Unused9 = 0x0200,214    /// <summary>215    /// Bit 10 is currently unused216    /// </summary>217    Unused10 = 0x0400,218    /// <summary>219    /// Bit 11 if set indicates the filename and220    /// comment fields for this file must be encoded using UTF-8.221    /// </summary>222    UnicodeText = 0x0800,223    /// <summary>224    /// Bit 12 is documented as being reserved by PKware for enhanced compression.225    /// </summary>226    EnhancedCompress = 0x1000,227    /// <summary>228    /// Bit 13 if set indicates that values in the local header are masked to hide229    /// their actual values, and the central directory is encrypted.230    /// </summary>231    /// <remarks>232    /// Used when encrypting the central directory contents.233    /// </remarks>234    HeaderMasked = 0x2000,235    /// <summary>236    /// Bit 14 is documented as being reserved for use by PKware237    /// </summary>238    ReservedPkware14 = 0x4000,239    /// <summary>240    /// Bit 15 is documented as being reserved for use by PKware241    /// </summary>242    ReservedPkware15 = 0x8000243  }244245  #endregion246247  /// <summary>248  /// This class contains constants used for Zip format files249  /// </summary>250  public sealed class ZipConstants251  {252    #region Versions253    /// <summary>254    /// The version made by field for entries in the central header when created by this library255    /// </summary>256    /// <remarks>257    /// This is also the Zip version for the library when comparing against the version required to extract258    /// for an entry.  See <see cref="ZipEntry.CanDecompress"/>.259    /// </remarks>260    public const int VersionMadeBy = 51; // was 45 before AES261262    /// <summary>263    /// The version made by field for entries in the central header when created by this library264    /// </summary>265    /// <remarks>266    /// This is also the Zip version for the library when comparing against the version required to extract267    /// for an entry.  See <see cref="ZipInputStream.CanDecompressEntry">ZipInputStream.CanDecompressEntry</see>.268    /// </remarks>269    [Obsolete("Use VersionMadeBy instead")]270    public const int VERSION_MADE_BY = 51;271272    /// <summary>273    /// The minimum version required to support strong encryption274    /// </summary>275    public const int VersionStrongEncryption = 50;276277    /// <summary>278    /// The minimum version required to support strong encryption279    /// </summary>280    [Obsolete("Use VersionStrongEncryption instead")]281    public const int VERSION_STRONG_ENCRYPTION = 50;282283    /// <summary>284    /// Version indicating AES encryption285    /// </summary>286    public const int VERSION_AES = 51;287288    /// <summary>289    /// The version required for Zip64 extensions (4.5 or higher)290    /// </summary>291    public const int VersionZip64 = 45;292    #endregion293294    #region Header Sizes295    /// <summary>296    /// Size of local entry header (excluding variable length fields at end)297    /// </summary>298    public const int LocalHeaderBaseSize = 30;299300    /// <summary>301    /// Size of local entry header (excluding variable length fields at end)302    /// </summary>303    [Obsolete("Use LocalHeaderBaseSize instead")]304    public const int LOCHDR = 30;305306    /// <summary>307    /// Size of Zip64 data descriptor308    /// </summary>309    public const int Zip64DataDescriptorSize = 24;310311    /// <summary>312    /// Size of data descriptor313    /// </summary>314    public const int DataDescriptorSize = 16;315316    /// <summary>317    /// Size of data descriptor318    /// </summary>319    [Obsolete("Use DataDescriptorSize instead")]320    public const int EXTHDR = 16;321322    /// <summary>323    /// Size of central header entry (excluding variable fields)324    /// </summary>325    public const int CentralHeaderBaseSize = 46;326327    /// <summary>328    /// Size of central header entry329    /// </summary>330    [Obsolete("Use CentralHeaderBaseSize instead")]331    public const int CENHDR = 46;332333    /// <summary>334    /// Size of end of central record (excluding variable fields)335    /// </summary>336    public const int EndOfCentralRecordBaseSize = 22;337338    /// <summary>339    /// Size of end of central record (excluding variable fields)340    /// </summary>341    [Obsolete("Use EndOfCentralRecordBaseSize instead")]342    public const int ENDHDR = 22;343344    /// <summary>345    /// Size of 'classic' cryptographic header stored before any entry data346    /// </summary>347    public const int CryptoHeaderSize = 12;348349    /// <summary>350    /// Size of cryptographic header stored before entry data351    /// </summary>352    [Obsolete("Use CryptoHeaderSize instead")]353    public const int CRYPTO_HEADER_SIZE = 12;354    #endregion194    /// Bit 15 is documented as being reserved for use by PKware195    /// </summary>196    ReservedPkware15 = 0x8000197  }198199  #endregion200201  /// <summary>202  /// This class contains constants used for Zip format files203  /// </summary>204  public sealed class ZipConstants205  {206    #region Versions207    /// <summary>208    /// The version made by field for entries in the central header when created by this library209    /// </summary>210    /// <remarks>211    /// This is also the Zip version for the library when comparing against the version required to extract212    /// for an entry.  See <see cref="ZipEntry.CanDecompress"/>.213    /// </remarks>214    public const int VersionMadeBy = 51; // was 45 before AES215216    /// <summary>217    /// The version made by field for entries in the central header when created by this library218    /// </summary>219    /// <remarks>220    /// This is also the Zip version for the library when comparing against the version required to extract221    /// 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;225226    /// <summary>227    /// The minimum version required to support strong encryption228    /// </summary>229    public const int VersionStrongEncryption = 50;230231    /// <summary>232    /// The minimum version required to support strong encryption233    /// </summary>234    [Obsolete("Use VersionStrongEncryption instead")]235    public const int VERSION_STRONG_ENCRYPTION = 50;236237    /// <summary>238    /// Version indicating AES encryption239    /// </summary>240    public const int VERSION_AES = 51;241242    /// <summary>243    /// The version required for Zip64 extensions (4.5 or higher)244    /// </summary>245    public const int VersionZip64 = 45;246    #endregion247248    #region Header Sizes249    /// <summary>250    /// Size of local entry header (excluding variable length fields at end)251    /// </summary>252    public const int LocalHeaderBaseSize = 30;253254    /// <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;259260    /// <summary>261    /// Size of Zip64 data descriptor262    /// </summary>263    public const int Zip64DataDescriptorSize = 24;264265    /// <summary>266    /// Size of data descriptor267    /// </summary>268    public const int DataDescriptorSize = 16;269270    /// <summary>271    /// Size of data descriptor272    /// </summary>273    [Obsolete("Use DataDescriptorSize instead")]274    public const int EXTHDR = 16;275276    /// <summary>277    /// Size of central header entry (excluding variable fields)278    /// </summary>279    public const int CentralHeaderBaseSize = 46;280281    /// <summary>282    /// Size of central header entry283    /// </summary>284    [Obsolete("Use CentralHeaderBaseSize instead")]285    public const int CENHDR = 46;286287    /// <summary>288    /// Size of end of central record (excluding variable fields)289    /// </summary>290    public const int EndOfCentralRecordBaseSize = 22;291292    /// <summary>293    /// Size of end of central record (excluding variable fields)294    /// </summary>295    [Obsolete("Use EndOfCentralRecordBaseSize instead")]296    public const int ENDHDR = 22;297298    /// <summary>299    /// Size of 'classic' cryptographic header stored before any entry data300    /// </summary>301    public const int CryptoHeaderSize = 12;302303    /// <summary>304    /// Size of cryptographic header stored before entry data305    /// </summary>306    [Obsolete("Use CryptoHeaderSize instead")]307    public const int CRYPTO_HEADER_SIZE = 12;308    #endregion309310    #region Header Signatures311312    /// <summary>313    /// Signature for local entry header314    /// </summary>315    public const int LocalHeaderSignature = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);316317    /// <summary>318    /// Signature for local entry header319    /// </summary>320    [Obsolete("Use LocalHeaderSignature instead")]321    public const int LOCSIG = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);322323    /// <summary>324    /// Signature for spanning entry325    /// </summary>326    public const int SpanningSignature = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);327328    /// <summary>329    /// Signature for spanning entry330    /// </summary>331    [Obsolete("Use SpanningSignature instead")]332    public const int SPANNINGSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);333334    /// <summary>335    /// Signature for temporary spanning entry336    /// </summary>337    public const int SpanningTempSignature = 'P' | ('K' << 8) | ('0' << 16) | ('0' << 24);338339    /// <summary>340    /// Signature for temporary spanning entry341    /// </summary>342    [Obsolete("Use SpanningTempSignature instead")]343    public const int SPANTEMPSIG = 'P' | ('K' << 8) | ('0' << 16) | ('0' << 24);344345    /// <summary>346    /// Signature for data descriptor347    /// </summary>348    /// <remarks>349    /// This is only used where the length, Crc, or compressed size isnt known when the350    /// entry is created and the output stream doesnt support seeking.351    /// The local entry cannot be 'patched' with the correct values in this case352    /// 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);  355356    #region Header Signatures357358    /// <summary>359    /// Signature for local entry header360    /// </summary>361    public const int LocalHeaderSignature = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);362363    /// <summary>364    /// Signature for local entry header365    /// </summary>366    [Obsolete("Use LocalHeaderSignature instead")]367    public const int LOCSIG = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);368369    /// <summary>370    /// Signature for spanning entry371    /// </summary>372    public const int SpanningSignature = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);356    /// <summary>357    /// Signature for data descriptor358    /// </summary>359    /// <remarks>360    /// This is only used where the length, Crc, or compressed size isnt known when the361    /// entry is created and the output stream doesnt support seeking.362    /// The local entry cannot be 'patched' with the correct values in this case363    /// 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);367368    /// <summary>369    /// Signature for central header370    /// </summary>371    [Obsolete("Use CentralHeaderSignature instead")]372    public const int CENSIG = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);  373  374    /// <summary>375    /// Signature for spanning entry375    /// Signature for central header  376    /// </summary>377    [Obsolete("Use SpanningSignature instead")]378    public const int SPANNINGSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);379380    /// <summary>381    /// Signature for temporary spanning entry382    /// </summary>383    public const int SpanningTempSignature = 'P' | ('K' << 8) | ('0' << 16) | ('0' << 24);384385    /// <summary>386    /// Signature for temporary spanning entry387    /// </summary>388    [Obsolete("Use SpanningTempSignature instead")]389    public const int SPANTEMPSIG = 'P' | ('K' << 8) | ('0' << 16) | ('0' << 24);390391    /// <summary>392    /// Signature for data descriptor393    /// </summary>394    /// <remarks>395    /// This is only used where the length, Crc, or compressed size isnt known when the396    /// entry is created and the output stream doesnt support seeking.397    /// The local entry cannot be 'patched' with the correct values in this case398    /// so the values are recorded after the data prefixed by this header, as well as in the central directory.399    /// </remarks>400    public const int DataDescriptorSignature = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);401402    /// <summary>403    /// Signature for data descriptor404    /// </summary>405    /// <remarks>406    /// This is only used where the length, Crc, or compressed size isnt known when the407    /// entry is created and the output stream doesnt support seeking.408    /// The local entry cannot be 'patched' with the correct values in this case409    /// so the values are recorded after the data prefixed by this header, as well as in the central directory.410    /// </remarks>411    [Obsolete("Use DataDescriptorSignature instead")]412    public const int EXTSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);413414    /// <summary>415    /// Signature for central header416    /// </summary>417    [Obsolete("Use CentralHeaderSignature instead")]418    public const int CENSIG = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);419420    /// <summary>421    /// Signature for central header422    /// </summary>423    public const int CentralHeaderSignature = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);424425    /// <summary>426    /// Signature for Zip64 central file header427    /// </summary>428    public const int Zip64CentralFileHeaderSignature = 'P' | ('K' << 8) | (6 << 16) | (6 << 24);429430    /// <summary>431    /// Signature for Zip64 central file header432    /// </summary>433    [Obsolete("Use Zip64CentralFileHeaderSignature instead")]434    public const int CENSIG64 = 'P' | ('K' << 8) | (6 << 16) | (6 << 24);377    public const int CentralHeaderSignature = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);378379    /// <summary>380    /// Signature for Zip64 central file header381    /// </summary>382    public const int Zip64CentralFileHeaderSignature = 'P' | ('K' << 8) | (6 << 16) | (6 << 24);383384    /// <summary>385    /// Signature for Zip64 central file header386    /// </summary>387    [Obsolete("Use Zip64CentralFileHeaderSignature instead")]388    public const int CENSIG64 = 'P' | ('K' << 8) | (6 << 16) | (6 << 24);389390    /// <summary>391    /// Signature for Zip64 central directory locator392    /// </summary>393    public const int Zip64CentralDirLocatorSignature = 'P' | ('K' << 8) | (6 << 16) | (7 << 24);394395    /// <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);399400    /// <summary>401    /// Central header digitial signature402    /// </summary>403    public const int CentralHeaderDigitalSignature = 'P' | ('K' << 8) | (5 << 16) | (5 << 24);404405    /// <summary>406    /// Central header digitial signature407    /// </summary>408    [Obsolete("Use CentralHeaderDigitalSignaure instead")]409    public const int CENDIGITALSIG = 'P' | ('K' << 8) | (5 << 16) | (5 << 24);410411    /// <summary>412    /// End of central directory record signature413    /// </summary>414    public const int EndOfCentralDirectorySignature = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);415416    /// <summary>417    /// End of central directory record signature418    /// </summary>419    [Obsolete("Use EndOfCentralDirectorySignature instead")]420    public const int ENDSIG = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);421    #endregion422423    /// <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 installat429    /// </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    /// Signature for Zip64 central directory locator438    /// </summary>439    public const int Zip64CentralDirLocatorSignature = 'P' | ('K' << 8) | (6 << 16) | (7 << 24);440441    /// <summary>442    /// Signature for archive extra data signature (were headers are encrypted).443    /// </summary>444    public const int ArchiveExtraDataSignature = 'P' | ('K' << 8) | (6 << 16) | (7 << 24);445446    /// <summary>447    /// Central header digitial signature448    /// </summary>449    public const int CentralHeaderDigitalSignature = 'P' | ('K' << 8) | (5 << 16) | (5 << 24);450451    /// <summary>452    /// Central header digitial signature453    /// </summary>454    [Obsolete("Use CentralHeaderDigitalSignaure instead")]455    public const int CENDIGITALSIG = 'P' | ('K' << 8) | (5 << 16) | (5 << 24);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 neccessarily440    /// there are many variable factors, codepage 850 is often a good choice for441    /// 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    /// End of central directory record signature458    /// Convert a portion of a byte array to a string.  459    /// </summary>460    public const int EndOfCentralDirectorySignature = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);461462    /// <summary>463    /// End of central directory record signature464    /// </summary>465    [Obsolete("Use EndOfCentralDirectorySignature instead")]466    public const int ENDSIG = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);467    #endregion468469#if NETCF_1_0 || NETCF_2_0470    // This isnt so great but is better than nothing.471        // Trying to work out an appropriate OEM code page would be good.472        // 850 is a good default for english speakers particularly in Europe.473    static int defaultCodePage = CultureInfo.CurrentCulture.TextInfo.ANSICodePage;474#else475      /// <remarks>476      /// Get OEM codepage from NetFX, which parses the NLP file with culture info table etc etc.477      /// But sometimes it yields the special value of 1 which is nicknamed <c>CodePageNoOEM</c> in <see cref="Encoding"478      /// This was observed on Ukranian and Hindu systems.479      /// Given this value, <see cref="Encoding.GetEncoding(int)"/> throws an <see cref="ArgumentException"/>.480      /// So replace it with some fallback, e.g. 437 which is the default cpcp in a console in a default Windows install481      /// </remarks> - 1482      static int defaultCodePage = - 1483            // these values cause ArgumentException in subsequent calls to Encoding::GetEncoding() - 1484            ((Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage == 1) || (Thread.CurrentThread.CurrentCulture.Tex - 1485            ? 437 // The default OEM encoding in a console in a default Windows installation, as a fallback. - 1486          : Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage;487#endif488489    /// <summary>490    /// Default encoding used for string conversion.  0 gives the default system OEM code page.491    /// Dont use unicode encodings if you want to be Zip compatible!492    /// Using the default code page isnt the full solution neccessarily493    /// there are many variable factors, codepage 850 is often a good choice for494    /// European users, however be careful about compatability.495    /// </summary>496    public static int DefaultCodePage {497      get { - 263846498        return defaultCodePage;499      }500      set { - 1501                 if ((value < 0) || (value > 65535) || - 1502                    (value == 1) || (value == 2) || (value == 3) || (value == 42)) { - 0503                    throw new ArgumentOutOfRangeException(nameof(value));504                }505 - 1506                defaultCodePage = value; - 1507      }508    }509510      /// <summary>511    /// Convert a portion of a byte array to a string.512    /// </summary>513    /// <param name="data">514    /// Data to convert to string515    /// </param>516    /// <param name="count">517    /// Number of bytes to convert starting from index 0518    /// </param>519    /// <returns>520    /// data[0]..data[count - 1] converted to a string521    /// </returns>522    public static string ConvertToString(byte[] data, int count)523    { - 131960524       if ( data == null ) { - 0525        return string.Empty;526      }527 - 131960528      return Encoding.GetEncoding(DefaultCodePage).GetString(data, 0, count);529    }530531    /// <summary>532    /// Convert a byte array to string533    /// </summary>534    /// <param name="data">535    /// Byte array to convert536    /// </param>537    /// <returns>538    /// <paramref name="data">data</paramref>converted to a string539    /// </returns>540    public static string ConvertToString(byte[] data)541    { - 12542       if ( data == null ) { - 0543        return string.Empty;544      } - 12545      return ConvertToString(data, data.Length);546    }547548    /// <summary>549    /// Convert a byte array to string550    /// </summary>551    /// <param name="flags">The applicable general purpose bits flags</param>552    /// <param name="data">553    /// Byte array to convert554    /// </param>555    /// <param name="count">The number of bytes to convert.</param>556    /// <returns>557    /// <paramref name="data">data</paramref>converted to a string558    /// </returns>559    public static string ConvertToStringExt(int flags, byte[] data, int count)560    { - 65956561       if ( data == null ) { - 0562        return string.Empty;563      }564 - 65956565       if ( (flags & (int)GeneralBitFlags.UnicodeText) != 0 ) { - 5566        return Encoding.UTF8.GetString(data, 0, count);567      }568      else { - 65951569        return ConvertToString(data, count);460    /// <param name="data">461    /// Data to convert to string462    /// </param>463    /// <param name="count">464    /// Number of bytes to convert starting from index 0465    /// </param>466    /// <returns>467    /// data[0]..data[count - 1] converted to a string468    /// </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    }477478    /// <summary>479    /// Convert a byte array to string480    /// </summary>481    /// <param name="data">482    /// Byte array to convert483    /// </param>484    /// <returns>485    /// <paramref name="data">data</paramref>converted to a string486    /// </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    }494495    /// <summary>496    /// Convert a byte array to string497    /// </summary>498    /// <param name="flags">The applicable general purpose bits flags</param>499    /// <param name="data">500    /// Byte array to convert501    /// </param>502    /// <param name="count">The number of bytes to convert.</param>503    /// <returns>504    /// <paramref name="data">data</paramref>converted to a string505    /// </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    }518519    /// <summary>520    /// Convert a byte array to string521    /// </summary>522    /// <param name="data">523    /// Byte array to convert524    /// </param>525    /// <param name="flags">The applicable general purpose bits flags</param>526    /// <returns>527    /// <paramref name="data">data</paramref>converted to a string528    /// </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    }541542    /// <summary>543    /// Convert a string to a byte array544    /// </summary>545    /// <param name="str">546    /// String to convert to an array547    /// </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    }557558    /// <summary>559    /// Convert a string to a byte array560    /// </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 array564    /// </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    }572573    /// <summary>574    /// Convert a byte array to string575    /// </summary>576    /// <param name="data">577    /// Byte array to convert578    /// </param>579    /// <param name="flags">The applicable general purpose bits flags</param>580    /// <returns>581    /// <paramref name="data">data</paramref>converted to a string582    /// </returns>583    public static string ConvertToStringExt(int flags, byte[] data)584    { - 66004585       if ( data == null ) { - 0586        return string.Empty;587      }588 - 66004589       if ( (flags & (int)GeneralBitFlags.UnicodeText) != 0 ) { - 7590        return Encoding.UTF8.GetString(data, 0, data.Length);591      }592      else { - 65997593        return ConvertToString(data, data.Length);594      }595    }596597    /// <summary>598    /// Convert a string to a byte array599    /// </summary>600    /// <param name="str">601    /// String to convert to an array602    /// </param>603    /// <returns>Converted array</returns>604    public static byte[] ConvertToArray(string str)605    { - 131903606       if ( str == null ) { - 17607        return new byte[0];608      }609 - 131886610      return Encoding.GetEncoding(DefaultCodePage).GetBytes(str);611    }612613    /// <summary>614    /// Convert a string to a byte array615    /// </summary>616        /// <param name="flags">The applicable <see cref="GeneralBitFlags">general purpose bits flags</see></param>617    /// <param name="str">618    /// String to convert to an array619    /// </param>620    /// <returns>Converted array</returns>621    public static byte[] ConvertToArray(int flags, string str)622    { - 131783623       if (str == null) { - 0624        return new byte[0];625      }626 - 131783627       if ((flags & (int)GeneralBitFlags.UnicodeText) != 0) { - 12628        return Encoding.UTF8.GetBytes(str);629      }630      else { - 131771631        return ConvertToArray(str);632      }633    }634635636    /// <summary>637    /// Initialise default instance of <see cref="ZipConstants">ZipConstants</see>638    /// </summary>639    /// <remarks>640    /// Private to prevent instances being created.641    /// </remarks> - 0642    ZipConstants()643    {644      // Do nothing - 0645    }646  }647}571 + 131777572       if ((flags & (int)GeneralBitFlags.UnicodeText) != 0) { + 12573        return Encoding.UTF8.GetBytes(str);574      } else { + 131765575        return ConvertToArray(str);576      }577    }578579580    /// <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/Documentation/opencover/ICSharpCode.SharpZipLib_ZipEntry.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipEntry.htm index 9e686d517..8e988a284 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipEntry.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipEntry.htm @@ -15,12 +15,12 @@

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:234 +Covered lines:219 Uncovered lines:69 -Coverable lines:303 -Total lines:1251 -Line coverage:77.2% -Branch coverage:62.4% +Coverable lines:288 +Total lines:1175 +Line coverage:76% +Branch coverage:59.5%

Metrics

@@ -30,17 +30,18 @@

Metrics

.ctor(...)1100100 .ctor(...)1100100 .ctor(...)587.577.78 -.ctor(...)39660 +.ctor(...)396.1560 HasDosAttributes(...)4100100 ForceZip64()1100100 IsZip64Forced()1100100 -ProcessExtraData(...)2148.7256.10 +ProcessExtraData(...)1172.2266.67 +GetDateTime(...)59033.33 ProcessAESExtraData(...)300 IsCompressionMethodSupported()1100100 Clone()2100100 ToString()100 IsCompressionMethodSupported(...)2100100 -CleanName(...)587.577.78 +CleanName(...)562.555.56

File(s)

@@ -48,1259 +49,1183 @@

#LineLine coverage - 1// ZipEntry.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  2009-12-22  Z-1649  Added AES support41//  2010-02-02  DavidP  Changed NTFS Extra Data min length to 442//  2012-06-03  Z-1744  Use only the low order byte of "Version Needed to Extract"43//  2012-07-18  Z-1676  Translate to forward slashes and remove drive from name in constructor4445using System;46using System.IO;4748namespace ICSharpCode.SharpZipLib.Zip49{5051  /// <summary>52  /// Defines known values for the <see cref="HostSystemID"/> property.53  /// </summary>54  public enum HostSystemID55  {56    /// <summary>57    /// Host system = MSDOS58    /// </summary>59    Msdos = 0,60    /// <summary>61    /// Host system = Amiga62    /// </summary>63    Amiga = 1,64    /// <summary>65    /// Host system = Open VMS66    /// </summary>67    OpenVms = 2,68    /// <summary>69    /// Host system = Unix70    /// </summary>71    Unix = 3,72    /// <summary>73    /// Host system = VMCms74    /// </summary>75    VMCms = 4,76    /// <summary>77    /// Host system = Atari ST78    /// </summary>79    AtariST = 5,80    /// <summary>81    /// Host system = OS282    /// </summary>83    OS2 = 6,84    /// <summary>85    /// Host system = Macintosh86    /// </summary>87    Macintosh = 7,88    /// <summary>89    /// Host system = ZSystem90    /// </summary>91    ZSystem = 8,92    /// <summary>93    /// Host system = Cpm94    /// </summary>95    Cpm = 9,96    /// <summary>97    /// Host system = Windows NT98    /// </summary>99    WindowsNT = 10,100    /// <summary>101    /// Host system = MVS102    /// </summary>103    MVS = 11,104    /// <summary>105    /// Host system = VSE106    /// </summary>107    Vse = 12,108    /// <summary>109    /// Host system = Acorn RISC110    /// </summary>111    AcornRisc = 13,112    /// <summary>113    /// Host system = VFAT114    /// </summary>115    Vfat = 14,116    /// <summary>117    /// Host system = Alternate MVS118    /// </summary>119    AlternateMvs = 15,1using System;2using System.IO;34namespace ICSharpCode.SharpZipLib.Zip5{6  /// <summary>7  /// Defines known values for the <see cref="HostSystemID"/> property.8  /// </summary>9  public enum HostSystemID10  {11    /// <summary>12    /// Host system = MSDOS13    /// </summary>14    Msdos = 0,15    /// <summary>16    /// Host system = Amiga17    /// </summary>18    Amiga = 1,19    /// <summary>20    /// Host system = Open VMS21    /// </summary>22    OpenVms = 2,23    /// <summary>24    /// Host system = Unix25    /// </summary>26    Unix = 3,27    /// <summary>28    /// Host system = VMCms29    /// </summary>30    VMCms = 4,31    /// <summary>32    /// Host system = Atari ST33    /// </summary>34    AtariST = 5,35    /// <summary>36    /// Host system = OS237    /// </summary>38    OS2 = 6,39    /// <summary>40    /// Host system = Macintosh41    /// </summary>42    Macintosh = 7,43    /// <summary>44    /// Host system = ZSystem45    /// </summary>46    ZSystem = 8,47    /// <summary>48    /// Host system = Cpm49    /// </summary>50    Cpm = 9,51    /// <summary>52    /// Host system = Windows NT53    /// </summary>54    WindowsNT = 10,55    /// <summary>56    /// Host system = MVS57    /// </summary>58    MVS = 11,59    /// <summary>60    /// Host system = VSE61    /// </summary>62    Vse = 12,63    /// <summary>64    /// Host system = Acorn RISC65    /// </summary>66    AcornRisc = 13,67    /// <summary>68    /// Host system = VFAT69    /// </summary>70    Vfat = 14,71    /// <summary>72    /// Host system = Alternate MVS73    /// </summary>74    AlternateMvs = 15,75    /// <summary>76    /// Host system = BEOS77    /// </summary>78    BeOS = 16,79    /// <summary>80    /// Host system = Tandem81    /// </summary>82    Tandem = 17,83    /// <summary>84    /// Host system = OS40085    /// </summary>86    OS400 = 18,87    /// <summary>88    /// Host system = OSX89    /// </summary>90    OSX = 19,91    /// <summary>92    /// Host system = WinZIP AES93    /// </summary>94    WinZipAES = 99,95  }9697  /// <summary>98  /// This class represents an entry in a zip archive.  This can be a file99  /// or a directory100  /// ZipFile and ZipInputStream will give you instances of this class as101  /// information about the members in an archive.  ZipOutputStream102  /// 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 Hoenicke105  /// </summary>106  public class ZipEntry : ICloneable107  {108    [Flags]109    enum Known : byte110    {111      None = 0,112      Size = 0x01,113      CompressedSize = 0x02,114      Crc = 0x04,115      Time = 0x08,116      ExternalAttributes = 0x10,117    }118119    #region Constructors  120    /// <summary>121    /// Host system = BEOS121    /// Creates a zip entry with the given name.  122    /// </summary>123    BeOS = 16,124    /// <summary>125    /// Host system = Tandem126    /// </summary>127    Tandem = 17,128    /// <summary>129    /// Host system = OS400130    /// </summary>131    OS400 = 18,132    /// <summary>133    /// Host system = OSX134    /// </summary>135    OSX = 19,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 null130    /// </exception>131    public ZipEntry(string name) + 65841132      : this(name, 0, ZipConstants.VersionMadeBy, CompressionMethod.Deflated)133    { + 65840134    }135  136    /// <summary>137    /// Host system = WinZIP AES137    /// Creates a zip entry with the given name and version required to extract  138    /// </summary>139    WinZipAES = 99,140  }141142  /// <summary>143  /// This class represents an entry in a zip archive.  This can be a file144  /// or a directory145  /// ZipFile and ZipInputStream will give you instances of this class as146  /// information about the members in an archive.  ZipOutputStream147  /// uses an instance of this class when creating an entry in a Zip file.148  /// <br/>149  /// <br/>Author of the original java version : Jochen Hoenicke150  /// </summary>151  public class ZipEntry : ICloneable152  {153    [Flags]154    enum Known : byte155    {156      None = 0,157      Size = 0x01,158      CompressedSize = 0x02,159      Crc = 0x04,160      Time = 0x08,161      ExternalAttributes = 0x10,162    }163164    #region Constructors165    /// <summary>166    /// Creates a zip entry with the given name.167    /// </summary>168    /// <param name="name">169    /// The name for this entry. Can include directory components.170    /// The convention for names is 'unix' style paths with relative names only.171    /// There are with no device names and path elements are separated by '/' characters.172    /// </param>173    /// <exception cref="ArgumentNullException">174    /// The name passed is null175    /// </exception>176    public ZipEntry(string name) - 65855177      : this(name, 0, ZipConstants.VersionMadeBy, CompressionMethod.Deflated)178    { - 65854179    }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 and142    /// path elements separated by '/' characters.  This is not enforced see <see cref="CleanName(string)">CleanName</se143    /// on how to ensure names are valid if this is desired.144    /// </param>145    /// <param name="versionRequiredToExtract">146    /// The minimum 'feature version' required this entry147    /// </param>148    /// <exception cref="ArgumentNullException">149    /// The name passed is null150    /// </exception>151    internal ZipEntry(string name, int versionRequiredToExtract) + 81152      : this(name, versionRequiredToExtract, ZipConstants.VersionMadeBy, + 81153      CompressionMethod.Deflated)154    { + 81155    }156157    /// <summary>158    /// Initializes an entry with the given name and made by information159    /// </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</para163    /// <param name="method">Compression method for this entry.</param>164    /// <exception cref="ArgumentNullException">165    /// The name passed is null166    /// </exception>167    /// <exception cref="ArgumentOutOfRangeException">168    /// versionRequiredToExtract should be 0 (auto-calculate) or > 10169    /// </exception>170    /// <remarks>171    /// This constructor is used by the ZipFile class when reading from the central header172    /// 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      }  180181    /// <summary>182    /// Creates a zip entry with the given name and version required to extract183    /// </summary>184    /// <param name="name">185    /// The name for this entry. Can include directory components.186    /// The convention for names is 'unix'  style paths with no device names and187    /// path elements separated by '/' characters.  This is not enforced see <see cref="CleanName(string)">CleanName</se188    /// on how to ensure names are valid if this is desired.189    /// </param>190    /// <param name="versionRequiredToExtract">191    /// The minimum 'feature version' required this entry192    /// </param>193    /// <exception cref="ArgumentNullException">194    /// The name passed is null195    /// </exception>196    internal ZipEntry(string name, int versionRequiredToExtract) - 85197      : this(name, versionRequiredToExtract, ZipConstants.VersionMadeBy, - 85198      CompressionMethod.Deflated)199    { - 85200    }201202    /// <summary>203    /// Initializes an entry with the given name and made by information204    /// </summary>205    /// <param name="name">Name for this entry</param>206    /// <param name="madeByInfo">Version and HostSystem Information</param>207    /// <param name="versionRequiredToExtract">Minimum required zip feature version required to extract this entry</para208    /// <param name="method">Compression method for this entry.</param>209    /// <exception cref="ArgumentNullException">210    /// The name passed is null211    /// </exception>212    /// <exception cref="ArgumentOutOfRangeException">213    /// versionRequiredToExtract should be 0 (auto-calculate) or > 10214    /// </exception>215    /// <remarks>216    /// This constructor is used by the ZipFile class when reading from the central header217    /// It is not generally useful, use the constructor specifying the name only.218    /// </remarks> - 131896219    internal ZipEntry(string name, int versionRequiredToExtract, int madeByInfo, - 131896220      CompressionMethod method)221    { - 131896222       if (name == null) { - 1223        throw new ArgumentNullException(nameof(name));224      } + 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    }195196    /// <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 - 131895226       if ( name.Length > 0xffff )  { - 0227        throw new ArgumentException("Name is too long", nameof(name));228      }229 - 131895230       if ( (versionRequiredToExtract != 0) && (versionRequiredToExtract < 10) ) { - 0231        throw new ArgumentOutOfRangeException(nameof(versionRequiredToExtract));232      } + 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 - 131895234      this.DateTime = DateTime.Now; - 131895235      this.name = CleanName(name); - 131895236      this.versionMadeBy = (ushort)madeByInfo; - 131895237      this.versionToExtract = (ushort)versionRequiredToExtract; - 131895238      this.method = method; - 131895239    }240241    /// <summary>242    /// Creates a deep copy of the given zip entry.243    /// </summary>244    /// <param name="entry">245    /// The entry to copy.246    /// </param>247    [Obsolete("Use Clone instead")] - 1248    public ZipEntry(ZipEntry entry)249    { - 1250       if ( entry == null ) { - 0251        throw new ArgumentNullException(nameof(entry));252      }253 - 1254      known                  = entry.known; - 1255      name                   = entry.name; - 1256      size                   = entry.size; - 1257      compressedSize         = entry.compressedSize; - 1258      crc                    = entry.crc; - 1259      dosTime                = entry.dosTime; - 1260      method                 = entry.method; - 1261      comment                = entry.comment; - 1262      versionToExtract       = entry.versionToExtract; - 1263      versionMadeBy          = entry.versionMadeBy; - 1264      externalFileAttributes = entry.externalFileAttributes; - 1265      flags                  = entry.flags;266 - 1267      zipFileIndex           = entry.zipFileIndex; - 1268      offset                 = entry.offset;269 - 1270      forceZip64_         = entry.forceZip64_;271 - 1272       if ( entry.extra != null ) { - 1273        extra = new byte[entry.extra.Length]; - 1274        Array.Copy(entry.extra, 0, extra, 0, entry.extra.Length);275      } - 1276    }277278    #endregion279280    /// <summary>281    /// Get a value indicating wether the entry has a CRC value available.282    /// </summary>283    public bool HasCrc284    {234    #endregion235236    /// <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    }244245    /// <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    }262263    /// <summary>264    /// Get / set a flag indicating wether entry name and comment text are265    /// 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    }280281    /// <summary>282    /// Value used during password checking for PKZIP 2.0 / 'classic' encryption.283    /// </summary>284    internal byte CryptoCheckValue {  285      get { - 65754286        return (known & Known.Crc) != 0; + 34286        return cryptoCheckValue_;  287      }288    }289290    /// <summary>291    /// Get/Set flag indicating if entry is encrypted.292    /// A simple helper routine to aid interpretation of <see cref="Flags">flags</see>293    /// </summary>294    /// <remarks>This is an assistant that interprets the <see cref="Flags">flags</see> property.</remarks>295    public bool IsCrypted296    {297      get { - 592011298        return (flags & 1) != 0;299      }300      set { - 65741301         if (value) { - 41302          flags |= 1; - 41303        }304        else { - 65700305          flags &= ~1;306        } - 65700307      }308    }309310    /// <summary>311    /// Get / set a flag indicating wether entry name and comment text are312    /// encoded in <a href="http://www.unicode.org">unicode UTF8</a>.313    /// </summary>314    /// <remarks>This is an assistant that interprets the <see cref="Flags">flags</see> property.</remarks>315    public bool IsUnicodeText316    {317      get { - 4318        return ( flags & (int)GeneralBitFlags.UnicodeText ) != 0;319      }320      set { - 186321         if ( value ) { - 8322          flags |= (int)GeneralBitFlags.UnicodeText; - 8323        }324        else { - 178325          flags &= ~(int)GeneralBitFlags.UnicodeText;326        } - 178327      }328    }329330    /// <summary>331    /// Value used during password checking for PKZIP 2.0 / 'classic' encryption.332    /// </summary>333    internal byte CryptoCheckValue334    {335      get { - 37336        return cryptoCheckValue_;337      }338339      set  { - 66041340        cryptoCheckValue_ = value; - 66041341      }342    }343344    /// <summary>345    /// Get/Set general purpose bit flag for entry346    /// </summary>347    /// <remarks>348    /// General purpose bit flag<br/>349    /// <br/>350    /// Bit 0: If set, indicates the file is encrypted<br/>351    /// Bit 1-2 Only used for compression type 6 Imploding, and 8, 9 deflating<br/>352    /// Imploding:<br/>353    /// Bit 1 if set indicates an 8K sliding dictionary was used.  If clear a 4k dictionary was used<br/>354    /// Bit 2 if set indicates 3 Shannon-Fanno trees were used to encode the sliding dictionary, 2 otherwise<br/>355    /// <br/>356    /// Deflating:<br/>357    ///   Bit 2    Bit 1<br/>358    ///     0        0       Normal compression was used<br/>359    ///     0        1       Maximum compression was used<br/>360    ///     1        0       Fast compression was used<br/>361    ///     1        1       Super fast compression was used<br/>362    /// <br/>363    /// Bit 3: If set, the fields crc-32, compressed size364    /// and uncompressed size are were not able to be written during zip file creation365    /// The correct values are held in a data descriptor immediately following the compressed data. <br/>366    /// Bit 4: Reserved for use by PKZIP for enhanced deflating<br/>367    /// Bit 5: If set indicates the file contains compressed patch data<br/>368    /// Bit 6: If set indicates strong encryption was used.<br/>369    /// Bit 7-10: Unused or reserved<br/>370    /// Bit 11: If set the name and comments for this entry are in <a href="http://www.unicode.org">unicode</a>.<br/>371    /// Bit 12-15: Unused or reserved<br/>372    /// </remarks>373    /// <seealso cref="IsUnicodeText"></seealso>374    /// <seealso cref="IsCrypted"></seealso>375    public int Flags376    {377      get { - 396016378        return flags;379      }380      set { - 66260381        flags = value; - 66260382      }383    }384385    /// <summary>386    /// Get/Set index of this entry in Zip file387    /// </summary>388    /// <remarks>This is only valid when the entry is part of a <see cref="ZipFile"></see></remarks>389    public long ZipFileIndex390    {391      get { - 65933392        return zipFileIndex;393      }394      set { - 65956395        zipFileIndex = value; - 65956396      }397    }398399    /// <summary>400    /// Get/set offset for use in central header401    /// </summary>402    public long Offset403    {404      get { - 396702405        return offset;406      }407      set { - 131836408        offset = value; - 131836409      }410    }411412    /// <summary>413    /// Get/Set external file attributes as an integer.414    /// The values of this are operating system dependant see415    /// <see cref="HostSystem">HostSystem</see> for details416    /// </summary>417    public int ExternalFileAttributes418    {419      get { - 527444420         if ((known & Known.ExternalAttributes) == 0) { - 65827421          return -1;422        }423        else { - 461617424          return externalFileAttributes;425        }426      }427428      set { - 65974429        externalFileAttributes = value; - 65974430        known |= Known.ExternalAttributes; - 65974431      }432    }433434    /// <summary>435    /// Get the version made by for this entry or zero if unknown.436    /// The value / 10 indicates the major version number, and437    /// the value mod 10 is the minor version number438    /// </summary>439    public int VersionMadeBy440    {441      get { - 0442        return (versionMadeBy & 0xff);443      }444    }445446    /// <summary>447    /// Get a value indicating this entry is for a DOS/Windows system.448    /// </summary>449    public bool IsDOSEntry450    {451      get { - 2452        return ((HostSystem == ( int )HostSystemID.Msdos) || - 2453          (HostSystem == ( int )HostSystemID.WindowsNT));454      }455    }456457    /// <summary>458    /// Test the external attributes for this <see cref="ZipEntry"/> to459    /// see if the external attributes are Dos based (including WINNT and variants)460    /// and match the values461    /// </summary>462    /// <param name="attributes">The attributes to test.</param>463    /// <returns>Returns true if the external attributes are known to be DOS/Windows464    /// based and have the same attributes set as the value passed.</returns>465    bool HasDosAttributes(int attributes)466    { - 920889467      bool result = false; - 920889468       if ( (known & Known.ExternalAttributes) != 0 ) { - 461462469        result |= (((HostSystem == (int)HostSystemID.Msdos) || - 461462470          (HostSystem == (int)HostSystemID.WindowsNT)) && - 461462471          (ExternalFileAttributes & attributes) == attributes);472      } - 920889473      return result;474    }475476    /// <summary>477    /// Gets the compatability information for the <see cref="ExternalFileAttributes">external file attribute</see>478    /// If the external file attributes are compatible with MS-DOS and can be read479    /// by PKZIP for DOS version 2.04g then this value will be zero.  Otherwise the value480    /// will be non-zero and identify the host system on which the attributes are compatible.481    /// </summary>482    ///483    /// <remarks>484    /// The values for this as defined in the Zip File format and by others are shown below.  The values are somewhat485    /// misleading in some cases as they are not all used as shown.  You should consult the relevant documentation486    /// to obtain up to date and correct information.  The modified appnote by the infozip group is487    /// particularly helpful as it documents a lot of peculiarities.  The document is however a little dated.488    /// <list type="table">489    /// <item>0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)</item>490    /// <item>1 - Amiga</item>491    /// <item>2 - OpenVMS</item>492    /// <item>3 - Unix</item>493    /// <item>4 - VM/CMS</item>494    /// <item>5 - Atari ST</item>495    /// <item>6 - OS/2 HPFS</item>496    /// <item>7 - Macintosh</item>497    /// <item>8 - Z-System</item>498    /// <item>9 - CP/M</item>499    /// <item>10 - Windows NTFS</item>500    /// <item>11 - MVS (OS/390 - Z/OS)</item>501    /// <item>12 - VSE</item>502    /// <item>13 - Acorn Risc</item>503    /// <item>14 - VFAT</item>504    /// <item>15 - Alternate MVS</item>505    /// <item>16 - BeOS</item>506    /// <item>17 - Tandem</item>507    /// <item>18 - OS/400</item>508    /// <item>19 - OS/X (Darwin)</item>509    /// <item>99 - WinZip AES</item>510    /// <item>remainder - unused</item>511    /// </list>512    /// </remarks>513    public int HostSystem514    {515      get { - 461464516        return (versionMadeBy >> 8) & 0xff;517      }518519      set { - 0520        versionMadeBy &= 0xff; - 0521        versionMadeBy |= (ushort)((value & 0xff) << 8); - 0522      }523    }524525    /// <summary>526    /// Get minimum Zip feature version required to extract this entry527    /// </summary>528    /// <remarks>529    /// Minimum features are defined as:<br/>530    /// 1.0 - Default value<br/>531    /// 1.1 - File is a volume label<br/>532    /// 2.0 - File is a folder/directory<br/>533    /// 2.0 - File is compressed using Deflate compression<br/>534    /// 2.0 - File is encrypted using traditional encryption<br/>535    /// 2.1 - File is compressed using Deflate64<br/>536    /// 2.5 - File is compressed using PKWARE DCL Implode<br/>537    /// 2.7 - File is a patch data set<br/>538    /// 4.5 - File uses Zip64 format extensions<br/>539    /// 4.6 - File is compressed using BZIP2 compression<br/>540    /// 5.0 - File is encrypted using DES<br/>541    /// 5.0 - File is encrypted using 3DES<br/>542    /// 5.0 - File is encrypted using original RC2 encryption<br/>543    /// 5.0 - File is encrypted using RC4 encryption<br/>544    /// 5.1 - File is encrypted using AES encryption<br/>545    /// 5.1 - File is encrypted using corrected RC2 encryption<br/>546    /// 5.1 - File is encrypted using corrected RC2-64 encryption<br/>547    /// 6.1 - File is encrypted using non-OAEP key wrapping<br/>548    /// 6.2 - Central directory encryption (not confirmed yet)<br/>549    /// 6.3 - File is compressed using LZMA<br/>550    /// 6.3 - File is compressed using PPMD+<br/>551    /// 6.3 - File is encrypted using Blowfish<br/>552    /// 6.3 - File is encrypted using Twofish<br/>553    /// </remarks>554    /// <seealso cref="CanDecompress"></seealso>555    public int Version556    {557      get {558        // Return recorded version if known. - 198092559         if (versionToExtract != 0) { - 66414560          return versionToExtract & 0x00ff;        // Only lower order byte. High order is O/S file system.561        }562        else { - 131678563          int result = 10; - 131678564           if (AESKeySize > 0) { - 0565            result = ZipConstants.VERSION_AES;      // Ver 5.1 = AES - 0566          } - 131678567           else if (CentralHeaderRequiresZip64) { - 253568            result = ZipConstants.VersionZip64; - 253569          } - 131425570           else if (CompressionMethod.Deflated == method) { - 321571            result = 20; - 321572          } - 131104573           else if (IsDirectory == true) { - 0574            result = 20; - 0575          } - 131104576           else if (IsCrypted == true) { - 0577            result = 20; - 0578          } - 131104579           else if (HasDosAttributes(0x08) ) { - 0580            result = 11;581          } - 131678582          return result;583        }584      }585    }586587    /// <summary>588    /// Get a value indicating whether this entry can be decompressed by the library.589    /// </summary>590    /// <remarks>This is based on the <see cref="Version"></see> and591    /// wether the <see cref="IsCompressionMethodSupported()">compression method</see> is supported.</remarks>592    public bool CanDecompress593    {594      get { - 77595         return (Version <= ZipConstants.VersionMadeBy) && - 77596          ((Version == 10) || - 77597          (Version == 11) || - 77598          (Version == 20) || - 77599          (Version == 45) || - 77600          (Version == 51)) && - 77601          IsCompressionMethodSupported();602      }603    }604605    /// <summary>606    /// Force this entry to be recorded using Zip64 extensions.607    /// </summary>608    public void ForceZip64()609    { - 127610      forceZip64_ = true; - 127611    }612613    /// <summary>614    /// Get a value indicating wether Zip64 extensions were forced.615    /// </summary>616    /// <returns>A <see cref="bool"/> value of true if Zip64 extensions have been forced on; false if not.</returns>617    public bool IsZip64Forced()618    { - 132054619      return forceZip64_;620    }621622    /// <summary>623    /// Gets a value indicating if the entry requires Zip64 extensions624    /// to store the full entry values.625    /// </summary>626    /// <value>A <see cref="bool"/> value of true if a local header requires Zip64 extensions; false if not.</value>627    public bool LocalHeaderRequiresZip64628    {629      get { - 395560630        bool result = forceZip64_;631 - 395560632         if ( !result ) { - 394651633          ulong trueCompressedSize = compressedSize;634 - 394651635           if ( (versionToExtract == 0) && IsCrypted ) { - 68636            trueCompressedSize += ZipConstants.CryptoHeaderSize;637          }638639          // TODO: A better estimation of the true limit based on compression overhead should be used640          // to determine when an entry should use Zip64. - 394651641          result = - 394651642            ((this.size >= uint.MaxValue) || (trueCompressedSize >= uint.MaxValue)) && - 394651643            ((versionToExtract == 0) || (versionToExtract >= ZipConstants.VersionZip64));644        }645 - 395560646        return result;647      }648    }288289      set { + 66037290        cryptoCheckValue_ = value; + 66037291      }292    }293294    /// <summary>295    /// Get/Set general purpose bit flag for entry296    /// </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 size314    /// and uncompressed size are were not able to be written during zip file creation315    /// 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    }333334    /// <summary>335    /// Get/Set index of this entry in Zip file336    /// </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    }346347    /// <summary>348    /// Get/set offset for use in central header349    /// </summary>350    public long Offset {351      get { + 396693352        return offset;353      }354      set { + 131833355        offset = value; + 131833356      }357    }358359    /// <summary>360    /// Get/Set external file attributes as an integer.361    /// The values of this are operating system dependant see362    /// <see cref="HostSystem">HostSystem</see> for details363    /// </summary>364    public int ExternalFileAttributes {365      get { + 527438366         if ((known & Known.ExternalAttributes) == 0) { + 65824367          return -1;368        } else { + 461614369          return externalFileAttributes;370        }371      }372373      set { + 65965374        externalFileAttributes = value; + 65965375        known |= Known.ExternalAttributes; + 65965376      }377    }378379    /// <summary>380    /// Get the version made by for this entry or zero if unknown.381    /// The value / 10 indicates the major version number, and382    /// the value mod 10 is the minor version number383    /// </summary>384    public int VersionMadeBy {385      get { + 0386        return (versionMadeBy & 0xff);387      }388    }389390    /// <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    }399400    /// <summary>401    /// Test the external attributes for this <see cref="ZipEntry"/> to402    /// see if the external attributes are Dos based (including WINNT and variants)403    /// and match the values404    /// </summary>405    /// <param name="attributes">The attributes to test.</param>406    /// <returns>Returns true if the external attributes are known to be DOS/Windows407    /// 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    }418419    /// <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 read422    /// by PKZIP for DOS version 2.04g then this value will be zero.  Otherwise the value423    /// 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 somewhat428    /// misleading in some cases as they are not all used as shown.  You should consult the relevant documentation429    /// to obtain up to date and correct information.  The modified appnote by the infozip group is430    /// 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      }460461      set { + 0462        versionMadeBy &= 0xff; + 0463        versionMadeBy |= (ushort)((value & 0xff) << 8); + 0464      }465    }466467    /// <summary>468    /// Get minimum Zip feature version required to extract this entry469    /// </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    }521522    /// <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> and526    /// 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    }538539    /// <summary>540    /// Force this entry to be recorded using Zip64 extensions.541    /// </summary>542    public void ForceZip64()543    { + 124544      forceZip64_ = true; + 124545    }546547    /// <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    }555556    /// <summary>557    /// Gets a value indicating if the entry requires Zip64 extensions558    /// 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          }571572          // TODO: A better estimation of the true limit based on compression overhead should be used573          // 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    }582583    /// <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    }591592    /// <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      }606607      set {608        unchecked { + 197925609          dosTime = (uint)value;610        }611 + 197925612        known |= Known.Time; + 197925613      }614    }615616    /// <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 DateTime623    { + 2624      get { return dateTime; }625626      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        }  649650    /// <summary>651    /// Get a value indicating wether the central directory entry requires Zip64 extensions to be stored.652    /// </summary>653    public bool CentralHeaderRequiresZip64654    {655      get { - 197581656        return LocalHeaderRequiresZip64 || (offset >= uint.MaxValue);657      }658    }659660    /// <summary>661    /// Get/Set DosTime value.662    /// </summary>663    /// <remarks>664    /// The MS-DOS date format can only represent dates between 1/1/1980 and 12/31/2107.665    /// </remarks>666    public long DosTime667    {668      get { - 131823669         if ((known & Known.Time) == 0) { - 0670          return 0;671        }672        else { - 131823673          return dosTime;674        }675      }676677      set {678        unchecked { - 197962679          dosTime = (uint)value;680        }681 - 197962682        known |= Known.Time; - 197962683      }684    }685686    /// <summary>687    /// Gets/Sets the time of last modification of the entry.688    /// </summary>689    /// <remarks>690    /// The <see cref="DosTime"></see> property is updated to match this as far as possible.691    /// </remarks>692    public DateTime DateTime693    {694      get { - 18695        uint sec  = Math.Min(59, 2 * (dosTime & 0x1f)); - 18696        uint min  = Math.Min(59, (dosTime >> 5) & 0x3f); - 18697        uint hrs  = Math.Min(23, (dosTime >> 11) & 0x1f); - 18698        uint mon  = Math.Max(1, Math.Min(12, ((dosTime >> 21) & 0xf))); - 18699        uint year = ((dosTime >> 25) & 0x7f) + 1980; - 18700        int day = Math.Max(1, Math.Min(DateTime.DaysInMonth((int)year, (int)mon), (int)((dosTime >> 16) & 0x1f))); - 18701        return new System.DateTime((int)year, (int)mon, day, (int)hrs, (int)min, (int)sec);702      }703704      set { - 131916705        var year = (uint) value.Year; - 131916706        var month = (uint) value.Month; - 131916707        var day = (uint) value.Day; - 131916708        var hour = (uint) value.Hour; - 131916709        var minute = (uint) value.Minute; - 131916710        var second = (uint) value.Second;711 - 131916712         if ( year < 1980 ) { - 1713          year = 1980; - 1714          month = 1; - 1715          day = 1; - 1716          hour = 0; - 1717          minute = 0; - 1718          second = 0; - 1719        } - 131915720         else if ( year > 2107 ) { - 1721          year = 2107; - 1722          month = 12; - 1723          day = 31; - 1724          hour = 23; - 1725          minute = 59; - 1726          second = 59;727        }728 - 131916729        DosTime = ((year - 1980) & 0x7f) << 25 | - 131916730          (month << 21) | - 131916731          (day << 16) | - 131916732          (hour << 11) | - 131916733          (minute << 5) | - 131916734          (second >> 1); - 131916735      }736    }737738    /// <summary>739    /// Returns the entry name.740    /// </summary>741    /// <remarks>742    /// The unix naming convention is followed.743    /// Path components in the entry should always separated by forward slashes ('/').744    /// Dos device names like C: should also be removed.745    /// See the <see cref="ZipNameTransform"/> class, or <see cref="CleanName(string)"/>746    ///</remarks>747    public string Name748    {749      get { - 527092750        return name;751      }752    }753754    /// <summary>755    /// Gets/Sets the size of the uncompressed data.756    /// </summary>757    /// <returns>758    /// The size or -1 if unknown.759    /// </returns>760    /// <remarks>Setting the size before adding an entry to an archive can help761    /// avoid compatability problems with some archivers which dont understand Zip64 extensions.</remarks>762    public long Size763    {764      get { - 724299765         return (known & Known.Size) != 0 ? (long)size : -1L;766      }767      set { - 131891768        this.size  = (ulong)value; - 131891769        this.known |= Known.Size; - 131891770      }771    } + 131886650        DosTime = ((year - 1980) & 0x7f) << 25 | + 131886651          (month << 21) | + 131886652          (day << 16) | + 131886653          (hour << 11) | + 131886654          (minute << 5) | + 131886655          (second >> 1); + 131886656      }657    }658659    /// <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    }673674    /// <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 help681    /// 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    }691692    /// <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    }707708    /// <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..0xffffffffL713    /// </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    }729730    /// <summary>731    /// Gets/Sets the compression method. Only Deflated and Stored are supported.732    /// </summary>733    /// <returns>734    /// The compression method for this entry735    /// </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      }742743      set { + 65837744         if (!IsCompressionMethodSupported(value)) { + 1745          throw new NotSupportedException("Compression method not supported");746        } + 65836747        this.method = value; + 65836748      }749    }750751    /// <summary>752    /// Gets the compression method for outputting to the local or central header.753    /// Returns same value as CompressionMethod except when AES encrypting, which754    /// 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    }761762    /// <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 {  772773    /// <summary>774    /// Gets/Sets the size of the compressed data.775    /// </summary>776    /// <returns>777    /// The compressed entry size or -1 if unknown.778    /// </returns>779    public long CompressedSize780    {781      get { - 593187782         return (known & Known.CompressedSize) != 0 ? (long)compressedSize : -1L;783      }784      set { - 262995785        this.compressedSize = (ulong)value; - 262995786        this.known |= Known.CompressedSize; - 262995787      }788    }789790    /// <summary>791    /// Gets/Sets the crc of the uncompressed data.792    /// </summary>793    /// <exception cref="System.ArgumentOutOfRangeException">794    /// Crc is not in the range 0..0xffffffffL795    /// </exception>796    /// <returns>797    /// The crc value or -1 if unknown.798    /// </returns>799    public long Crc800    {801      get { - 329653802         return (known & Known.Crc) != 0 ? crc & 0xffffffffL : -1L;803      }804      set { - 131859805         if (((ulong)crc & 0xffffffff00000000L) != 0) { - 0806          throw new ArgumentOutOfRangeException(nameof(value));807        } - 131859808        this.crc = (uint)value; - 131859809        this.known |= Known.Crc; - 131859810      }811    }812813    /// <summary>814    /// Gets/Sets the compression method. Only Deflated and Stored are supported.815    /// </summary>816    /// <returns>817    /// The compression method for this entry818    /// </returns>819    /// <see cref="ICSharpCode.SharpZipLib.Zip.CompressionMethod.Deflated"/>820    /// <see cref="ICSharpCode.SharpZipLib.Zip.CompressionMethod.Stored"/>821    public CompressionMethod CompressionMethod {822      get { - 461425823        return method;824      }825826      set { - 65846827         if ( !IsCompressionMethodSupported(value) ) { - 1828          throw new NotSupportedException("Compression method not supported");829        } - 65845830        this.method = value; - 65845831      }832    }833834    /// <summary>835    /// Gets the compression method for outputting to the local or central header.836    /// Returns same value as CompressionMethod except when AES encrypting, which837    /// places 99 in the method and places the real method in the extra data.838    /// </summary>839    internal CompressionMethod CompressionMethodForHeader {840      get { - 263841         return (AESKeySize > 0) ? CompressionMethod.WinZipAES : method;842      }843    }844845    /// <summary>846    /// Gets/Sets the extra data.847    /// </summary>848    /// <exception cref="System.ArgumentOutOfRangeException">849    /// Extra data is longer than 64KB (0xffff) bytes.850    /// </exception>851    /// <returns>852    /// Extra data or null if not set.853    /// </returns>854    public byte[] ExtraData {855856      get {857// TODO: This is slightly safer but less efficient.  Think about wether it should change.858//        return (byte[]) extra.Clone(); - 263294859        return extra;860      }861862      set { - 65879863         if (value == null) { - 0864          extra = null; - 0865        }866        else { - 65879867           if (value.Length > 0xffff) { - 0868            throw new System.ArgumentOutOfRangeException(nameof(value));869          }870 - 65879871          extra = new byte[value.Length]; - 65879872          Array.Copy(value, 0, extra, 0, value.Length);873        } - 65879874      }875    }876877878#if !NET_1_1 && !NETCF_2_0879    /// <summary>880    /// For AES encrypted files returns or sets the number of bits of encryption (128, 192 or 256).881    /// When setting, only 0 (off), 128 or 256 is supported.882    /// </summary>883    public int AESKeySize {884      get {885        // the strength (1 or 3) is in the entry header - 132538886         switch (_aesEncryptionStrength) { - 132538887          case 0: return 0;  // Not AES - 0888          case 1: return 128; - 0889          case 2: return 192; // Not used by WinZip - 0890          case 3: return 256; - 0891          default: throw new ZipException("Invalid AESEncryptionStrength " + _aesEncryptionStrength);892        }893      }894      set { - 0895         switch (value) { - 0896          case 0:   _aesEncryptionStrength = 0; break; - 0897          case 128: _aesEncryptionStrength = 1; break; - 0898          case 256: _aesEncryptionStrength = 3; break; - 0899          default: throw new ZipException("AESKeySize must be 0, 128 or 256: " + value);900        }901      }902    }903904    /// <summary>905    /// AES Encryption strength for storage in extra data in entry header.906    /// 1 is 128 bit, 2 is 192 bit, 3 is 256 bit.907    /// </summary>908    internal byte AESEncryptionStrength {909      get { - 0910        return (byte)_aesEncryptionStrength;911      }912    }913#else914    /// <summary>915    /// AES unsupported prior to .NET 2.0916    /// </summary>917    internal int AESKeySize;918#endif919920    /// <summary>921    /// Returns the length of the salt, in bytes922    /// </summary>923    internal int AESSaltLen {924      get {925        // Key size -> Salt length: 128 bits = 8 bytes, 192 bits = 12 bytes, 256 bits = 16 bytes. - 0926        return AESKeySize / 16;927      }928    }929930    /// <summary>931    /// Number of extra bytes required to hold the AES Header fields (Salt, Pwd verify, AuthCode)932    /// </summary>933    internal int AESOverheadSize {934      get {935        // File format:936        //   Bytes    Content937        // Variable    Salt value938        //     2    Password verification value939        // Variable    Encrypted file data940        //    10    Authentication code - 0941        return 12 + AESSaltLen;942      }943    }944945    /// <summary>946    /// Process extra data fields updating the entry based on the contents.947    /// </summary>948    /// <param name="localHeader">True if the extra data fields should be handled949    /// for a local header, rather than for a central header.950    /// </param>951    internal void ProcessExtraData(bool localHeader)952    { - 66041953      var extraData = new ZipExtraData(this.extra);954 - 66041955       if ( extraData.Find(0x0001) ) {956                // Version required to extract is ignored here as some archivers dont set it correctly957                // in theory it should be version 45 or higher958959        // The recorded size will change but remember that this is zip64. - 127960        forceZip64_ = true;961 - 127962         if ( extraData.ValueLength < 4 ) { - 0963          throw new ZipException("Extra data extended Zip64 information length is invalid");964        }965 - 127966         if ( localHeader || (size == uint.MaxValue) ) { - 127967          size = (ulong)extraData.ReadLong();968        }969 - 127970         if ( localHeader || (compressedSize == uint.MaxValue) ) { - 127971          compressedSize = (ulong)extraData.ReadLong();972        }973 - 127974         if ( !localHeader && (offset == uint.MaxValue) ) { - 0975          offset = extraData.ReadLong();976        }977978                // Disk number on which file starts is ignored - 0979      }980      else { - 65914981         if ( - 65914982          ((versionToExtract & 0xff) >= ZipConstants.VersionZip64) && - 65914983          ((size == uint.MaxValue) || (compressedSize == uint.MaxValue)) - 65914984        ) { - 0985          throw new ZipException("Zip64 Extended information required but is missing.");986        }987      }988 - 66041989       if ( extraData.Find(10) ) {990        // No room for any tags. - 0991         if ( extraData.ValueLength < 4 ) { - 0992          throw new ZipException("NTFS Extra data invalid");993        }994 - 0995        extraData.ReadInt(); // Reserved996 - 0997         while ( extraData.UnreadCount >= 4 ) { - 0998          int ntfsTag = extraData.ReadShort(); - 0999          int ntfsLength = extraData.ReadShort(); - 01000           if ( ntfsTag == 1 ) { - 01001             if ( ntfsLength >= 24 ) { - 01002              long lastModification = extraData.ReadLong(); - 01003              long lastAccess = extraData.ReadLong(); - 01004              long createTime = extraData.ReadLong();1005 - 01006              DateTime = System.DateTime.FromFileTime(lastModification);1007            } - 01008            break;1009          }1010          else {1011            // An unknown NTFS tag so simply skip it. - 01012            extraData.Skip(ntfsLength);1013          }1014        } - 01015      } - 660411016       else if ( extraData.Find(0x5455) ) { - 11017        int length = extraData.ValueLength; - 11018        int flags = extraData.ReadByte();10191020        // Can include other times but these are ignored.  Length of data should1021        // actually be 1 + 4 * no of bits in flags. - 11022         if ( ((flags & 1) != 0) && (length >= 5) ) { - 11023          int iTime = extraData.ReadInt();1024 - 11025          DateTime = (new System.DateTime ( 1970, 1, 1, 0, 0, 0 ).ToUniversalTime() + - 11026            new TimeSpan ( 0, 0, 0, iTime, 0 )).ToLocalTime();1027        }1028      } - 660411029       if (method == CompressionMethod.WinZipAES) { - 01030        ProcessAESExtraData(extraData);1031      } - 660411032    }10331034    // For AES the method in the entry is 99, and the real compression method is in the extradata1035    //1036    private void ProcessAESExtraData(ZipExtraData extraData) {10371038#if !NET_1_1 && !NETCF_2_0 - 01039       if (extraData.Find(0x9901)) {1040        // Set version and flag for Zipfile.CreateAndInitDecryptionStream - 01041        versionToExtract = ZipConstants.VERSION_AES;      // Ver 5.1 = AES see "Version" getter1042        // Set StrongEncryption flag for ZipFile.CreateAndInitDecryptionStream - 01043        Flags = Flags | (int)GeneralBitFlags.StrongEncryption;1044        //1045        // Unpack AES extra data field see http://www.winzip.com/aes_info.htm - 01046        int length = extraData.ValueLength;      // Data size currently 7 - 01047         if (length < 7) - 01048          throw new ZipException("AES Extra Data Length " + length + " invalid."); - 01049        int ver = extraData.ReadShort();      // Version number (1=AE-1 2=AE-2) - 01050        int vendorId = extraData.ReadShort();    // 2-character vendor ID 0x4541 = "AE" - 01051        int encrStrength = extraData.ReadByte();  // encryption strength 1 = 128 2 = 192 3 = 256 - 01052        int actualCompress = extraData.ReadShort(); // The actual compression method used to compress the file - 01053        _aesVer = ver; - 01054        _aesEncryptionStrength = encrStrength; - 01055        method = (CompressionMethod)actualCompress; - 01056      } else - 01057        throw new ZipException("AES Extra Data missing");1058#else1059        throw new ZipException("AES unsupported");1060#endif1061    }10621063    /// <summary>1064    /// Gets/Sets the entry comment.1065    /// </summary>1066    /// <exception cref="System.ArgumentOutOfRangeException">1067    /// If comment is longer than 0xffff.1068    /// </exception>1069    /// <returns>1070    /// The comment or null if not set.1071    /// </returns>1072    /// <remarks>1073    /// A comment is only available for entries when read via the <see cref="ZipFile"/> class.1074    /// The <see cref="ZipInputStream"/> class doesnt have the comment data available.1075    /// </remarks>1076    public string Comment {1077      get { - 1316761078        return comment;1079      }1080      set {1081        // This test is strictly incorrect as the length is in characters1082        // while the storage limit is in bytes.1083        // While the test is partially correct in that a comment of this length or greater1084        // is definitely invalid, shorter comments may also have an invalid length1085        // where there are multi-byte characters1086        // The full test is not possible here however as the code page to apply conversions with1087        // isnt available. - 31088         if ( (value != null) && (value.Length > 0xffff) ) {1089#if NETCF_1_01090          throw new ArgumentOutOfRangeException("value");1091#else - 01092          throw new ArgumentOutOfRangeException(nameof(value), "cannot exceed 65535");1093#endif1094        }1095 - 31096        comment = value; - 31097      }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      }778779      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    }792793794    /// <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 AES804          case 1: + 0805            return 128;806          case 2: + 0807            return 192; // Not used by WinZip808          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    }830831    /// <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    }840841    /// <summary>842    /// Returns the length of the salt, in bytes843    /// </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    }850851    /// <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    Content858        // Variable    Salt value859        //     2    Password verification value860        // Variable    Encrypted file data861        //    10    Authentication code + 0862        return 12 + AESSaltLen;863      }864    }865866    /// <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 handled870    /// 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 correctly878        // in theory it should be version 45 or higher879880        // 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        }886887        // (localHeader ||) was deleted, because actually there is no specific difference with reading sizes between loc888        // https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT889        // ...890        // 4.4  Explanation of fields891        // ...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 it897        //    will be placed in front of the file data and the value of the898        //    compressed file size will include the bytes of the decryption899        //    header.  If bit 3 of the general purpose bit flag is set,900        //    these fields are set to zero in the local header and the901        //    correct values are put in the data descriptor and902        //    in the central directory.  If an archive is in ZIP64 format903        //    and the value in this field is 0xFFFFFFFF, the size will be904        //    in the corresponding 8 byte ZIP64 extended information905        //    extra field.  When encrypting the central directory, if the906        //    local header is not in ZIP64 format and general purpose bit907        //    flag 13 is set indicating masking, the value stored for the908        //    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        }922923        // 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    }938939    private DateTime GetDateTime(ZipExtraData extraData) {940      // Check for NT timestamp941            // NOTE: Disable by default to match behavior of InfoZIP942#if RESPECT_NT_TIMESTAMP943      NTTaggedData ntData = extraData.GetData<NTTaggedData>();944      if (ntData != null)945        return ntData.LastModificationTime;946#endif947948      // 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;957958      // 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    }967968    // For AES the method in the entry is 99, and the real compression method is in the extradata969    //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" getter976                                    // 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    }993994    /// <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 characters1013        // while the storage limit is in bytes.1014        // While the test is partially correct in that a comment of this length or greater1015        // is definitely invalid, shorter comments may also have an invalid length1016        // where there are multi-byte characters1017        // The full test is not possible here however as the code page to apply conversions with1018        // 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    }10261027    /// <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    }10481049    /// <summary>1050    /// Get a value of true if the entry appears to be a file; false otherwise1051    /// </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    }10611062    /// <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    }10701071    #region ICloneable Members1072    /// <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();10791080      // 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    }10881089    #endregion10901091    /// <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    /// Gets a value indicating if the entry is a directory.1102    /// however.1101    /// Test a <see cref="CompressionMethod">compression method</see> to see if this library1102    /// supports extracting data compressed with that method  1103    /// </summary>1104    /// <remarks>1105    /// A directory is determined by an entry name with a trailing slash '/'.1106    /// The external file attributes can also indicate an entry is for a directory.1107    /// Currently only dos/windows attributes are tested in this manner.1108    /// The trailing slash convention should always be followed.1109    /// </remarks>1110    public bool IsDirectory1111    {1112      get { - 5263371113        int nameLength = name.Length; - 5263371114        bool result = - 5263371115          ((nameLength > 0) && - 5263371116          ((name[nameLength - 1] == '/') || (name[nameLength - 1] == '\\'))) || - 5263371117          HasDosAttributes(16) - 5263371118          ; - 271119        return result;1120      }1121    }11221123    /// <summary>1124    /// Get a value of true if the entry appears to be a file; false otherwise1125    /// </summary>1126    /// <remarks>1127    /// This only takes account of DOS/Windows attributes.  Other operating systems are ignored.1128    /// For linux and others the result may be incorrect.1129    /// </remarks>1130    public bool IsFile1131    {1132      get { - 2634861133        return !IsDirectory && !HasDosAttributes(8);1134      }1135    }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    }11121113    /// <summary>1114    /// Cleans a name making it conform to Zip file conventions.1115    /// Devices names ('c:\') and UNC share names ('\\server\share') are removed1116    /// and forward slashes ('\') are converted to back slashes ('/').1117    /// Names are made relative by trimming leading slashes which is compatible1118    /// 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      }  11361137    /// <summary>1138    /// Test entry to see if data can be extracted.1139    /// </summary>1140    /// <returns>Returns true if data can be extracted for this entry; false otherwise.</returns>1141    public bool IsCompressionMethodSupported()1142    { - 1320201143      return IsCompressionMethodSupported(CompressionMethod);1144    }11451146    #region ICloneable Members1147    /// <summary>1148    /// Creates a copy of this zip entry.1149    /// </summary>1150    /// <returns>An <see cref="Object"/> that is a copy of the current instance.</returns>1151    public object Clone()1152    { - 4610931153      var result = (ZipEntry)this.MemberwiseClone();11541155      // Ensure extra data is unique if it exists. - 4610931156       if ( extra != null ) { - 721157        result.extra = new byte[extra.Length]; - 721158        Array.Copy(extra, 0, result.extra, 0, extra.Length);1159      }1160 - 4610931161      return result;1162    } + 1318771137      name = name.Replace(@"\", "/");1138 + 1318771139       while ((name.Length > 0) && (name[0] == '/')) { + 01140        name = name.Remove(0, 1);1141      } + 1318771142      return name;1143    }11441145    #region Instance Fields1146    Known known; + 1318791147    int externalFileAttributes = -1;     // contains external attributes (O/S dependant)11481149    ushort versionMadeBy;                   // Contains host system and version information1150                        // only relevant for central header entries11511152    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;  11631164    #endregion1164    int flags;                             // general purpose bit flags  11651166    /// <summary>1167    /// Gets a string representation of this ZipEntry.1168    /// </summary>1169    /// <returns>A readable textual representation of this <see cref="ZipEntry"/></returns>1170    public override string ToString()1171    { - 01172      return name;1173    }11741175    /// <summary>1176    /// Test a <see cref="CompressionMethod">compression method</see> to see if this library1177    /// supports extracting data compressed with that method1178    /// </summary>1179    /// <param name="method">The compression method to test.</param>1180    /// <returns>Returns true if the compression method is supported; false otherwise</returns>1181    public static bool IsCompressionMethodSupported(CompressionMethod method)1182    { - 1978661183      return - 1978661184        ( method == CompressionMethod.Deflated ) || - 1978661185        ( method == CompressionMethod.Stored );1186    }11871188    /// <summary>1189    /// Cleans a name making it conform to Zip file conventions.1190    /// Devices names ('c:\') and UNC share names ('\\server\share') are removed1191    /// and forward slashes ('\') are converted to back slashes ('/').1192    /// Names are made relative by trimming leading slashes which is compatible1193    /// with the ZIP naming convention.1194    /// </summary>1195    /// <param name="name">The name to clean</param>1196    /// <returns>The 'cleaned' name.</returns>1197    /// <remarks>1198    /// The <seealso cref="ZipNameTransform">Zip name transform</seealso> class is more flexible.1199    /// </remarks>1200    public static string CleanName(string name)1201    { - 1318991202       if (name == null) { - 01203        return string.Empty;1204      }1205 - 1318991206       if (Path.IsPathRooted(name)) {1207        // NOTE:1208        // for UNC names...  \\machine\share\zoom\beet.txt gives \zoom\beet.txt - 31209        name = name.Substring(Path.GetPathRoot(name).Length);1210      }1211 - 1318991212      name = name.Replace(@"\", "/");1213 - 1319011214       while ( (name.Length > 0) && (name[0] == '/')) { - 21215        name = name.Remove(0, 1);1216      } - 1318991217      return name;1218    }12191220    #region Instance Fields1221    Known known; - 1318971222    int    externalFileAttributes = -1;     // contains external attributes (O/S dependant)12231224    ushort versionMadeBy;          // Contains host system and version information1225                        // only relevant for central header entries12261227    string name;1228    ulong  size;1229    ulong  compressedSize;1230    ushort versionToExtract;                // Version required to extract (library handles <= 2.0)1231    uint   crc;1232    uint   dosTime;1233 - 1318971234    CompressionMethod  method = CompressionMethod.Deflated;1235    byte[] extra;1236    string comment;12371238    int flags;                             // general purpose bit flags1239 - 1318971240    long zipFileIndex = -1;                // used by ZipFile1241    long offset;                           // used by ZipFile and ZipOutputStream12421243    bool forceZip64_;1244    byte cryptoCheckValue_;1245#if !NET_1_1 && !NETCF_2_01246    int _aesVer;              // Version number (2 = AE-2 ?). Assigned but not used.1247    int _aesEncryptionStrength;        // Encryption strength 1 = 128 2 = 192 3 = 2561248#endif1249    #endregion1250  }1251} + 1318791166    long zipFileIndex = -1;                // used by ZipFile1167    long offset;                           // used by ZipFile and ZipOutputStream11681169    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 = 2561173    #endregion1174  }1175} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipEntryFactory.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipEntryFactory.htm index d9b1c0c71..514410af1 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipEntryFactory.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipEntryFactory.htm @@ -15,12 +15,12 @@

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:77 -Uncovered lines:24 +Covered lines:51 +Uncovered lines:50 Coverable lines:101 -Total lines:428 -Line coverage:76.2% -Branch coverage:55% +Total lines:341 +Line coverage:50.4% +Branch coverage:35%

Metrics

@@ -32,9 +32,9 @@

Metrics

.ctor(...)1100100 MakeFileEntry(...)1100100 MakeFileEntry(...)1100100 -MakeFileEntry(...)1673.5371.43 -MakeDirectoryEntry(...)1100100 -MakeDirectoryEntry(...)1364.5241.18 +MakeFileEntry(...)1661.7661.90 +MakeDirectoryEntry(...)100 +MakeDirectoryEntry(...)1300

File(s)

@@ -42,436 +42,349 @@

#LineLine coverage - 1// ZipEntryFactory.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  2012-11-29  Z-1684  Added MakeFileEntry(string fileName, string entryName, bool useFileSystem)4142using System;43using System.IO;4445using ICSharpCode.SharpZipLib.Core;4647namespace ICSharpCode.SharpZipLib.Zip48{49  /// <summary>50  /// Basic implementation of <see cref="IEntryFactory"></see>51  /// </summary>52  public class ZipEntryFactory : IEntryFactory53  {54    #region Enumerations1using System;2using System.IO;3using ICSharpCode.SharpZipLib.Core;45namespace ICSharpCode.SharpZipLib.Zip6{7  /// <summary>8  /// Basic implementation of <see cref="IEntryFactory"></see>9  /// </summary>10  public class ZipEntryFactory : IEntryFactory11  {12    #region Enumerations13    /// <summary>14    /// Defines the possible values to be used for the <see cref="ZipEntry.DateTime"/>.15    /// </summary>16    public enum TimeSetting17    {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 file24      /// </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 be46      /// specified via the <see cref="ZipEntryFactory(DateTime)"/> constructor or47      /// using the <see cref="ZipEntryFactory(TimeSetting)"/> with the setting set48      /// 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    #endregion5354    #region Constructors  55    /// <summary>56    /// Defines the possible values to be used for the <see cref="ZipEntry.DateTime"/>.56    /// Initialise a new instance of the <see cref="ZipEntryFactory"/> class.  57    /// </summary>58    public enum TimeSetting59    {60      /// <summary>61      /// Use the recorded LastWriteTime value for the file.62      /// </summary>63      LastWriteTime,64      /// <summary>65      /// Use the recorded LastWriteTimeUtc value for the file66      /// </summary>67      LastWriteTimeUtc,68      /// <summary>69      /// Use the recorded CreateTime value for the file.70      /// </summary>71      CreateTime,72      /// <summary>73      /// Use the recorded CreateTimeUtc value for the file.74      /// </summary>75      CreateTimeUtc,76      /// <summary>77      /// Use the recorded LastAccessTime value for the file.78      /// </summary>79      LastAccessTime,80      /// <summary>81      /// Use the recorded LastAccessTimeUtc value for the file.82      /// </summary>83      LastAccessTimeUtc,84      /// <summary>85      /// Use a fixed value.86      /// </summary>87      /// <remarks>The actual <see cref="DateTime"/> value used can be88      /// specified via the <see cref="ZipEntryFactory(DateTime)"/> constructor or89      /// using the <see cref="ZipEntryFactory(TimeSetting)"/> with the setting set90      /// to <see cref="TimeSetting.Fixed"/> which will use the <see cref="DateTime"/> when this class was constructed.91      /// The <see cref="FixedDateTime"/> property can also be used to set this value.</remarks>92      Fixed,93    }94    #endregion9596    #region Constructors97    /// <summary>98    /// Initialise a new instance of the <see cref="ZipEntryFactory"/> class.99    /// </summary>100    /// <remarks>A default <see cref="INameTransform"/>, and the LastWriteTime for files is used.</remarks> - 100101    public ZipEntryFactory()102    { - 100103      nameTransform_ = new ZipNameTransform(); - 100104    }105106    /// <summary>107    /// Initialise a new instance of <see cref="ZipEntryFactory"/> using the specified <see cref="TimeSetting"/>108    /// </summary>109    /// <param name="timeSetting">The <see cref="TimeSetting">time setting</see> to use when creating <see cref="ZipEntr - 1110    public ZipEntryFactory(TimeSetting timeSetting)111    { - 1112      timeSetting_ = timeSetting; - 1113      nameTransform_ = new ZipNameTransform(); - 1114    }115116    /// <summary>117    /// Initialise a new instance of <see cref="ZipEntryFactory"/> using the specified <see cref="DateTime"/>118    /// </summary>119    /// <param name="time">The time to set all <see cref="ZipEntry.DateTime"/> values to.</param> - 1120    public ZipEntryFactory(DateTime time)121    { - 1122      timeSetting_ = TimeSetting.Fixed; - 1123      FixedDateTime = time; - 1124      nameTransform_ = new ZipNameTransform(); - 1125    }126127    #endregion128129    #region Properties130    /// <summary>131    /// Get / set the <see cref="INameTransform"/> to be used when creating new <see cref="ZipEntry"/> values.132    /// </summary>133    /// <remarks>134    /// Setting this property to null will cause a default <see cref="ZipNameTransform">name transform</see> to be used.135    /// </remarks>136    public INameTransform NameTransform137    { - 65743138      get { return nameTransform_; }139      set140      { - 6141         if (value == null) { - 0142          nameTransform_ = new ZipNameTransform(); - 0143        }144        else { - 6145          nameTransform_ = value;146        } - 6147      }148    }149150    /// <summary>151    /// Get / set the <see cref="TimeSetting"/> in use.152    /// </summary>153    public TimeSetting Setting154    { - 3155      get { return timeSetting_; } - 20156      set { timeSetting_ = value; }157    }158159    /// <summary>160    /// Get / set the <see cref="DateTime"/> value to use when <see cref="Setting"/> is set to <see cref="TimeSetting.Fi161    /// </summary>162    public DateTime FixedDateTime163    { - 5164      get { return fixedDateTime_; }165      set166      { - 3167         if (value.Year < 1970) { - 0168          throw new ArgumentException("Value is too old to be valid", nameof(value));169        } - 3170        fixedDateTime_ = value; - 3171      }172    }173174    /// <summary>175    /// A bitmask defining the attributes to be retrieved from the actual file.176    /// </summary>177    /// <remarks>The default is to get all possible attributes from the actual file.</remarks>178    public int GetAttributes179    { - 3180      get { return getAttributes_; } - 4181      set { getAttributes_ = value; }182    }183184    /// <summary>185    /// A bitmask defining which attributes are to be set on.186    /// </summary>187    /// <remarks>By default no attributes are set on.</remarks>188    public int SetAttributes189    { - 3190      get { return setAttributes_; } - 6191      set { setAttributes_ = value; }192    }193194    /// <summary>195    /// Get set a value indicating wether unidoce text should be set on.196    /// </summary>197    public bool IsUnicodeText198    { - 0199      get { return isUnicodeText_; } - 4200      set { isUnicodeText_ = value; }201    }58    /// <remarks>A default <see cref="INameTransform"/>, and the LastWriteTime for files is used.</remarks> + 9559    public ZipEntryFactory()60    { + 9561      nameTransform_ = new ZipNameTransform(); + 9562    }6364    /// <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    }7374    /// <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    }8485    #endregion8687    #region Properties88    /// <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    }104105    /// <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    }112113    /// <summary>114    /// Get / set the <see cref="DateTime"/> value to use when <see cref="Setting"/> is set to <see cref="TimeSetting.Fi115    /// </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    }125126    /// <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    }134135    /// <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    }143144    /// <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    }151152    #endregion153154    #region IEntryFactory Members155156    /// <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    }165166    /// <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    }176177    /// <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;  202203    #endregion204205    #region IEntryFactory Members203          case TimeSetting.CreateTimeUtc: + 0204            result.DateTime = fi.CreationTimeUtc; + 0205            break;  206207    /// <summary>208    /// Make a new <see cref="ZipEntry"/> for a file.209    /// </summary>210    /// <param name="fileName">The name of the file to create a new entry for.</param>211    /// <returns>Returns a new <see cref="ZipEntry"/> based on the <paramref name="fileName"/>.</returns>212    public ZipEntry MakeFileEntry(string fileName)213    { - 10214      return MakeFileEntry(fileName, null, true);215    }216217    /// <summary>218    /// Make a new <see cref="ZipEntry"/> for a file.219    /// </summary>220    /// <param name="fileName">The name of the file to create a new entry for.</param>221    /// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>222    /// <returns>Returns a new <see cref="ZipEntry"/> based on the <paramref name="fileName"/>.</returns>223    public ZipEntry MakeFileEntry(string fileName, bool useFileSystem) { - 168224      return MakeFileEntry(fileName, null, useFileSystem);225    }207          case TimeSetting.LastAccessTime: + 0208            result.DateTime = fi.LastAccessTime; + 0209            break;210211          case TimeSetting.LastAccessTimeUtc: + 0212            result.DateTime = fi.LastAccessTimeUtc; + 0213            break;214215          case TimeSetting.LastWriteTime: + 7216            result.DateTime = fi.LastWriteTime; + 7217            break;218219          case TimeSetting.LastWriteTimeUtc: + 0220            result.DateTime = fi.LastWriteTimeUtc; + 0221            break;222223          case TimeSetting.Fixed: + 0224            result.DateTime = fixedDateTime_; + 0225            break;  226227    /// <summary>228    /// Make a new <see cref="ZipEntry"/> from a name.229    /// </summary>230    /// <param name="fileName">The name of the file to create a new entry for.</param>231    /// <param name="entryName">An alternative name to be used for the new entry. Null if not applicable.</param>232    /// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>233    /// <returns>Returns a new <see cref="ZipEntry"/> based on the <paramref name="fileName"/>.</returns>234    public ZipEntry MakeFileEntry(string fileName, string entryName, bool useFileSystem)235    { - 178236       var result = new ZipEntry(nameTransform_.TransformFile(!string.IsNullOrEmpty(entryName)? entryName : fileName)); - 178237      result.IsUnicodeText = isUnicodeText_;238 - 178239      int externalAttributes = 0; - 178240      bool useAttributes = (setAttributes_ != 0);241 - 178242      FileInfo fi = null; - 178243       if (useFileSystem)244      { - 10245        fi = new FileInfo(fileName);246      }247 - 178248       if ((fi != null) && fi.Exists)249      { - 10250         switch (timeSetting_)251        {252          case TimeSetting.CreateTime: - 1253            result.DateTime = fi.CreationTime; - 1254            break;255256          case TimeSetting.CreateTimeUtc:257#if NETCF_1_0 || NETCF_2_0258            result.DateTime = fi.CreationTime.ToUniversalTime();259#else - 0260            result.DateTime = fi.CreationTimeUtc;261#endif - 0262            break;263264          case TimeSetting.LastAccessTime: - 1265            result.DateTime = fi.LastAccessTime; - 1266            break;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    }248249    /// <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    }258259    /// <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    {  267268          case TimeSetting.LastAccessTimeUtc:269#if NETCF_1_0 || NETCF_2_0270            result.DateTime = fi.LastAccessTime.ToUniversalTime();271#else - 0272            result.DateTime = fi.LastAccessTimeUtc;273#endif - 0274            break; + 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;  275276          case TimeSetting.LastWriteTime: - 8277            result.DateTime = fi.LastWriteTime; - 8278            break; + 0276       if (useFileSystem) { + 0277        di = new DirectoryInfo(directoryName);278      }  279280          case TimeSetting.LastWriteTimeUtc:281#if NETCF_1_0 || NETCF_2_0282            result.DateTime = fi.LastWriteTime.ToUniversalTime();283#else - 0284            result.DateTime = fi.LastWriteTimeUtc;285#endif - 0286            break;287288          case TimeSetting.Fixed: - 0289            result.DateTime = fixedDateTime_; - 0290            break;291292          default: - 0293            throw new ZipException("Unhandled time setting in MakeFileEntry");294        }295 - 10296        result.Size = fi.Length;297 - 10298        useAttributes = true; - 10299        externalAttributes = ((int)fi.Attributes & getAttributes_); - 10300      }301      else302      { - 168303         if (timeSetting_ == TimeSetting.Fixed)304        { - 3305          result.DateTime = fixedDateTime_;306        }307      }308 - 178309       if (useAttributes)310      { - 15311        externalAttributes |= setAttributes_; - 15312        result.ExternalFileAttributes = externalAttributes;313      }280 + 0281       if ((di != null) && di.Exists) { + 0282         switch (timeSetting_) {283          case TimeSetting.CreateTime: + 0284            result.DateTime = di.CreationTime; + 0285            break;286287          case TimeSetting.CreateTimeUtc: + 0288            result.DateTime = di.CreationTimeUtc; + 0289            break;290291          case TimeSetting.LastAccessTime: + 0292            result.DateTime = di.LastAccessTime; + 0293            break;294295          case TimeSetting.LastAccessTimeUtc: + 0296            result.DateTime = di.LastAccessTimeUtc; + 0297            break;298299          case TimeSetting.LastWriteTime: + 0300            result.DateTime = di.LastWriteTime; + 0301            break;302303          case TimeSetting.LastWriteTimeUtc: + 0304            result.DateTime = di.LastWriteTimeUtc; + 0305            break;306307          case TimeSetting.Fixed: + 0308            result.DateTime = fixedDateTime_; + 0309            break;310311          default: + 0312            throw new ZipException("Unhandled time setting in MakeDirectoryEntry");313        }  314 - 178315      return result;316    }317318    /// <summary>319    /// Make a new <see cref="ZipEntry"></see> for a directory.320    /// </summary>321    /// <param name="directoryName">The raw untransformed name for the new directory</param>322    /// <returns>Returns a new <see cref="ZipEntry"></see> representing a directory.</returns>323    public ZipEntry MakeDirectoryEntry(string directoryName)324    { - 3325      return MakeDirectoryEntry(directoryName, true);326    }327328    /// <summary>329    /// Make a new <see cref="ZipEntry"></see> for a directory.330    /// </summary>331    /// <param name="directoryName">The raw untransformed name for the new directory</param>332    /// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>333    /// <returns>Returns a new <see cref="ZipEntry"></see> representing a directory.</returns>334    public ZipEntry MakeDirectoryEntry(string directoryName, bool useFileSystem)335    { + 0315        externalAttributes = ((int)di.Attributes & getAttributes_); + 0316      } else { + 0317         if (timeSetting_ == TimeSetting.Fixed) { + 0318          result.DateTime = fixedDateTime_;319        }320      }321322      // Always set directory attribute on. + 0323      externalAttributes |= (setAttributes_ | 16); + 0324      result.ExternalFileAttributes = externalAttributes;325 + 0326      return result;327    }328329    #endregion330331    #region Instance Fields332    INameTransform nameTransform_; + 97333    DateTime fixedDateTime_ = DateTime.Now;334    TimeSetting timeSetting_;335    bool isUnicodeText_;  336 - 3337      var result = new ZipEntry(nameTransform_.TransformDirectory(directoryName)); - 3338            result.IsUnicodeText = isUnicodeText_; - 3339            result.Size = 0;340 - 3341      int externalAttributes = 0;342 - 3343      DirectoryInfo di = null;344 - 3345       if (useFileSystem)346      { - 3347        di = new DirectoryInfo(directoryName);348      }349350 - 3351       if ((di != null) && di.Exists)352      { - 3353         switch (timeSetting_)354        {355          case TimeSetting.CreateTime: - 1356            result.DateTime = di.CreationTime; - 1357            break;358359          case TimeSetting.CreateTimeUtc:360#if NETCF_1_0 || NETCF_2_0361            result.DateTime = di.CreationTime.ToUniversalTime();362#else - 0363            result.DateTime = di.CreationTimeUtc;364#endif - 0365            break;366367          case TimeSetting.LastAccessTime: - 1368            result.DateTime = di.LastAccessTime; - 1369            break;370371          case TimeSetting.LastAccessTimeUtc:372#if NETCF_1_0 || NETCF_2_0373            result.DateTime = di.LastAccessTime.ToUniversalTime();374#else - 0375            result.DateTime = di.LastAccessTimeUtc;376#endif - 0377            break;378379          case TimeSetting.LastWriteTime: - 1380            result.DateTime = di.LastWriteTime; - 1381            break;382383          case TimeSetting.LastWriteTimeUtc:384#if NETCF_1_0 || NETCF_2_0385            result.DateTime = di.LastWriteTime.ToUniversalTime();386#else - 0387            result.DateTime = di.LastWriteTimeUtc;388#endif - 0389            break;390391          case TimeSetting.Fixed: - 0392            result.DateTime = fixedDateTime_; - 0393            break;394395          default: - 0396            throw new ZipException("Unhandled time setting in MakeDirectoryEntry");397        }398 - 3399        externalAttributes = ((int)di.Attributes & getAttributes_); - 3400      }401      else402      { - 0403         if (timeSetting_ == TimeSetting.Fixed)404        { - 0405          result.DateTime = fixedDateTime_;406        }407      }408409      // Always set directory attribute on. - 3410      externalAttributes |= (setAttributes_ | 16); - 3411      result.ExternalFileAttributes = externalAttributes;412 - 3413      return result;414    }415416    #endregion417418    #region Instance Fields419    INameTransform nameTransform_; - 102420    DateTime fixedDateTime_ = DateTime.Now;421    TimeSetting timeSetting_;422    bool isUnicodeText_;423 - 102424    int getAttributes_ = -1;425    int setAttributes_;426    #endregion427  }428} + 97337    int getAttributes_ = -1;338    int setAttributes_;339    #endregion340  }341} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipException.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipException.htm index 7fd4bca42..bcc7392a7 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipException.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipException.htm @@ -18,7 +18,7 @@

Summary

Covered lines:2 Uncovered lines:6 Coverable lines:8 -Total lines:94 +Total lines:48 Line coverage:25% @@ -37,102 +37,56 @@

#LineLine coverage - 1// ZipException.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839using System;4041#if !NETCF_1_0 && !NETCF_2_042using System.Runtime.Serialization;43#endif4445namespace ICSharpCode.SharpZipLib.Zip46{4748  /// <summary>49  /// Represents exception conditions specific to Zip archive handling50  /// </summary>51#if !NETCF_1_0 && !NETCF_2_052  [Serializable]53#endif54  public class ZipException : SharpZipBaseException55  {56#if !NETCF_1_0 && !NETCF_2_057    /// <summary>58    /// Deserialization constructor59    /// </summary>60    /// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>61    /// <param name="context"><see cref="StreamingContext"/> for this constructor</param>62    protected ZipException(SerializationInfo info, StreamingContext context ) - 063      : base( info, context )64    { - 065    }66#endif6768    /// <summary>69    /// Initializes a new instance of the ZipException class.70    /// </summary> - 071    public ZipException()72    { - 073    }7475    /// <summary>76    /// Initializes a new instance of the ZipException class with a specified error message.77    /// </summary>78    /// <param name="message">The error message that explains the reason for the exception.</param>79    public ZipException(string message) - 1680      : base(message)81    { - 1682    }8384    /// <summary>85    /// Initialise a new instance of ZipException.86    /// </summary>87    /// <param name="message">A message describing the error.</param>88    /// <param name="exception">The exception that is the cause of the current exception.</param>89    public ZipException(string message, Exception exception) - 090      : base(message, exception)91    { - 092    }93  }94}1using System;2using System.Runtime.Serialization;34namespace ICSharpCode.SharpZipLib.Zip5{6  /// <summary>7  /// ZipException represents exceptions specific to Zip classes and code.8  /// </summary>9  [Serializable]10  public class ZipException : SharpZipBaseException11  {12    /// <summary>13    /// Deserialization constructor14    /// </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    }2122    /// <summary>23    /// Initialise a new instance of <see cref="ZipException" />.24    /// </summary> + 025    public ZipException()26    { + 027    }2829    /// <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    }3738    /// <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/Documentation/opencover/ICSharpCode.SharpZipLib_ZipExtraData.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipExtraData.htm index fdce80251..441e65890 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipExtraData.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipExtraData.htm @@ -15,12 +15,12 @@

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:118 -Uncovered lines:30 -Coverable lines:148 -Total lines:987 -Line coverage:79.7% -Branch coverage:61.2% +Covered lines:121 +Uncovered lines:19 +Coverable lines:140 +Total lines:896 +Line coverage:86.4% +Branch coverage:67.2%

Metrics

@@ -32,8 +32,7 @@

Metrics

GetEntryData()266.6766.67 Clear()310060 GetStreamForTag(...)210066.67 -GetData(...)200 -Create(...)300 +GetData()26066.67 Find(...)6100100 AddEntry(...)200 AddEntry(...)89076.92 @@ -61,995 +60,904 @@

#LineLine coverage - 1//2// ZipExtraData.cs3//4// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team5//6// This program is free software; you can redistribute it and/or7// modify it under the terms of the GNU General Public License8// as published by the Free Software Foundation; either version 29// of the License, or (at your option) any later version.10//11// This program is distributed in the hope that it will be useful,12// but WITHOUT ANY WARRANTY; without even the implied warranty of13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the14// GNU General Public License for more details.15//16// You should have received a copy of the GNU General Public License17// along with this program; if not, write to the Free Software18// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.19//20// Linking this library statically or dynamically with other modules is21// making a combined work based on this library.  Thus, the terms and22// conditions of the GNU General Public License cover the whole23// combination.24//25// As a special exception, the copyright holders of this library give you26// permission to link this library with independent modules to produce an27// executable, regardless of the license terms of these independent28// modules, and to copy and distribute the resulting executable under29// terms of your choice, provided that you also meet, for each linked30// independent module, the terms and conditions of the license of that31// module.  An independent module is a module which is not derived from32// or based on this library.  If you modify this library, you may extend33// this exception to your version of the library, but you are not34// obligated to do so.  If you do not wish to do so, delete this35// exception statement from your version.3637using System;38using System.IO;3940namespace ICSharpCode.SharpZipLib.Zip41{42  // TODO: Sort out wether tagged data is useful and what a good implementation might look like.43  // Its just a sketch of an idea at the moment.4445  /// <summary>46  /// ExtraData tagged value interface.47  /// </summary>48  public interface ITaggedData49  {1using System;2using System.IO;34namespace ICSharpCode.SharpZipLib.Zip5{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.89  /// <summary>10  /// ExtraData tagged value interface.11  /// </summary>12  public interface ITaggedData13  {14    /// <summary>15    /// Get the ID for this tagged data value.16    /// </summary>17    short TagID { get; }1819    /// <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);2627    /// <summary>28    /// Get the data representing this instance.29    /// </summary>30    /// <returns>Returns the data for this instance.</returns>31    byte[] GetData();32  }3334  /// <summary>35  /// A raw binary tagged value36  /// </summary>37  public class RawTaggedData : ITaggedData38  {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    }4748    #region ITaggedData Members49  50    /// <summary>  51    /// Get the ID for this tagged data value.  52    /// </summary>53    short TagID { get; }5455    /// <summary>56    /// Set the contents of this instance from the data passed.57    /// </summary>58    /// <param name="data">The data to extract contents from.</param>59    /// <param name="offset">The offset to begin extracting data from.</param>60    /// <param name="count">The number of bytes to extract.</param>61    void SetData(byte[] data, int offset, int count);6263    /// <summary>64    /// Get the data representing this instance.65    /// </summary>66    /// <returns>Returns the data for this instance.</returns>67    byte[] GetData();68  }53    public short TagID {54      get { return _tag; }55      set { _tag = value; }56    }5758    /// <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      }  6970  /// <summary>71  /// A raw binary tagged value72  /// </summary>73  public class RawTaggedData : ITaggedData74  {75    /// <summary>76    /// Initialise a new instance.77    /// </summary>78    /// <param name="tag">The tag ID.</param>79    public RawTaggedData(short tag)80    {81      _tag = tag;82    }8384    #region ITaggedData Members8586    /// <summary>87    /// Get the ID for this tagged data value.88    /// </summary>89    public short TagID90    {91      get { return _tag; }92      set { _tag = value; }93    }9470      _data = new byte[count];71      Array.Copy(data, offset, _data, 0, count);72    }7374    /// <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    }8283    #endregion8485    /// <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    }9394    #region Instance Fields  95    /// <summary>96    /// Set the data from the raw values provided.96    /// The tag ID for this instance.  97    /// </summary>98    /// <param name="data">The raw data to extract values from.</param>99    /// <param name="offset">The index to start extracting values from.</param>100    /// <param name="count">The number of bytes available.</param>101    public void SetData(byte[] data, int offset, int count)102    {103      if( data==null )104      {105        throw new ArgumentNullException(nameof(data));106      }107108      _data=new byte[count];109      Array.Copy(data, offset, _data, 0, count);110    }111112    /// <summary>113    /// Get the binary data representing this instance.114    /// </summary>115    /// <returns>The raw binary data representing this instance.</returns>116    public byte[] GetData()117    {118      return _data;119    }120121    #endregion122123    /// <summary>124    /// Get /set the binary data representing this instance.125    /// </summary>126    /// <returns>The raw binary data representing this instance.</returns>127    public byte[] Data128    {129      get { return _data; }130      set { _data=value; }131    }98    short _tag;99100    byte[] _data;101    #endregion102  }103104  /// <summary>105  /// Class representing extended unix date time values.106  /// </summary>107  public class ExtendedUnixData : ITaggedData108  {109    /// <summary>110    /// Flags indicate which values are included in this instance.111    /// </summary>112    [Flags]113    public enum Flags : byte114    {115      /// <summary>116      /// The modification time is included117      /// </summary>118      ModificationTime = 0x01,119120      /// <summary>121      /// The access time is included122      /// </summary>123      AccessTime = 0x02,124125      /// <summary>126      /// The create time is included.127      /// </summary>128      CreateTime = 0x04,129    }130131    #region ITaggedData Members  132133    #region Instance Fields134    /// <summary>135    /// The tag ID for this instance.136    /// </summary>137    short _tag;138139    byte[] _data;140    #endregion141  }142143  /// <summary>144  /// Class representing extended unix date time values.145  /// </summary>146  public class ExtendedUnixData : ITaggedData147  {148    /// <summary>149    /// Flags indicate which values are included in this instance.150    /// </summary>151    [Flags]152    public enum Flags : byte153    {154      /// <summary>155      /// The modification time is included156      /// </summary>157      ModificationTime = 0x01,133    /// <summary>134    /// Get the ID135    /// </summary>136    public short TagID {137      get { return 0x5455; }138    }139140    /// <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 present151        // bit 1           if set, access time is present152        // bit 2           if set, creation time is present153154        _flags = (Flags)helperStream.ReadByte();155        if (((_flags & Flags.ModificationTime) != 0))156        {157          int iTime = helperStream.ReadLEInt();  158159      /// <summary>160      /// The access time is included161      /// </summary>162      AccessTime = 0x02,163164      /// <summary>165      /// The create time is included.166      /// </summary>167      CreateTime = 0x04,168    }169170    #region ITaggedData Members171172    /// <summary>173    /// Get the ID174    /// </summary>175    public short TagID176    {177      get { return 0x5455; }178    }179180    /// <summary>181    /// Set the data from the raw values provided.182    /// </summary>183    /// <param name="data">The raw data to extract values from.</param>184    /// <param name="index">The index to start extracting values from.</param>185    /// <param name="count">The number of bytes available.</param>186    public void SetData(byte[] data, int index, int count)159          _modificationTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +160            new TimeSpan(0, 0, 0, iTime, 0);161162          // Central-header version is truncated after modification time163          if (count <= 5) return;164        }165166        if ((_flags & Flags.AccessTime) != 0) {167          int iTime = helperStream.ReadLEInt();168169          _lastAccessTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +170            new TimeSpan(0, 0, 0, iTime, 0);171        }172173        if ((_flags & Flags.CreateTime) != 0) {174          int iTime = helperStream.ReadLEInt();175176          _createTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +177            new TimeSpan(0, 0, 0, iTime, 0);178        }179      }180    }181182    /// <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(data, index, count, false))189      using (ZipHelperStream helperStream = new ZipHelperStream(ms))190      {191        // bit 0           if set, modification time is present192        // bit 1           if set, access time is present193        // bit 2           if set, creation time is present194195        _flags = (Flags)helperStream.ReadByte();196        if (((_flags & Flags.ModificationTime) != 0) && (count >= 5))197        {198          int iTime = helperStream.ReadLEInt();199200          _modificationTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +201            new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();202        }203204        if ((_flags & Flags.AccessTime) != 0)205        {206          int iTime = helperStream.ReadLEInt();207208          _lastAccessTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +209            new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();210        }211212        if ((_flags & Flags.CreateTime) != 0)213        {214          int iTime = helperStream.ReadLEInt();215216          _createTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +217            new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();218        }219      }220    }221222    /// <summary>223    /// Get the binary data representing this instance.224    /// </summary>225    /// <returns>The raw binary data representing this instance.</returns>226    public byte[] GetData()227    {228      using (MemoryStream ms = new MemoryStream())229      using (ZipHelperStream helperStream = new ZipHelperStream(ms))230      {231        helperStream.IsStreamOwner = false;232        helperStream.WriteByte((byte)_flags);     // Flags233        if ( (_flags & Flags.ModificationTime) != 0) {234          TimeSpan span = _modificationTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();235          var seconds = (int)span.TotalSeconds;236          helperStream.WriteLEInt(seconds);237        }238        if ( (_flags & Flags.AccessTime) != 0) {239          TimeSpan span = _lastAccessTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();240          var seconds = (int)span.TotalSeconds;241          helperStream.WriteLEInt(seconds);242        }243        if ( (_flags & Flags.CreateTime) != 0) {244          TimeSpan span = _createTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();245          var seconds = (int)span.TotalSeconds;246          helperStream.WriteLEInt(seconds);247        }248        return ms.ToArray();249      }250    }251252    #endregion253254    /// <summary>255    /// Test a <see cref="DateTime"> value to see if is valid and can be represented here.</see>256    /// </summary>257    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>258    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>259    /// <remarks>The standard Unix time is a signed integer data type, directly encoding the Unix time number,260    /// which is the number of seconds since 1970-01-01.261    /// Being 32 bits means the values here cover a range of about 136 years.262    /// The minimum representable time is 1901-12-13 20:45:52,263    /// and the maximum representable time is 2038-01-19 03:14:07.264    /// </remarks>265    public static bool IsValidValue(DateTime value)266    {267      return (( value >= new DateTime(1901, 12, 13, 20, 45, 52)) ||268          ( value <= new DateTime(2038, 1, 19, 03, 14, 07) ));269    }270271    /// <summary>272    /// Get /set the Modification Time273    /// </summary>274    /// <exception cref="ArgumentOutOfRangeException"></exception>275    /// <seealso cref="IsValidValue"></seealso>276    public DateTime ModificationTime277    {278      get { return _modificationTime; }279      set280      {281        if ( !IsValidValue(value) ) {282          throw new ArgumentOutOfRangeException(nameof(value));283        }284285        _flags |= Flags.ModificationTime;286        _modificationTime=value;287      }188      using (MemoryStream ms = new MemoryStream())189      using (ZipHelperStream helperStream = new ZipHelperStream(ms)) {190        helperStream.IsStreamOwner = false;191        helperStream.WriteByte((byte)_flags);     // Flags192        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    }210211    #endregion212213    /// <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    }229230    /// <summary>231    /// Get /set the Modification Time232    /// </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        }241242        _flags |= Flags.ModificationTime;243        _modificationTime = value;244      }245    }246247    /// <summary>248    /// Get / set the Access Time249    /// </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        }258259        _flags |= Flags.AccessTime;260        _lastAccessTime = value;261      }262    }263264    /// <summary>265    /// Get / Set the Create Time266    /// </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        }275276        _flags |= Flags.CreateTime;277        _createTime = value;278      }279    }280281    /// <summary>282    /// Get/set the <see cref="Flags">values</see> to include.283    /// </summary>284    public Flags Include285    {286      get { return _flags; }287      set { _flags = value; }  288    }  289290    /// <summary>291    /// Get / set the Access Time292    /// </summary>293    /// <exception cref="ArgumentOutOfRangeException"></exception>294    /// <seealso cref="IsValidValue"></seealso>295    public DateTime AccessTime296    {297      get { return _lastAccessTime; }298      set {299        if ( !IsValidValue(value) ) {300          throw new ArgumentOutOfRangeException(nameof(value));301        }302303        _flags |= Flags.AccessTime;304        _lastAccessTime=value;305      }306    }307308    /// <summary>309    /// Get / Set the Create Time310    /// </summary>311    /// <exception cref="ArgumentOutOfRangeException"></exception>312    /// <seealso cref="IsValidValue"></seealso>313    public DateTime CreateTime314    {315      get { return _createTime; }316      set {317        if ( !IsValidValue(value) ) {318          throw new ArgumentOutOfRangeException(nameof(value));319        }320321        _flags |= Flags.CreateTime;322        _createTime=value;323      }324    }325326    /// <summary>327    /// Get/set the <see cref="Flags">values</see> to include.328    /// </summary>329    Flags Include330    {331      get { return _flags; }332      set { _flags = value; }333    }334335    #region Instance Fields336    Flags _flags;337    DateTime _modificationTime = new DateTime(1970,1,1);338    DateTime _lastAccessTime = new DateTime(1970, 1, 1);339    DateTime _createTime = new DateTime(1970, 1, 1);340    #endregion341  }342343  /// <summary>344  /// Class handling NT date time values.345  /// </summary>346  public class NTTaggedData : ITaggedData347  {348    /// <summary>349    /// Get the ID for this tagged data value.350    /// </summary>351    public short TagID352    {353      get { return 10; }354    }355356    /// <summary>357    /// Set the data from the raw values provided.358    /// </summary>359    /// <param name="data">The raw data to extract values from.</param>360    /// <param name="index">The index to start extracting values from.</param>361    /// <param name="count">The number of bytes available.</param>362    public void SetData(byte[] data, int index, int count)363    {364      using (MemoryStream ms = new MemoryStream(data, index, count, false))365      using (ZipHelperStream helperStream = new ZipHelperStream(ms))366      {367        helperStream.ReadLEInt(); // Reserved368        while (helperStream.Position < helperStream.Length)369        {370          int ntfsTag = helperStream.ReadLEShort();371          int ntfsLength = helperStream.ReadLEShort();372          if (ntfsTag == 1)373          {374            if (ntfsLength >= 24)375            {376              long lastModificationTicks = helperStream.ReadLELong();377              _lastModificationTime = DateTime.FromFileTime(lastModificationTicks);378379              long lastAccessTicks = helperStream.ReadLELong();380              _lastAccessTime = DateTime.FromFileTime(lastAccessTicks);381382              long createTimeTicks = helperStream.ReadLELong();383              _createTime = DateTime.FromFileTime(createTimeTicks);384            }385            break;386          }387          else388          {389            // An unknown NTFS tag so simply skip it.390            helperStream.Seek(ntfsLength, SeekOrigin.Current);391          }392        }393      }394    }395396    /// <summary>397    /// Get the binary data representing this instance.398    /// </summary>399    /// <returns>The raw binary data representing this instance.</returns>400    public byte[] GetData()401    {402      using (MemoryStream ms = new MemoryStream())403      using (ZipHelperStream helperStream = new ZipHelperStream(ms))404      {405        helperStream.IsStreamOwner = false;406        helperStream.WriteLEInt(0);       // Reserved407        helperStream.WriteLEShort(1);     // Tag408        helperStream.WriteLEShort(24);    // Length = 3 x 8.409        helperStream.WriteLELong(_lastModificationTime.ToFileTime());410        helperStream.WriteLELong(_lastAccessTime.ToFileTime());411        helperStream.WriteLELong(_createTime.ToFileTime());412        return ms.ToArray();413      }414    }415416    /// <summary>417    /// Test a <see cref="DateTime"> valuie to see if is valid and can be represented here.</see>418    /// </summary>419    /// <param name="value">The <see cref="DateTime">value</see> to test.</param>420    /// <returns>Returns true if the value is valid and can be represented; false if not.</returns>421    /// <remarks>422    /// NTFS filetimes are 64-bit unsigned integers, stored in Intel423    /// (least significant byte first) byte order. They determine the424    /// number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",425    /// which is "01-Jan-1601 00:00:00 UTC". 28 May 60056 is the upper limit426    /// </remarks>427    public static bool IsValidValue(DateTime value)428    {429      bool result = true;430      try431      {432        value.ToFileTimeUtc();433      }434      catch435      {436        result = false;437      }438      return result;439    }440441    /// <summary>442    /// Get/set the <see cref="DateTime">last modification time</see>.443    /// </summary>444    public DateTime LastModificationTime445    {446      get { return _lastModificationTime; }447      set {448        if (! IsValidValue(value))449        {450          throw new ArgumentOutOfRangeException(nameof(value));451        }452        _lastModificationTime = value;453      }454    }455456    /// <summary>457    /// Get /set the <see cref="DateTime">create time</see>458    /// </summary>459    public DateTime CreateTime460    {461      get { return _createTime; }462      set {463        if ( !IsValidValue(value)) {464          throw new ArgumentOutOfRangeException(nameof(value));465        }466        _createTime = value;467      }468    }469470    /// <summary>471    /// Get /set the <see cref="DateTime">last access time</see>.472    /// </summary>473    public DateTime LastAccessTime290    #region Instance Fields291    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    #endregion296  }297298  /// <summary>299  /// Class handling NT date time values.300  /// </summary>301  public class NTTaggedData : ITaggedData302  {303    /// <summary>304    /// Get the ID for this tagged data value.305    /// </summary>306    public short TagID {307      get { return 10; }308    }309310    /// <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(); // Reserved321        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);328329              long lastAccessTicks = helperStream.ReadLELong();330              _lastAccessTime = DateTime.FromFileTimeUtc(lastAccessTicks);331332              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    }343344    /// <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);       // Reserved354        helperStream.WriteLEShort(1);     // Tag355        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    }362363    /// <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 Intel370    /// (least significant byte first) byte order. They determine the371    /// 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 limit373    /// </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    }384385    /// <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    }397398    /// <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    }410411    /// <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    }423424    #region Instance Fields425    DateTime _lastAccessTime = DateTime.FromFileTimeUtc(0);426    DateTime _lastModificationTime = DateTime.FromFileTimeUtc(0);427    DateTime _createTime = DateTime.FromFileTimeUtc(0);428    #endregion429  }430431  /// <summary>432  /// A factory that creates <see cref="ITaggedData">tagged data</see> instances.433  /// </summary>434  interface ITaggedDataFactory435  {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  }446447  ///448  /// <summary>449  /// A class to handle the extra data field for Zip entries450  /// </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 but455  /// means that for extra data created by passing in data can have the values modified by the caller456  /// in some circumstances.457  /// </remarks>458  sealed public class ZipExtraData : IDisposable459  {460    #region Constructors461    /// <summary>462    /// Initialise a default instance.463    /// </summary> + 5464    public ZipExtraData()465    { + 5466      Clear(); + 5467    }468469    /// <summary>470    /// Initialise with known extra data.471    /// </summary>472    /// <param name="data">The extra data.</param> + 329692473    public ZipExtraData(byte[] data)  474    {475      get { return _lastAccessTime; }476      set {477        if (!IsValidValue(value)) {478          throw new ArgumentOutOfRangeException(nameof(value));479        }480        _lastAccessTime = value;481      }482    }483484    #region Instance Fields485    DateTime _lastAccessTime = DateTime.FromFileTime(0);486    DateTime _lastModificationTime = DateTime.FromFileTime(0);487    DateTime _createTime = DateTime.FromFileTime(0);488    #endregion489  }490491  /// <summary>492  /// A factory that creates <see cref="ITaggedData">tagged data</see> instances.493  /// </summary>494  interface ITaggedDataFactory495  { + 329692475       if (data == null) { + 131944476        _data = new byte[0]; + 131944477      } else { + 197748478        _data = data;479      } + 197748480    }481    #endregion482483    /// <summary>484    /// Get the raw extra data value485    /// </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    /// Get data for a specific tag value.497    /// Clear the stored data.  498    /// </summary>499    /// <param name="tag">The tag ID to find.</param>500    /// <param name="data">The data to search.</param>501    /// <param name="offset">The offset to begin extracting data from.</param>502    /// <param name="count">The number of bytes to extract.</param>503    /// <returns>The located <see cref="ITaggedData">value found</see>, or null if not found.</returns>504    ITaggedData Create(short tag, byte[] data, int offset, int count);505  }506507  ///508  /// <summary>509  /// A class to handle the extra data field for Zip entries510  /// </summary>511  /// <remarks>512  /// Extra data contains 0 or more values each prefixed by a header tag and length.513  /// They contain zero or more bytes of actual data.514  /// The data is held internally using a copy on write strategy.  This is more efficient but515  /// means that for extra data created by passing in data can have the values modified by the caller516  /// in some circumstances.517  /// </remarks>518  sealed public class ZipExtraData : IDisposable519  {520    #region Constructors521    /// <summary>522    /// Initialise a default instance.523    /// </summary> - 6524    public ZipExtraData()525    { - 6526      Clear(); - 6527    }528529    /// <summary>530    /// Initialise with known extra data.531    /// </summary>532    /// <param name="data">The extra data.</param> - 329702533    public ZipExtraData(byte[] data)499    public void Clear()500    { + 5501       if ((_data == null) || (_data.Length != 0)) { + 5502        _data = new byte[0];503      } + 5504    }505506    /// <summary>507    /// Gets the current extra data length.508    /// </summary>509    public int Length { + 131811510      get { return _data.Length; }511    }512513    /// <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    }526527    /// <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    { - 329702535       if ( data == null )536      { - 131948537        _data = new byte[0]; - 131948538      }539      else540      { - 197754541        _data = data;542      } - 197754543    }544    #endregion545546    /// <summary>547    /// Get the raw extra data value548    /// </summary>549    /// <returns>Returns the raw byte[] extra data this instance represents.</returns>550    public byte[] GetEntryData()551    { - 131795552       if ( Length > ushort.MaxValue ) { - 0553        throw new ZipException("Data exceeds maximum length");554      }555 - 131795556      return (byte[])_data.Clone();557    }558559    /// <summary>560    /// Clear the stored data.561    /// </summary>562    public void Clear()563    { - 6564       if ( (_data == null) || (_data.Length != 0) ) { - 6565        _data = new byte[0];566      } - 6567    }568569    /// <summary>570    /// Gets the current extra data length.571    /// </summary>572    public int Length573    { - 131818574      get { return _data.Length; }575    }576577    /// <summary>578    /// Get a read-only <see cref="Stream"/> for the associated tag.579    /// </summary>580    /// <param name="tag">The tag to locate data for.</param>581    /// <returns>Returns a <see cref="Stream"/> containing tag data or null if no tag was found.</returns>582    public Stream GetStreamForTag(int tag)583    { - 4584      Stream result = null; - 4585       if ( Find(tag) ) { - 4586        result = new MemoryStream(_data, _index, _readValueLength, false);587      } - 4588      return result;589    }590591    /// <summary>592    /// Get the <see cref="ITaggedData">tagged data</see> for a tag.593    /// </summary>594    /// <param name="tag">The tag to search for.</param>595    /// <returns>Returns a <see cref="ITaggedData">tagged value</see> or null if none found.</returns>596    private ITaggedData GetData(short tag)597    { - 0598      ITaggedData result = null; - 0599       if (Find(tag))600      { - 0601        result = Create(tag, _data, _readValueStart, _readValueLength);602      } - 0603      return result;604    }605606    static ITaggedData Create(short tag, byte[] data, int offset, int count)607    { - 0608      ITaggedData result = null; - 0609       switch ( tag )610      {611        case 0x000A: - 0612          result = new NTTaggedData(); - 0613          break;614        case 0x5455: - 0615          result = new ExtendedUnixData(); - 0616          break;617        default: - 0618          result = new RawTaggedData(tag);619          break;620      } - 0621      result.SetData(data, offset, count); - 0622      return result;623    }624625    /// <summary>626    /// Get the length of the last value found by <see cref="Find"/>627    /// </summary>628    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.</remarks>629    public int ValueLength630    { - 151631      get { return _readValueLength; }632    } + 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    }543544    /// <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    }551552    /// <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 to557    /// <see cref="ReadInt"/>, <see cref="ReadShort"/> and <see cref="ReadLong"/>. </remarks>558    public int CurrentReadIndex { + 101559      get { return _index; }560    }561562    /// <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    }575576    /// <summary>577    /// Find an extra data value578    /// </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;589590      // Trailing bytes that cant make up an entry (as there arent enough591      // 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    }609610    /// <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    }621622    /// <summary>623    /// Add a new entry to extra data624    /// </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      }  633634    /// <summary>635    /// Get the index for the current read value.636    /// </summary>637    /// <remarks>This is only valid if <see cref="Find"/> has previously returned true.638    /// Initially the result will be the index of the first byte of actual data.  The value is updated after calls to639    /// <see cref="ReadInt"/>, <see cref="ReadShort"/> and <see cref="ReadLong"/>. </remarks>640    public int CurrentReadIndex641    { - 103642      get { return _index; }643    }644645    /// <summary>646    /// Get the number of bytes remaining to be read for the current value;647    /// </summary>648    public int UnreadCount649    {650      get651      { - 16652         if ((_readValueStart > _data.Length) || - 16653          (_readValueStart < 4) ) { - 0654          throw new ZipException("Find must be called before calling a Read method");655        }656 - 16657        return _readValueStart + _readValueLength - _index;658      }659    }660661    /// <summary>662    /// Find an extra data value663    /// </summary>664    /// <param name="headerID">The identifier for the value to find.</param>665    /// <returns>Returns true if the value was found; false otherwise.</returns>666    public bool Find(int headerID)667    { - 462202668      _readValueStart = _data.Length; - 462202669      _readValueLength = 0; - 462202670      _index = 0;671 - 462202672      int localLength = _readValueStart; - 462202673      int localTag = headerID - 1; + 261634      int addLength = (fieldData == null) ? 0 : fieldData.Length;635 + 261636       if (addLength > ushort.MaxValue) { + 0637        throw new ArgumentOutOfRangeException(nameof(fieldData), "exceeds maximum length");638      }639640      // 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    }663664    /// <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 <see668    /// 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    }  674675      // Trailing bytes that cant make up an entry (as there arent enough676      // bytes for a tag and length) are ignored! - 462825677       while ( (localTag != headerID) && (_index < _data.Length - 3) ) { - 623678        localTag = ReadShortInternal(); - 623679        localLength = ReadShortInternal(); - 623680         if ( localTag != headerID ) { - 285681          _index += localLength;682        }683      }684 - 462202685      bool result = (localTag == headerID) && ((_index + localLength) <= _data.Length);686 - 462202687       if ( result ) { - 338688        _readValueStart = _index; - 338689        _readValueLength = localLength;690      }691 - 462202692      return result;693    }694695    /// <summary>696    /// Add a new entry to extra data.697    /// </summary>698    /// <param name="taggedData">The <see cref="ITaggedData"/> value to add.</param>699    public void AddEntry(ITaggedData taggedData)700    { - 0701       if (taggedData == null)702      { - 0703        throw new ArgumentNullException(nameof(taggedData));704      } - 0705      AddEntry(taggedData.TagID, taggedData.GetData()); - 0706    }707708    /// <summary>709    /// Add a new entry to extra data710    /// </summary>711    /// <param name="headerID">The ID for this entry.</param>712    /// <param name="fieldData">The data to add.</param>713    /// <remarks>If the ID already exists its contents are replaced.</remarks>714    public void AddEntry(int headerID, byte[] fieldData)715    { - 268716       if ( (headerID > ushort.MaxValue) || (headerID < 0)) { - 0717        throw new ArgumentOutOfRangeException(nameof(headerID));718      }719 - 268720      int addLength = (fieldData == null) ? 0 : fieldData.Length;721 - 268722       if ( addLength > ushort.MaxValue ) {723#if NETCF_1_0724        throw new ArgumentOutOfRangeException("fieldData");725#else - 0726        throw new ArgumentOutOfRangeException(nameof(fieldData), "exceeds maximum length");727#endif728      }729730      // Test for new length before adjusting data. - 268731      int newLength = _data.Length + addLength + 4;732 - 268733       if ( Find(headerID) )734      { - 4735        newLength -= (ValueLength + 4);736      }737 - 268738       if ( newLength > ushort.MaxValue ) { - 2739        throw new ZipException("Data exceeds maximum length");740      }741 - 266742      Delete(headerID);743 - 266744      byte[] newData = new byte[newLength]; - 266745      _data.CopyTo(newData, 0); - 266746      int index = _data.Length; - 266747      _data = newData; - 266748      SetShort(ref index, headerID); - 266749      SetShort(ref index, addLength); - 266750       if ( fieldData != null ) { - 264751        fieldData.CopyTo(newData, index);752      } - 266753    }754755    /// <summary>756    /// Start adding a new entry.757    /// </summary>758    /// <remarks>Add data using <see cref="AddData(byte[])"/>, <see cref="AddLeShort"/>, <see cref="AddLeInt"/>, or <see759    /// The new entry is completed and actually added by calling <see cref="AddNewEntry"/></remarks>760    /// <seealso cref="AddEntry(ITaggedData)"/>761    public void StartNewEntry()762    { - 256763      _newEntry = new MemoryStream(); - 256764    }765766    /// <summary>767    /// Add entry data added since <see cref="StartNewEntry"/> using the ID passed.768    /// </summary>769    /// <param name="headerID">The identifier to use for this entry.</param>770    public void AddNewEntry(int headerID)771    { - 256772      byte[] newData = _newEntry.ToArray(); - 256773      _newEntry = null; - 256774      AddEntry(headerID, newData); - 256775    }776777    /// <summary>778    /// Add a byte of data to the pending new entry.779    /// </summary>780    /// <param name="data">The byte to add.</param>781    /// <seealso cref="StartNewEntry"/>782    public void AddData(byte data)783    { - 2784      _newEntry.WriteByte(data); - 2785    }786787    /// <summary>788    /// Add data to a pending new entry.789    /// </summary>790    /// <param name="data">The data to add.</param>791    /// <seealso cref="StartNewEntry"/>792    public void AddData(byte[] data)793    { - 0794       if ( data == null ) { - 0795        throw new ArgumentNullException(nameof(data));796      }797 - 0798      _newEntry.Write(data, 0, data.Length); - 0799    }800801    /// <summary>802    /// Add a short value in little endian order to the pending new entry.803    /// </summary>804    /// <param name="toAdd">The data to add.</param>805    /// <seealso cref="StartNewEntry"/>806    public void AddLeShort(int toAdd)807    {808      unchecked { - 2054809        _newEntry.WriteByte(( byte )toAdd); - 2054810        _newEntry.WriteByte(( byte )(toAdd >> 8));811      } - 2054812    }813814    /// <summary>815    /// Add an integer value in little endian order to the pending new entry.816    /// </summary>817    /// <param name="toAdd">The data to add.</param>818    /// <seealso cref="StartNewEntry"/>819    public void AddLeInt(int toAdd)820    {821      unchecked { - 1027822        AddLeShort(( short )toAdd); - 1027823        AddLeShort(( short )(toAdd >> 16));824      } - 1027825    }826827    /// <summary>828    /// Add a long value in little endian order to the pending new entry.829    /// </summary>830    /// <param name="toAdd">The data to add.</param>831    /// <seealso cref="StartNewEntry"/>832    public void AddLeLong(long toAdd)833    {834      unchecked { - 513835        AddLeInt(( int )(toAdd & 0xffffffff)); - 513836        AddLeInt(( int )(toAdd >> 32));837      } - 513838    }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    }685686    /// <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    }695696    /// <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    }709710    /// <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    }722723    /// <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    }735736    /// <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    }748749    /// <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    }771772    #region Reading Support773    /// <summary>774    /// Read a long in little endian form from the last <see cref="Find">found</see> data value775    /// </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    }782783    /// <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    }796797    /// <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    }808809    /// <summary>810    /// Read a byte from an extra data811    /// </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    }822823    /// <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    }832833    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      }  839840    /// <summary>841    /// Delete an extra data field.842    /// </summary>843    /// <param name="headerID">The identifier of the field to delete.</param>844    /// <returns>Returns true if the field was found and deleted.</returns>845    public bool Delete(int headerID)846    { - 131798847      bool result = false; + 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 - 131798849       if ( Find(headerID) ) { - 6850        result = true; - 6851        int trueStart = _readValueStart - 4;852 - 6853        byte[] newData = new byte[_data.Length - (ValueLength + 4)]; - 6854        Array.Copy(_data, 0, newData, 0, trueStart);855 - 6856        int trueEnd = trueStart + ValueLength + 4; - 6857        Array.Copy(_data, trueEnd, newData, trueStart, _data.Length - trueEnd); - 6858        _data = newData;859      } - 131798860      return result;861    }862863    #region Reading Support864    /// <summary>865    /// Read a long in little endian form from the last <see cref="Find">found</see> data value866    /// </summary>867    /// <returns>Returns the long value read.</returns>868    public long ReadLong()869    { - 365870      ReadCheck(8); - 362871      return (ReadInt() & 0xffffffff) | ((( long )ReadInt()) << 32);872    }873874    /// <summary>875    /// Read an integer in little endian form from the last <see cref="Find">found</see> data value.876    /// </summary>877    /// <returns>Returns the integer read.</returns>878    public int ReadInt()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    }863864    void SetShort(ref int index, int source)865    { + 518866      _data[index] = (byte)source; + 518867      _data[index + 1] = (byte)(source >> 8); + 518868      index += 2; + 518869    }870871    #endregion872873    #region IDisposable Members874875    /// <summary>876    /// Dispose of this instance.877    /// </summary>878    public void Dispose()  879    { - 729880      ReadCheck(4);881 - 726882      int result = _data[_index] + (_data[_index + 1] << 8) + - 726883        (_data[_index + 2] << 16) + (_data[_index + 3] << 24); - 726884      _index += 4; - 726885      return result;886    }887888    /// <summary>889    /// Read a short value in little endian form from the last <see cref="Find">found</see> data value.890    /// </summary>891    /// <returns>Returns the short value read.</returns>892    public int ReadShort()893    { - 4894      ReadCheck(2); - 1895      int result = _data[_index] + (_data[_index + 1] << 8); - 1896      _index += 2; - 1897      return result;898    }899900    /// <summary>901    /// Read a byte from an extra data902    /// </summary>903    /// <returns>The byte value read or -1 if the end of data has been reached.</returns>904    public int ReadByte()905    { - 27906      int result = -1; - 27907       if ( (_index < _data.Length) && (_readValueStart + _readValueLength > _index) ) { - 20908        result = _data[_index]; - 20909        _index += 1;910      } - 27911      return result;912    }913914    /// <summary>915    /// Skip data during reading.916    /// </summary>917    /// <param name="amount">The number of bytes to skip.</param>918    public void Skip(int amount)919    { - 6920      ReadCheck(amount); - 4921      _index += amount; - 4922    }923924    void ReadCheck(int length)925    { - 1104926       if ((_readValueStart > _data.Length) || - 1104927        (_readValueStart < 4) ) { - 0928        throw new ZipException("Find must be called before calling a Read method");929      }930 - 1104931       if (_index > _readValueStart + _readValueLength - length ) { - 10932        throw new ZipException("End of extra data");933      }934 - 1094935             if ( _index + length < 4 ) { - 1936                throw new ZipException("Cannot read before start of tag");937            } - 1093938    }939940    /// <summary>941    /// Internal form of <see cref="ReadShort"/> that reads data at any location.942    /// </summary>943    /// <returns>Returns the short value read.</returns>944    int ReadShortInternal()945    { - 1246946       if ( _index > _data.Length - 2) { - 0947        throw new ZipException("End of extra data");948      }949 - 1246950      int result = _data[_index] + (_data[_index + 1] << 8); - 1246951      _index += 2; - 1246952      return result;953    }954955    void SetShort(ref int index, int source)956    { - 532957      _data[index] = (byte)source; - 532958      _data[index + 1] = (byte)(source >> 8); - 532959      index += 2; - 532960    }961962    #endregion963964    #region IDisposable Members965966    /// <summary>967    /// Dispose of this instance.968    /// </summary>969    public void Dispose()970    { - 0971       if ( _newEntry != null ) { - 0972        _newEntry.Close();973      } - 0974    }975976    #endregion977978    #region Instance Fields979    int _index;980    int _readValueStart;981    int _readValueLength;982983    MemoryStream _newEntry;984    byte[] _data;985    #endregion986  }987} + 0880       if (_newEntry != null) { + 0881        _newEntry.Close();882      } + 0883    }884885    #endregion886887    #region Instance Fields888    int _index;889    int _readValueStart;890    int _readValueLength;891892    MemoryStream _newEntry;893    byte[] _data;894    #endregion895  }896} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipFile.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipFile.htm index 283c482f9..cba4fbe77 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipFile.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipFile.htm @@ -15,12 +15,12 @@

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:958 -Uncovered lines:360 -Coverable lines:1318 -Total lines:4476 -Line coverage:72.6% -Branch coverage:58.4% +Covered lines:953 +Uncovered lines:356 +Coverable lines:1309 +Total lines:4263 +Line coverage:72.8% +Branch coverage:58.6%

Metrics

@@ -43,7 +43,7 @@

Metrics

GetInputStream(...)678.5772.73 TestArchive(...)1100100 TestArchive(...)2553.6260 -TestLocalHeader(...)7165.9653.96 +TestLocalHeader(...)7465.9655.24 BeginUpdate(...)987.1063.64 BeginUpdate(...)1100100 BeginUpdate()2100100 @@ -133,7 +133,7 @@

Metrics

.ctor(...)1100100 ReadByte()383.3366.67 Close()1100100 -Read(...)510085.71 +Read(...)691.6777.78 Write(...)100 SetLength(...)100 Seek(...)661.5444.44 @@ -145,4484 +145,4271 @@

#LineLine coverage - 1// ZipFile.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  2009-12-22  Z-1649  Added AES support41//  2010-03-02  Z-1650  Fixed updating ODT archives in memory. Exposed exceptions in updating.42//  2010-05-25  Z-1663  Fixed exception when testing local header compressed size of -143//  2012-11-29  Z-1684  Fixed ZipFile.Add(string fileName, string entryName) losing the file TimeStamp4445using System;46using System.Collections;47using System.IO;48using System.Text;49using System.Globalization;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;1213namespace ICSharpCode.SharpZipLib.Zip14{15  #region Keys Required Event Args16  /// <summary>17  /// Arguments used with KeysRequiredEvent18  /// </summary>19  public class KeysRequiredEventArgs : EventArgs20  {21    #region Constructors22    /// <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    }3031    /// <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    }4142    #endregion43    #region Properties44    /// <summary>45    /// Gets the name of the file for which keys are required.46    /// </summary>47    public string FileName {48      get { return fileName; }49    }  5051#if !NETCF_1_052using System.Security.Cryptography;53using ICSharpCode.SharpZipLib.Encryption;54#endif5556using ICSharpCode.SharpZipLib.Core;57using ICSharpCode.SharpZipLib.Checksums;58using ICSharpCode.SharpZipLib.Zip.Compression.Streams;59using ICSharpCode.SharpZipLib.Zip.Compression;6061namespace ICSharpCode.SharpZipLib.Zip62{63  #region Keys Required Event Args64  /// <summary>65  /// Arguments used with KeysRequiredEvent66  /// </summary>67  public class KeysRequiredEventArgs : EventArgs68  {69    #region Constructors70    /// <summary>71    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>72    /// </summary>73    /// <param name="name">The name of the file for which keys are required.</param>74    public KeysRequiredEventArgs(string name)75    {76      fileName = name;77    }7879    /// <summary>80    /// Initialise a new instance of <see cref="KeysRequiredEventArgs"></see>81    /// </summary>82    /// <param name="name">The name of the file for which keys are required.</param>83    /// <param name="keyValue">The current key value.</param>84    public KeysRequiredEventArgs(string name, byte[] keyValue)85    {86      fileName = name;87      key = keyValue;88    }8990    #endregion91    #region Properties92    /// <summary>93    /// Gets the name of the file for which keys are required.94    /// </summary>95    public string FileName96    {97      get { return fileName; }98    }99100    /// <summary>101    /// Gets or sets the key value102    /// </summary>103    public byte[] Key104    {105      get { return key; }106      set { key = value; }107    }108    #endregion109110    #region Instance Fields111    string fileName;112    byte[] key;113    #endregion114  }115  #endregion116117  #region Test Definitions118  /// <summary>119  /// The strategy to apply to testing.120  /// </summary>121  public enum TestStrategy122  {123    /// <summary>124    /// Find the first error only.125    /// </summary>126    FindFirstError,51    /// <summary>52    /// Gets or sets the key value53    /// </summary>54    public byte[] Key {55      get { return key; }56      set { key = value; }57    }58    #endregion5960    #region Instance Fields61    string fileName;62    byte[] key;63    #endregion64  }65  #endregion6667  #region Test Definitions68  /// <summary>69  /// The strategy to apply to testing.70  /// </summary>71  public enum TestStrategy72  {73    /// <summary>74    /// Find the first error only.75    /// </summary>76    FindFirstError,77    /// <summary>78    /// Find all possible errors.79    /// </summary>80    FindAllErrors,81  }8283  /// <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 TestOperation88  {89    /// <summary>90    /// Setting up testing.91    /// </summary>92    Initialising,9394    /// <summary>95    /// Testing an individual entries header96    /// </summary>97    EntryHeader,9899    /// <summary>100    /// Testing an individual entries data101    /// </summary>102    EntryData,103104    /// <summary>105    /// Testing an individual entry has completed.106    /// </summary>107    EntryComplete,108109    /// <summary>110    /// Running miscellaneous tests111    /// </summary>112    MiscellaneousTests,113114    /// <summary>115    /// Testing is complete116    /// </summary>117    Complete,118  }119120  /// <summary>121  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.122  /// </summary>123  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>124  public class TestStatus125  {126    #region Constructors  127    /// <summary>128    /// Find all possible errors.128    /// Initialise a new instance of <see cref="TestStatus"/>  129    /// </summary>130    FindAllErrors,131  }132133  /// <summary>134  /// The operation in progress reported by a <see cref="ZipTestResultHandler"/> during testing.135  /// </summary>136  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>137  public enum TestOperation138  {130    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>131    public TestStatus(ZipFile file)132    {133      file_ = file;134    }135    #endregion136137    #region Properties138  139    /// <summary>140    /// Setting up testing.140    /// Get the current <see cref="TestOperation"/> in progress.  141    /// </summary>142    Initialising,143144    /// <summary>145    /// Testing an individual entries header146    /// </summary>147    EntryHeader,148149    /// <summary>150    /// Testing an individual entries data151    /// </summary>152    EntryData,153154    /// <summary>155    /// Testing an individual entry has completed.156    /// </summary>157    EntryComplete,158159    /// <summary>160    /// Running miscellaneous tests161    /// </summary>162    MiscellaneousTests,163164    /// <summary>165    /// Testing is complete166    /// </summary>167    Complete,168  }169170  /// <summary>171  /// Status returned returned by <see cref="ZipTestResultHandler"/> during testing.172  /// </summary>173  /// <seealso cref="ZipFile.TestArchive(bool)">TestArchive</seealso>174  public class TestStatus175  {176    #region Constructors177    /// <summary>178    /// Initialise a new instance of <see cref="TestStatus"/>179    /// </summary>180    /// <param name="file">The <see cref="ZipFile"/> this status applies to.</param>181    public TestStatus(ZipFile file)182    {183      file_ = file;184    }185    #endregion186187    #region Properties142    public TestOperation Operation {143      get { return operation_; }144    }145146    /// <summary>147    /// Get the <see cref="ZipFile"/> this status is applicable to.148    /// </summary>149    public ZipFile File {150      get { return file_; }151    }152153    /// <summary>154    /// Get the current/last entry tested.155    /// </summary>156    public ZipEntry Entry {157      get { return entry_; }158    }159160    /// <summary>161    /// Get the number of errors detected so far.162    /// </summary>163    public int ErrorCount {164      get { return errorCount_; }165    }166167    /// <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    }173174    /// <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    #endregion181182    #region Internal API183    internal void AddError()184    {185      errorCount_++;186      entryValid_ = false;187    }  188189    /// <summary>190    /// Get the current <see cref="TestOperation"/> in progress.191    /// </summary>192    public TestOperation Operation193    {194      get { return operation_; }195    }196197    /// <summary>198    /// Get the <see cref="ZipFile"/> this status is applicable to.199    /// </summary>200    public ZipFile File201    {202      get { return file_; }203    }204205    /// <summary>206    /// Get the current/last entry tested.207    /// </summary>208    public ZipEntry Entry209    {210      get { return entry_; }211    }212213    /// <summary>214    /// Get the number of errors detected so far.215    /// </summary>216    public int ErrorCount217    {218      get { return errorCount_; }219    }220221    /// <summary>222    /// Get the number of bytes tested so far for the current entry.223    /// </summary>224    public long BytesTested225    {226      get { return bytesTested_; }227    }228229    /// <summary>230    /// Get a value indicating wether the last entry test was valid.231    /// </summary>232    public bool EntryValid233    {234      get { return entryValid_; }235    }236    #endregion237238    #region Internal API239    internal void AddError()240    {241      errorCount_++;242      entryValid_ = false;243    }244245    internal void SetOperation(TestOperation operation)246    {247      operation_ = operation;248    }249250    internal void SetEntry(ZipEntry entry)251    {252      entry_ = entry;253      entryValid_ = true;254      bytesTested_ = 0;255    }256257    internal void SetBytesTested(long value)258    {259      bytesTested_ = value;260    }261    #endregion262263    #region Instance Fields264    ZipFile file_;265    ZipEntry entry_;266    bool entryValid_;267    int errorCount_;268    long bytesTested_;269    TestOperation operation_;270    #endregion271  }272273  /// <summary>274  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if275  /// </summary>276  /// <remarks>If the message is non-null an error has occured.  If the message is null277  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>278  public delegate void ZipTestResultHandler(TestStatus status, string message);279  #endregion280281  #region Update Definitions282  /// <summary>283  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.284  /// </summary>285  public enum FileUpdateMode286  {287    /// <summary>288    /// Perform all updates on temporary files ensuring that the original file is saved.289    /// </summary>290    Safe,291    /// <summary>292    /// Update the archive directly, which is faster but less safe.293    /// </summary>294    Direct,295  }296  #endregion189    internal void SetOperation(TestOperation operation)190    {191      operation_ = operation;192    }193194    internal void SetEntry(ZipEntry entry)195    {196      entry_ = entry;197      entryValid_ = true;198      bytesTested_ = 0;199    }200201    internal void SetBytesTested(long value)202    {203      bytesTested_ = value;204    }205    #endregion206207    #region Instance Fields208    ZipFile file_;209    ZipEntry entry_;210    bool entryValid_;211    int errorCount_;212    long bytesTested_;213    TestOperation operation_;214    #endregion215  }216217  /// <summary>218  /// Delegate invoked during <see cref="ZipFile.TestArchive(bool, TestStrategy, ZipTestResultHandler)">testing</see> if219  /// </summary>220  /// <remarks>If the message is non-null an error has occured.  If the message is null221  /// the operation as found in <see cref="TestStatus">status</see> has started.</remarks>222  public delegate void ZipTestResultHandler(TestStatus status, string message);223  #endregion224225  #region Update Definitions226  /// <summary>227  /// The possible ways of <see cref="ZipFile.CommitUpdate()">applying updates</see> to an archive.228  /// </summary>229  public enum FileUpdateMode230  {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  #endregion241242  #region ZipFile Class243  /// <summary>244  /// This class represents a Zip archive.  You can ask for the contained245  /// entries, or get an input stream for a file entry.  The entry is246  /// 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 arbitrary251  /// entries in different threads.252  /// <br/>253  /// <br/>Author of the original java version : Jochen Hoenicke254  /// </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 MainClass265  /// {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, IDisposable287  {288    #region KeyHandling289290    /// <summary>291    /// Delegate for handling keys/password setting during compresion/decompression.292    /// </summary>293    public delegate void KeysRequiredEventHandler(294      object sender,295      KeysRequiredEventArgs e296    );  297298  #region ZipFile Class299  /// <summary>300  /// This class represents a Zip archive.  You can ask for the contained301  /// entries, or get an input stream for a file entry.  The entry is302  /// automatically decompressed.303  ///304  /// You can also update the archive adding or deleting entries.305  ///306  /// This class is thread safe for input:  You can open input streams for arbitrary307  /// entries in different threads.308  /// <br/>309  /// <br/>Author of the original java version : Jochen Hoenicke310  /// </summary>311  /// <example>312  /// <code>313  /// using System;314  /// using System.Text;315  /// using System.Collections;316  /// using System.IO;317  ///318  /// using ICSharpCode.SharpZipLib.Zip;319  ///320  /// class MainClass321  /// {322  ///   static public void Main(string[] args)323  ///   {324  ///     using (ZipFile zFile = new ZipFile(args[0])) {325  ///       Console.WriteLine("Listing of : " + zFile.Name);326  ///       Console.WriteLine("");327  ///       Console.WriteLine("Raw Size    Size      Date     Time     Name");328  ///       Console.WriteLine("--------  --------  --------  ------  ---------");329  ///       foreach (ZipEntry e in zFile) {330  ///         if ( e.IsFile ) {331  ///           DateTime d = e.DateTime;332  ///           Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,333  ///             d.ToString("dd-MM-yy"), d.ToString("HH:mm"),334  ///             e.Name);335  ///         }336  ///       }337  ///     }338  ///   }339  /// }340  /// </code>341  /// </example>342  public class ZipFile : IEnumerable, IDisposable343  {344    #region KeyHandling345346    /// <summary>347    /// Delegate for handling keys/password setting during compresion/decompression.348    /// </summary>349    public delegate void KeysRequiredEventHandler(350      object sender,351      KeysRequiredEventArgs e352    );353354    /// <summary>355    /// Event handler for handling encryption keys.356    /// </summary>357    public KeysRequiredEventHandler KeysRequired;358359    /// <summary>360    /// Handles getting of encryption keys when required.361    /// </summary>362    /// <param name="fileName">The file for which encryption keys are required.</param>363    void OnKeysRequired(string fileName)364    { - 15365       if (KeysRequired != null) { - 0366        var krea = new KeysRequiredEventArgs(fileName, key); - 0367        KeysRequired(this, krea); - 0368        key = krea.Key;369      } - 15370    }371372    /// <summary>373    /// Get/set the encryption key value.374    /// </summary>375    byte[] Key376    { - 0377      get { return key; } - 0378      set { key = value; }379    }380381#if !NETCF_1_0382    /// <summary>383    /// Password to be used for encrypting/decrypting files.384    /// </summary>385    /// <remarks>Set to null if no password is required.</remarks>386    public string Password387    {388      set389      { - 16390         if ( string.IsNullOrEmpty(value)) { - 5391          key = null; - 5392        }393        else { - 11394          rawPassword_ = value; - 11395          key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(value));396        } - 11397      }398    }399#endif400401    /// <summary>402    /// Get a value indicating wether encryption keys are currently available.403    /// </summary>404    bool HaveKeys405    { - 65720406      get { return key != null; }407    }408    #endregion409410    #region Constructors298    /// <summary>299    /// Event handler for handling encryption keys.300    /// </summary>301    public KeysRequiredEventHandler KeysRequired;302303    /// <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    }315316    /// <summary>317    /// Get/set the encryption key value.318    /// </summary>319    byte[] Key { + 0320      get { return key; } + 0321      set { key = value; }322    }323324    /// <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    }338339    /// <summary>340    /// Get a value indicating wether encryption keys are currently available.341    /// </summary>342    bool HaveKeys { + 65720343      get { return key != null; }344    }345    #endregion346347    #region Constructors348    /// <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 occurs355    /// </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;369370      try { + 15371        ReadEntries(); + 15372      } catch { + 1373        DisposeInternal(true); + 1374        throw;375      } + 14376    }377378    /// <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;402403      try { + 0404        ReadEntries(); + 0405      } catch { + 0406        DisposeInternal(true); + 0407        throw;408      } + 0409    }410  411    /// <summary>412    /// Opens a Zip file with the given name for reading.412    /// Opens a Zip file reading the given <see cref="Stream"/>.  413    /// </summary>414    /// <param name="name">The name of the file to open.</param>415    /// <exception cref="ArgumentNullException">The argument supplied is null.</exception>416    /// <exception cref="IOException">417    /// An i/o error occurs418    /// </exception>419    /// <exception cref="ZipException">420    /// The file doesn't contain a valid zip archive.421    /// </exception> - 15422    public ZipFile(string name)423    { - 15424       if ( name == null ) { - 0425        throw new ArgumentNullException(nameof(name));426      }427 - 15428      name_ = name;429 - 15430      baseStream_ = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read); - 15431      isStreamOwner = true;414    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>415    /// <exception cref="IOException">416    /// An i/o error occurs417    /// </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      }  432433      try { - 15434        ReadEntries(); - 14435      } - 1436      catch { - 1437        DisposeInternal(true); - 1438        throw;439      } - 14440    }441442    /// <summary>443    /// Opens a Zip file reading the given <see cref="FileStream"/>.444    /// </summary>445    /// <param name="file">The <see cref="FileStream"/> to read archive data from.</param>446    /// <exception cref="ArgumentNullException">The supplied argument is null.</exception>447    /// <exception cref="IOException">448    /// An i/o error occurs.449    /// </exception>450    /// <exception cref="ZipException">451    /// The file doesn't contain a valid zip archive.452    /// </exception> - 1453    public ZipFile(FileStream file)454    { - 1455       if ( file == null ) { - 1456        throw new ArgumentNullException(nameof(file));457      }458 - 0459       if ( !file.CanSeek ) { - 0460        throw new ArgumentException("Stream is not seekable", nameof(file));461      }462 - 0463      baseStream_  = file; - 0464      name_ = file.Name; - 0465      isStreamOwner = true;466467      try { - 0468        ReadEntries(); - 0469      } - 0470      catch { - 0471        DisposeInternal(true); - 0472        throw;473      } - 0474    }475476    /// <summary>477    /// Opens a Zip file reading the given <see cref="Stream"/>.478    /// </summary>479    /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>480    /// <exception cref="IOException">481    /// An i/o error occurs482    /// </exception>483    /// <exception cref="ZipException">484    /// The stream doesn't contain a valid zip archive.<br/>485    /// </exception>486    /// <exception cref="ArgumentException">487    /// The <see cref="Stream">stream</see> doesnt support seeking.488    /// </exception>489    /// <exception cref="ArgumentNullException">490    /// The <see cref="Stream">stream</see> argument is null.491    /// </exception> - 62492    public ZipFile(Stream stream)493    { - 62494       if ( stream == null ) { - 0495        throw new ArgumentNullException(nameof(stream));496      }497 - 62498       if ( !stream.CanSeek ) { - 0499        throw new ArgumentException("Stream is not seekable", nameof(stream));500      }501 - 62502      baseStream_  = stream; - 62503      isStreamOwner = true;504 - 62505       if ( baseStream_.Length > 0 ) {506        try { - 52507          ReadEntries(); - 52508        } - 0509        catch { - 0510          DisposeInternal(true); - 0511          throw;512        }513      } else { - 10514        entries_ = new ZipEntry[0]; - 10515        isNewArchive_ = true;516      } - 62517    }518519    /// <summary>520    /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.521    /// </summary> - 10522    internal ZipFile()523    { - 10524      entries_ = new ZipEntry[0]; - 10525      isNewArchive_ = true; - 10526    }527528    #endregion529530    #region Destructors and Closing531    /// <summary>532    /// Finalize this instance.533    /// </summary>534    ~ZipFile()535    { - 6536      Dispose(false); - 12537    }538 + 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    }452453    /// <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    }461462    #endregion463464    #region Destructors and Closing465    /// <summary>466    /// Finalize this instance.467    /// </summary>468    ~ZipFile()469    { + 6470      Dispose(false); + 12471    }472473    /// <summary>474    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying475    /// 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    }485486    #endregion487488    #region Creators489    /// <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    }509510    /// <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    }535536    #endregion537538    #region Properties  539    /// <summary>540    /// Closes the ZipFile.  If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying541    /// Once closed, no further instance methods should be called.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    /// <exception cref="System.IO.IOException">544    /// An i/o error occurs.545    /// </exception>546    public void Close()547    { - 91548      DisposeInternal(true); - 91549      GC.SuppressFinalize(this); - 91550    }551552    #endregion553554    #region Creators555    /// <summary>556    /// Create a new <see cref="ZipFile"/> whose data will be stored in a file.557    /// </summary>558    /// <param name="fileName">The name of the archive to create.</param>559    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>560    /// <exception cref="ArgumentNullException"><paramref name="fileName"></paramref> is null</exception>561    public static ZipFile Create(string fileName)562    { - 7563       if ( fileName == null ) { - 0564        throw new ArgumentNullException(nameof(fileName));565      }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    }550551    /// <summary>552    /// Get a value indicating wether553    /// 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    }559560    /// <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 - 7567      FileStream fs = File.Create(fileName);568 - 7569      var result = new ZipFile(); - 7570      result.name_ = fileName; - 7571      result.baseStream_ = fs; - 7572      result.isStreamOwner = true; - 7573      return result;574    }575576    /// <summary>577    /// Create a new <see cref="ZipFile"/> whose data will be stored on a stream.578    /// </summary>579    /// <param name="outStream">The stream providing data storage.</param>580    /// <returns>Returns the newly created <see cref="ZipFile"/></returns>581    /// <exception cref="ArgumentNullException"><paramref name="outStream"> is null</paramref></exception>582    /// <exception cref="ArgumentException"><paramref name="outStream"> doesnt support writing.</paramref></exception>583    public static ZipFile Create(Stream outStream)584    { - 3585       if ( outStream == null ) { - 0586        throw new ArgumentNullException(nameof(outStream));587      }588 - 3589       if ( !outStream.CanWrite ) { - 0590        throw new ArgumentException("Stream is not writeable", nameof(outStream));567    /// <summary>568    /// Gets the comment for the zip file.569    /// </summary>570    public string ZipFileComment { + 6571      get { return comment_; }572    }573574    /// <summary>575    /// Gets the name of this zip file.576    /// </summary>577    public string Name { + 38578      get { return name_; }579    }580581    /// <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 - 3593       if ( !outStream.CanSeek ) { - 0594        throw new ArgumentException("Stream is not seekable", nameof(outStream));595      }596 - 3597      var result = new ZipFile(); - 3598      result.baseStream_ = outStream; - 3599      return result;600    }601602    #endregion603604    #region Properties605    /// <summary>606    /// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.607    /// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.608    /// </summary>609    /// <remarks>610    /// The default value is true in all cases.611    /// </remarks>612    public bool IsStreamOwner613    { - 88614      get { return isStreamOwner; } - 74615      set { isStreamOwner = value; }616    }617618    /// <summary>619    /// Get a value indicating wether620    /// this archive is embedded in another file or not.621    /// </summary>622    public bool IsEmbeddedArchive623    {624      // Not strictly correct in all circumstances currently - 48625      get { return offsetOfFirstEntry > 0; }626    }627628    /// <summary>629    /// Get a value indicating that this archive is a new one.630    /// </summary>631    public bool IsNewArchive632    { - 65793633      get { return isNewArchive_; }634    }635636    /// <summary>637    /// Gets the comment for the zip file.638    /// </summary>639    public string ZipFileComment640    { - 6641      get { return comment_; }642    }643644    /// <summary>645    /// Gets the name of this zip file.646    /// </summary>647    public string Name648    { - 38649      get { return name_; }650    }651652    /// <summary>653    /// Gets the number of entries in this zip file.654    /// </summary>655    /// <exception cref="InvalidOperationException">656    /// The Zip file has been closed.657    /// </exception>658    [Obsolete("Use the Count property instead")]659    public int Size660    {661      get662      { - 0663        return entries_.Length;664      }665    }666667    /// <summary>668    /// Get the number of entries contained in this <see cref="ZipFile"/>.669    /// </summary>670    public long Count671    {672      get673      { - 66100674        return entries_.Length;675      }676    }677678    /// <summary>679    /// Indexer property for ZipEntries680    /// </summary>681    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]682    public ZipEntry this[int index]683    {684      get { - 329670685        return (ZipEntry) entries_[index].Clone();686      }687    }688689    #endregion690691    #region Input Handling692    /// <summary>693    /// Gets an enumerator for the Zip entries in this Zip file.694    /// </summary>695    /// <returns>Returns an <see cref="IEnumerator"/> for this archive.</returns>696    /// <exception cref="ObjectDisposedException">697    /// The Zip file has been closed.698    /// </exception>699    public IEnumerator GetEnumerator()700    { - 4701       if (isDisposed_) { - 0702        throw new ObjectDisposedException("ZipFile");703      }704 - 4705      return new ZipEntryEnumerator(entries_);706    }707708    /// <summary>709    /// Return the index of the entry with a matching name710    /// </summary>711    /// <param name="name">Entry name to find</param>712    /// <param name="ignoreCase">If true the comparison is case insensitive</param>713    /// <returns>The index position of the matching entry or -1 if not found</returns>714    /// <exception cref="ObjectDisposedException">715    /// The Zip file has been closed.716    /// </exception>717    public int FindEntry(string name, bool ignoreCase)718    { - 12719       if (isDisposed_) { - 0720        throw new ObjectDisposedException("ZipFile");721      }722723      // TODO: This will be slow as the next ice age for huge archives! - 62724       for (int i = 0; i < entries_.Length; i++) { - 28725         if (string.Compare(name, entries_[i].Name, ignoreCase, CultureInfo.InvariantCulture) == 0) { - 9726          return i;727        }728      } - 3729      return -1;730    }731732    /// <summary>733    /// Searches for a zip entry in this archive with the given name.734    /// String comparisons are case insensitive735    /// </summary>736    /// <param name="name">737    /// The name to find. May contain directory components separated by slashes ('/').738    /// </param>739    /// <returns>740    /// A clone of the zip entry, or null if no entry with that name exists.741    /// </returns>742    /// <exception cref="ObjectDisposedException">743    /// The Zip file has been closed.744    /// </exception>745    public ZipEntry GetEntry(string name)746    { - 0747       if (isDisposed_) { - 0748        throw new ObjectDisposedException("ZipFile");749      }750 - 0751      int index = FindEntry(name, true); - 0752       return (index >= 0) ? (ZipEntry) entries_[index].Clone() : null;753    }754755    /// <summary>756    /// Gets an input stream for reading the given zip entry data in an uncompressed form.757    /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().758    /// </summary>759    /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>760    /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>761    /// <exception cref="ObjectDisposedException">762    /// The ZipFile has already been closed763    /// </exception>764    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">765    /// The compression method for the entry is unknown766    /// </exception>767    /// <exception cref="IndexOutOfRangeException">768    /// The entry is not found in the ZipFile769    /// </exception>770    public Stream GetInputStream(ZipEntry entry)771    { - 65933772       if ( entry == null ) { - 0773        throw new ArgumentNullException(nameof(entry));774      }775 - 65933776       if ( isDisposed_ ) { - 0777        throw new ObjectDisposedException("ZipFile");778      }779 - 65933780      long index = entry.ZipFileIndex; - 65933781       if ( (index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name) ) { - 0782        index = FindEntry(entry.Name, true); - 0783         if (index < 0) { - 0784          throw new ZipException("Entry cannot be found");785        }786      } - 65933787      return GetInputStream(index);788    }789790    /// <summary>791    /// Creates an input stream reading a zip entry792    /// </summary>793    /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>794    /// <returns>795    /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/>796    /// </returns>797    /// <exception cref="ObjectDisposedException">798    /// The ZipFile has already been closed799    /// </exception>800    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">801    /// The compression method for the entry is unknown802    /// </exception>803    /// <exception cref="IndexOutOfRangeException">804    /// The entry is not found in the ZipFile805    /// </exception>806    public Stream GetInputStream(long entryIndex)807    { - 65946808       if ( isDisposed_ ) { - 0809        throw new ObjectDisposedException("ZipFile");810      }592    }593594    /// <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    }602603    /// <summary>604    /// Indexer property for ZipEntries605    /// </summary>606    [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]607    public ZipEntry this[int index] {608      get { + 329670609        return (ZipEntry)entries_[index].Clone();610      }611    }612613    #endregion614615    #region Input Handling616    /// <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    }631632    /// <summary>633    /// Return the index of the entry with a matching name634    /// </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      }646647      // 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    }655656    /// <summary>657    /// Searches for a zip entry in this archive with the given name.658    /// String comparisons are case insensitive659    /// </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    }678679    /// <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 closed687    /// </exception>688    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">689    /// The compression method for the entry is unknown690    /// </exception>691    /// <exception cref="IndexOutOfRangeException">692    /// The entry is not found in the ZipFile693    /// </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    }713714    /// <summary>715    /// Creates an input stream reading a zip entry716    /// </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 closed723    /// </exception>724    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">725    /// The compression method for the entry is unknown726    /// </exception>727    /// <exception cref="IndexOutOfRangeException">728    /// The entry is not found in the ZipFile729    /// </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;751752        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;756757        default: + 0758          throw new ZipException("Unsupported compression method " + method);759      }760 + 65946761      return result;762    }763764    #endregion765766    #region Archive Testing767    /// <summary>768    /// Test an archive for integrity/validity769    /// </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    }777778    /// <summary>779    /// Test an archive for integrity/validity780    /// </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;801802      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 - 65946812      long start = LocateEntry(entries_[entryIndex]); - 65946813      CompressionMethod method = entries_[entryIndex].CompressionMethod; - 65946814      Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize);815 - 65946816       if (entries_[entryIndex].IsCrypted == true) {817#if NETCF_1_0818        throw new ZipException("decryption not supported for Compact Framework 1.0");819#else - 10820        result = CreateAndInitDecryptionStream(result, entries_[entryIndex]); - 10821         if (result == null) { - 0822          throw new ZipException("Unable to decrypt this entry");823        }824#endif825      }826 - 65946827       switch (method) {828        case CompressionMethod.Stored:829          // read as is.830          break;831832        case CompressionMethod.Deflated:833          // No need to worry about ownership and closing as underlying stream close does nothing. - 353834          result = new InflaterInputStream(result, new Inflater(true)); - 353835          break;836837        default: - 0838          throw new ZipException("Unsupported compression method " + method);839      }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 - 65946841      return result;842    }843844    #endregion845846    #region Archive Testing847    /// <summary>848    /// Test an archive for integrity/validity849    /// </summary>850    /// <param name="testData">Perform low level data Crc check</param>851    /// <returns>true if all tests pass, false otherwise</returns>852    /// <remarks>Testing will terminate on the first error found.</remarks>853    public bool TestArchive(bool testData)854    { - 96855      return TestArchive(testData, TestStrategy.FindFirstError, null);856    }857858    /// <summary>859    /// Test an archive for integrity/validity860    /// </summary>861    /// <param name="testData">Perform low level data Crc check</param>862    /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>863    /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>864    /// <returns>true if all tests pass, false otherwise</returns>865    /// <exception cref="ObjectDisposedException">The object has already been closed.</exception>866    public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)867    { - 96868       if (isDisposed_) { - 0869        throw new ObjectDisposedException("ZipFile");870      }871 - 96872      var status = new TestStatus(this);873 - 96874       if ( resultHandler != null ) { - 0875        resultHandler(status, null);876      }877 - 96878       HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;879 - 96880      bool testing = true; + 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          }  881882      try { - 96883        int entryIndex = 0; + 65916882          entryIndex += 1;883        }  884 - 66012885         while ( testing && (entryIndex < Count) ) { - 65916886           if ( resultHandler != null ) { - 0887            status.SetEntry(this[entryIndex]); - 0888            status.SetOperation(TestOperation.EntryHeader); - 0889            resultHandler(status, null);890          }891892          try  { - 65916893            TestLocalHeader(this[entryIndex], test); - 65916894          } - 0895          catch(ZipException ex) { - 0896            status.AddError();897 - 0898             if ( resultHandler != null ) { - 0899              resultHandler(status, - 0900                string.Format("Exception during test - '{0}'", ex.Message));901            }902 - 0903            testing &= strategy != TestStrategy.FindFirstError; - 0904          } + 96885         if (resultHandler != null) { + 0886          status.SetOperation(TestOperation.MiscellaneousTests); + 0887          resultHandler(status, null);888        }889890        // TODO: the 'Corrina Johns' test where local headers are missing from891        // 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 - 65916906           if ( testing && testData && this[entryIndex].IsFile ) { - 65912907             if ( resultHandler != null ) { - 0908              status.SetOperation(TestOperation.EntryData); - 0909              resultHandler(status, null);910            }911 - 65912912                        var crc = new Crc32();913 - 65912914                        using (Stream entryStream = this.GetInputStream(this[entryIndex]))915                        {916 - 65912917                            byte[] buffer = new byte[4096]; - 65912918                            long totalBytes = 0;919                            int bytesRead; - 66297920                             while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0)921                            { - 385922                                crc.Update(buffer, 0, bytesRead);923 - 385924                                 if (resultHandler != null)925                                { - 0926                                    totalBytes += bytesRead; - 0927                                    status.SetBytesTested(totalBytes); - 0928                                    resultHandler(status, null);929                                }930                            } - 65912931                        }932 - 65912933             if (this[entryIndex].Crc != crc.Value) { - 1934              status.AddError();935 - 1936               if ( resultHandler != null ) { - 0937                resultHandler(status, "CRC mismatch");938              }939 - 1940              testing &= strategy != TestStrategy.FindFirstError;941            }942 - 65912943             if (( this[entryIndex].Flags & (int)GeneralBitFlags.Descriptor) != 0 ) { - 13944              var helper = new ZipHelperStream(baseStream_); - 13945              var data = new DescriptorData(); - 13946              helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data); - 13947               if (this[entryIndex].Crc != data.Crc) { - 0948                status.AddError();949              }950 - 13951               if (this[entryIndex].CompressedSize != data.CompressedSize) { - 0952                status.AddError();953              }954 - 13955               if (this[entryIndex].Size != data.Size) { - 0956                status.AddError();957              }958            }959          }960 - 65916961           if ( resultHandler != null ) { - 0962            status.SetOperation(TestOperation.EntryComplete); - 0963            resultHandler(status, null);964          }965 - 65916966          entryIndex += 1;967        }968 - 96969         if ( resultHandler != null ) { - 0970          status.SetOperation(TestOperation.MiscellaneousTests); - 0971          resultHandler(status, null);972        }973974        // TODO: the 'Corrina Johns' test where local headers are missing from975        // the central directory.  They are therefore invisible to many archivers. - 96976      } - 0977      catch (Exception ex) { - 0978        status.AddError(); + 96906      return (status.ErrorCount == 0);907    }908909    [Flags]910    enum HeaderTest911    {912      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted913      Header = 0x02,     // Check that this header contents are valid914    }915916    /// <summary>917    /// Test a local header against that provided from the central directory918    /// </summary>919    /// <param name="entry">920    /// The entry to test against921    /// </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);953954        // Extra data / zip64 checks + 131862955         if (localExtraData.Find(1)) {956          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64957          // 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 - 0980         if ( resultHandler != null ) { - 0981          resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));982        } - 0983      }984 - 96985       if ( resultHandler != null ) { - 0986        status.SetOperation(TestOperation.Complete); - 0987        status.SetEntry(null); - 0988        resultHandler(status, null);989      } + 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})", extract989            }  990 - 96991      return (status.ErrorCount == 0);992    }993994    [Flags]995    enum HeaderTest996    {997      Extract = 0x01,     // Check that this header represents an entry whose data can be extracted998      Header  = 0x02,     // Check that this header contents are valid999    }10001001    /// <summary>1002    /// Test a local header against that provided from the central directory1003    /// </summary>1004    /// <param name="entry">1005    /// The entry to test against1006    /// </param>1007    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>1008    /// <returns>The offset of the entries data in the file</returns>1009    long TestLocalHeader(ZipEntry entry, HeaderTest tests)1010    { - 1318621011      lock(baseStream_)1012      { - 1318621013        bool testHeader = (tests & HeaderTest.Header) != 0; - 1318621014        bool testData = (tests & HeaderTest.Extract) != 0;1015 - 1318621016        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin); - 1318621017         if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) { - 01018          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)1019        }1020 - 1318621021        var extractVersion = ( short ) (ReadLEUshort() & 0x00ff); - 1318621022        var localFlags = ( short )ReadLEUshort(); - 1318621023        var compressionMethod = ( short )ReadLEUshort(); - 1318621024        var fileTime = ( short )ReadLEUshort(); - 1318621025        var fileDate = ( short )ReadLEUshort(); - 1318621026        uint crcValue = ReadLEUint(); - 1318621027        long compressedSize = ReadLEUint(); - 1318621028        long size = ReadLEUint(); - 1318621029        int storedNameLength = ReadLEUshort(); - 1318621030        int extraDataLength = ReadLEUshort();1031 - 1318621032        byte[] nameData = new byte[storedNameLength]; - 1318621033        StreamUtils.ReadFully(baseStream_, nameData);1034 - 1318621035        byte[] extraData = new byte[extraDataLength]; - 1318621036        StreamUtils.ReadFully(baseStream_, extraData); + 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})", extractVersi1015          }10161017          // 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          }10211022          // 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          }10261027          // 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 ({01035            }1036          }  1037 - 1318621038        var localExtraData = new ZipExtraData(extraData);10391040        // Extra data / zip64 checks - 1318621041         if (localExtraData.Find(1))1042        {1043          // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip641044          // and size or compressedSize = MaxValue, due to rogue creators.1045 - 501046          size = localExtraData.ReadLong(); - 501047          compressedSize = localExtraData.ReadLong();1048 - 501049                     if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0)1050                    {1051                        // These may be valid if patched later - 91052                         if ( (size != -1) && (size != entry.Size)) { - 01053                            throw new ZipException("Size invalid for descriptor");1054                        }1055 - 91056                         if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) { - 01057                            throw new ZipException("Compressed size invalid for descriptor");1058                        }1059                    }1060                }1061        else1062        {1063          // No zip64 extra data but entry requires it. - 1318121064           if ((extractVersion >= ZipConstants.VersionZip64) && - 1318121065            (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue)))1066          { - 01067            throw new ZipException("Required Zip64 extended information missing");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          }10421043          // Central header flags match local entry flags. + 659161044           if (localFlags != entry.Flags) { + 01045            throw new ZipException("Central header/local header flags mismatch");1046          }10471048          // 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          }10561057          // 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        }1070 - 1318621071         if ( testData ) { - 1318621072           if ( entry.IsFile ) { - 1318581073             if ( !entry.IsCompressionMethodSupported() ) { - 01074              throw new ZipException("Compression method not supported");1075            }1076 - 1318581077             if ( (extractVersion > ZipConstants.VersionMadeBy) - 1318581078              || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)) ) { - 01079              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extract1080            }1081 - 1318581082             if ( (localFlags & ( int )(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.Enha - 01083              throw new ZipException("The library does not support the zip version required to extract this entry");1084            }1085          }1086        }1087 - 1318621088                 if (testHeader)1089                { - 659161090                     if ((extractVersion <= 63) &&  // Ignore later versions as we dont know about them.. - 659161091                        (extractVersion != 10) && - 659161092                        (extractVersion != 11) && - 659161093                        (extractVersion != 20) && - 659161094                        (extractVersion != 21) && - 659161095                        (extractVersion != 25) && - 659161096                        (extractVersion != 27) && - 659161097                        (extractVersion != 45) && - 659161098                        (extractVersion != 46) && - 659161099                        (extractVersion != 50) && - 659161100                        (extractVersion != 51) && - 659161101                        (extractVersion != 52) && - 659161102                        (extractVersion != 61) && - 659161103                        (extractVersion != 62) && - 659161104                        (extractVersion != 63) - 659161105                        )1106                    { - 01107                        throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", 1108                    }11091110                    // Local entry flags dont have reserved bit set on. - 659161111                     if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | General1112                    { - 01113                        throw new ZipException("Reserved bit flags cannot be set.");1114                    }11151116                    // Encryption requires extract version >= 20 - 659161117                     if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20))1118                    { - 01119                        throw new ZipException(string.Format("Version required to extract this entry is too low for encr1120                    }11211122                    // Strong encryption requires encryption flag to be set and extract version >= 50. - 659161123                     if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1124                    { - 01125                         if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0)1126                        { - 01127                            throw new ZipException("Strong encryption flag set but encryption flag is not set");1128                        }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          }10751076          // 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          }10831084          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS str1085          // 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          }10891090          // Name data has already been read convert it and compare. + 659161091          string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);10921093          // 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          }10971098          // 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            }11031104            // 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 bytes1112              // 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        }11221123        // Tests that apply to both data and header.11241125        // 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 - 01130                         if (extractVersion < 50)1131                        { - 01132                            throw new ZipException(string.Format("Version required to extract this entry is too low for 1133                        }1134                    }11351136                    // Patched entries require extract version >= 27 - 659161137                     if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27))1138                    { - 01139                        throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractV1140                    }11411142                    // Central header flags match local entry flags. - 659161143                     if (localFlags != entry.Flags)1144                    { - 01145                        throw new ZipException("Central header/local header flags mismatch");1146                    }11471148                    // Central header compression method matches local entry - 659161149                     if (entry.CompressionMethod != (CompressionMethod)compressionMethod)1150                    { - 01151                        throw new ZipException("Central header/local header compression method mismatch");1152                    } + 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    }11491150    #endregion11511152    #region Updating  1153 - 659161154                     if (entry.Version != extractVersion)1155                    { - 01156                        throw new ZipException("Extract version mismatch");1157                    }11581159                    // Strong encryption and extract version match - 659161160                     if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)1161                    { - 01162                         if (extractVersion < 62)1163                        { - 01164                            throw new ZipException("Strong encryption flag set but version not high enough");1165                        }1166                    }1167 - 659161168                     if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0)1169                    { - 01170                         if ((fileTime != 0) || (fileDate != 0))1171                        { - 01172                            throw new ZipException("Header masked set but date/time values non-zero");1173                        }1174                    }1175 - 659161176                     if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0)1177                    { - 659001178                         if (crcValue != (uint)entry.Crc)1179                        { - 01180                            throw new ZipException("Central header/local header crc mismatch");1181                        }1182                    }11831184                    // Crc valid for empty entry.1185                    // This will also apply to streamed entries where size isnt known and the header cant be patched - 659161186                     if ((size == 0) && (compressedSize == 0))1187                    { - 655411188                         if (crcValue != 0)1189                        { - 01190                            throw new ZipException("Invalid CRC for empty entry");1191                        }1192                    }11931194                    // TODO: make test more correct...  can't compare lengths as was done originally as this can fail fo1195                    // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntr - 659161196                     if (entry.Name.Length > storedNameLength)1197                    { - 01198                        throw new ZipException("File name length mismatch");1199                    }12001201                    // Name data has already been read convert it and compare. - 659161202                    string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);12031204                    // Central directory and local entry name match - 659161205                     if (localName != entry.Name)1206                    { - 01207                        throw new ZipException("Central header and local header file name mismatch");1208                    }12091210                    // Directories have zero actual size but can have compressed size - 659161211                     if (entry.IsDirectory)1212                    { - 41213                         if (size > 0)1214                        { - 01215                            throw new ZipException("Directory cannot have size");1216                        }12171218                        // There may be other cases where the compressed size can be greater than this?1219                        // If so until details are known we will be strict. - 41220                         if (entry.IsCrypted)1221                        { - 21222                             if (compressedSize > ZipConstants.CryptoHeaderSize + 2)1223                            { - 01224                                throw new ZipException("Directory compressed size invalid");1225                            }1226                        } - 21227                         else if (compressedSize > 2)1228                        {1229                            // When not compressed the directory size can validly be 2 bytes1230                            // if the true size wasnt known when data was originally being written.1231                            // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes - 01232                            throw new ZipException("Directory compressed size invalid");1233                        }1234                    }1235 - 659161236                     if (!ZipNameTransform.IsValidName(localName, true))1237                    { - 01238                        throw new ZipException("Name is invalid");1239                    }1240                }12411242        // Tests that apply to both data and header.1154    const int DefaultBufferSize = 4096;11551156    /// <summary>1157    /// The kind of update to apply.1158    /// </summary>1159    enum UpdateCommand1160    {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    }11651166    #region Properties1167    /// <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      }11741175      set { + 01176        updateEntryFactory_.NameTransform = value; + 01177      }1178    }11791180    /// <summary>1181    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1182    /// during updates.1183    /// </summary>1184    public IEntryFactory EntryFactory {1185      get { + 1721186        return updateEntryFactory_;1187      }11881189      set { + 01190         if (value == null) { + 01191          updateEntryFactory_ = new ZipEntryFactory(); + 01192        } else { + 01193          updateEntryFactory_ = value;1194        } + 01195      }1196    }11971198    /// <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    }12141215    /// <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    }12211222    /// <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    }12291230    #endregion12311232    #region Immediate updating1233    //    TBD: Direct form of updating1234    //1235    //    public void Update(IEntryMatcher deleteMatcher)1236    //    {1237    //    }1238    //1239    //    public void Update(IScanner addScanner)1240    //    {1241    //    }1242    #endregion  12431244        // Size can be verified only if it is known in the local header.1245        // it will always be known in the central header. - 1318621246         if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) || - 1318621247          ((size > 0) || (compressedSize > 0))) {1248 - 1318481249           if (size != entry.Size) { - 01250            throw new ZipException( - 01251              string.Format("Size mismatch between central header({0}) and local header({1})", - 01252                entry.Size, size));1253          }1254 - 1318481255           if (compressedSize != entry.CompressedSize && - 1318481256            compressedSize != 0xFFFFFFFF && compressedSize != -1) { - 01257            throw new ZipException( - 01258              string.Format("Compressed size mismatch between central header({0}) and local header({1})", - 01259              entry.CompressedSize, compressedSize));1260          }1261        }1244    #region Deferred Updating1245    /// <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.</p1249    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1250    /// <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 - 1318621263        int extraLength = storedNameLength + extraDataLength; - 1318621264        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength; + 481263       if (isDisposed_) { + 01264        throw new ObjectDisposedException("ZipFile");  1265      } - 1318621266    }12671268    #endregion12691270    #region Updating12711272    const int DefaultBufferSize = 4096;1266 + 481267       if (IsEmbeddedArchive) { + 01268        throw new ZipException("Cannot update embedded/SFX archives");1269      }1270 + 481271      archiveStorage_ = archiveStorage; + 481272      updateDataSource_ = dataSource;  12731274    /// <summary>1275    /// The kind of update to apply.1276    /// </summary>1277    enum UpdateCommand1278    {1279      Copy,       // Copy original file contents.1280      Modify,     // Change encryption, compression, attributes, name, time etc, of an existing file.1281      Add,        // Add a new file to the archive.1282    }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      }  12831284    #region Properties1285    /// <summary>1286    /// Get / set the <see cref="INameTransform"/> to apply to names when updating.1287    /// </summary>1288    public INameTransform NameTransform1289    {1290      get { - 657401291        return updateEntryFactory_.NameTransform;1292      }12931294      set { - 01295        updateEntryFactory_.NameTransform = value; - 01296      }1297    }12981299    /// <summary>1300    /// Get/set the <see cref="IEntryFactory"/> used to generate <see cref="ZipEntry"/> values1301    /// during updates.1302    /// </summary>1303    public IEntryFactory EntryFactory1304    {1305      get { - 1721306        return updateEntryFactory_;1307      }13081309      set { - 01310         if (value == null) { - 01311          updateEntryFactory_ = new ZipEntryFactory(); - 01312        }1313        else { - 01314          updateEntryFactory_ = value;1315        } - 01316      }1317    }13181319    /// <summary>1320    /// Get /set the buffer size to be used when updating this zip file.1321    /// </summary>1322    public int BufferSize1323    { - 01324      get { return bufferSize_; }1325      set { - 01326         if ( value < 1024 ) {1327#if NETCF_1_01328          throw new ArgumentOutOfRangeException("value");1329#else - 01330          throw new ArgumentOutOfRangeException(nameof(value), "cannot be below 1024");1331#endif1332        }1333 - 01334         if ( bufferSize_ != value ) { - 01335          bufferSize_ = value; - 01336          copyBuffer_ = null;1337        } - 01338      }1339    }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    }13021303    /// <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    }13111312    /// <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    }13261327    /// <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();  13401341    /// <summary>1342    /// Get a value indicating an update has <see cref="BeginUpdate()">been started</see>.1343    /// </summary>1344    public bool IsUpdating1345    { - 01346      get { return updates_ != null; }1347    }13481349    /// <summary>1350    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.1351    /// </summary>1352    public UseZip64 UseZip641353    { - 31354      get { return useZip64_; } - 121355      set { useZip64_ = value; }1356    }13571358    #endregion13591360    #region Immediate updating1361//    TBD: Direct form of updating1362//1363//    public void Update(IEntryMatcher deleteMatcher)1364//    {1365//    }1366//1367//    public void Update(IScanner addScanner)1368//    {1369//    }1370    #endregion13711372    #region Deferred Updating1373    /// <summary>1374    /// Begin updating this <see cref="ZipFile"/> archive.1375    /// </summary>1376    /// <param name="archiveStorage">The <see cref="IArchiveStorage">archive storage</see> for use during the update.</p1377    /// <param name="dataSource">The <see cref="IDynamicDataSource">data source</see> to utilise during updating.</param1341      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    }13631364    /// <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    }13731374    /// <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    /// <exception cref="ArgumentNullException">One of the arguments provided is null</exception>1380    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1381    public void BeginUpdate(IArchiveStorage archiveStorage, IDynamicDataSource dataSource)1382    { - 481383       if ( archiveStorage == null ) { - 01384        throw new ArgumentNullException(nameof(archiveStorage));1385      }1379    public void SetComment(string comment)1380    { + 31381       if (isDisposed_) { + 01382        throw new ObjectDisposedException("ZipFile");1383      }1384 + 31385      CheckUpdating();  1386 - 481387       if ( dataSource == null ) { - 01388        throw new ArgumentNullException(nameof(dataSource));1389      }1390 - 481391       if ( isDisposed_ ) { - 01392        throw new ObjectDisposedException("ZipFile");1393      }1394 - 481395       if ( IsEmbeddedArchive ) { - 01396        throw new ZipException ("Cannot update embedded/SFX archives");1397      } + 31387      newComment_ = new ZipString(comment);1388 + 31389       if (newComment_.RawLength > 0xffff) { + 01390        newComment_ = null; + 01391        throw new ZipException("Comment length exceeds maximum - 65535");1392      }13931394      // We dont take account of the original and current comment appearing to be the same1395      // as encoding may be different. + 31396      commentEdited_ = true; + 31397    }  1398 - 481399      archiveStorage_ = archiveStorage; - 481400      updateDataSource_ = dataSource;14011402      // NOTE: the baseStream_ may not currently support writing or seeking.1403 - 481404      updateIndex_ = new Hashtable();1405 - 481406      updates_ = new ArrayList(entries_.Length); - 3181407      foreach(ZipEntry entry in entries_) { - 1111408        int index = updates_.Add(new ZipUpdate(entry)); - 1111409        updateIndex_.Add(entry.Name, index);1410      }14111412      // We must sort by offset before using offset's calculated sizes - 481413      updates_.Sort(new UpdateComparer());1414 - 481415      int idx = 0; - 2871416      foreach (ZipUpdate update in updates_) {1417        //If last entry, there is no next entry offset to use - 1111418         if (idx == updates_.Count - 1) - 311419          break;1420 - 801421        update.OffsetBasedSize = ((ZipUpdate)updates_[idx + 1]).Entry.Offset - update.Entry.Offset; - 801422        idx++;1423      } - 481424      updateCount_ = updates_.Count;1425 - 481426      contentsEdited_ = false; - 481427      commentEdited_ = false; - 481428      newComment_ = null; - 481429    }14301431    /// <summary>1432    /// Begin updating to this <see cref="ZipFile"/> archive.1433    /// </summary>1434    /// <param name="archiveStorage">The storage to use during the update.</param>1435    public void BeginUpdate(IArchiveStorage archiveStorage)1436    { - 321437      BeginUpdate(archiveStorage, new DynamicDiskDataSource()); - 321438    }14391440    /// <summary>1441    /// Begin updating this <see cref="ZipFile"/> archive.1442    /// </summary>1443    /// <seealso cref="BeginUpdate(IArchiveStorage)"/>1444    /// <seealso cref="CommitUpdate"></seealso>1445    /// <seealso cref="AbortUpdate"></seealso>1446    public void BeginUpdate()1447    { - 161448       if ( Name == null ) { - 61449        BeginUpdate(new MemoryArchiveStorage(), new DynamicDiskDataSource()); - 61450      }1451      else { - 101452        BeginUpdate(new DiskArchiveStorage(this), new DynamicDiskDataSource());1453      } - 101454    }1399    #endregion14001401    #region Adding Entries14021403    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        }14131414        // 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    }14221423    /// <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    /// Commit current updates, updating this archive.1457    /// Add a new entry to the archive.  1458    /// </summary>1459    /// <seealso cref="BeginUpdate()"></seealso>1460    /// <seealso cref="AbortUpdate"></seealso>1461    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1462    public void CommitUpdate()1463    { - 481464       if ( isDisposed_ ) { - 01465        throw new ObjectDisposedException("ZipFile");1466      }1467 - 481468      CheckUpdating();14691470      try { - 481471        updateIndex_.Clear(); - 481472        updateIndex_=null;1473 - 481474         if( contentsEdited_ ) { - 441475          RunUpdates(); - 441476        } - 41477         else if( commentEdited_ ) { - 31478          UpdateCommentOnly(); - 31479        }1480        else {1481          // Create an empty archive if none existed originally. - 11482           if( entries_.Length==0 ) { - 11483            byte[] theComment=(newComment_!=null)?newComment_.RawComment:ZipConstants.ConvertToArray(comment_); - 11484            using( ZipHelperStream zhs=new ZipHelperStream(baseStream_) ) { - 11485              zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment); - 11486            }1487          }1488        }1489 - 01490      }1491      finally { - 481492        PostUpdateCleanup(); - 481493      } - 481494    }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    }14801481    /// <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    /// Abort updating leaving the archive unchanged.1497    /// Add a file to the archive.  1498    /// </summary>1499    /// <seealso cref="BeginUpdate()"></seealso>1500    /// <seealso cref="CommitUpdate"></seealso>1501    public void AbortUpdate()1502    { - 01503      PostUpdateCleanup(); - 01504    }15051506    /// <summary>1507    /// Set the file comment to be recorded when the current update is <see cref="CommitUpdate">commited</see>.1508    /// </summary>1509    /// <param name="comment">The comment to record.</param>1510    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1511    public void SetComment(string comment)1512    { - 31513       if ( isDisposed_ ) { - 01514        throw new ObjectDisposedException("ZipFile");1515      }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 - 31517      CheckUpdating();1518 - 31519      newComment_ = new ZipString(comment);1520 - 31521       if ( newComment_.RawLength  > 0xffff ) { - 01522        newComment_ = null; - 01523        throw new ZipException("Comment length exceeds maximum - 65535");1524      }15251526      // We dont take account of the original and current comment appearing to be the same1527      // as encoding may be different. - 31528      commentEdited_ = true; - 31529    }15301531    #endregion15321533    #region Adding Entries15341535    void AddUpdate(ZipUpdate update)1536    { - 657051537      contentsEdited_ = true;1538 - 657051539      int index = FindExistingUpdate(update.Entry.Name);1540 - 657051541       if (index >= 0) { - 01542         if ( updates_[index] == null ) { - 01543          updateCount_ += 1;1544        }15451546        // Direct replacement is faster than delete and add. - 01547        updates_[index] = update; - 01548      }1549      else { - 657051550        index = updates_.Add(update); - 657051551        updateCount_ += 1; - 657051552        updateIndex_.Add(update.Entry.Name, index);1553      } - 657051554    }15551556    /// <summary>1557    /// Add a new entry to the archive.1558    /// </summary>1559    /// <param name="fileName">The name of the file to add.</param>1560    /// <param name="compressionMethod">The compression method to use.</param>1561    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comment for this entry.</param>1562    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1563    /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>1564    /// <exception cref="ArgumentOutOfRangeException">Compression method is not supported.</exception>1565    public void Add(string fileName, CompressionMethod compressionMethod, bool useUnicodeText )1566    { - 01567       if (fileName == null) { - 01568        throw new ArgumentNullException(nameof(fileName));1569      }1570 - 01571       if ( isDisposed_ ) { - 01572        throw new ObjectDisposedException("ZipFile");1573      }1574 - 01575       if (!ZipEntry.IsCompressionMethodSupported(compressionMethod)) { - 01576        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1577      }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    }15351536    /// <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    }15591560    /// <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 useUnicode1568    { + 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 - 01579      CheckUpdating(); - 01580      contentsEdited_ = true;1581 - 01582      ZipEntry entry = EntryFactory.MakeFileEntry(fileName); - 01583      entry.IsUnicodeText = useUnicodeText; - 01584      entry.CompressionMethod = compressionMethod; + 41579      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false); + 41580      entry.IsUnicodeText = useUnicodeText; + 41581      entry.CompressionMethod = compressionMethod;1582 + 41583      AddUpdate(new ZipUpdate(dataSource, entry)); + 41584    }  1585 - 01586      AddUpdate(new ZipUpdate(fileName, entry)); - 01587    }15881589    /// <summary>1590    /// Add a new entry to the archive.1591    /// </summary>1592    /// <param name="fileName">The name of the file to add.</param>1593    /// <param name="compressionMethod">The compression method to use.</param>1594    /// <exception cref="ArgumentNullException">ZipFile has been closed.</exception>1595    /// <exception cref="ArgumentOutOfRangeException">The compression method is not supported.</exception>1596    public void Add(string fileName, CompressionMethod compressionMethod)1597    { - 01598       if ( fileName == null ) { - 01599        throw new ArgumentNullException(nameof(fileName));1600      }1601 - 01602       if ( !ZipEntry.IsCompressionMethodSupported(compressionMethod) ) { - 01603        throw new ArgumentOutOfRangeException(nameof(compressionMethod));1604      }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 - 01606      CheckUpdating(); - 01607      contentsEdited_ = true;1608 - 01609      ZipEntry entry = EntryFactory.MakeFileEntry(fileName); - 01610      entry.CompressionMethod = compressionMethod; - 01611      AddUpdate(new ZipUpdate(fileName, entry)); - 01612    }16131614    /// <summary>1615    /// Add a file to the archive.1616    /// </summary>1617    /// <param name="fileName">The name of the file to add.</param>1618    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1619    public void Add(string fileName)1620    { - 31621       if ( fileName == null ) { - 01622        throw new ArgumentNullException(nameof(fileName));1623      }1624 - 31625      CheckUpdating(); - 31626      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName))); - 31627    }16281629    /// <summary>1630    /// Add a file to the archive.1631    /// </summary>1632    /// <param name="fileName">The name of the file to add.</param>1633    /// <param name="entryName">The name to use for the <see cref="ZipEntry"/> on the Zip file created.</param>1634    /// <exception cref="ArgumentNullException">Argument supplied is null.</exception>1635    public void Add(string fileName, string entryName)1636    { - 01637       if (fileName == null) { - 01638        throw new ArgumentNullException(nameof(fileName));1639      }1640 - 01641       if ( entryName == null ) { - 01642        throw new ArgumentNullException(nameof(entryName));1643      }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    }16211622    #endregion16231624    #region Modifying Entries1625    /* 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          }16331634          if ( updated == null ) {1635            throw new ArgumentNullException("updated");1636          }16371638          CheckUpdating();1639          contentsEdited_ = true;1640          updates_.Add(new ZipUpdate(original, updated));1641        }1642    */1643    #endregion  1644 - 01645      CheckUpdating(); - 01646      AddUpdate(new ZipUpdate(fileName, EntryFactory.MakeFileEntry(fileName, entryName, true))); - 01647    }164816491650    /// <summary>1651    /// Add a file entry with data.1652    /// </summary>1653    /// <param name="dataSource">The source of the data for this entry.</param>1654    /// <param name="entryName">The name to give to the entry.</param>1655    public void Add(IStaticDataSource dataSource, string entryName)1656    { - 1461657       if ( dataSource == null ) { - 01658        throw new ArgumentNullException(nameof(dataSource));1659      }1660 - 1461661       if ( entryName == null ) { - 01662        throw new ArgumentNullException(nameof(entryName));1663      }1664 - 1461665      CheckUpdating(); - 1461666      AddUpdate(new ZipUpdate(dataSource, EntryFactory.MakeFileEntry(entryName, false))); - 1461667    }16681669    /// <summary>1670    /// Add a file entry with data.1671    /// </summary>1672    /// <param name="dataSource">The source of the data for this entry.</param>1673    /// <param name="entryName">The name to give to the entry.</param>1674    /// <param name="compressionMethod">The compression method to use.</param>1675    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)1676    { - 151677       if ( dataSource == null ) { - 01678        throw new ArgumentNullException(nameof(dataSource));1679      }1680 - 151681       if ( entryName == null ) { - 01682        throw new ArgumentNullException(nameof(entryName));1683      }1684 - 151685      CheckUpdating();1686 - 151687      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false); - 151688      entry.CompressionMethod = compressionMethod;1689 - 151690      AddUpdate(new ZipUpdate(dataSource, entry)); - 151691    }16921693    /// <summary>1694    /// Add a file entry with data.1695    /// </summary>1696    /// <param name="dataSource">The source of the data for this entry.</param>1697    /// <param name="entryName">The name to give to the entry.</param>1698    /// <param name="compressionMethod">The compression method to use.</param>1699    /// <param name="useUnicodeText">Ensure Unicode text is used for name and comments for this entry.</param>1700    public void Add(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod, bool useUnicode1701    { - 41702       if (dataSource == null) { - 01703        throw new ArgumentNullException(nameof(dataSource));1704      }1705 - 41706       if ( entryName == null ) { - 01707        throw new ArgumentNullException(nameof(entryName));1708      }1709 - 41710      CheckUpdating();1711 - 41712      ZipEntry entry = EntryFactory.MakeFileEntry(entryName, false); - 41713      entry.IsUnicodeText = useUnicodeText; - 41714      entry.CompressionMethod = compressionMethod;1715 - 41716      AddUpdate(new ZipUpdate(dataSource, entry)); - 41717    }17181719    /// <summary>1720    /// Add a <see cref="ZipEntry"/> that contains no data.1721    /// </summary>1722    /// <param name="entry">The entry to add.</param>1723    /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>1724    public void Add(ZipEntry entry)1725    { - 655371726       if ( entry == null ) { - 01727        throw new ArgumentNullException(nameof(entry));1728      }1729 - 655371730      CheckUpdating();1645    #region Deleting Entries1646    /// <summary>1647    /// Delete an entry by name1648    /// </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    }16711672    /// <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    }16931694    #endregion16951696    #region Update Support16971698    #region Writing Values/Headers1699    void WriteLEShort(int value)1700    { + 22370481701      baseStream_.WriteByte((byte)(value & 0xff)); + 22370481702      baseStream_.WriteByte((byte)((value >> 8) & 0xff)); + 22370481703    }17041705    /// <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    }17131714    /// <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    }17221723    /// <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 - 655371732       if ( (entry.Size != 0) || (entry.CompressedSize != 0) ) { - 01733        throw new ZipException("Entry cannot have any data");1734      }1735 - 655371736      AddUpdate(new ZipUpdate(UpdateCommand.Add, entry)); - 655371737    }17381739    /// <summary>1740    /// Add a directory entry to the archive.1741    /// </summary>1742    /// <param name="directoryName">The directory to add.</param>1743    public void AddDirectory(string directoryName)1744    { - 01745       if ( directoryName == null ) { - 01746        throw new ArgumentNullException(nameof(directoryName));1747      }1748 - 01749      CheckUpdating();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    }17401741    void WriteLEUlong(ulong value)1742    { + 01743      WriteLEUint((uint)(value & 0xffffffff)); + 01744      WriteLEUint((uint)(value >> 32)); + 01745    }17461747    void WriteLocalEntryHeader(ZipUpdate update)1748    { + 657481749      ZipEntry entry = update.OutEntry;  1750 - 01751      ZipEntry dirEntry = EntryFactory.MakeDirectoryEntry(directoryName); - 01752      AddUpdate(new ZipUpdate(UpdateCommand.Add, dirEntry)); - 01753    }17541755    #endregion17561757    #region Modifying Entries1758/* Modify not yet ready for public consumption.1759   Direct modification of an entry should not overwrite original data before its read.1760   Safe mode is trivial in this sense.1761    public void Modify(ZipEntry original, ZipEntry updated)1762    {1763      if ( original == null ) {1764        throw new ArgumentNullException("original");1765      }1751      // TODO: Local offset will require adjusting for multi-disk zip files. + 657481752      entry.Offset = baseStream_.Position;17531754      // 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        }  17661767      if ( updated == null ) {1768        throw new ArgumentNullException("updated");1769      }17701771      CheckUpdating();1772      contentsEdited_ = true;1773      updates_.Add(new ZipUpdate(original, updated));1774    }1775*/1776    #endregion17771778    #region Deleting Entries1779    /// <summary>1780    /// Delete an entry by name1781    /// </summary>1782    /// <param name="fileName">The filename to delete</param>1783    /// <returns>True if the entry was found and deleted; false otherwise.</returns>1784    public bool Delete(string fileName)1785    { - 31786       if ( fileName == null ) { - 01787        throw new ArgumentNullException(nameof(fileName));1788      }1789 - 31790      CheckUpdating();1791 - 31792      bool result = false; - 31793      int index = FindExistingUpdate(fileName); - 31794       if ( (index >= 0) && (updates_[index] != null) ) { - 31795        result = true; - 31796        contentsEdited_ = true; - 31797        updates_[index] = null; - 31798        updateCount_ -= 1; - 31799      }1800      else { - 01801        throw new ZipException("Cannot find entry to delete");1802      } - 31803      return result;1804    }18051806    /// <summary>1807    /// Delete a <see cref="ZipEntry"/> from the archive.1808    /// </summary>1809    /// <param name="entry">The entry to delete.</param>1810    public void Delete(ZipEntry entry)1811    { - 321812       if ( entry == null ) { - 01813        throw new ArgumentNullException(nameof(entry));1814      }1815 - 321816      CheckUpdating(); + 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;17821783          case UseZip64.On: + 21784            entry.ForceZip64();1785            break;17861787          case UseZip64.Off:1788            // Do nothing.  The entry itself may be using Zip64 independantly.1789            break;1790        }1791      }17921793      // 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 - 321818      int index = FindExistingUpdate(entry); - 321819       if ( index >= 0 ) { - 321820        contentsEdited_ = true; - 321821        updates_[index] = null; - 321822        updateCount_ -= 1; - 321823      }1824      else { - 01825        throw new ZipException("Cannot find entry to delete"); + 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    }18281829    #endregion18301831    #region Update Support1827 + 657481828      var ed = new ZipExtraData(entry.ExtraData);1829 + 657481830       if (entry.LocalHeaderRequiresZip64) { + 21831        ed.StartNewEntry();  18321833    #region Writing Values/Headers1834    void WriteLEShort(int value)1835    { - 22370481836      baseStream_.WriteByte(( byte )(value & 0xff)); - 22370481837      baseStream_.WriteByte(( byte )((value >> 8) & 0xff)); - 22370481838    }18391840    /// <summary>1841    /// Write an unsigned short in little endian byte order.1842    /// </summary>1843    void WriteLEUshort(ushort value)1844    { - 2629441845      baseStream_.WriteByte(( byte )(value & 0xff)); - 2629441846      baseStream_.WriteByte(( byte )(value >> 8)); - 2629441847    }18481849    /// <summary>1850    /// Write an int in little endian byte order.1851    /// </summary>1852    void WriteLEInt(int value)1853    { - 6581801854      WriteLEShort(value & 0xffff); - 6581801855      WriteLEShort(value >> 16); - 6581801856    }18571858    /// <summary>1859    /// Write an unsigned int in little endian byte order.1860    /// </summary>1861    void WriteLEUint(uint value)1862    { - 1314721863      WriteLEUshort((ushort)(value & 0xffff)); - 1314721864      WriteLEUshort((ushort)(value >> 16)); - 1314721865    }18661867    /// <summary>1868    /// Write a long in little endian byte order.1869    /// </summary>1870    void WriteLeLong(long value)1871    { - 41872      WriteLEInt(( int )(value & 0xffffffff)); - 41873      WriteLEInt(( int )(value >> 32)); - 41874    }18751876    void WriteLEUlong(ulong value)1877    { - 01878      WriteLEUint(( uint )(value & 0xffffffff)); - 01879      WriteLEUint(( uint )(value >> 32)); - 01880    }18811882    void WriteLocalEntryHeader(ZipUpdate update)1883    { - 657481884      ZipEntry entry = update.OutEntry;18851886      // TODO: Local offset will require adjusting for multi-disk zip files. - 657481887      entry.Offset = baseStream_.Position;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    }18631864    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      }18771878      // Write the central file header + 657721879      WriteLEInt(ZipConstants.CentralHeaderSignature);18801881      // Version made by + 657721882      WriteLEShort(ZipConstants.VersionMadeBy);18831884      // Version required to extract + 657721885      WriteLEShort(entry.Version);1886 + 657721887      WriteLEShort(entry.Flags);  18881889      // TODO: Need to clear any entry flags that dont make sense or throw an exception here. - 657481890       if (update.Command != UpdateCommand.Copy) { - 657051891         if (entry.CompressionMethod == CompressionMethod.Deflated) { - 656901892           if (entry.Size == 0) {1893            // No need to compress - no data. - 655371894            entry.CompressedSize = entry.Size; - 655371895            entry.Crc = 0; - 655371896            entry.CompressionMethod = CompressionMethod.Stored;1897          } - 655371898        } - 151899         else if (entry.CompressionMethod == CompressionMethod.Stored) { - 151900          entry.Flags &= ~(int)GeneralBitFlags.Descriptor;1901        }1902 - 657051903         if (HaveKeys) { - 51904          entry.IsCrypted = true; - 51905           if (entry.Crc < 0) { - 51906            entry.Flags |= (int)GeneralBitFlags.Descriptor;1907          } - 51908        }1909        else { - 657001910          entry.IsCrypted = false;1911        }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 - 657051913         switch (useZip64_) {1914          case UseZip64.Dynamic: - 657011915             if (entry.Size < 0) { - 01916              entry.ForceZip64();1917            } - 01918            break;19191920          case UseZip64.On: - 21921            entry.ForceZip64();1922            break;19231924          case UseZip64.Off:1925            // Do nothing.  The entry itself may be using Zip64 independantly.1926            break; + 657721913      WriteLEShort(name.Length);19141915      // 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      }19291930      // Write the local file header - 657481931      WriteLEInt(ZipConstants.LocalHeaderSignature);1928 + 21929         if (entry.Offset >= 0xffffffff) { + 01930          ed.AddLeLong(entry.Offset);1931        }  1932 - 657481933      WriteLEShort(entry.Version); - 657481934      WriteLEShort(entry.Flags);1935 - 657481936      WriteLEShort((byte)entry.CompressionMethod); - 657481937      WriteLEInt(( int )entry.DosTime);1938 - 657481939       if ( !entry.HasCrc ) {1940        // Note patch address for updating CRC later. - 1681941        update.CrcPatchOffset = baseStream_.Position; - 1681942        WriteLEInt(( int )0); - 1681943      }1944      else { - 655801945        WriteLEInt(unchecked(( int )entry.Crc));1946      }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 - 657481948       if (entry.LocalHeaderRequiresZip64) { - 21949        WriteLEInt(-1); - 21950        WriteLEInt(-1); - 21951      }1952      else { - 657461953         if ( (entry.CompressedSize < 0) || (entry.Size < 0) ) { - 1661954          update.SizePatchOffset = baseStream_.Position;1955        }1956 - 657461957        WriteLEInt(( int )entry.CompressedSize); - 657461958        WriteLEInt(( int )entry.Size);1959      }1960 - 657481961      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);1962 - 657481963       if ( name.Length > 0xFFFF ) { - 01964        throw new ZipException("Entry name too long.");1965      }1966 - 657481967      var ed = new ZipExtraData(entry.ExtraData);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 - 657481969       if ( entry.LocalHeaderRequiresZip64 ) { - 21970        ed.StartNewEntry();19711972        // Local entry header always includes size and compressed size.1973        // NOTE the order of these fields is reversed when compared to the normal headers! - 21974        ed.AddLeLong(entry.Size); - 21975        ed.AddLeLong(entry.CompressedSize); - 21976        ed.AddNewEntry(1); - 21977      }1978      else { - 657461979        ed.Delete(1);1980      }1981 - 657481982      entry.ExtraData = ed.GetEntryData();1983 - 657481984      WriteLEShort(name.Length); - 657481985      WriteLEShort(entry.ExtraData.Length);1986 - 657481987       if ( name.Length > 0 ) { - 657481988        baseStream_.Write(name, 0, name.Length);1989      }1990 - 657481991       if ( entry.LocalHeaderRequiresZip64 ) { - 21992         if ( !ed.Find(1) ) { - 01993          throw new ZipException("Internal error cannot find extra data");1994        }1995 - 21996        update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;1997      }1998 - 657481999       if ( entry.ExtraData.Length > 0 ) { - 22000        baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);2001      } - 657482002    }20032004    int WriteCentralDirectoryHeader(ZipEntry entry)2005    { - 657722006       if ( entry.CompressedSize < 0 ) { - 02007        throw new ZipException("Attempt to write central directory entry with unknown csize");2008      }2009 - 657722010       if ( entry.Size < 0 ) { - 02011        throw new ZipException("Attempt to write central directory entry with unknown size");2012      }2013 - 657722014       if ( entry.Crc < 0 ) { - 02015        throw new ZipException("Attempt to write central directory entry with unknown crc");2016      }20172018      // Write the central file header - 657722019      WriteLEInt(ZipConstants.CentralHeaderSignature);20202021      // Version made by - 657722022      WriteLEShort(ZipConstants.VersionMadeBy);20232024      // Version required to extract - 657722025      WriteLEShort(entry.Version); + 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    #endregion19821983    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    }19941995    string GetTransformedFileName(string name)1996    { + 657401997      INameTransform transform = NameTransform; + 657401998       return (transform != null) ? + 657401999        transform.TransformFile(name) : + 657402000        name;2001    }20022003    string GetTransformedDirectoryName(string name)2004    { + 02005      INameTransform transform = NameTransform; + 02006       return (transform != null) ? + 02007        transform.TransformDirectory(name) : + 02008        name;2009    }20102011    /// <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    }20222023    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2024    { + 42025      int bytesToCopy = GetDescriptorSize(update);  2026 - 657722027      WriteLEShort(entry.Flags);20282029      unchecked { - 657722030        WriteLEShort((byte)entry.CompressionMethod); - 657722031        WriteLEInt((int)entry.DosTime); - 657722032        WriteLEInt((int)entry.Crc);2033      }2034 - 657722035       if ( (entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff) ) { - 22036        WriteLEInt(-1); - 22037      }2038      else { - 657702039        WriteLEInt((int)(entry.CompressedSize & 0xffffffff));2040      }2041 - 657722042       if ( (entry.IsZip64Forced()) || (entry.Size >= 0xffffffff) ) { - 22043        WriteLEInt(-1); - 22044      }2045      else { - 657702046        WriteLEInt((int)entry.Size);2047      }2048 - 657722049      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name); + 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    }20432044    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 - 657722051       if ( name.Length > 0xFFFF ) { - 02052        throw new ZipException("Entry name is too long.");2053      }2051      // NOTE: Compressed size is updated elsewhere. + 1722052      var crc = new Crc32(); + 1722053      byte[] buffer = GetBuffer();  2054 - 657722055      WriteLEShort(name.Length);20562057      // Central header extra data is different to local header version so regenerate. - 657722058      var ed = new ZipExtraData(entry.ExtraData);2059 - 657722060       if ( entry.CentralHeaderRequiresZip64 ) { - 22061        ed.StartNewEntry();2062 - 22063         if ( (entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On) )2064        { - 22065          ed.AddLeLong(entry.Size);2066        }2067 - 22068         if ( (entry.CompressedSize >= 0xffffffff) || (useZip64_ == UseZip64.On) )2069        { - 22070          ed.AddLeLong(entry.CompressedSize);2071        }2072 - 22073         if ( entry.Offset >= 0xffffffff ) { - 02074          ed.AddLeLong(entry.Offset);2075        }20762077        // Number of disk on which this file starts isnt supported and is never written here. - 22078        ed.AddNewEntry(1); - 22079      }2080      else {2081        // Should have already be done when local header was added. - 657702082        ed.Delete(1);2083      }2084 - 657722085      byte[] centralExtraData = ed.GetEntryData(); + 1722055      long targetBytes = bytesToCopy; + 1722056      long totalBytesRead = 0;20572058      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 - 657722087      WriteLEShort(centralExtraData.Length); - 657722088       WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);2089 - 657722090      WriteLEShort(0);  // disk number - 657722091      WriteLEShort(0);  // internal file attributes20922093      // External file attributes... - 657722094       if ( entry.ExternalFileAttributes != -1 ) { - 722095        WriteLEInt(entry.ExternalFileAttributes); - 722096      }2097      else { - 657002098         if ( entry.IsDirectory ) { - 02099          WriteLEUint(16); - 02100        }2101        else { - 657002102          WriteLEUint(0);2103        }2104      }2105 - 657722106       if ( entry.Offset >= 0xffffffff ) { - 02107        WriteLEUint(0xffffffff); - 02108      }2109      else { - 657722110        WriteLEUint((uint)(int)entry.Offset);2111      }2112 - 657722113       if ( name.Length > 0 ) { - 657722114        baseStream_.Write(name, 0, name.Length);2115      }2116 - 657722117       if ( centralExtraData.Length > 0 ) { - 22118        baseStream_.Write(centralExtraData, 0, centralExtraData.Length);2119      }2120 - 657722121       byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];2122 - 657722123       if ( rawComment.Length > 0 ) { - 02124        baseStream_.Write(rawComment, 0, rawComment.Length);2125      }2126 - 657722127      return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;2128    }2129    #endregion21302131    void PostUpdateCleanup()2132    { - 1362133            updateDataSource_ = null; - 1362134            updates_ = null; - 1362135            updateIndex_ = null;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    }21032104    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    }21252126    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2127    { + 392128      long bytesToCopy = update.Entry.CompressedSize;21292130      // 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 - 1362137             if (archiveStorage_ != null)2138            { - 482139        archiveStorage_.Dispose(); - 482140        archiveStorage_=null;2141      } - 1362142    }21432144    string GetTransformedFileName(string name)2145    { - 657402146            INameTransform transform = NameTransform; - 657402147       return (transform != null) ? - 657402148        transform.TransformFile(name) : - 657402149        name;2150    }21512152    string GetTransformedDirectoryName(string name)2153    { - 02154            INameTransform transform = NameTransform; - 02155             return (transform != null) ? - 02156        transform.TransformDirectory(name) : - 02157        name;2158    }21592160    /// <summary>2161    /// Get a raw memory buffer.2162    /// </summary>2163    /// <returns>Returns a raw memory buffer.</returns>2164    byte[] GetBuffer()2165    { - 2112166       if ( copyBuffer_ == null ) { - 412167        copyBuffer_ = new byte[bufferSize_];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      } - 2112169      return copyBuffer_;2170    }21712172    void CopyDescriptorBytes(ZipUpdate update, Stream dest, Stream source)2173    { - 42174      int bytesToCopy = GetDescriptorSize(update); + 392169    }21702171    int FindExistingUpdate(ZipEntry entry)2172    { + 322173      int result = -1; + 322174      string convertedName = GetTransformedFileName(entry.Name);  2175 - 42176       if ( bytesToCopy > 0 ) { - 02177        byte[] buffer = GetBuffer();2178 - 02179         while ( bytesToCopy > 0 ) { - 02180          int readSize = Math.Min(buffer.Length, bytesToCopy);2181 - 02182          int bytesRead = source.Read(buffer, 0, readSize); - 02183           if ( bytesRead > 0 ) { - 02184            dest.Write(buffer, 0, bytesRead); - 02185            bytesToCopy -= bytesRead; - 02186          }2187          else { - 02188            throw new ZipException("Unxpected end of stream");2189          }2190        }2191      } - 42192    }21932194    void CopyBytes(ZipUpdate update, Stream destination, Stream source,2195      long bytesToCopy, bool updateCrc) + 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 useful2181            // 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    }21942195    int FindExistingUpdate(string fileName)  2196    { - 1722197       if ( destination == source ) { - 02198        throw new InvalidOperationException("Destination and source are the same");2199      } + 657082197      int result = -1;2198 + 657082199      string convertedName = GetTransformedFileName(fileName);  22002201      // NOTE: Compressed size is updated elsewhere. - 1722202      var crc = new Crc32(); - 1722203      byte[] buffer = GetBuffer(); + 657082201       if (updateIndex_.ContainsKey(convertedName)) { + 32202        result = (int)updateIndex_[convertedName];2203      }  2204 - 1722205      long targetBytes = bytesToCopy; - 1722206      long totalBytesRead = 0;22072208      int bytesRead;2209      do { - 1722210        int readSize = buffer.Length;2211 - 1722212         if ( bytesToCopy < readSize ) { - 1722213          readSize = (int)bytesToCopy;2214        }2215 - 1722216        bytesRead = source.Read(buffer, 0, readSize); - 1722217         if ( bytesRead > 0 ) { - 1722218           if ( updateCrc ) { - 1682219            crc.Update(buffer, 0, bytesRead);2220          } - 1722221          destination.Write(buffer, 0, bytesRead); - 1722222          bytesToCopy -= bytesRead; - 1722223          totalBytesRead += bytesRead;2224        }2225      } - 1722226       while ( (bytesRead > 0) && (bytesToCopy > 0) );2227 - 1722228       if ( totalBytesRead != targetBytes ) { - 02229        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2230      }2231 - 1722232       if ( updateCrc ) { - 1682233        update.OutEntry.Crc = crc.Value;2234      } - 1722235    }22362237    /// <summary>2238    /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.2239    /// </summary>2240    /// <param name="update">The update to get the size for.</param>2241    /// <returns>The descriptor size, zero if there isnt one.</returns>2242    int GetDescriptorSize(ZipUpdate update)2243    { - 452244      int result = 0; - 452245       if ( (update.Entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) { - 02246        result = ZipConstants.DataDescriptorSize - 4; - 02247         if ( update.Entry.LocalHeaderRequiresZip64 ) { - 02248          result = ZipConstants.Zip64DataDescriptorSize - 4;2249        }2250      } - 452251      return result;2252    }2205      /*2206            // This is slow like the coming of the next ice age but takes less storage and may be useful2207            // 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    }22192220    /// <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;22372238        case CompressionMethod.Deflated: + 1532239          var dos = new DeflaterOutputStream(result, new Deflater(9, true)); + 1532240          dos.IsStreamOwner = false; + 1532241          result = dos; + 1532242          break;22432244        default: + 02245          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2246      } + 1682247      return result;2248    }22492250    void AddEntry(ZipFile workFile, ZipUpdate update)2251    { + 657052252      Stream source = null;  22532254    void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)2255    { - 392256      int bytesToCopy = GetDescriptorSize(update);2257 - 392258       while ( bytesToCopy > 0 ) { - 02259        var readSize = (int)bytesToCopy; - 02260        byte[] buffer = GetBuffer(); + 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 - 02262        stream.Position = sourcePosition; - 02263        int bytesRead = stream.Read(buffer, 0, readSize); - 02264         if ( bytesRead > 0 ) { - 02265          stream.Position = destinationPosition; - 02266          stream.Write(buffer, 0, bytesRead); - 02267          bytesToCopy -= bytesRead; - 02268          destinationPosition += bytesRead; - 02269          sourcePosition += bytesRead; - 02270        }2271        else { - 02272          throw new ZipException("Unxpected end of stream");2273        }2274      } - 392275    }22762277    void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sou2278    { - 392279      long bytesToCopy = update.Entry.CompressedSize;22802281      // NOTE: Compressed size is updated elsewhere. - 392282      var crc = new Crc32(); - 392283      byte[] buffer = GetBuffer(); + 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 - 392285      long targetBytes = bytesToCopy; - 392286      long totalBytesRead = 0;22872288      int bytesRead;2289      do2290      { - 392291        int readSize = buffer.Length;2292 - 392293         if ( bytesToCopy < readSize ) { - 392294          readSize = (int)bytesToCopy;2295        } + 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 - 392297        stream.Position = sourcePosition; - 392298        bytesRead = stream.Read(buffer, 0, readSize); - 392299         if ( bytesRead > 0 ) { - 392300           if ( updateCrc ) { - 02301            crc.Update(buffer, 0, bytesRead);2302          } - 392303          stream.Position = destinationPosition; - 392304          stream.Write(buffer, 0, bytesRead);2305 - 392306          destinationPosition += bytesRead; - 392307          sourcePosition += bytesRead; - 392308          bytesToCopy -= bytesRead; - 392309          totalBytesRead += bytesRead;2310        }2311      } - 392312       while ( (bytesRead > 0) && (bytesToCopy > 0) );2313 - 392314       if ( totalBytesRead != targetBytes ) { - 02315        throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead))2316      }2317 - 392318       if ( updateCrc ) { - 02319        update.OutEntry.Crc = crc.Value;2320      } - 392321    }23222323    int FindExistingUpdate(ZipEntry entry)2324    { - 322325      int result = -1; - 322326      string convertedName = GetTransformedFileName(entry.Name);2327 - 322328       if (updateIndex_.ContainsKey(convertedName)) { - 322329        result = (int)updateIndex_[convertedName];2330      }2331/*2332      // This is slow like the coming of the next ice age but takes less storage and may be useful2333      // for CF?2334      for (int index = 0; index < updates_.Count; ++index)2335      {2336        ZipUpdate zu = ( ZipUpdate )updates_[index];2337        if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&2338          (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {2339          result = index;2340          break;2341        }2342      }2343 */ - 322344      return result;2345    }23462347    int FindExistingUpdate(string fileName)2348    { - 657082349      int result = -1;2350 - 657082351      string convertedName = GetTransformedFileName(fileName);2352 - 657082353       if (updateIndex_.ContainsKey(convertedName)) { - 32354        result = (int)updateIndex_[convertedName];2355      }23562357/*2358      // This is slow like the coming of the next ice age but takes less storage and may be useful2359      // for CF?2360      for ( int index = 0; index < updates_.Count; ++index ) {2361        if ( string.Compare(convertedName, (( ZipUpdate )updates_[index]).Entry.Name,2362          true, CultureInfo.InvariantCulture) == 0 ) {2363          result = index;2364          break;2365        }2366      }2367 */2368 - 657082369      return result;2370    }23712372    /// <summary>2373    /// Get an output stream for the specified <see cref="ZipEntry"/>2374    /// </summary>2375    /// <param name="entry">The entry to get an output stream for.</param>2376    /// <returns>The output stream obtained for the entry.</returns>2377    Stream GetOutputStream(ZipEntry entry)2378    { - 1682379      Stream result = baseStream_;2297    void ModifyEntry(ZipFile workFile, ZipUpdate update)2298    { + 02299      workFile.WriteLocalEntryHeader(update); + 02300      long dataStart = workFile.baseStream_.Position;23012302      // 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    }23142315    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;23262327      const int NameLengthOffset = 26;23282329      // TODO: Add base for SFX friendly handling + 632330      long entryDataOffset = update.Entry.Offset + NameLengthOffset;2331 + 632332      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);23332334      // 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        else2345          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2346          // 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    }23582359    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;23672368        // 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 - 1682381       if ( entry.IsCrypted == true ) {2382#if NETCF_1_02383        throw new ZipException("Encryption not supported for Compact Framework 1.0");2384#else - 52385        result = CreateAndInitEncryptionStream(result, entry);2386#endif2387      }2388 - 1682389       switch ( entry.CompressionMethod ) {2390        case CompressionMethod.Stored: - 152391          result = new UncompressedStream(result); - 152392          break;23932394        case CompressionMethod.Deflated: - 1532395          var dos = new DeflaterOutputStream(result, new Deflater(9, true)); - 1532396          dos.IsStreamOwner = false; - 1532397          result = dos; - 1532398          break;23992400        default: - 02401          throw new ZipException("Unknown compression method " + entry.CompressionMethod);2402      } - 1682403      return result;2404    }24052406    void AddEntry(ZipFile workFile, ZipUpdate update)2407    { - 657052408      Stream source = null;2409 - 657052410       if ( update.Entry.IsFile ) { - 657052411        source = update.GetSource();2412 - 657052413         if ( source == null ) { - 655402414          source = updateDataSource_.GetSource(update.Entry, update.Filename);2415        }2416      }2417 - 657052418       if ( source != null ) { - 1682419        using ( source ) { - 1682420          long sourceStreamLength = source.Length; - 1682421           if ( update.OutEntry.Size < 0 ) { - 1652422            update.OutEntry.Size = sourceStreamLength; - 1652423          }2424          else {2425            // Check for errant entries. - 32426             if ( update.OutEntry.Size != sourceStreamLength ) { - 02427              throw new ZipException("Entry size/stream size mismatch");2428            }2429          }2430 - 1682431          workFile.WriteLocalEntryHeader(update);2432 - 1682433          long dataStart = workFile.baseStream_.Position;2434 - 1682435          using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) { - 1682436            CopyBytes(update, output, source, sourceStreamLength, true); - 1682437          }2438 - 1682439          long dataEnd = workFile.baseStream_.Position; - 1682440          update.OutEntry.CompressedSize = dataEnd - dataStart;2441 - 1682442           if ((update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor) == (int)GeneralBitFlags.Descriptor)2443          { - 52444            var helper = new ZipHelperStream(workFile.baseStream_); - 52445            helper.WriteDataDescriptor(update.OutEntry);2446          } - 1682447        }2448      }2449      else { - 655372450        workFile.WriteLocalEntryHeader(update); - 655372451        update.OutEntry.CompressedSize = 0;2452      }2453 - 657052454    }24552456    void ModifyEntry(ZipFile workFile, ZipUpdate update)2457    { - 02458      workFile.WriteLocalEntryHeader(update); - 02459      long dataStart = workFile.baseStream_.Position;24602461      // TODO: This is slow if the changes don't effect the data!! - 02462       if ( update.Entry.IsFile && (update.Filename != null) ) { - 02463        using ( Stream output = workFile.GetOutputStream(update.OutEntry) ) { - 02464          using ( Stream source = this.GetInputStream(update.Entry) ) { - 02465            CopyBytes(update, output, source, source.Length, true); - 02466          }2467        }2468      }2469 - 02470      long dataEnd = workFile.baseStream_.Position; - 02471      update.Entry.CompressedSize = dataEnd - dataStart; - 02472    }24732474    void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destinationPosition)2475    { - 632476      bool skipOver = false || update.Entry.Offset == destinationPosition;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    }23912392    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    }24002401    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 doesnt2418          // 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.24212422          // 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        }24392440        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    }24562457    /// <summary>2458    /// Class used to sort updates.2459    /// </summary>2460    class UpdateComparer : IComparer2461    {2462      /// <summary>2463      /// Compares two objects and returns a value indicating whether one is2464      /// 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;24752476        int result;  2477 - 632478       if ( !skipOver ) { - 392479        baseStream_.Position = destinationPosition; - 392480        workFile.WriteLocalEntryHeader(update); - 392481        destinationPosition = baseStream_.Position;2482      }2483 - 632484      long sourcePosition = 0;24852486      const int NameLengthOffset = 26;24872488      // TODO: Add base for SFX friendly handling - 632489      long entryDataOffset = update.Entry.Offset + NameLengthOffset;2490 - 632491      baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);24922493      // Clumsy way of handling retrieving the original name and extra data length for now.2494      // TODO: Stop re-reading name and data length in CopyEntryDirect. - 632495      uint nameLength = ReadLEUshort(); - 632496      uint extraLength = ReadLEUshort();2497 - 632498      sourcePosition = baseStream_.Position + nameLength + extraLength;2499 - 632500       if (skipOver) { - 242501         if (update.OffsetBasedSize != -1) - 222502          destinationPosition += update.OffsetBasedSize;2503        else2504          // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) ar2505          // WinZip produces a warning on these entries:2506          // "caution: value of lrec.csize (compressed size) changed from ..." - 22507          destinationPosition += - 22508            (sourcePosition - entryDataOffset) + NameLengthOffset +  // Header size - 22509            update.Entry.CompressedSize + GetDescriptorSize(update); - 22510      }2511      else { - 392512         if ( update.Entry.CompressedSize > 0 ) { - 392513          CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition );2514        } - 392515        CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);2516      } - 392517    }25182519    void CopyEntry(ZipFile workFile, ZipUpdate update)2520    { - 42521      workFile.WriteLocalEntryHeader(update);2522 - 42523       if ( update.Entry.CompressedSize > 0 ) {2524        const int NameLengthOffset = 26;2525 - 42526        long entryDataOffset = update.Entry.Offset + NameLengthOffset;25272528        // TODO: This wont work for SFX files! - 42529        baseStream_.Seek(entryDataOffset, SeekOrigin.Begin); + 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    }25052506    void RunUpdates()2507    { + 442508      long sizeEntries = 0; + 442509      long endOfStream = 0; + 442510      bool directUpdate = false; + 442511      long destinationPosition = 0; // NOT SFX friendly25122513      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;25232524        // 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 - 42531        uint nameLength = ReadLEUshort(); - 42532        uint extraLength = ReadLEUshort();2533 - 42534        baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current); + 32531         if (key != null) { + 12532          workFile.key = (byte[])key.Clone();2533        }2534      }  2535 - 42536        CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);2537      } - 42538      CopyDescriptorBytes(update, workFile.baseStream_, baseStream_); - 42539    }25402541    void Reopen(Stream source)2542    { - 42543       if ( source == null ) { - 02544        throw new ZipException("Failed to reopen archive - no source");2545      }2546 - 42547      isNewArchive_ = false; - 42548      baseStream_ = source; - 42549      ReadEntries(); - 42550    }25512552    void Reopen()2553    { - 02554       if (Name == null) { - 02555        throw new InvalidOperationException("Name is not known cannot Reopen");2556      }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;25472548              case UpdateCommand.Modify:2549                // TODO: Direct modifying of an entry will take some legwork. + 02550                ModifyEntry(workFile, update); + 02551                break;25522553              case UpdateCommand.Add: + 657052554                 if (!IsNewArchive && directUpdate) { + 1342555                  workFile.baseStream_.Position = destinationPosition;2556                }  2557 - 02558      Reopen(File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read)); - 02559    }25602561    void UpdateCommentOnly()2562    { - 32563      long baseLength = baseStream_.Length;2564 - 32565      ZipHelperStream updateFile = null;2566 - 32567       if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) { - 12568        Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_); - 12569        updateFile = new ZipHelperStream(copyStream); - 12570        updateFile.IsStreamOwner = true; + 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 - 12572        baseStream_.Close(); - 12573        baseStream_ = null; - 12574      }2575      else { - 22576         if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) {2577          // TODO: archiveStorage wasnt originally intended for this use.2578          // Need to revisit this to tidy up handling as archive storage currently doesnt2579          // handle the original stream well.2580          // The problem is when using an existing zip archive with an in memory archive storage.2581          // The open stream wont support writing but the memory storage should open the same file not an in memory one.25822583          // Need to tidy up the archive storage interface and contract basically. - 22584          baseStream_ = archiveStorage_.OpenForDirectUpdate(baseStream_); - 22585          updateFile = new ZipHelperStream(baseStream_); - 22586        }2587        else { - 02588          baseStream_.Close(); - 02589          baseStream_ = null; - 02590          updateFile = new ZipHelperStream(Name);2591        }2592      }2593 - 32594      using ( updateFile ) { - 32595        long locatedCentralDirOffset = - 32596          updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature, - 32597                            baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff); - 32598         if ( locatedCentralDirOffset < 0 ) { - 02599          throw new ZipException("Cannot find central directory");2600        }26012602        const int CentralHeaderCommentSizeOffset = 16; - 32603        updateFile.Position += CentralHeaderCommentSizeOffset;2604 - 32605        byte[] rawComment = newComment_.RawComment;2606 - 32607        updateFile.WriteLEShort(rawComment.Length); - 32608        updateFile.Write(rawComment, 0, rawComment.Length); - 32609        updateFile.SetLength(updateFile.Position); - 32610      }2611 - 32612       if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) { - 12613        Reopen(archiveStorage_.ConvertTemporaryToFinal()); - 12614      }2615      else { - 22616        ReadEntries();2617      } - 22618    }26192620    /// <summary>2621    /// Class used to sort updates.2622    /// </summary>2623    class UpdateComparer : IComparer2624    {2625      /// <summary>2626      /// Compares two objects and returns a value indicating whether one is2627      /// less than, equal to or greater than the other.2628      /// </summary>2629      /// <param name="x">First object to compare</param>2630      /// <param name="y">Second object to compare.</param>2631      /// <returns>Compare result.</returns>2632      public int Compare(2633        object x,2634        object y)2635      { - 4712636        var zx = x as ZipUpdate; - 4712637        var zy = y as ZipUpdate;26382639        int result;2640 - 4712641         if (zx == null) { - 502642           if (zy == null) { - 102643            result = 0; - 102644          }2645          else { - 402646            result = -1;2647          } - 402648        } - 4212649         else if (zy == null) { - 112650          result = 1; - 112651        }2652        else { - 4102653           int xCmdValue = ((zx.Command == UpdateCommand.Copy) || (zx.Command == UpdateCommand.Modify)) ? 0 : 1; - 4102654           int yCmdValue = ((zy.Command == UpdateCommand.Copy) || (zy.Command == UpdateCommand.Modify)) ? 0 : 1;2655 - 4102656          result = xCmdValue - yCmdValue; - 4102657           if (result == 0) { - 3782658            long offsetDiff = zx.Entry.Offset - zy.Entry.Offset; - 3782659             if (offsetDiff < 0) { - 162660              result = -1; - 162661            } - 3622662             else if (offsetDiff == 0) { - 2552663              result = 0; - 2552664            }2665            else { - 1072666              result = 1;2667            }2668          }2669        } - 4712670        return result;2671      }2672    }26732674    void RunUpdates()2675    { - 442676      long sizeEntries = 0; - 442677      long endOfStream = 0; - 442678      bool directUpdate = false; - 442679      long destinationPosition = 0; // NOT SFX friendly26802681      ZipFile workFile; + 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;25862587        // 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    }26272628    void CheckUpdating()2629    { + 657912630       if (updates_ == null) { + 02631        throw new InvalidOperationException("BeginUpdate has not been called");2632      } + 657912633    }26342635    #endregion26362637    #region ZipUpdate class2638    /// <summary>2639    /// Represents a pending update to a Zip file.2640    /// </summary>2641    class ZipUpdate2642    {2643      #region Constructors + 32644      public ZipUpdate(string fileName, ZipEntry entry)2645      { + 32646        command_ = UpdateCommand.Add; + 32647        entry_ = entry; + 32648        filename_ = fileName; + 32649      }26502651      [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      }26592660      [Obsolete]2661      public ZipUpdate(string fileName, string entryName) + 02662        : this(fileName, entryName, CompressionMethod.Deflated)2663      {2664        // Do nothing. + 02665      }26662667      [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 - 442683       if ( IsNewArchive ) { - 162684        workFile = this; - 162685        workFile.baseStream_.Position = 0; - 162686        directUpdate = true; - 162687      } - 282688       else if ( archiveStorage_.UpdateMode == FileUpdateMode.Direct ) { - 252689        workFile = this; - 252690        workFile.baseStream_.Position = 0; - 252691        directUpdate = true; + 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      }  26922693        // Sort the updates by offset within copies/modifies, then adds.2694        // This ensures that data required by copies will not be overwritten. - 252695        updates_.Sort(new UpdateComparer()); - 252696      }2697      else { - 32698        workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput()); - 32699        workFile.UseZip64 = UseZip64;2700 - 32701         if (key != null) { - 12702          workFile.key = (byte[])key.Clone();2703        }2704      }27052706      try { - 1317022707        foreach ( ZipUpdate update in updates_ ) { - 658072708           if (update != null) { - 657722709             switch (update.Command) {2710              case UpdateCommand.Copy: - 672711                 if (directUpdate) { - 632712                  CopyEntryDirect(workFile, update, ref destinationPosition); - 632713                }2714                else { - 42715                  CopyEntry(workFile, update);2716                } - 42717                break; + 656482693      public ZipUpdate(UpdateCommand command, ZipEntry entry)2694      { + 656482695        command_ = command; + 656482696        entry_ = (ZipEntry)entry.Clone(); + 656482697      }269826992700      /// <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      #endregion27102711      /// <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      }  27182719              case UpdateCommand.Modify:2720                // TODO: Direct modifying of an entry will take some legwork. - 02721                ModifyEntry(workFile, update); - 02722                break;27232724              case UpdateCommand.Add: - 657052725                 if (!IsNewArchive && directUpdate) { - 1342726                  workFile.baseStream_.Position = destinationPosition;2727                }2728 - 657052729                AddEntry(workFile, update);2730 - 657052731                 if (directUpdate) { - 657042732                  destinationPosition = workFile.baseStream_.Position;2733                }2734                break;2735            }2736          }2737        }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      }27312732      /// <summary>2733      /// Get the command for this update.2734      /// </summary>2735      public UpdateCommand Command { + 1328822736        get { return command_; }2737      }  2738 - 442739         if ( !IsNewArchive && directUpdate ) { - 252740          workFile.baseStream_.Position = destinationPosition;2741        }2742 - 442743        long centralDirOffset = workFile.baseStream_.Position;2744 - 1317022745        foreach ( ZipUpdate update in updates_ ) { - 658072746           if (update != null) { - 657722747            sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);2748          }2749        }2750 - 442751        byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_); - 442752        using ( ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_) ) { - 442753          zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment); - 442754        }2755 - 442756        endOfStream = workFile.baseStream_.Position;27572758        // And now patch entries... - 1317022759        foreach ( ZipUpdate update in updates_ ) { - 658072760           if (update != null)2761          {2762            // If the size of the entry is zero leave the crc as 0 as well.2763            // The calculated crc will be all bits on... - 657722764             if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) { - 1682765              workFile.baseStream_.Position = update.CrcPatchOffset; - 1682766              workFile.WriteLEInt((int)update.OutEntry.Crc);2767            }2768 - 657722769             if (update.SizePatchOffset > 0) { - 1682770              workFile.baseStream_.Position = update.SizePatchOffset; - 1682771               if (update.OutEntry.LocalHeaderRequiresZip64) { - 22772                workFile.WriteLeLong(update.OutEntry.Size); - 22773                workFile.WriteLeLong(update.OutEntry.CompressedSize); - 22774              }2775              else { - 1662776                workFile.WriteLEInt((int)update.OutEntry.CompressedSize); - 1662777                workFile.WriteLEInt((int)update.OutEntry.Size);2778              }2779            }2780          }2781        } - 442782      } - 02783      catch { - 02784        workFile.Close(); - 02785         if (!directUpdate && (workFile.Name != null)) { - 02786          File.Delete(workFile.Name);2787        } - 02788        throw;2789      }2790 - 442791       if (directUpdate) { - 412792        workFile.baseStream_.SetLength(endOfStream); - 412793        workFile.baseStream_.Flush(); - 412794        isNewArchive_ = false; - 412795        ReadEntries(); - 412796      }2797      else { - 32798        baseStream_.Close(); - 32799        Reopen(archiveStorage_.ConvertTemporaryToFinal());2800      } - 32801    }28022803    void CheckUpdating()2804    { - 657912805       if ( updates_ == null ) { - 02806        throw new InvalidOperationException("BeginUpdate has not been called");2807      } - 657912808    }28092810    #endregion28112812    #region ZipUpdate class2813    /// <summary>2814    /// Represents a pending update to a Zip file.2815    /// </summary>2816    class ZipUpdate2817    {2818      #region Constructors - 32819      public ZipUpdate(string fileName, ZipEntry entry)2820      { - 32821        command_ = UpdateCommand.Add; - 32822        entry_ = entry; - 32823        filename_ = fileName; - 32824      }28252826      [Obsolete] - 02827      public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)2828      { - 02829        command_ = UpdateCommand.Add; - 02830        entry_ = new ZipEntry(entryName); - 02831        entry_.CompressionMethod = compressionMethod; - 02832        filename_ = fileName; - 02833      }28342835      [Obsolete]2836      public ZipUpdate(string fileName, string entryName) - 02837        : this(fileName, entryName, CompressionMethod.Deflated)2838      {2839        // Do nothing. - 02840      }28412842      [Obsolete] - 02843      public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)2844      { - 02845        command_ = UpdateCommand.Add; - 02846        entry_ = new ZipEntry(entryName); - 02847        entry_.CompressionMethod = compressionMethod; - 02848        dataSource_ = dataSource; - 02849      }2850 - 1652851      public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)2852      { - 1652853        command_ = UpdateCommand.Add; - 1652854        entry_ = entry; - 1652855        dataSource_ = dataSource; - 1652856      }2857 - 02858      public ZipUpdate(ZipEntry original, ZipEntry updated)2859      { - 02860        throw new ZipException("Modify not currently supported");2861      /*2862        command_ = UpdateCommand.Modify;2863        entry_ = ( ZipEntry )original.Clone();2864        outEntry_ = ( ZipEntry )updated.Clone();2865      */2866      }2867 - 656482868      public ZipUpdate(UpdateCommand command, ZipEntry entry)2869      { - 656482870        command_ = command; - 656482871        entry_ = ( ZipEntry )entry.Clone(); - 656482872      }28732739      /// <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      }27452746      /// <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      }27532754      /// <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      }27612762      /// <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      }27702771      public Stream GetSource()2772      { + 657052773        Stream result = null; + 657052774         if (dataSource_ != null) { + 1652775          result = dataSource_.GetSource();2776        }2777 + 657052778        return result;2779      }27802781      #region Instance Fields2782      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      #endregion2791    }27922793    #endregion2794    #endregion27952796    #region Disposing27972798    #region IDisposable Members2799    void IDisposable.Dispose()2800    { + 822801      Close(); + 822802    }2803    #endregion28042805    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    }28202821    /// <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    }28302831    #endregion28322833    #region Internal routines2834    #region Reading2835    /// <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 prematurely2841    /// </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      }28552856 + 34961052857      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));2858    }28592860    /// <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 prematurely2869    /// </exception>2870    uint ReadLEUint()2871    { + 9893832872      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));2873    }  28742875      /// <summary>2876      /// Copy an existing entry.2877      /// </summary>2878      /// <param name="entry">The existing entry to copy.</param>2879      public ZipUpdate(ZipEntry entry) - 1112880        : this(UpdateCommand.Copy, entry)2881      {2882        // Do nothing. - 1112883      }2884      #endregion28852886      /// <summary>2887      /// Get the <see cref="ZipEntry"/> for this update.2888      /// </summary>2889      /// <remarks>This is the source or original entry.</remarks>2890      public ZipEntry Entry2891      { - 2638342892        get { return entry_; }2893      }28942895      /// <summary>2896      /// Get the <see cref="ZipEntry"/> that will be written to the updated/new file.2897      /// </summary>2898      public ZipEntry OutEntry2899      {2900        get { - 1989102901           if ( outEntry_ == null ) { - 657722902            outEntry_ = (ZipEntry)entry_.Clone();2903          }2904 - 1989102905          return outEntry_;2906        }2907      }2875    ulong ReadLEUlong()2876    { + 62877      return ReadLEUint() | ((ulong)ReadLEUint() << 32);2878    }28792880    #endregion2881    // 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    }28882889    /// <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 found2897    /// </exception>2898    void ReadEntries()2899    {2900      // Search for the End Of Central Directory.  When a zip comment is2901      // present the directory will start earlier2902      //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 files2905      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then2906      // this could be invalid.2907      // Could also speed this up by reading memory in larger blocks.  29082909      /// <summary>2910      /// Get the command for this update.2911      /// </summary>2912      public UpdateCommand Command2913      { - 1328822914        get { return command_; }2915      }29162917      /// <summary>2918      /// Get the filename if any for this update.  Null if none exists.2919      /// </summary>2920      public string Filename2921      { - 655402922        get { return filename_; }2923      }29242925      /// <summary>2926      /// Get/set the location of the size patch for this update.2927      /// </summary>2928      public long SizePatchOffset2929      { - 659402930        get { return sizePatchOffset_; } - 3362931        set { sizePatchOffset_ = value; }2932      }29332934      /// <summary>2935      /// Get /set the location of the crc patch for this update.2936      /// </summary>2937      public long CrcPatchOffset2938      { - 659402939        get { return crcPatchOffset_; } - 3362940        set { crcPatchOffset_ = value; }2941      }29422943      /// <summary>2944      /// Get/set the size calculated by offset.2945      /// Specifically, the difference between this and next entry's starting offset.2946      /// </summary>2947      public long OffsetBasedSize2948      { - 462949        get { return _offsetBasedSize; } - 1602950        set { _offsetBasedSize = value; }2951      }29522953      public Stream GetSource()2954      { - 657052955        Stream result = null; - 657052956         if ( dataSource_ != null ) { - 1652957          result = dataSource_.GetSource();2958        }2959 - 657052960        return result;2961      }29622963      #region Instance Fields2964      ZipEntry entry_;2965      ZipEntry outEntry_;2966      UpdateCommand command_;2967      IStaticDataSource dataSource_;2968      string filename_; - 658162969      long sizePatchOffset_ = -1; - 658162970      long crcPatchOffset_ = -1; - 658162971      long _offsetBasedSize = -1;2972      #endregion2973    }29742975    #endregion2976    #endregion29772978    #region Disposing29792980    #region IDisposable Members2981    void IDisposable.Dispose()2982    { - 822983      Close(); - 822984    }2985    #endregion29862987    void DisposeInternal(bool disposing)2988    { - 982989       if ( !isDisposed_ ) { - 882990        isDisposed_ = true; - 882991        entries_ = new ZipEntry[0];2992 - 882993         if ( IsStreamOwner && (baseStream_ != null) ) { - 492994          lock(baseStream_) { - 492995            baseStream_.Close(); - 492996          }2997        } + 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      }29192920      // 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;29392940      // 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        }29532954        // number of the disk with the start of the zip64 end of central directory 4 bytes2955        // relative offset of the zip64 end of central directory record 8 bytes2956        // 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        }29672968        // 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();29782979        // NOTE: zip64 extensible data sector (variable size) is ignored.2980      }2981 + 1132982      entries_ = new ZipEntry[entriesForThisDisk];29832984      // SFX/embedded support, find the offset of the first entry vis the start of the stream2985      // 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 offsets2988      // 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 - 882999        PostUpdateCleanup();3000      } - 983001    }30023003    /// <summary>3004    /// Releases the unmanaged resources used by the this instance and optionally releases the managed resources.3005    /// </summary>3006    /// <param name="disposing">true to release both managed and unmanaged resources;3007    /// false to release only unmanaged resources.</param>3008    protected virtual void Dispose(bool disposing)3009    { - 63010      DisposeInternal(disposing); - 63011    }30123013    #endregion30143015    #region Internal routines3016    #region Reading3017    /// <summary>3018    /// Read an unsigned short in little endian byte order.3019    /// </summary>3020    /// <returns>Returns the value read.</returns>3021    /// <exception cref="EndOfStreamException">3022    /// The stream ends prematurely3023    /// </exception>3024    ushort ReadLEUshort()3025    { - 34961053026      int data1 = baseStream_.ReadByte();3027 - 34961053028       if ( data1 < 0 ) { - 03029        throw new EndOfStreamException("End of stream");3030      }3031 - 34961053032      int data2 = baseStream_.ReadByte();3033 - 34961053034       if ( data2 < 0 ) { - 03035        throw new EndOfStreamException("End of stream");3036      }30373038 - 34961053039      return unchecked((ushort)((ushort)data1 | (ushort)(data2 << 8)));3040    }30413042    /// <summary>3043    /// Read a uint in little endian byte order.3044    /// </summary>3045    /// <returns>Returns the value read.</returns>3046    /// <exception cref="IOException">3047    /// An i/o error occurs.3048    /// </exception>3049    /// <exception cref="System.IO.EndOfStreamException">3050    /// The file ends prematurely3051    /// </exception>3052    uint ReadLEUint()3053    { - 9893833054      return (uint)(ReadLEUshort() | (ReadLEUshort() << 16));3055    }30563057    ulong ReadLEUlong()3058    { - 63059      return ReadLEUint() | ((ulong)ReadLEUint() << 32);3060    }30613062    #endregion3063    // NOTE this returns the offset of the first byte after the signature.3064    long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)3065    { - 1153066      using ( ZipHelperStream les = new ZipHelperStream(baseStream_) ) { - 1153067        return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);3068      } - 1153069    }30703071    /// <summary>3072    /// Search for and read the central directory of a zip file filling the entries array.3073    /// </summary>3074    /// <exception cref="System.IO.IOException">3075    /// An i/o error occurs.3076    /// </exception>3077    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3078    /// The central directory is malformed or cannot be found3079    /// </exception>3080    void ReadEntries()3081    {3082      // Search for the End Of Central Directory.  When a zip comment is3083      // present the directory will start earlier3084      //3085      // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.3086      // This should be compatible with both SFX and ZIP files but has only been tested for Zip files3087      // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then3088      // this could be invalid.3089      // Could also speed this up by reading memory in larger blocks. + 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 used3018 + 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    }30593060    /// <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 prematurely3068    /// </exception>3069    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3070    /// The local header signature is invalid, the entry and central header file name lengths are different3071    /// or the local and entry compression methods dont match3072    /// </exception>3073    long LocateEntry(ZipEntry entry)3074    { + 659463075      return TestLocalHeader(entry, HeaderTest.Extract);3076    }30773078    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 - 1143091       if (baseStream_.CanSeek == false) { - 03092        throw new ZipException("ZipFile stream must be seekable");3093      }3094 - 1143095      long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature, - 1143096        baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);3097 - 1143098       if (locatedEndOfCentralDir < 0) { - 13099        throw new ZipException("Cannot find central directory");3100      }31013102      // Read end of central directory record - 1133103      ushort thisDiskNumber           = ReadLEUshort(); - 1133104      ushort startCentralDirDisk      = ReadLEUshort(); - 1133105      ulong entriesForThisDisk        = ReadLEUshort(); - 1133106      ulong entriesForWholeCentralDir = ReadLEUshort(); - 1133107      ulong centralDirSize            = ReadLEUint(); - 1133108      long offsetOfCentralDir         = ReadLEUint(); - 1133109      uint commentSize                = ReadLEUshort();3110 - 1133111       if ( commentSize > 0 ) { - 103112        byte[] comment = new byte[commentSize];3113 - 103114        StreamUtils.ReadFully(baseStream_, comment); - 103115        comment_ = ZipConstants.ConvertToString(comment); - 103116      }3117      else { - 1033118        comment_ = string.Empty;3119      }3120 - 1133121      bool isZip64 = false; + 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 bytes3109 + 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    }  31223123      // Check if zip64 header information is required. - 1133124       if ( (thisDiskNumber == 0xffff) || - 1133125        (startCentralDirDisk == 0xffff) || - 1133126        (entriesForThisDisk == 0xffff) || - 1133127        (entriesForWholeCentralDir == 0xffff) || - 1133128        (centralDirSize == 0xffffffff) || - 1133129        (offsetOfCentralDir == 0xffffffff) ) { - 13130        isZip64 = true;3131 - 13132        long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0,  - 13133         if ( offset < 0 ) { - 03134          throw new ZipException("Cannot find Zip64 locator");3135        }31363137        // number of the disk with the start of the zip64 end of central directory 4 bytes3138        // relative offset of the zip64 end of central directory record 8 bytes3139        // total number of disks 4 bytes - 13140        ReadLEUint(); // startDisk64 is not currently used - 13141        ulong offset64 = ReadLEUlong(); - 13142        uint totalDisks = ReadLEUint();3143 - 13144        baseStream_.Position = (long)offset64; - 13145        long sig64 = ReadLEUint();3146 - 13147         if ( sig64 != ZipConstants.Zip64CentralFileHeaderSignature ) { - 03148          throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));3149        }31503151        // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12. - 13152        ulong recordSize = ReadLEUlong(); - 13153        int versionMadeBy = ReadLEUshort(); - 13154        int versionToExtract = ReadLEUshort(); - 13155        uint thisDisk = ReadLEUint(); - 13156        uint centralDirDisk = ReadLEUint(); - 13157        entriesForThisDisk = ReadLEUlong(); - 13158        entriesForWholeCentralDir = ReadLEUlong(); - 13159        centralDirSize = ReadLEUlong(); - 13160        offsetOfCentralDir = (long)ReadLEUlong();31613162        // NOTE: zip64 extensible data sector (variable size) is ignored.3163      }3164 - 1133165      entries_ = new ZipEntry[entriesForThisDisk];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        }31343135        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3136        // 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    }31483149    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    }31573158    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    }  31663167      // SFX/embedded support, find the offset of the first entry vis the start of the stream3168      // This applies to Zip files that are appended to the end of an SFX stub.3169      // Or are appended as a resource to an executable.3170      // Zip files created by some archivers have the offsets altered to reflect the true offsets3171      // and so dont require any adjustment here...3172      // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths? - 1133173       if ( !isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize)) ) { - 23174        offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir); - 23175         if (offsetOfFirstEntry <= 0) { - 03176          throw new ZipException("Invalid embedded zip archive");3177        }3178      }3179 - 1133180      baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);3181 - 1321383182       for (ulong i = 0; i < entriesForThisDisk; i++) { - 659563183         if (ReadLEUint() != ZipConstants.CentralHeaderSignature) { - 03184          throw new ZipException("Wrong Central Directory signature");3185        }3167    #endregion31683169    #region Instance Fields3170    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_;31803181    // Default is dynamic which is not backwards compatible and can cause problems3182    // 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 - 659563187        int versionMadeBy      = ReadLEUshort(); - 659563188        int versionToExtract   = ReadLEUshort(); - 659563189        int bitFlags           = ReadLEUshort(); - 659563190        int method             = ReadLEUshort(); - 659563191        uint dostime           = ReadLEUint(); - 659563192        uint crc               = ReadLEUint(); - 659563193        var csize             = (long)ReadLEUint(); - 659563194        var size              = (long)ReadLEUint(); - 659563195        int nameLen            = ReadLEUshort(); - 659563196        int extraLen           = ReadLEUshort(); - 659563197        int commentLen         = ReadLEUshort();3198 - 659563199        int diskStartNo        = ReadLEUshort();  // Not currently used - 659563200        int internalAttributes = ReadLEUshort();  // Not currently used3187    #region Zip Update Instance Fields3188    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    #endregion3200    #endregion  3201 - 659563202        uint externalAttributes = ReadLEUint(); - 659563203        long offset             = ReadLEUint();3204 - 659563205        byte[] buffer = new byte[Math.Max(nameLen, commentLen)];3206 - 659563207        StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen); - 659563208        string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);3209 - 659563210        var entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method); - 659563211        entry.Crc = crc & 0xffffffffL; - 659563212        entry.Size = size & 0xffffffffL; - 659563213        entry.CompressedSize = csize & 0xffffffffL; - 659563214        entry.Flags = bitFlags; - 659563215        entry.DosTime = (uint)dostime; - 659563216        entry.ZipFileIndex = (long)i; - 659563217        entry.Offset = offset; - 659563218        entry.ExternalFileAttributes = (int)externalAttributes;3219 - 659563220         if ((bitFlags & 8) == 0) { - 659373221          entry.CryptoCheckValue = (byte)(crc >> 24); - 659373222        }3223        else { - 193224          entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);3225        }3226 - 659563227         if (extraLen > 0) { - 453228          byte[] extra = new byte[extraLen]; - 453229          StreamUtils.ReadFully(baseStream_, extra); - 453230          entry.ExtraData = extra;3231        }3232 - 659563233        entry.ProcessExtraData(false);3234 - 659563235         if (commentLen > 0) { - 03236          StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen); - 03237          entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);3238        }3239 - 659563240        entries_[i] = entry;3241      } - 1133242    }32433244    /// <summary>3245    /// Locate the data for a given entry.3246    /// </summary>3247    /// <returns>3248    /// The start offset of the data.3249    /// </returns>3250    /// <exception cref="System.IO.EndOfStreamException">3251    /// The stream ends prematurely3252    /// </exception>3253    /// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">3254    /// The local header signature is invalid, the entry and central header file name lengths are different3255    /// or the local and entry compression methods dont match3256    /// </exception>3257    long LocateEntry(ZipEntry entry)3258    { - 659463259      return TestLocalHeader(entry, HeaderTest.Extract);3260    }32613262#if !NETCF_1_03263    Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)3264    { - 103265      CryptoStream result = null;3266 - 103267       if ( (entry.Version < ZipConstants.VersionStrongEncryption) - 103268        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) { - 103269        var classicManaged = new PkzipClassicManaged();3270 - 103271        OnKeysRequired(entry.Name); - 103272         if (HaveKeys == false) { - 03273          throw new ZipException("No password available for encrypted stream");3274        }3202    #region Support Classes3203    /// <summary>3204    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3205    /// </summary>3206    class ZipString3207    {3208      #region Constructors3209      /// <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      }32183219      /// <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      #endregion32283229      /// <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      }32363237      /// <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      }32463247      /// <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      }32563257      /// <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      }32683269      void MakeTextAvailable()3270      { + 03271         if (comment_ == null) { + 03272          comment_ = ZipConstants.ConvertToString(rawComment_);3273        } + 03274      }  3275 - 103276        result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read); - 103277        CheckClassicPassword(result, entry); - 103278      }3279      else {3280#if !NET_1_1 && !NETCF_2_0 - 03281         if (entry.Version == ZipConstants.VERSION_AES) {3282          // - 03283          OnKeysRequired(entry.Name); - 03284           if (HaveKeys == false) { - 03285            throw new ZipException("No password available for AES encrypted stream");3286          } - 03287          int saltLen = entry.AESSaltLen; - 03288          byte[] saltBytes = new byte[saltLen]; - 03289          int saltIn = baseStream.Read(saltBytes, 0, saltLen); - 03290           if (saltIn != saltLen) - 03291            throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);3292          // - 03293          byte[] pwdVerifyRead = new byte[2]; - 03294          baseStream.Read(pwdVerifyRead, 0, 2); - 03295          int blockSize = entry.AESKeySize / 8;  // bits to bytes3296 - 03297          var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false); - 03298          byte[] pwdVerifyCalc = decryptor.PwdVerifier; - 03299           if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1]) - 03300            throw new Exception("Invalid password for AES"); - 03301          result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read); - 03302        }3303        else3304#endif3305        { - 03306          throw new ZipException("Decryption method not supported");3307        }3308      }3309 - 103310      return result;3311    }33123313    Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)3314    { - 53315      CryptoStream result = null; - 53316       if ( (entry.Version < ZipConstants.VersionStrongEncryption) - 53317        || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) { - 53318        var classicManaged = new PkzipClassicManaged();3276      void MakeBytesAvailable()3277      { + 63278         if (rawComment_ == null) { + 33279          rawComment_ = ZipConstants.ConvertToArray(comment_);3280        } + 63281      }32823283      /// <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      }32933294      #region Instance Fields3295      string comment_;3296      byte[] rawComment_;3297      bool isSourceString_;3298      #endregion3299    }33003301    /// <summary>3302    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3303    /// </summary>3304    class ZipEntryEnumerator : IEnumerator3305    {3306      #region Constructors + 43307      public ZipEntryEnumerator(ZipEntry[] entries)3308      { + 43309        array = entries; + 43310      }33113312      #endregion3313      #region IEnumerator Members3314      public object Current {3315        get { + 223316          return array[index];3317        }3318      }  3319 - 53320        OnKeysRequired(entry.Name); - 53321         if (HaveKeys == false) { - 03322          throw new ZipException("No password available for encrypted stream");3323        }3320      public void Reset()3321      { + 03322        index = -1; + 03323      }  33243325        // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream3326        // which doesnt do this. - 53327        result = new CryptoStream(new UncompressedStream(baseStream), - 53328          classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);3329 - 53330         if ( (entry.Crc < 0) || (entry.Flags & 8) != 0) { - 53331          WriteEncryptionHeader(result, entry.DosTime << 16); - 53332        }3333        else { - 03334          WriteEncryptionHeader(result, entry.Crc);3335        }3336      } - 53337      return result;3338    }33393340    static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)3325      public bool MoveNext()3326      { + 263327        return (++index < array.Length);3328      }3329      #endregion3330      #region Instance Fields3331      ZipEntry[] array; + 43332      int index = -1;3333      #endregion3334    }33353336    /// <summary>3337    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3338    /// to and flush, but cannot read, seek or do anything else to.3339    /// </summary>3340    class UncompressedStream : Stream  3341    { - 103342      byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize]; - 103343      StreamUtils.ReadFully(classicCryptoStream, cryptbuffer); - 103344       if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) { - 03345        throw new ZipException("Invalid password");3346      } - 103347    }3348#endif3342      #region Constructors + 203343      public UncompressedStream(Stream baseStream)3344      { + 203345        baseStream_ = baseStream; + 203346      }33473348      #endregion  33493350    static void WriteEncryptionHeader(Stream stream, long crcValue)3351    { - 53352      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize]; - 53353      var rnd = new Random(); - 53354      rnd.NextBytes(cryptBuffer); - 53355      cryptBuffer[11] = (byte)(crcValue >> 24); - 53356      stream.Write(cryptBuffer, 0, cryptBuffer.Length); - 53357    }33583359    #endregion33603361    #region Instance Fields3362    bool       isDisposed_;3363    string     name_;3364    string     comment_;3365    string     rawPassword_;3366    Stream     baseStream_;3367    bool       isStreamOwner;3368    long       offsetOfFirstEntry;3369    ZipEntry[] entries_;3370    byte[] key;3371    bool isNewArchive_;33723373    // Default is dynamic which is not backwards compatible and can cause problems3374    // with XP's built in compression which cant read Zip64 archives.3375    // However it does avoid the situation were a large file is added and cannot be completed correctly.3376    // Hint: Set always ZipEntry size before they are added to an archive and this setting isnt needed. - 883377    UseZip64 useZip64_ = UseZip64.Dynamic ;33783379    #region Zip Update Instance Fields3380    ArrayList updates_;3381    long updateCount_; // Count is managed manually as updates_ can contain nulls!3382    Hashtable updateIndex_;3383    IArchiveStorage archiveStorage_;3384    IDynamicDataSource updateDataSource_;3385    bool contentsEdited_; - 883386    int bufferSize_ = DefaultBufferSize;3387    byte[] copyBuffer_;3388    ZipString newComment_;3389    bool commentEdited_; - 883390    IEntryFactory updateEntryFactory_ = new ZipEntryFactory();3391    #endregion3392    #endregion33933394    #region Support Classes3395    /// <summary>3396    /// Represents a string from a <see cref="ZipFile"/> which is stored as an array of bytes.3397    /// </summary>3398    class ZipString3399    {3400      #region Constructors3401      /// <summary>3402      /// Initialise a <see cref="ZipString"/> with a string.3403      /// </summary>3404      /// <param name="comment">The textual string form.</param> - 33405      public ZipString(string comment)3406      { - 33407        comment_ = comment; - 33408        isSourceString_ = true; - 33409      }34103411      /// <summary>3412      /// Initialise a <see cref="ZipString"/> using a string in its binary 'raw' form.3413      /// </summary>3414      /// <param name="rawString"></param> - 03415      public ZipString(byte[] rawString)3416      { - 03417        rawComment_ = rawString; - 03418      }3419      #endregion34203421      /// <summary>3422      /// Get a value indicating the original source of data for this instance.3423      /// True if the source was a string; false if the source was binary data.3424      /// </summary>3425      public bool IsSourceString3426      { - 03427        get { return isSourceString_; }3428      }34293430      /// <summary>3431      /// Get the length of the comment when represented as raw bytes.3432      /// </summary>3433      public int RawLength3434      {3435        get { - 33436          MakeBytesAvailable(); - 33437          return rawComment_.Length;3438        }3439      }34403441      /// <summary>3442      /// Get the comment in its 'raw' form as plain bytes.3443      /// </summary>3444      public byte[] RawComment3445      {3446        get { - 33447          MakeBytesAvailable(); - 33448          return (byte[])rawComment_.Clone();3449        }3450      }34513452      /// <summary>3453      /// Reset the comment to its initial state.3454      /// </summary>3455      public void Reset()3456      { - 03457         if ( isSourceString_ ) { - 03458          rawComment_ = null; - 03459        }3460        else { - 03461          comment_ = null;3462        } - 03463      }34643465      void MakeTextAvailable()3466      { - 03467         if ( comment_ == null ) { - 03468          comment_ = ZipConstants.ConvertToString(rawComment_);3469        } - 03470      }34713472      void MakeBytesAvailable()3473      { - 63474         if ( rawComment_ == null ) { - 33475          rawComment_ = ZipConstants.ConvertToArray(comment_);3476        } - 63477      }34783479      /// <summary>3480      /// Implicit conversion of comment to a string.3481      /// </summary>3482      /// <param name="zipString">The <see cref="ZipString"/> to convert to a string.</param>3483      /// <returns>The textual equivalent for the input value.</returns>3484      static public implicit operator string(ZipString zipString)3485      { - 03486        zipString.MakeTextAvailable(); - 03487        return zipString.comment_;3488      }34893490      #region Instance Fields3491      string comment_;3492      byte[] rawComment_;3493      bool isSourceString_;3494      #endregion3495    }34963497    /// <summary>3498    /// An <see cref="IEnumerator">enumerator</see> for <see cref="ZipEntry">Zip entries</see>3499    /// </summary>3500    class ZipEntryEnumerator : IEnumerator3501    {3502      #region Constructors - 43503      public ZipEntryEnumerator(ZipEntry[] entries)3504      { - 43505        array = entries; - 43506      }35073508      #endregion3509      #region IEnumerator Members3510      public object Current3511      {3512        get { - 223513          return array[index];3514        }3515      }35163517      public void Reset()3518      { - 03519        index = -1; - 03520      }35213522      public bool MoveNext()3523      { - 263524        return (++index < array.Length);3525      }3526      #endregion3527      #region Instance Fields3528      ZipEntry[] array; - 43529      int index = -1;3530      #endregion3531    }35323533    /// <summary>3534    /// An <see cref="UncompressedStream"/> is a stream that you can write uncompressed data3535    /// to and flush, but cannot read, seek or do anything else to.3536    /// </summary>3537    class UncompressedStream : Stream3538    {3539      #region Constructors - 203540      public UncompressedStream(Stream baseStream)3541      { - 203542        baseStream_ = baseStream; - 203543      }35443545      #endregion35463547      /// <summary>3548      /// Close this stream instance.3549      /// </summary>3550      public override void Close()3551      {3552        // Do nothing - 153553      }35543555      /// <summary>3556      /// Gets a value indicating whether the current stream supports reading.3557      /// </summary>3558      public override bool CanRead3559      {3560        get { - 03561          return false;3562        }3563      }35643565      /// <summary>3566      /// Write any buffered data to underlying storage.3567      /// </summary>3568      public override void Flush()3569      { - 03570        baseStream_.Flush(); - 03571      }35723573      /// <summary>3574      /// Gets a value indicating whether the current stream supports writing.3575      /// </summary>3576      public override bool CanWrite3577      {3578        get { - 53579          return baseStream_.CanWrite;3580        }3581      }35823583      /// <summary>3584      /// Gets a value indicating whether the current stream supports seeking.3585      /// </summary>3586      public override bool CanSeek3587      {3588        get { - 03589          return false;3590        }3591      }35923593      /// <summary>3594      /// Get the length in bytes of the stream.3595      /// </summary>3596      public override long Length3597      {3598        get { - 03599          return 0;3600        }3601      }36023603      /// <summary>3604      /// Gets or sets the position within the current stream.3605      /// </summary>3606      public override long Position3607      {3608        get  { - 03609          return baseStream_.Position;3610        }3611                set { - 03612                    throw new NotImplementedException();3613                }3614            }36153616            /// <summary>3617            /// Reads a sequence of bytes from the current stream and advances the position within the stream by the num3618            /// </summary>3619            /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte3620            /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from t3621            /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3622            /// <returns>3623            /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if t3624            /// </returns>3625            /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer lengt3626            /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </ex3627            /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3628            /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3629            /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3630            /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3631            public override int Read(byte[] buffer, int offset, int count)3632      { - 03633        return 0;3634      }36353636      /// <summary>3637      /// Sets the position within the current stream.3638      /// </summary>3639      /// <param name="offset">A byte offset relative to the origin parameter.</param>3640      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3641      /// <returns>3642      /// The new position within the current stream.3643      /// </returns>3644      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3645      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3646      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3647      public override long Seek(long offset, SeekOrigin origin)3648      { - 03649        return 0;3650      }36513652      /// <summary>3653      /// Sets the length of the current stream.3654      /// </summary>3655      /// <param name="value">The desired length of the current stream in bytes.</param>3656      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3350      /// <summary>3351      /// Close this stream instance.3352      /// </summary>3353      public override void Close()3354      {3355        // Do nothing + 153356      }33573358      /// <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      }33663367      /// <summary>3368      /// Write any buffered data to underlying storage.3369      /// </summary>3370      public override void Flush()3371      { + 03372        baseStream_.Flush(); + 03373      }33743375      /// <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      }33833384      /// <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      }33923393      /// <summary>3394      /// Get the length in bytes of the stream.3395      /// </summary>3396      public override long Length {3397        get { + 03398          return 0;3399        }3400      }34013402      /// <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      }34133414      /// <summary>3415      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3416      /// </summary>3417      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3418      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3419      /// <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 ma3422      /// </returns>3423      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3424      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3425      /// <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      }34333434      /// <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 is3444      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3445      public override long Seek(long offset, SeekOrigin origin)3446      { + 03447        return 0;3448      }34493450      /// <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 as3455      /// <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. </exceptio3457      public override void SetLength(long value)3458      { + 03459      }34603461      /// <summary>3462      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3463      /// </summary>3464      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3465      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3466      /// <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. </exceptio3470      /// <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      }34773478      readonly34793480      #region Instance Fields3481      Stream baseStream_;3482      #endregion3483    }34843485    /// <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 : Stream3490    {3491      #region Constructors3492      /// <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;35023503        // Although this is the only time the zipfile is used3504        // keeping a reference here prevents premature closure of3505        // this zip file and thus the baseStream_.35063507        // Code like this will cause apparently random failures depending3508        // 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      #endregion35193520      /// <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      }35363537      /// <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      }35473548      /// <summary>3549      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3550      /// </summary>3551      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3552      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3553      /// <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 ma3556      /// </returns>3557      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3558      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3559      /// <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 Seek3573          // (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      }35843585      /// <summary>3586      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3587      /// </summary>3588      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3589      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3590      /// <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. </exceptio3594      /// <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      }36013602      /// <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 as3607      /// <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. </exceptio3609      public override void SetLength(long value)3610      { + 03611        throw new NotSupportedException();3612      }36133614      /// <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 is3624      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3625      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;36333634          case SeekOrigin.Current: + 03635            newPos = readPos_ + offset; + 03636            break;36373638          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      }36533654      /// <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      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3659      public override void SetLength(long value)3660      {3658      public override void Flush()3659      {3660        // Nothing to do.  03661      }  3662  3663      /// <summary>3664      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3664      /// Gets or sets the position within the current stream.  3665      /// </summary>3666      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3667      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3668      /// <param name="count">The number of bytes to be written to the current stream.</param>3669      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3670      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3671      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3672      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3673      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3674      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3675      public override void Write(byte[] buffer, int offset, int count)3676      { - 253677        baseStream_.Write(buffer, offset, count); - 253678      }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. </exceptio3671      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          }  36793680      readonly36813682      #region Instance Fields3683      Stream baseStream_;3684      #endregion3685    } + 03680           if (newPos >= end_) { + 03681            throw new InvalidOperationException("Cannot seek past end");3682          } + 03683          readPos_ = newPos; + 03684        }3685      }  36863687    /// <summary>3688    /// A <see cref="PartialInputStream"/> is an <see cref="InflaterInputStream"/>3689    /// whose data is only a part or subsection of a file.3690    /// </summary>3691    class PartialInputStream : Stream3692    {3693      #region Constructors3694      /// <summary>3695      /// Initialise a new instance of the <see cref="PartialInputStream"/> class.3696      /// </summary>3697      /// <param name="zipFile">The <see cref="ZipFile"/> containing the underlying stream to use for IO.</param>3698      /// <param name="start">The start of the partial data.</param>3699      /// <param name="length">The length of the partial data.</param> - 659463700      public PartialInputStream(ZipFile zipFile, long start, long length)3701      { - 659463702        start_ = start; - 659463703        length_ = length;37043705        // Although this is the only time the zipfile is used3706        // keeping a reference here prevents premature closure of3707        // this zip file and thus the baseStream_.37083709        // Code like this will cause apparently random failures depending3710        // on the size of the files and when garbage is collected.3711        //3712        // ZipFile z = new ZipFile (stream);3713        // Stream reader = z.GetInputStream(0);3714        // uses reader here.... - 659463715        zipFile_ = zipFile; - 659463716        baseStream_ = zipFile_.baseStream_; - 659463717        readPos_ = start; - 659463718        end_ = start + length; - 659463719      }3720      #endregion37213722      /// <summary>3723      /// Read a byte from this stream.3724      /// </summary>3725      /// <returns>Returns the byte read or -1 on end of stream.</returns>3726      public override int ReadByte()3727      { - 1583728         if (readPos_ >= end_) {3729           // -1 is the correct value at end of stream. - 03730          return -1;3731        }3732 - 1583733        lock( baseStream_ ) { - 1583734          baseStream_.Seek(readPos_++, SeekOrigin.Begin); - 1583735          return baseStream_.ReadByte();3736        } - 1583737      }37383739      /// <summary>3740      /// Close this <see cref="PartialInputStream">partial input stream</see>.3741      /// </summary>3742      /// <remarks>3743      /// The underlying stream is not closed.  Close the parent ZipFile class to do that.3744      /// </remarks>3745      public override void Close()3746      {3747        // Do nothing at all! - 659183748      }37493750      /// <summary>3751      /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of3752      /// </summary>3753      /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array3754      /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the cur3755      /// <param name="count">The maximum number of bytes to be read from the current stream.</param>3756      /// <returns>3757      /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that ma3758      /// </returns>3759      /// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </e3760      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3761      /// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>3762      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3763      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3764      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3765      public override int Read(byte[] buffer, int offset, int count)3766      { - 663793767        lock(baseStream_) { - 663793768           if (count > end_ - readPos_) { - 663483769            count = (int) (end_ - readPos_); - 663483770             if (count == 0) { - 659433771              return 0;3772            }3773          }3774 - 4363775          baseStream_.Seek(readPos_, SeekOrigin.Begin); - 4363776          int readCount = baseStream_.Read(buffer, offset, count); - 4363777           if (readCount > 0) { - 4363778            readPos_ += readCount;3779          } - 4363780          return readCount;3781        } - 663793782      }37833784      /// <summary>3785      /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the n3786      /// </summary>3787      /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</par3788      /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current strea3789      /// <param name="count">The number of bytes to be written to the current stream.</param>3790      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3791      /// <exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>3792      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3793      /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>3794      /// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </3795      /// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>3796      public override void Write(byte[] buffer, int offset, int count)3797      { - 03798        throw new NotSupportedException();3799      }38003801      /// <summary>3802      /// When overridden in a derived class, sets the length of the current stream.3803      /// </summary>3804      /// <param name="value">The desired length of the current stream in bytes.</param>3805      /// <exception cref="T:System.NotSupportedException">The stream does not support both writing and seeking, such as3806      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3807      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3808      public override void SetLength(long value)3809      { - 03810        throw new NotSupportedException();3811      }38123813      /// <summary>3814      /// When overridden in a derived class, sets the position within the current stream.3815      /// </summary>3816      /// <param name="offset">A byte offset relative to the origin parameter.</param>3817      /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point 3818      /// <returns>3819      /// The new position within the current stream.3820      /// </returns>3821      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3822      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking, such as if the stream is3823      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3824      public override long Seek(long offset, SeekOrigin origin)3825      { - 73826        long newPos = readPos_;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. </excep3693      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3694      public override long Length { + 23695        get { return length_; }3696      }36973698      /// <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      }37063707      /// <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      }37153716      /// <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      }37243725      /// <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 Fields3734      ZipFile zipFile_;3735      Stream baseStream_;3736      long start_;3737      long length_;3738      long readPos_;3739      long end_;3740      #endregion3741    }3742    #endregion3743  }37443745  #endregion37463747  #region DataSources3748  /// <summary>3749  /// Provides a static way to obtain a source of data for an entry.3750  /// </summary>3751  public interface IStaticDataSource3752  {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  }37603761  /// <summary>3762  /// Represents a source of data that can dynamically provide3763  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3764  /// </summary>3765  public interface IDynamicDataSource3766  {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  }37763777  /// <summary>3778  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3779  /// </summary>3780  public class StaticDiskDataSource : IStaticDataSource3781  {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    }37903791    #region IDataSource Members37923793    /// <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    }38013802    readonly38033804    #endregion3805    #region Instance Fields3806    string fileName_;3807    #endregion3808  }380938103811  /// <summary>3812  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.3813  /// </summary>3814  public class DynamicDiskDataSource : IDynamicDataSource3815  {38163817    #region IDataSource Members3818    /// <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 - 73828         switch ( origin )3829        {3830          case SeekOrigin.Begin: - 73831            newPos = start_ + offset; - 73832            break;38333834          case SeekOrigin.Current: - 03835            newPos = readPos_ + offset; - 03836            break;3828      if (name != null) {3829        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);3830      }38313832      return result;3833    }38343835    #endregion3836  }  38373838          case SeekOrigin.End: - 03839            newPos = end_ + offset;3840            break;3841        }3842 - 73843         if ( newPos < start_ ) { - 03844          throw new ArgumentException("Negative position is invalid");3845        }3846 - 73847         if ( newPos >= end_ ) { - 03848          throw new IOException("Cannot seek past end");3849        } - 73850        readPos_ = newPos; - 73851        return readPos_;3852      }38533854      /// <summary>3855      /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.3856      /// </summary>3857      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3858      public override void Flush()3859      {3860        // Nothing to do. - 03861      }38623863      /// <summary>3864      /// Gets or sets the position within the current stream.3865      /// </summary>3866      /// <value></value>3867      /// <returns>The current position within the stream.</returns>3868      /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>3869      /// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>3870      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3871      public override long Position { - 13872        get { return readPos_ - start_; }3873        set { - 03874          long newPos = start_ + value;3875 - 03876           if ( newPos < start_ ) { - 03877            throw new ArgumentException("Negative position is invalid");3878          }3838  #endregion38393840  #region Archive Storage3841  /// <summary>3842  /// Defines facilities for data storage when updating Zip Archives.3843  /// </summary>3844  public interface IArchiveStorage3845  {3846    /// <summary>3847    /// Get the <see cref="FileUpdateMode"/> to apply during updates.3848    /// </summary>3849    FileUpdateMode UpdateMode { get; }38503851    /// <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();38573858    /// <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();38643865    /// <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);38713872    /// <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 - 03880           if ( newPos >= end_ ) { - 03881            throw new InvalidOperationException("Cannot seek past end");3882          } - 03883          readPos_ = newPos; - 03884        }3885      }38863887      /// <summary>3888      /// Gets the length in bytes of the stream.3889      /// </summary>3890      /// <value></value>3891      /// <returns>A long value representing the length of the stream in bytes.</returns>3892      /// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </excep3893      /// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exceptio3894      public override long Length { - 23895        get { return length_; }3896      }38973898      /// <summary>3899      /// Gets a value indicating whether the current stream supports writing.3900      /// </summary>3901      /// <value>false</value>3902      /// <returns>true if the stream supports writing; otherwise, false.</returns>3903      public override bool CanWrite { - 03904        get { return false; }3905      }39063907      /// <summary>3908      /// Gets a value indicating whether the current stream supports seeking.3909      /// </summary>3910      /// <value>true</value>3911      /// <returns>true if the stream supports seeking; otherwise, false.</returns>3912      public override bool CanSeek { - 23913        get { return true; }3914      }39153916      /// <summary>3917      /// Gets a value indicating whether the current stream supports reading.3918      /// </summary>3919      /// <value>true.</value>3920      /// <returns>true if the stream supports reading; otherwise, false.</returns>3921      public override bool CanRead { - 133922        get { return true; }3923      }39243925#if !NET_1_0 && !NET_1_1 && !NETCF_1_03926      /// <summary>3927      /// Gets a value that determines whether the current stream can time out.3928      /// </summary>3929      /// <value></value>3930      /// <returns>A value that determines whether the current stream can time out.</returns>3931      public override bool CanTimeout { - 03932        get { return baseStream_.CanTimeout; }3933      }3934#endif3935      #region Instance Fields3936      ZipFile zipFile_;3937      Stream baseStream_;3938      long start_;3939      long length_;3940      long readPos_;3941      long end_;3942      #endregion3943    }3944    #endregion3945  }39463947  #endregion39483949  #region DataSources3950  /// <summary>3951  /// Provides a static way to obtain a source of data for an entry.3952  /// </summary>3953  public interface IStaticDataSource3954  {3955    /// <summary>3956    /// Get a source of data by creating a new stream.3957    /// </summary>3958    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3959    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3960    Stream GetSource();3961  }39623963  /// <summary>3964  /// Represents a source of data that can dynamically provide3965  /// multiple <see cref="Stream">data sources</see> based on the parameters passed.3966  /// </summary>3967  public interface IDynamicDataSource3968  {3969    /// <summary>3970    /// Get a data source.3971    /// </summary>3972    /// <param name="entry">The <see cref="ZipEntry"/> to get a source for.</param>3973    /// <param name="name">The name for data if known.</param>3974    /// <returns>Returns a <see cref="Stream"/> to use for compression input.</returns>3975    /// <remarks>Ideally a new stream is created and opened to achieve this, to avoid locking problems.</remarks>3976    Stream GetSource(ZipEntry entry, string name);3977  }39783979  /// <summary>3980  /// Default implementation of a <see cref="IStaticDataSource"/> for use with files stored on disk.3981  /// </summary>3982  public class StaticDiskDataSource : IStaticDataSource3983  {3984    /// <summary>3985    /// Initialise a new instnace of <see cref="StaticDiskDataSource"/>3986    /// </summary>3987    /// <param name="fileName">The name of the file to obtain data from.</param>3988    public StaticDiskDataSource(string fileName)3989    {3990      fileName_ = fileName;3991    }39923993    #region IDataSource Members39943995    /// <summary>3996    /// Get a <see cref="Stream"/> providing data.3997    /// </summary>3998    /// <returns>Returns a <see cref="Stream"/> provising data.</returns>3999    public Stream GetSource()4000    {4001      return File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4002    }3880    /// <summary>3881    /// Dispose of this instance.3882    /// </summary>3883    void Dispose();3884  }38853886  /// <summary>3887  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.3888  /// </summary>3889  abstract public class BaseArchiveStorage : IArchiveStorage3890  {3891    #region Constructors3892    /// <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    #endregion39013902    #region IArchiveStorage Members39033904    /// <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();39103911    /// <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 read3915    /// the final storage for the archive.</returns>3916    /// <seealso cref="GetTemporaryOutput"/>3917    public abstract Stream ConvertTemporaryToFinal();39183919    /// <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);39253926    /// <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);39323933    /// <summary>3934    /// Disposes this instance.3935    /// </summary>3936    public abstract void Dispose();39373938    /// <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    }39473948    #endregion39493950    #region Instance Fields3951    FileUpdateMode updateMode_;3952    #endregion3953  }39543955  /// <summary>3956  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.3957  /// </summary>3958  public class DiskArchiveStorage : BaseArchiveStorage3959  {3960    #region Constructors3961    /// <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      }39723973      fileName_ = file.Name;3974    }39753976    /// <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    #endregion39853986    #region IArchiveStorage Members39873988    /// <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      }  40034004    readonly40054006    #endregion4007    #region Instance Fields4008    string fileName_;4009    #endregion4010  }401140124013  /// <summary>4014  /// Default implementation of <see cref="IDynamicDataSource"/> for files stored on disk.4015  /// </summary>4016  public class DynamicDiskDataSource : IDynamicDataSource4017  {40184019    #region IDataSource Members4020    /// <summary>4021    /// Get a <see cref="Stream"/> providing data for an entry.4022    /// </summary>4023    /// <param name="entry">The entry to provide data for.</param>4024    /// <param name="name">The file name for data if known.</param>4025    /// <returns>Returns a stream providing data; or null if not available</returns>4026    public Stream GetSource(ZipEntry entry, string name)4027    {4028      Stream result = null;4004      return temporaryStream_;4005    }40064007    /// <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 read4011    /// 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      }40174018      Stream result = null;40194020      string moveTempName = GetTempFileName(fileName_, false);4021      bool newFileCreated = false;40224023      try {4024        temporaryStream_.Close();4025        File.Move(fileName_, moveTempName);4026        File.Move(temporaryName_, fileName_);4027        newFileCreated = true;4028        File.Delete(moveTempName);  40294030      if ( name != null ) {4031        result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);4032      }4030        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4031      } catch (Exception) {4032        result = null;  40334034      return result;4035    }40364037    #endregion4038  }4034        // Try to roll back changes...4035        if (!newFileCreated) {4036          File.Move(moveTempName, fileName_);4037          File.Delete(temporaryName_);4038        }  40394040  #endregion40414042  #region Archive Storage4043  /// <summary>4044  /// Defines facilities for data storage when updating Zip Archives.4045  /// </summary>4046  public interface IArchiveStorage4047  {4048    /// <summary>4049    /// Get the <see cref="FileUpdateMode"/> to apply during updates.4050    /// </summary>4051    FileUpdateMode UpdateMode { get; }40524053    /// <summary>4054    /// Get an empty <see cref="Stream"/> that can be used for temporary output.4055    /// </summary>4056    /// <returns>Returns a temporary output <see cref="Stream"/></returns>4057    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4058    Stream GetTemporaryOutput();40594060    /// <summary>4061    /// Convert a temporary output stream to a final stream.4062    /// </summary>4063    /// <returns>The resulting final <see cref="Stream"/></returns>4064    /// <seealso cref="GetTemporaryOutput"/>4065    Stream ConvertTemporaryToFinal();40664067    /// <summary>4068    /// Make a temporary copy of the original stream.4069    /// </summary>4070    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4071    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4072    Stream MakeTemporaryCopy(Stream stream);40734074    /// <summary>4075    /// Return a stream suitable for performing direct updates on the original source.4076    /// </summary>4077    /// <param name="stream">The current stream.</param>4078    /// <returns>Returns a stream suitable for direct updating.</returns>4079    /// <remarks>This may be the current stream passed.</remarks>4080    Stream OpenForDirectUpdate(Stream stream);40814082    /// <summary>4083    /// Dispose of this instance.4084    /// </summary>4085    void Dispose();4086  }4040        throw;4041      }40424043      return result;4044    }40454046    /// <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();40544055      temporaryName_ = GetTempFileName(fileName_, true);4056      File.Copy(fileName_, temporaryName_, true);40574058      temporaryStream_ = new FileStream(temporaryName_,4059        FileMode.Open,4060        FileAccess.ReadWrite);4061      return temporaryStream_;4062    }40634064    /// <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        }40774078        result = new FileStream(fileName_,4079            FileMode.Open,4080            FileAccess.ReadWrite);4081      } else {4082        result = stream;4083      }40844085      return result;4086    }  40874088  /// <summary>4089  /// An abstract <see cref="IArchiveStorage"/> suitable for extension by inheritance.4090  /// </summary>4091  abstract public class BaseArchiveStorage : IArchiveStorage4092  {4093    #region Constructors4094    /// <summary>4095    /// Initializes a new instance of the <see cref="BaseArchiveStorage"/> class.4096    /// </summary>4097    /// <param name="updateMode">The update mode.</param>4098    protected BaseArchiveStorage(FileUpdateMode updateMode)4099    {4100      updateMode_ = updateMode;4101    }4102    #endregion41034104    #region IArchiveStorage Members41054106    /// <summary>4107    /// Gets a temporary output <see cref="Stream"/>4108    /// </summary>4109    /// <returns>Returns the temporary output stream.</returns>4110    /// <seealso cref="ConvertTemporaryToFinal"></seealso>4111    public abstract Stream GetTemporaryOutput();41124113    /// <summary>4114    /// Converts the temporary <see cref="Stream"/> to its final form.4115    /// </summary>4116    /// <returns>Returns a <see cref="Stream"/> that can be used to read4117    /// the final storage for the archive.</returns>4118    /// <seealso cref="GetTemporaryOutput"/>4119    public abstract Stream ConvertTemporaryToFinal();41204121    /// <summary>4122    /// Make a temporary copy of a <see cref="Stream"/>.4123    /// </summary>4124    /// <param name="stream">The <see cref="Stream"/> to make a copy of.</param>4125    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4126    public abstract Stream MakeTemporaryCopy(Stream stream);41274128    /// <summary>4129    /// Return a stream suitable for performing direct updates on the original source.4130    /// </summary>4131    /// <param name="stream">The <see cref="Stream"/> to open for direct update.</param>4132    /// <returns>Returns a stream suitable for direct updating.</returns>4133    public abstract Stream OpenForDirectUpdate(Stream stream);41344135    /// <summary>4136    /// Disposes this instance.4137    /// </summary>4138    public abstract void Dispose();41394140    /// <summary>4141    /// Gets the update mode applicable.4142    /// </summary>4143    /// <value>The update mode.</value>4144    public FileUpdateMode UpdateMode4145    {4146      get {4147        return updateMode_;4148      }4149    }41504151    #endregion41524153    #region Instance Fields4154    FileUpdateMode updateMode_;4155    #endregion4156  }41574158  /// <summary>4159  /// An <see cref="IArchiveStorage"/> implementation suitable for hard disks.4160  /// </summary>4161  public class DiskArchiveStorage : BaseArchiveStorage4162  {4163    #region Constructors4164    /// <summary>4165    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4166    /// </summary>4167    /// <param name="file">The file.</param>4168    /// <param name="updateMode">The update mode.</param>4169    public DiskArchiveStorage(ZipFile file, FileUpdateMode updateMode)4170      : base(updateMode)4171    {4172      if ( file.Name == null ) {4173        throw new ZipException("Cant handle non file archives");4174      }41754176      fileName_ = file.Name;4177    }4088    /// <summary>4089    /// Disposes this instance.4090    /// </summary>4091    public override void Dispose()4092    {4093      if (temporaryStream_ != null) {4094        temporaryStream_.Close();4095      }4096    }40974098    #endregion40994100    #region Internal routines4101    static string GetTempFileName(string original, bool makeTempFile)4102    {4103      string result = null;41044105      if (original == null) {4106        result = Path.GetTempFileName();4107      } else {4108        int counter = 0;4109        int suffixSeed = DateTime.Now.Second;41104111        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    #endregion41334134    #region Instance Fields4135    Stream temporaryStream_;4136    string fileName_;4137    string temporaryName_;4138    #endregion4139  }41404141  /// <summary>4142  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4143  /// </summary>4144  public class MemoryArchiveStorage : BaseArchiveStorage4145  {4146    #region Constructors4147    /// <summary>4148    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4149    /// </summary>4150    public MemoryArchiveStorage()4151      : base(FileUpdateMode.Direct)4152    {4153    }41544155    /// <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    }41644165    #endregion41664167    #region Properties4168    /// <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    }41744175    #endregion41764177    #region IArchiveStorage Members  4178  4179    /// <summary>4180    /// Initializes a new instance of the <see cref="DiskArchiveStorage"/> class.4180    /// Gets the temporary output <see cref="Stream"/>  4181    /// </summary>4182    /// <param name="file">The file.</param>4183    public DiskArchiveStorage(ZipFile file)4184      : this(file, FileUpdateMode.Safe)4185    {4186    }4187    #endregion4182    /// <returns>Returns the temporary output stream.</returns>4183    public override Stream GetTemporaryOutput()4184    {4185      temporaryStream_ = new MemoryStream();4186      return temporaryStream_;4187    }  41884189    #region IArchiveStorage Members41904191    /// <summary>4192    /// Gets a temporary output <see cref="Stream"/> for performing updates on.4193    /// </summary>4194    /// <returns>Returns the temporary output stream.</returns>4195    public override Stream GetTemporaryOutput()4196    {4197      if ( temporaryName_ != null ) {4198        temporaryName_ = GetTempFileName(temporaryName_, true);4199        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4200      }4201      else {4202        // Determine where to place files based on internal strategy.4203        // Currently this is always done in system temp directory.4204        temporaryName_ = Path.GetTempFileName();4205        temporaryStream_ = File.Open(temporaryName_, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);4206      }42074208      return temporaryStream_;4209    }42104211    /// <summary>4212    /// Converts a temporary <see cref="Stream"/> to its final form.4213    /// </summary>4214    /// <returns>Returns a <see cref="Stream"/> that can be used to read4215    /// the final storage for the archive.</returns>4216    public override Stream ConvertTemporaryToFinal()4217    {4218      if ( temporaryStream_ == null ) {4219        throw new ZipException("No temporary stream has been created");4220      }42214222      Stream result = null;42234224      string moveTempName = GetTempFileName(fileName_, false);4225      bool newFileCreated = false;42264227      try  {4228        temporaryStream_.Close();4229        File.Move(fileName_, moveTempName);4230        File.Move(temporaryName_, fileName_);4231        newFileCreated = true;4232        File.Delete(moveTempName);42334234        result = File.Open(fileName_, FileMode.Open, FileAccess.Read, FileShare.Read);4235      }4236      catch(Exception) {4237        result  = null;42384239        // Try to roll back changes...4240        if ( !newFileCreated ) {4241          File.Move(moveTempName, fileName_);4242          File.Delete(temporaryName_);4243        }42444245        throw;4246      }42474248      return result;4249    }42504251    /// <summary>4252    /// Make a temporary copy of a stream.4253    /// </summary>4254    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4255    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4256    public override Stream MakeTemporaryCopy(Stream stream)4257    {4258      stream.Close();42594260      temporaryName_ = GetTempFileName(fileName_, true);4261      File.Copy(fileName_, temporaryName_, true);42624263      temporaryStream_ = new FileStream(temporaryName_,4264        FileMode.Open,4265        FileAccess.ReadWrite);4266      return temporaryStream_;4267    }42684269    /// <summary>4270    /// Return a stream suitable for performing direct updates on the original source.4271    /// </summary>4272    /// <param name="stream">The current stream.</param>4273    /// <returns>Returns a stream suitable for direct updating.</returns>4274    /// <remarks>If the <paramref name="stream"/> is not null this is used as is.</remarks>4275    public override Stream OpenForDirectUpdate(Stream stream)4276    {4277      Stream result;4278      if ((stream == null) || !stream.CanWrite)4279      {4280        if (stream != null) {4281          stream.Close();4282        }42834284        result = new FileStream(fileName_,4285            FileMode.Open,4286            FileAccess.ReadWrite);4287      }4288      else4289      {4290        result = stream;4291      }42924293      return result;4294    }42954296    /// <summary>4297    /// Disposes this instance.4298    /// </summary>4299    public override void Dispose()4300    {4301      if ( temporaryStream_ != null ) {4302        temporaryStream_.Close();4303      }4304    }43054306    #endregion43074308    #region Internal routines4309    static string GetTempFileName(string original, bool makeTempFile)4310    {4311      string result = null;43124313      if ( original == null ) {4314        result = Path.GetTempFileName();4315      }4316      else {4317        int counter = 0;4318        int suffixSeed = DateTime.Now.Second;43194320        while ( result == null ) {4321          counter += 1;4322          string newName = string.Format("{0}.{1}{2}.tmp", original, suffixSeed, counter);4323          if ( !File.Exists(newName) ) {4324            if ( makeTempFile) {4325              try  {4326                // Try and create the file.4327                using ( FileStream stream = File.Create(newName) ) {4328                }4329                result = newName;4330              }4331              catch {4332                suffixSeed = DateTime.Now.Second;4333              }4334            }4335            else {4336              result = newName;4337            }4338          }4339        }4340      }4341      return result;4342    }4343    #endregion43444345    #region Instance Fields4346    Stream temporaryStream_;4347    string fileName_;4348    string temporaryName_;4349    #endregion4350  }43514352  /// <summary>4353  /// An <see cref="IArchiveStorage"/> implementation suitable for in memory streams.4354  /// </summary>4355  public class MemoryArchiveStorage : BaseArchiveStorage4356  {4357    #region Constructors4358    /// <summary>4359    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4360    /// </summary>4361    public MemoryArchiveStorage()4362      : base(FileUpdateMode.Direct)4363    {4364    }43654366    /// <summary>4367    /// Initializes a new instance of the <see cref="MemoryArchiveStorage"/> class.4368    /// </summary>4369    /// <param name="updateMode">The <see cref="FileUpdateMode"/> to use</param>4370    /// <remarks>This constructor is for testing as memory streams dont really require safe mode.</remarks>4371    public MemoryArchiveStorage(FileUpdateMode updateMode)4372      : base(updateMode)4373    {4374    }43754376    #endregion43774378    #region Properties4379    /// <summary>4380    /// Get the stream returned by <see cref="ConvertTemporaryToFinal"/> if this was in fact called.4381    /// </summary>4382    public MemoryStream FinalStream4383    {4384      get { return finalStream_; }4385    }43864387    #endregion43884389    #region IArchiveStorage Members43904391    /// <summary>4392    /// Gets the temporary output <see cref="Stream"/>4393    /// </summary>4394    /// <returns>Returns the temporary output stream.</returns>4395    public override Stream GetTemporaryOutput()4396    {4397      temporaryStream_ = new MemoryStream();4398      return temporaryStream_;4399    }44004401    /// <summary>4402    /// Converts the temporary <see cref="Stream"/> to its final form.4403    /// </summary>4404    /// <returns>Returns a <see cref="Stream"/> that can be used to read4405    /// the final storage for the archive.</returns>4406    public override Stream ConvertTemporaryToFinal()4407    {4408      if ( temporaryStream_ == null ) {4409        throw new ZipException("No temporary stream has been created");4410      }44114412      finalStream_ = new MemoryStream(temporaryStream_.ToArray());4413      return finalStream_;4414    }44154416    /// <summary>4417    /// Make a temporary copy of the original stream.4418    /// </summary>4419    /// <param name="stream">The <see cref="Stream"/> to copy.</param>4420    /// <returns>Returns a temporary output <see cref="Stream"/> that is a copy of the input.</returns>4421    public override Stream MakeTemporaryCopy(Stream stream)4422    {4423      temporaryStream_ = new MemoryStream();4424      stream.Position = 0;4425      StreamUtils.Copy(stream, temporaryStream_, new byte[4096]);4426      return temporaryStream_;4427    }44284429    /// <summary>4430    /// Return a stream suitable for performing direct updates on the original source.4431    /// </summary>4432    /// <param name="stream">The original source stream</param>4433    /// <returns>Returns a stream suitable for direct updating.</returns>4434    /// <remarks>If the <paramref name="stream"/> passed is not null this is used;4435    /// otherwise a new <see cref="MemoryStream"/> is returned.</remarks>4436    public override Stream OpenForDirectUpdate(Stream stream)4437    {4438      Stream result;4439      if ((stream == null) || !stream.CanWrite) {44404441        result = new MemoryStream();44424443        if (stream != null) {4444          stream.Position = 0;4445          StreamUtils.Copy(stream, result, new byte[4096]);44464447          stream.Close();4448        }4449      }4450      else {4451        result = stream;4452      }44534454      return result;4455    }44564457    /// <summary>4458    /// Disposes this instance.4459    /// </summary>4460    public override void Dispose()4461    {4462      if ( temporaryStream_ != null ) {4463        temporaryStream_.Close();4464      }4465    }44664467    #endregion44684469    #region Instance Fields4470    MemoryStream temporaryStream_;4471    MemoryStream finalStream_;4472    #endregion4473  }44744475  #endregion4476}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 read4193    /// 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      }41994200      finalStream_ = new MemoryStream(temporaryStream_.ToArray());4201      return finalStream_;4202    }42034204    /// <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    }42164217    /// <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) {42284229        result = new MemoryStream();42304231        if (stream != null) {4232          stream.Position = 0;4233          StreamUtils.Copy(stream, result, new byte[4096]);42344235          stream.Close();4236        }4237      } else {4238        result = stream;4239      }42404241      return result;4242    }42434244    /// <summary>4245    /// Disposes this instance.4246    /// </summary>4247    public override void Dispose()4248    {4249      if (temporaryStream_ != null) {4250        temporaryStream_.Close();4251      }4252    }42534254    #endregion42554256    #region Instance Fields4257    MemoryStream temporaryStream_;4258    MemoryStream finalStream_;4259    #endregion4260  }42614262  #endregion4263} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipHelperStream.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipHelperStream.htm index f225ee51f..a45baa092 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipHelperStream.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipHelperStream.htm @@ -18,7 +18,7 @@

Summary

Covered lines:106 Uncovered lines:88 Coverable lines:194 -Total lines:623 +Total lines:560 Line coverage:54.6% Branch coverage:42.8% @@ -57,631 +57,568 @@

#LineLine coverage - 1// ZipHelperStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.1using System;2using System.IO;3using System.Text;45namespace ICSharpCode.SharpZipLib.Zip6{7  /// <summary>8  /// Holds data pertinent to a data descriptor.9  /// </summary>10  public class DescriptorData11  {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    }1920    /// <summary>21    /// Get / set the uncompressed size of data22    /// </summary>23    public long Size {24      get { return size; }25      set { size = value; }26    }2728    /// <summary>29    /// Get /set the crc value.30    /// </summary>31    public long Crc {32      get { return crc; }33      set { crc = (value & 0xffffffff); }34    }  3536using System;37using System.IO;38using System.Text;3940namespace ICSharpCode.SharpZipLib.Zip41{36    #region Instance Fields37    long size;38    long compressedSize;39    long crc;40    #endregion41  }  4243  /// <summary>44  /// Holds data pertinent to a data descriptor.45  /// </summary>46  public class DescriptorData47  {48    /// <summary>49    /// Get /set the compressed size of data.50    /// </summary>51    public long CompressedSize52    {53      get { return compressedSize; }54      set { compressedSize = value; }55    }5657    /// <summary>58    /// Get / set the uncompressed size of data59    /// </summary>60    public long Size61    {62      get { return size; }63      set { size = value; }64    }6566    /// <summary>67    /// Get /set the crc value.68    /// </summary>69    public long Crc70    {71      get { return crc; }72      set { crc = (value & 0xffffffff); }73    }7475    #region Instance Fields76    long size;77    long compressedSize;78    long crc;79    #endregion80  }8182  class EntryPatchData83  {84    public long SizePatchOffset85    {86      get { return sizePatchOffset_; }87      set { sizePatchOffset_ = value; }88    }8990    public long CrcPatchOffset91    {92      get { return crcPatchOffset_; }93      set { crcPatchOffset_ = value; }43  class EntryPatchData44  {45    public long SizePatchOffset {46      get { return sizePatchOffset_; }47      set { sizePatchOffset_ = value; }48    }4950    public long CrcPatchOffset {51      get { return crcPatchOffset_; }52      set { crcPatchOffset_ = value; }53    }5455    #region Instance Fields56    long sizePatchOffset_;57    long crcPatchOffset_;58    #endregion59  }6061  /// <summary>62  /// This class assists with writing/reading from Zip files.63  /// </summary>64  internal class ZipHelperStream : Stream65  {66    #region Constructors67    /// <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    }7677    /// <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    #endregion8687    /// <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    }  9596    #region Instance Fields97    long sizePatchOffset_;98    long crcPatchOffset_;99    #endregion100  }101102  /// <summary>103  /// This class assists with writing/reading from Zip files.104  /// </summary>105  internal class ZipHelperStream : Stream106  {107    #region Constructors108    /// <summary>109    /// Initialise an instance of this class.110    /// </summary>111    /// <param name="name">The name of the file to open.</param> - 0112    public ZipHelperStream(string name)113    { - 0114      stream_ = new FileStream(name, FileMode.Open, FileAccess.ReadWrite); - 0115      isOwner_ = true; - 0116    }96    #region Base Stream Methods97    public override bool CanRead { + 098      get { return stream_.CanRead; }99    }100101    public override bool CanSeek { + 0102      get { return stream_.CanSeek; }103    }104105    public override bool CanTimeout { + 0106      get { return stream_.CanTimeout; }107    }108109    public override long Length { + 1110      get { return stream_.Length; }111    }112113    public override long Position { + 124114      get { return stream_.Position; } + 6115      set { stream_.Position = value; }116    }  117118    /// <summary>119    /// Initialise a new instance of <see cref="ZipHelperStream"/>.120    /// </summary>121    /// <param name="stream">The stream to use.</param> - 277122    public ZipHelperStream(Stream stream)118    public override bool CanWrite { + 0119      get { return stream_.CanWrite; }120    }121122    public override void Flush()  123    { - 277124      stream_ = stream; - 277125    }126    #endregion127128    /// <summary>129    /// Get / set a value indicating wether the the underlying stream is owned or not.130    /// </summary>131    /// <remarks>If the stream is owned it is closed when this instance is closed.</remarks>132    public bool IsStreamOwner + 0124      stream_.Flush(); + 0125    }126127    public override long Seek(long offset, SeekOrigin origin)128    { + 131329129      return stream_.Seek(offset, origin);130    }131132    public override void SetLength(long value)  133    { - 0134      get { return isOwner_; } - 8135      set { isOwner_ = value; }136    }137138    #region Base Stream Methods139    public override bool CanRead140    { - 0141      get { return stream_.CanRead; }142    }143144    public override bool CanSeek145    { - 0146      get { return stream_.CanSeek; }147    }148149#if !NET_1_0 && !NET_1_1 && !NETCF_1_0150    public override bool CanTimeout151    { - 0152      get { return stream_.CanTimeout; }153    }154#endif155156    public override long Length157    { - 1158      get { return stream_.Length; }159    }160161    public override long Position162    { - 124163      get { return stream_.Position; } - 6164      set { stream_.Position = value;  }165    }166167    public override bool CanWrite168    { - 0169      get { return stream_.CanWrite; }170    } + 3134      stream_.SetLength(value); + 3135    }136137    public override int Read(byte[] buffer, int offset, int count)138    { + 1139      return stream_.Read(buffer, offset, count);140    }141142    public override void Write(byte[] buffer, int offset, int count)143    { + 9144      stream_.Write(buffer, offset, count); + 9145    }146147    /// <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    #endregion163164    // Write the local file header165    // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage166    void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)167    { + 0168      CompressionMethod method = entry.CompressionMethod; + 0169      bool headerInfoAvailable = true; // How to get this? + 0170      bool patchEntryHeader = false;  171172    public override void Flush()173    { - 0174      stream_.Flush(); - 0175    }176177    public override long Seek(long offset, SeekOrigin origin)178    { - 131329179      return stream_.Seek(offset, origin);180    }181182    public override void SetLength(long value)183    { - 3184      stream_.SetLength(value); - 3185    }186187    public override int Read(byte[] buffer, int offset, int count)188    { - 1189      return stream_.Read(buffer, offset, count);190    }191192    public override void Write(byte[] buffer, int offset, int count)193    { - 9194      stream_.Write(buffer, offset, count); - 9195    }196197    /// <summary>198    /// Close the stream.199    /// </summary>200    /// <remarks>201    /// The underlying stream is closed only if <see cref="IsStreamOwner"/> is true.202    /// </remarks>203    override public void Close()204    { - 259205      Stream toClose = stream_; - 259206      stream_ = null; - 259207       if (isOwner_ && (toClose != null))208      { - 1209        isOwner_ = false; - 1210        toClose.Close();211      } - 259212    }213    #endregion214215    // Write the local file header216    // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage217    void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)218    { - 0219      CompressionMethod method = entry.CompressionMethod; - 0220      bool headerInfoAvailable = true; // How to get this? - 0221      bool patchEntryHeader = false;222 - 0223      WriteLEInt(ZipConstants.LocalHeaderSignature);224 - 0225      WriteLEShort(entry.Version); - 0226      WriteLEShort(entry.Flags); - 0227      WriteLEShort((byte)method); - 0228      WriteLEInt((int)entry.DosTime);229 - 0230       if (headerInfoAvailable == true) { - 0231        WriteLEInt((int)entry.Crc); - 0232         if ( entry.LocalHeaderRequiresZip64 ) { - 0233          WriteLEInt(-1); - 0234          WriteLEInt(-1); - 0235        }236        else { - 0237          WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.Compressed - 0238          WriteLEInt((int)entry.Size);239        } - 0240      } else { - 0241         if (patchData != null) { - 0242          patchData.CrcPatchOffset = stream_.Position;243        } - 0244        WriteLEInt(0);  // Crc245 - 0246         if ( patchData != null ) { - 0247          patchData.SizePatchOffset = stream_.Position;248        }249250        // For local header both sizes appear in Zip64 Extended Information - 0251         if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) { - 0252          WriteLEInt(-1); - 0253          WriteLEInt(-1); - 0254        }255        else { - 0256          WriteLEInt(0);  // Compressed size - 0257          WriteLEInt(0);  // Uncompressed size258        }259      }260 - 0261      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);262 - 0263       if (name.Length > 0xFFFF) { - 0264        throw new ZipException("Entry name too long.");265      }266 - 0267      var ed = new ZipExtraData(entry.ExtraData);268 - 0269       if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader)) { - 0270        ed.StartNewEntry(); - 0271         if (headerInfoAvailable) { - 0272          ed.AddLeLong(entry.Size); - 0273          ed.AddLeLong(entry.CompressedSize); - 0274        }275        else { - 0276          ed.AddLeLong(-1); - 0277          ed.AddLeLong(-1);278        } - 0279        ed.AddNewEntry(1); + 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);  // Crc193 + 0194         if (patchData != null) { + 0195          patchData.SizePatchOffset = stream_.Position;196        }197198        // 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 size205        }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    }255256    /// <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);272273      // 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 - 0281         if ( !ed.Find(1) ) { - 0282          throw new ZipException("Internal error cant find extra data");283        }284 - 0285         if ( patchData != null ) { - 0286          patchData.SizePatchOffset = ed.CurrentReadIndex;287        } - 0288      }289      else { - 0290        ed.Delete(1);291      }292 - 0293      byte[] extra = ed.GetEntryData();294 - 0295      WriteLEShort(name.Length); - 0296      WriteLEShort(extra.Length);297 - 0298       if ( name.Length > 0 ) { - 0299        stream_.Write(name, 0, name.Length);300      }301 - 0302       if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) { - 0303        patchData.SizePatchOffset += stream_.Position;304      }305 - 0306       if ( extra.Length > 0 ) { - 0307        stream_.Write(extra, 0, extra.Length);308      } - 0309    } + 117281      return Position;282    }283284    /// <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 directory303                      // zip64 extensible data sector not catered for here (variable size)304305      // Write the Zip64 end of central directory locator + 1306      WriteLEInt(ZipConstants.Zip64CentralDirLocatorSignature);307308      // no of the disk with the start of the zip64 end of central directory + 1309      WriteLEInt(0);  310311    /// <summary>312    /// Locates a block with the desired <paramref name="signature"/>.313    /// </summary>314    /// <param name="signature">The signature to find.</param>315    /// <param name="endLocation">Location, marking the end of block.</param>316    /// <param name="minimumBlockSize">Minimum size of the block.</param>317    /// <param name="maximumVariableData">The maximum variable data.</param>318    /// <returns>Eeturns the offset of the first byte after the signature; -1 if not found</returns>319    public long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)320    { - 118321      long pos = endLocation - minimumBlockSize; - 118322       if ( pos < 0 ) { - 0323        return -1;324      }325 - 118326      long giveUpMarker = Math.Max(pos - maximumVariableData, 0);327328      // TODO: This loop could be optimised for speed.329      do { - 131330330         if ( pos < giveUpMarker ) { - 1331          return -1;332        } - 131329333        Seek(pos--, SeekOrigin.Begin); - 131329334       } while ( ReadLEInt() != signature );335 - 117336      return Position;337    }338339    /// <summary>340    /// Write Zip64 end of central directory records (File header and locator).341    /// </summary>342    /// <param name="noOfEntries">The number of entries in the central directory.</param>343    /// <param name="sizeEntries">The size of entries in the central directory.</param>344    /// <param name="centralDirOffset">The offset of the dentral directory.</param>345    public void WriteZip64EndOfCentralDirectory(long noOfEntries, long sizeEntries, long centralDirOffset)346    { - 1347      long centralSignatureOffset = stream_.Position; - 1348      WriteLEInt(ZipConstants.Zip64CentralFileHeaderSignature); - 1349      WriteLELong(44);    // Size of this record (total size of remaining fields in header or full size - 12) - 1350      WriteLEShort(ZipConstants.VersionMadeBy);   // Version made by - 1351      WriteLEShort(ZipConstants.VersionZip64);   // Version to extract - 1352      WriteLEInt(0);      // Number of this disk - 1353      WriteLEInt(0);      // number of the disk with the start of the central directory - 1354      WriteLELong(noOfEntries);       // No of entries on this disk - 1355      WriteLELong(noOfEntries);       // Total No of entries in central directory - 1356      WriteLELong(sizeEntries);       // Size of the central directory - 1357      WriteLELong(centralDirOffset);  // offset of start of central directory358      // zip64 extensible data sector not catered for here (variable size)359360      // Write the Zip64 end of central directory locator - 1361      WriteLEInt(ZipConstants.Zip64CentralDirLocatorSignature);362363      // no of the disk with the start of the zip64 end of central directory - 1364      WriteLEInt(0);311      // relative offset of the zip64 end of central directory record + 1312      WriteLELong(centralSignatureOffset);313314      // total number of disks + 1315      WriteLEInt(1); + 1316    }317318    /// <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);336337      // TODO: ZipFile Multi disk handling not done + 130338      WriteLEShort(0);                    // number of this disk + 130339      WriteLEShort(0);                    // no of disk with start of central dir340341342      // 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 directory349      }350351      // Size of the central directory + 130352       if (sizeEntries >= 0xffffffff) { + 0353        WriteLEUint(0xffffffff);    // Zip64 marker + 0354      } else { + 130355        WriteLEInt((int)sizeEntries);356      }357358359      // offset of start of central directory + 130360       if (startOfCentralDirectory >= 0xffffffff) { + 0361        WriteLEUint(0xffffffff);    // Zip64 marker + 0362      } else { + 130363        WriteLEInt((int)startOfCentralDirectory);364      }  365366      // relative offset of the zip64 end of central directory record - 1367      WriteLELong(centralSignatureOffset);368369      // total number of disks - 1370      WriteLEInt(1); - 1371    }372373    /// <summary>374    /// Write the required records to end the central directory.375    /// </summary>376    /// <param name="noOfEntries">The number of entries in the directory.</param>377    /// <param name="sizeEntries">The size of the entries in the directory.</param>378    /// <param name="startOfCentralDirectory">The start of the central directory.</param>379    /// <param name="comment">The archive comment.  (This can be null).</param>380    public void WriteEndOfCentralDirectory(long noOfEntries, long sizeEntries,381      long startOfCentralDirectory, byte[] comment)382    {383 - 136384       if ( (noOfEntries >= 0xffff) || - 136385        (startOfCentralDirectory >= 0xffffffff) || - 136386        (sizeEntries >= 0xffffffff) ) { - 1387        WriteZip64EndOfCentralDirectory(noOfEntries, sizeEntries, startOfCentralDirectory);388      }389 - 136390      WriteLEInt(ZipConstants.EndOfCentralDirectorySignature);391392      // TODO: ZipFile Multi disk handling not done - 135393      WriteLEShort(0);                    // number of this disk - 135394      WriteLEShort(0);                    // no of disk with start of central dir395396397      // Number of entries - 135398       if ( noOfEntries >= 0xffff ) { - 1399        WriteLEUshort(0xffff);  // Zip64 marker - 1400        WriteLEUshort(0xffff); - 1401      }402      else { - 134403        WriteLEShort(( short )noOfEntries);          // entries in central dir for this disk - 134404        WriteLEShort(( short )noOfEntries);          // total entries in central directory405      }406407      // Size of the central directory - 135408       if ( sizeEntries >= 0xffffffff ) { - 0409        WriteLEUint(0xffffffff);    // Zip64 marker - 0410      }411      else { - 135412        WriteLEInt(( int )sizeEntries);413      }414415416      // offset of start of central directory - 135417       if ( startOfCentralDirectory >= 0xffffffff ) { - 0418        WriteLEUint(0xffffffff);    // Zip64 marker - 0419      }420      else { - 135421        WriteLEInt(( int )startOfCentralDirectory);422      }423 - 135424       int commentLength = (comment != null) ? comment.Length : 0;425 - 135426       if ( commentLength > 0xffff ) { - 0427        throw new ZipException(string.Format("Comment length({0}) is too long can only be 64K", commentLength));428      } + 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    }378379    #region LE value reading/writing380    /// <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 prematurely389    /// </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    }405406    /// <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 prematurely415    /// </exception>416    public int ReadLEInt()417    { + 131395418      return ReadLEShort() | (ReadLEShort() << 16);419    }420421    /// <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 - 135430      WriteLEShort(commentLength);431 - 135432       if ( commentLength > 0 ) { - 5433        Write(comment, 0, comment.Length);434      } - 135435    }436437    #region LE value reading/writing438    /// <summary>439    /// Read an unsigned short in little endian byte order.440    /// </summary>441    /// <returns>Returns the value read.</returns>442    /// <exception cref="IOException">443    /// An i/o error occurs.444    /// </exception>445    /// <exception cref="EndOfStreamException">446    /// The file ends prematurely447    /// </exception>448    public int ReadLEShort()449    { - 262792450      int byteValue1 = stream_.ReadByte();451 - 262792452       if (byteValue1 < 0) { - 0453        throw new EndOfStreamException();454      }455 - 262792456      int byteValue2 = stream_.ReadByte(); - 262792457       if (byteValue2 < 0) { - 0458        throw new EndOfStreamException();459      }460 - 262792461      return byteValue1 | (byteValue2 << 8);462    }463464    /// <summary>465    /// Read an int in little endian byte order.466    /// </summary>467    /// <returns>Returns the value read.</returns>468    /// <exception cref="IOException">469    /// An i/o error occurs.470    /// </exception>471    /// <exception cref="System.IO.EndOfStreamException">472    /// The file ends prematurely473    /// </exception>474    public int ReadLEInt()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    }439440    /// <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    }449450    /// <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    }459460    /// <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    }469470    /// <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    { - 131395476      return ReadLEShort() | (ReadLEShort() << 16);477    }478479    /// <summary>480    /// Read a long in little endian byte order.481    /// </summary>482    /// <returns>The value read.</returns>483    public long ReadLELong()484    { - 9485      return (uint)ReadLEInt() | ((long)ReadLEInt() << 32);486    }487488    /// <summary>489    /// Write an unsigned short in little endian byte order.490    /// </summary>491    /// <param name="value">The value to write.</param>492    public void WriteLEShort(int value)493    { - 1600494      stream_.WriteByte(( byte )(value & 0xff)); - 1599495      stream_.WriteByte(( byte )((value >> 8) & 0xff)); - 1599496    }497498    /// <summary>499    /// Write a ushort in little endian byte order.500    /// </summary>501    /// <param name="value">The value to write.</param>502    public void WriteLEUshort(ushort value)503    { - 2504      stream_.WriteByte(( byte )(value & 0xff)); - 2505      stream_.WriteByte(( byte )(value >> 8)); - 2506    }507508    /// <summary>509    /// Write an int in little endian byte order.510    /// </summary>511    /// <param name="value">The value to write.</param>512    public void WriteLEInt(int value)513    { - 459514      WriteLEShort(value); - 459515      WriteLEShort(value >> 16); - 458516    }517518    /// <summary>519    /// Write a uint in little endian byte order.520    /// </summary>521    /// <param name="value">The value to write.</param>522    public void WriteLEUint(uint value)523    { - 0524      WriteLEUshort(( ushort )(value & 0xffff)); - 0525      WriteLEUshort(( ushort )(value >> 16)); - 0526    } + 12476      WriteLEInt((int)value); + 12477      WriteLEInt((int)(value >> 32)); + 12478    }479480    /// <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    }489490    #endregion491492    /// <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;504505      // 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 optional508        // 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    /// Write a long in little endian byte order.529    /// Read data descriptor at the end of compressed data.  530    /// </summary>531    /// <param name="value">The value to write.</param>532    public void WriteLELong(long value)533    { - 12534      WriteLEInt(( int )value); - 12535      WriteLEInt(( int )(value >> 32)); - 12536    }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();  537538    /// <summary>539    /// Write a ulong in little endian byte order.540    /// </summary>541    /// <param name="value">The value to write.</param>542    public void WriteLEUlong(ulong value)543    { - 0544      WriteLEUint(( uint )(value & 0xffffffff)); - 0545      WriteLEUint(( uint )(value >> 32)); - 0546    }547548    #endregion549550    /// <summary>551    /// Write a data descriptor.552    /// </summary>553    /// <param name="entry">The entry to write a descriptor for.</param>554    /// <returns>Returns the number of descriptor bytes written.</returns>555    public int WriteDataDescriptor(ZipEntry entry)556    { - 5557       if (entry == null) { - 0558        throw new ArgumentNullException(nameof(entry));559      }560 - 5561      int result=0;562563      // Add data descriptor if flagged as required - 5564       if ((entry.Flags & (int)GeneralBitFlags.Descriptor) != 0)565      {566        // The signature is not PKZIP originally but is now described as optional567        // in the PKZIP Appnote documenting trhe format. - 5568        WriteLEInt(ZipConstants.DataDescriptorSignature); - 5569        WriteLEInt(unchecked((int)(entry.Crc)));570 - 5571        result+=8;572 - 5573         if (entry.LocalHeaderRequiresZip64)574        { - 0575          WriteLELong(entry.CompressedSize); - 0576          WriteLELong(entry.Size); - 0577          result+=16; - 0578        }579        else580        { - 5581          WriteLEInt((int)entry.CompressedSize); - 5582          WriteLEInt((int)entry.Size); - 5583          result+=8;584        }585      }586 - 5587      return result;588    }589590    /// <summary>591    /// Read data descriptor at the end of compressed data.592    /// </summary>593    /// <param name="zip64">if set to <c>true</c> [zip64].</param>594    /// <param name="data">The data to fill in.</param>595    /// <returns>Returns the number of bytes read in the descriptor.</returns>596    public void ReadDataDescriptor(bool zip64, DescriptorData data)597    { - 13598      int intValue = ReadLEInt();599600      // In theory this may not be a descriptor according to PKZIP appnote.601      // In practise its always there. - 13602       if (intValue != ZipConstants.DataDescriptorSignature) { - 0603        throw new ZipException("Data descriptor signature not found");604      }605 - 13606      data.Crc = ReadLEInt();607 - 13608       if (zip64) { - 3609        data.CompressedSize = ReadLELong(); - 3610        data.Size = ReadLELong(); - 3611      }612      else { - 10613        data.CompressedSize = ReadLEInt(); - 10614        data.Size = ReadLEInt();615      } - 10616    }617618    #region Instance Fields619    bool isOwner_;620    Stream stream_;621    #endregion622  }623}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    }554555    #region Instance Fields556    bool isOwner_;557    Stream stream_;558    #endregion559  }560} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipInputStream.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipInputStream.htm index 8d3b8682c..deb2b1ef0 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipInputStream.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipInputStream.htm @@ -15,12 +15,12 @@

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:165 -Uncovered lines:42 -Coverable lines:207 -Total lines:674 -Line coverage:79.7% -Branch coverage:68.6% +Covered lines:162 +Uncovered lines:44 +Coverable lines:206 +Total lines:610 +Line coverage:78.6% +Branch coverage:67.3%

Metrics

@@ -33,10 +33,10 @@

Metrics

ReadDataDescriptor()37560 CompleteCloseEntry(...)690.9181.82 CloseEntry()1047.8342.11 -ReadByte()2100100 +ReadByte()27566.67 ReadingNotAvailable(...)100 ReadingNotSupported(...)100 -InitialRead(...)118885.71 +InitialRead(...)118480.95 Read(...)5100100 BodyRead(...)2282.8669.23 Close()1100100 @@ -47,682 +47,618 @@

#LineLine coverage - 1// ZipInputStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  2010-05-25  Z-1663  Fixed exception when testing local header compressed size of -14142using System;43using System.IO;4445using ICSharpCode.SharpZipLib.Checksums;46using ICSharpCode.SharpZipLib.Zip.Compression;47using ICSharpCode.SharpZipLib.Zip.Compression.Streams;4849#if !NETCF_1_050using ICSharpCode.SharpZipLib.Encryption;51#endif5253namespace ICSharpCode.SharpZipLib.Zip54{55  /// <summary>56  /// This is an InflaterInputStream that reads the files baseInputStream an zip archive57  /// one after another.  It has a special method to get the zip entry of58  /// the next file.  The zip entry contains information about the file name59  /// size, compressed size, Crc, etc.60  /// It includes support for Stored and Deflated entries.61  /// <br/>62  /// <br/>Author of the original java version : Jochen Hoenicke63  /// </summary>64  ///65  /// <example> This sample shows how to read a zip file66  /// <code lang="C#">67  /// using System;68  /// using System.Text;69  /// using System.IO;70  ///71  /// using ICSharpCode.SharpZipLib.Zip;72  ///73  /// class MainClass74  /// {75  ///   public static void Main(string[] args)76  ///   {77  ///     using ( ZipInputStream s = new ZipInputStream(File.OpenRead(args[0]))) {78  ///79  ///       ZipEntry theEntry;80    ///       const int size = 2048;81    ///       byte[] data = new byte[2048];82    ///83    ///       while ((theEntry = s.GetNextEntry()) != null) {84  ///                 if ( entry.IsFile ) {85  ///             Console.Write("Show contents (y/n) ?");86  ///             if (Console.ReadLine() == "y") {87  ///               while (true) {88  ///                 size = s.Read(data, 0, data.Length);89  ///                 if (size > 0) {90  ///                   Console.Write(new ASCIIEncoding().GetString(data, 0, size));91  ///                 } else {92  ///                   break;93  ///                 }94  ///               }95  ///             }96    ///         }97  ///       }98  ///     }99  ///   }100  /// }101  /// </code>102  /// </example>103  public class ZipInputStream : InflaterInputStream104  {105    #region Instance Fields106107    /// <summary>108    /// Delegate for reading bytes from a stream.109    /// </summary>110    delegate int ReadDataHandler(byte[] b, int offset, int length);111112    /// <summary>113    /// The current reader this instance.114    /// </summary>115    ReadDataHandler internalReader;1using System;2using System.IO;3using ICSharpCode.SharpZipLib.Checksum;4using ICSharpCode.SharpZipLib.Encryption;5using ICSharpCode.SharpZipLib.Zip.Compression;6using ICSharpCode.SharpZipLib.Zip.Compression.Streams;78namespace ICSharpCode.SharpZipLib.Zip9{10  /// <summary>11  /// This is an InflaterInputStream that reads the files baseInputStream an zip archive12  /// one after another.  It has a special method to get the zip entry of13  /// the next file.  The zip entry contains information about the file name14  /// 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 Hoenicke18  /// </summary>19  ///20  /// <example> This sample shows how to read a zip file21  /// <code lang="C#">22  /// using System;23  /// using System.Text;24  /// using System.IO;25  ///26  /// using ICSharpCode.SharpZipLib.Zip;27  ///28  /// class MainClass29  /// {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 : InflaterInputStream59  {60    #region Instance Fields6162    /// <summary>63    /// Delegate for reading bytes from a stream.64    /// </summary>65    delegate int ReadDataHandler(byte[] b, int offset, int length);6667    /// <summary>68    /// The current reader this instance.69    /// </summary>70    ReadDataHandler internalReader;71 + 5772    Crc32 crc = new Crc32();73    ZipEntry entry;7475    long size;76    int method;77    int flags;78    string password;79    #endregion8081    #region Constructors82    /// <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    }9192    /// <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    #endregion103104    /// <summary>105    /// Optional password used for encryption when non-null106    /// </summary>107    /// <value>A password for all encrypted <see cref="ZipEntry">entries </see> in this <see cref="ZipInputStream"/></va108    public string Password {109      get { + 0110        return password;111      }112      set { + 23113        password = value; + 23114      }115    }  116 - 61117    Crc32 crc = new Crc32();118    ZipEntry entry;119120    long size;121    int method;122    int flags;123    string password;124    #endregion125126    #region Constructors127    /// <summary>128    /// Creates a new Zip input stream, for reading a zip archive.129    /// </summary>130    /// <param name="baseInputStream">The underlying <see cref="Stream"/> providing data.</param>131    public ZipInputStream(Stream baseInputStream) - 61132      : base(baseInputStream, new Inflater(true))133    { - 61134      internalReader = new ReadDataHandler(ReadingNotAvailable); - 61135    }136137        /// <summary>138        /// Creates a new Zip input stream, for reading a zip archive.139        /// </summary>140        /// <param name="baseInputStream">The underlying <see cref="Stream"/> providing data.</param>141        /// <param name="bufferSize">Size of the buffer.</param>142        public ZipInputStream( Stream baseInputStream, int bufferSize ) - 0143            : base(baseInputStream, new Inflater(true), bufferSize)144        { - 0145            internalReader = new ReadDataHandler(ReadingNotAvailable); - 0146        }147        #endregion148149    /// <summary>150    /// Optional password used for encryption when non-null151    /// </summary>152    /// <value>A password for all encrypted <see cref="ZipEntry">entries </see> in this <see cref="ZipInputStream"/></va153    public string Password154    {155      get { - 0156        return password;157      }158      set { - 26159        password = value; - 26160      }161    }162163164    /// <summary>165    /// Gets a value indicating if there is a current entry and it can be decompressed166    /// </summary>167    /// <remarks>168    /// The entry can only be decompressed if the library supports the zip features required to extract it.169    /// See the <see cref="ZipEntry.Version">ZipEntry Version</see> property for more details.170    /// </remarks>171    public bool CanDecompressEntry {172      get { - 74173        return (entry != null) && entry.CanDecompress;174      }175    }176177    /// <summary>178    /// Advances to the next entry in the archive179    /// </summary>180    /// <returns>181    /// The next <see cref="ZipEntry">entry</see> in the archive or null if there are no more entries.182    /// </returns>183    /// <remarks>184    /// If the previous entry is still open <see cref="CloseEntry">CloseEntry</see> is called.185    /// </remarks>186    /// <exception cref="InvalidOperationException">187    /// Input stream is closed188    /// </exception>189    /// <exception cref="ZipException">190    /// Password is not set, password is invalid, compression method is invalid,191    /// version required to extract is not supported192    /// </exception>193    public ZipEntry GetNextEntry()194    { - 91195       if (crc == null) { - 0196        throw new InvalidOperationException("Closed.");197      }198 - 91199       if (entry != null) { - 14200        CloseEntry();201      }202 - 91203      int header = inputBuffer.ReadLeInt();204 - 91205       if (header == ZipConstants.CentralHeaderSignature || - 91206        header == ZipConstants.EndOfCentralDirectorySignature || - 91207        header == ZipConstants.CentralHeaderDigitalSignature || - 91208        header == ZipConstants.ArchiveExtraDataSignature || - 91209        header == ZipConstants.Zip64CentralFileHeaderSignature) {210        // No more individual entries exist - 6211        Close(); - 6212        return null;213      }214215      // -jr- 07-Dec-2003 Ignore spanning temporary signatures if found216      // Spanning signature is same as descriptor signature and is untested as yet. - 85217       if ( (header == ZipConstants.SpanningTempSignature) || (header == ZipConstants.SpanningSignature) ) { - 0218        header = inputBuffer.ReadLeInt();219      }117118    /// <summary>119    /// Gets a value indicating if there is a current entry and it can be decompressed120    /// </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    }130131    /// <summary>132    /// Advances to the next entry in the archive133    /// </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 closed142    /// </exception>143    /// <exception cref="ZipException">144    /// Password is not set, password is invalid, compression method is invalid,145    /// version required to extract is not supported146    /// </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      }168169      // -jr- 07-Dec-2003 Ignore spanning temporary signatures if found170      // 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 {210211        // This allows for GNU, WinZip and possibly other archives, the PKZIP spec212        // 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 - 85221       if (header != ZipConstants.LocalHeaderSignature) { - 0222        throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header));223      } + 37221         if (csize != 0) { + 37222          entry.CompressedSize = csize & 0xFFFFFFFFL;223        }  224 - 85225      var versionRequiredToExtract = (short)inputBuffer.ReadLeShort();226 - 85227      flags          = inputBuffer.ReadLeShort(); - 85228      method         = inputBuffer.ReadLeShort(); - 85229      var dostime   = (uint)inputBuffer.ReadLeInt(); - 85230      int crc2       = inputBuffer.ReadLeInt(); - 85231      csize          = inputBuffer.ReadLeInt(); - 85232      size           = inputBuffer.ReadLeInt(); - 85233      int nameLen    = inputBuffer.ReadLeShort(); - 85234      int extraLen   = inputBuffer.ReadLeShort();235 - 85236      bool isCrypted = (flags & 1) == 1;237 - 85238      byte[] buffer = new byte[nameLen]; - 85239      inputBuffer.ReadRawBuffer(buffer);240 - 85241      string name = ZipConstants.ConvertToStringExt(flags, buffer);242 - 85243      entry = new ZipEntry(name, versionRequiredToExtract); - 85244      entry.Flags = flags;245 - 85246      entry.CompressionMethod = (CompressionMethod)method;247 - 85248       if ((flags & 8) == 0) { - 45249        entry.Crc  = crc2 & 0xFFFFFFFFL; - 45250        entry.Size = size & 0xFFFFFFFFL; - 45251        entry.CompressedSize = csize & 0xFFFFFFFFL; + 37225        entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);226      }227 + 81228      entry.DosTime = dostime;229230      // If local header requires Zip64 is true then the extended header should contain231      // both values.232233      // 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 - 45253        entry.CryptoCheckValue = (byte)((crc2 >> 24) & 0xff);254 - 45255      } else {256257        // This allows for GNU, WinZip and possibly other archives, the PKZIP spec258        // says these values are zero under these circumstances. - 40259         if (crc2 != 0) { - 14260          entry.Crc = crc2 & 0xFFFFFFFFL;261        }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 - 40263         if (size != 0) { - 40264          entry.Size = size & 0xFFFFFFFFL;265        }266 - 40267         if (csize != 0) { - 40268          entry.CompressedSize = csize & 0xFFFFFFFFL;269        }270 - 40271        entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);272      }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 - 85274      entry.DosTime = dostime;275276      // If local header requires Zip64 is true then the extended header should contain277      // both values.278279      // Handle extra data if present.  This can set/alter some fields of the entry. - 85280       if (extraLen > 0) { - 82281        byte[] extra = new byte[extraLen]; - 82282        inputBuffer.ReadRawBuffer(extra); - 82283        entry.ExtraData = extra;284      }285 - 85286      entry.ProcessExtraData(true); - 85287       if ( entry.CompressedSize >= 0 ) { - 60288        csize = entry.CompressedSize;289      }290 - 85291       if ( entry.Size >= 0 ) { - 60292        size = entry.Size;293      }294 - 85295       if (method == (int)CompressionMethod.Stored && (!isCrypted && csize != size || (isCrypted && csize - ZipConstants. - 0296        throw new ZipException("Stored, but compressed != uncompressed");297      } + 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    }284285    /// <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;  298299      // Determine how to handle reading of data if this is attempted. - 85300       if (entry.IsCompressionMethodSupported()) { - 85301        internalReader = new ReadDataHandler(InitialRead); - 85302      } else { - 0303        internalReader = new ReadDataHandler(ReadingNotSupported);304      } + 32299       if (testCrc && + 32300        ((crc.Value & 0xFFFFFFFFL) != entry.Crc) && (entry.Crc != -1)) { + 0301        throw new ZipException("CRC mismatch");302      }303 + 32304      crc.Reset();  305 - 85306      return entry;307    }308309    /// <summary>310    /// Read data descriptor at the end of compressed data.311    /// </summary>312    void ReadDataDescriptor()313    { - 6314       if (inputBuffer.ReadLeInt() != ZipConstants.DataDescriptorSignature) { - 0315        throw new ZipException("Data descriptor signature not found");316      }317 - 6318      entry.Crc = inputBuffer.ReadLeInt() & 0xFFFFFFFFL;319 - 6320       if ( entry.LocalHeaderRequiresZip64 ) { - 6321        csize = inputBuffer.ReadLeLong(); - 6322        size = inputBuffer.ReadLeLong(); - 6323      } else { - 0324        csize = inputBuffer.ReadLeInt(); - 0325        size = inputBuffer.ReadLeInt();326      } - 6327      entry.CompressedSize = csize; - 6328      entry.Size = size; - 6329    } + 32306       if (method == (int)CompressionMethod.Deflated) { + 25307        inf.Reset();308      } + 32309      entry = null; + 32310    }311312    /// <summary>313    /// Closes the current zip entry and moves to the next one.314    /// </summary>315    /// <exception cref="InvalidOperationException">316    /// The stream is closed317    /// </exception>318    /// <exception cref="ZipException">319    /// The Zip stream ends early320    /// </exception>321    public void CloseEntry()322    { + 14323       if (crc == null) { + 0324        throw new InvalidOperationException("Closed");325      }326 + 14327       if (entry == null) { + 0328        return;329      }  330331    /// <summary>332    /// Complete cleanup as the final part of closing.333    /// </summary>334    /// <param name="testCrc">True if the crc value should be tested</param>335    void CompleteCloseEntry(bool testCrc)336    { - 33337      StopDecrypting();338 - 33339       if ((flags & 8) != 0) { - 6340        ReadDataDescriptor();341      }342 - 33343      size = 0;344 - 33345       if ( testCrc && - 33346        ((crc.Value & 0xFFFFFFFFL) != entry.Crc) && (entry.Crc != -1)) { - 0347        throw new ZipException("CRC mismatch");348      }349 - 33350      crc.Reset();351 - 33352       if (method == (int)CompressionMethod.Deflated) { - 26353        inf.Reset();354      } - 33355      entry = null; - 33356    } + 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];335336          // 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          }  357358    /// <summary>359    /// Closes the current zip entry and moves to the next one.360    /// </summary>361    /// <exception cref="InvalidOperationException">362    /// The stream is closed363    /// </exception>364    /// <exception cref="ZipException">365    /// The Zip stream ends early366    /// </exception>367    public void CloseEntry()368    { - 14369       if (crc == null) { - 0370        throw new InvalidOperationException("Closed");371      }372 - 14373       if (entry == null) { - 0374        return;375      }376 - 14377       if (method == (int)CompressionMethod.Deflated) { - 9378         if ((flags & 8) != 0) {379          // We don't know how much we must skip, read until end. - 0380          byte[] tmp = new byte[4096];381382          // Read will close this entry - 0383           while (Read(tmp, 0, tmp.Length) > 0) {384          } - 0385          return;386        }387 - 9388        csize -= inf.TotalIn; - 9389        inputBuffer.Available += inf.RemainingInput;390      }391 - 14392       if ( (inputBuffer.Available > csize) && (csize >= 0) ) { - 14393        inputBuffer.Available = (int)((long)inputBuffer.Available - csize); - 14394      } else { - 0395        csize -= inputBuffer.Available; - 0396        inputBuffer.Available = 0; - 0397         while (csize != 0) { - 0398          long skipped = Skip(csize);399 - 0400           if (skipped <= 0) { - 0401            throw new ZipException("Zip archive ends early.");402          }403 - 0404          csize -= skipped;405        } + 0358          csize -= skipped;359        }360      }361 + 14362      CompleteCloseEntry(false); + 14363    }364365    /// <summary>366    /// Returns 1 if there is an entry available367    /// Otherwise returns 0.368    /// </summary>369    public override int Available {370      get { + 0371         return entry != null ? 1 : 0;372      }373    }374375    /// <summary>376    /// Returns the current size that can be read from the current entry if available377    /// </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      }392393    }394395    /// <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      }407 - 14408      CompleteCloseEntry(false); - 14409    }410411    /// <summary>412    /// Returns 1 if there is an entry available413    /// Otherwise returns 0.414    /// </summary>415    public override int Available {416      get { - 0417         return entry != null ? 1 : 0;418      }419    }420421    /// <summary>422    /// Returns the current size that can be read from the current entry if available423    /// </summary>424    /// <exception cref="ZipException">Thrown if the entry size is not known.</exception>425    /// <exception cref="InvalidOperationException">Thrown if no entry is currently available.</exception>426    public override long Length427    {428      get { - 0429         if ( entry != null ) { - 0430           if ( entry.Size >= 0 ) { - 0431            return entry.Size;432          } else { - 0433            throw new ZipException("Length not available for the current entry");434          }435        }436        else { - 0437          throw new InvalidOperationException("No current entry");438        }439      }440441    }442443    /// <summary>444    /// Reads a byte from the current zip entry.445    /// </summary>446    /// <returns>447    /// The byte or -1 if end of stream is reached.448    /// </returns>449    public override int ReadByte()450    { - 17451      byte[] b = new byte[1]; - 17452       if (Read(b, 0, 1) <= 0) { - 1453        return -1;454      } - 16455      return b[0] & 0xff;456    }457458    /// <summary>459    /// Handle attempts to read by throwing an <see cref="InvalidOperationException"/>.460    /// </summary>461    /// <param name="destination">The destination array to store data in.</param>462    /// <param name="offset">The offset at which data read should be stored.</param>463    /// <param name="count">The maximum number of bytes to read.</param>464    /// <returns>Returns the number of bytes actually read.</returns>465    int ReadingNotAvailable(byte[] destination, int offset, int count)466    { - 0467      throw new InvalidOperationException("Unable to read from this stream");468    }469470    /// <summary>471    /// Handle attempts to read from this entry by throwing an exception472    /// </summary>473    int ReadingNotSupported(byte[] destination, int offset, int count)474    { - 0475      throw new ZipException("The compression method for this entry is not supported");476    }477478    /// <summary>479    /// Perform the initial read on an entry which may include480    /// reading encryption headers and setting up inflation.481    /// </summary>482    /// <param name="destination">The destination to fill with data read.</param>483    /// <param name="offset">The offset to start reading at.</param>484    /// <param name="count">The maximum number of bytes to read.</param>485    /// <returns>The actual number of bytes read.</returns>486    int InitialRead(byte[] destination, int offset, int count)487    { - 74488       if ( !CanDecompressEntry ) { - 0489        throw new ZipException("Library cannot extract this entry. Version required is (" + entry.Version + ")");490      }491492      // Handle encryption if required. - 74493       if (entry.IsCrypted) {494#if NETCF_1_0495        throw new ZipException("Encryption not supported for Compact Framework 1.0");496#else - 27497         if (password == null) { - 0498          throw new ZipException("No password set.");499        }500501        // Generate and set crypto transform... - 27502        var managed = new PkzipClassicManaged(); - 27503        byte[] key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(password));504 - 27505        inputBuffer.CryptoTransform = managed.CreateDecryptor(key, null); + 12407      return b[0] & 0xff;408    }409410    /// <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    }421422    /// <summary>423    /// Handle attempts to read from this entry by throwing an exception424    /// </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    }429430    /// <summary>431    /// Perform the initial read on an entry which may include432    /// 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      }443444      // Handle encryption if required. + 70445       if (entry.IsCrypted) { + 24446         if (password == null) { + 0447          throw new ZipException("No password set.");448        }449450        // 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    }484485    /// <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 - 27507        byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize]; - 27508        inputBuffer.ReadClearTextBuffer(cryptbuffer, 0, ZipConstants.CryptoHeaderSize);509 - 27510         if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) { - 2511          throw new ZipException("Invalid password");512        } + 145507       if ((buffer.Length - offset) < count) { + 3508        throw new ArgumentException("Invalid offset/count combination");509      }510 + 142511      return internalReader(buffer, offset, count);512    }  513 - 25514         if (csize >= ZipConstants.CryptoHeaderSize) { - 14515          csize -= ZipConstants.CryptoHeaderSize; - 14516        } - 11517         else if ( (entry.Flags & (int)GeneralBitFlags.Descriptor) == 0 ) { - 0518          throw new ZipException(string.Format("Entry compressed size {0} too small for encryption", csize));519        }520#endif521      } else {522#if !NETCF_1_0 - 47523        inputBuffer.CryptoTransform = null;524#endif525      }526 - 72527       if ((csize > 0) || ((flags & (int)GeneralBitFlags.Descriptor) != 0)) { - 71528         if ((method == (int)CompressionMethod.Deflated) && (inputBuffer.Available > 0)) { - 68529          inputBuffer.SetInflaterInput(inf);530        }531 - 71532        internalReader = new ReadDataHandler(BodyRead); - 71533        return BodyRead(destination, offset, count);534      }535      else { - 1536        internalReader = new ReadDataHandler(ReadingNotAvailable); - 1537        return 0;538      }539    }540541    /// <summary>542    /// Read a block of bytes from the stream.543    /// </summary>544    /// <param name="buffer">The destination for the bytes.</param>545    /// <param name="offset">The index to start storing data.</param>546    /// <param name="count">The number of bytes to attempt to read.</param>547    /// <returns>Returns the number of bytes read.</returns>548    /// <remarks>Zero bytes read means end of stream.</remarks>549    public override int Read(byte[] buffer, int offset, int count)550    { - 158551       if ( buffer == null ) { - 1552        throw new ArgumentNullException(nameof(buffer));553      }554 - 157555       if ( offset < 0 ) {556#if NETCF_1_0557        throw new ArgumentOutOfRangeException("offset");558#else - 1559        throw new ArgumentOutOfRangeException(nameof(offset), "Cannot be negative");560#endif561      }562 - 156563       if ( count < 0 ) {564#if NETCF_1_0565        throw new ArgumentOutOfRangeException("count");566#else - 1567        throw new ArgumentOutOfRangeException(nameof(count), "Cannot be negative");568#endif569      }570 - 155571       if ( (buffer.Length - offset) < count ) { - 3572        throw new ArgumentException("Invalid offset/count combination");573      }574 - 152575      return internalReader(buffer, offset, count);576    }577578    /// <summary>579    /// Reads a block of bytes from the current zip entry.580    /// </summary>581    /// <returns>582    /// The number of bytes read (this may be less than the length requested, even before the end of stream), or 0 on en583    /// </returns>584    /// <exception name="IOException">585    /// An i/o error occured.586    /// </exception>587    /// <exception cref="ZipException">588    /// The deflated stream is corrupted.589    /// </exception>590    /// <exception cref="InvalidOperationException">591    /// The stream is not open.592    /// </exception>593    int BodyRead(byte[] buffer, int offset, int count)594    { - 149595       if ( crc == null ) { - 0596        throw new InvalidOperationException("Closed");597      }598 - 149599       if ( (entry == null) || (count <= 0) ) { - 46600        return 0;601      }602 - 103603       if ( offset + count > buffer.Length ) { - 0604        throw new ArgumentException("Offset + count exceeds buffer size");605      }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 en519    /// </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;553554            // 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.TotalOut558            } + 16559            inf.Reset(); + 16560            finished = true;561          } + 16562          break;563564        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    }597598    /// <summary>599    /// Closes the zip input stream600    /// </summary>601    public override void Close()602    { + 61603      internalReader = new ReadDataHandler(ReadingNotAvailable); + 61604      crc = null; + 61605      entry = null;  606 - 103607      bool finished = false;608 - 103609       switch (method) {610        case (int)CompressionMethod.Deflated: - 100611          count = base.Read(buffer, offset, count); - 100612           if (count <= 0) { - 17613             if (!inf.IsFinished) { - 0614              throw new ZipException("Inflater not finished!");615            } - 17616            inputBuffer.Available = inf.RemainingInput;617618            // A csize of -1 is from an unpatched local header - 17619             if ((flags & 8) == 0 && - 17620              (inf.TotalIn != csize && csize != 0xFFFFFFFF && csize != -1 || inf.TotalOut != size)) { - 0621              throw new ZipException("Size mismatch: " + csize + ";" + size + " <-> " + inf.TotalIn + ";" + inf.TotalOut622            } - 17623            inf.Reset(); - 17624            finished = true;625          } - 17626          break;627628        case (int)CompressionMethod.Stored: - 3629           if ( (count > csize) && (csize >= 0) ) { - 0630            count = (int)csize;631          }632 - 3633           if ( count > 0 ) { - 3634            count = inputBuffer.ReadClearTextBuffer(buffer, offset, count); - 3635             if (count > 0) { - 3636              csize -= count; - 3637              size -= count;638            }639          }640 - 3641           if (csize == 0) { - 2642            finished = true; - 2643          } else { - 1644             if (count < 0) { - 0645              throw new ZipException("EOF in stored block");646            }647          }648          break;649      }650 - 103651       if (count > 0) { - 86652        crc.Update(buffer, offset, count);653      }654 - 103655       if (finished) { - 19656        CompleteCloseEntry(true);657      }658 - 103659      return count;660    }661662    /// <summary>663    /// Closes the zip input stream664    /// </summary>665    public override void Close()666    { - 64667      internalReader = new ReadDataHandler(ReadingNotAvailable); - 64668      crc = null; - 64669      entry = null;670 - 64671      base.Close(); - 64672    }673  }674} + 61607      base.Close(); + 61608    }609  }610} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipNameTransform.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipNameTransform.htm index e249c817d..5f58e073a 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipNameTransform.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipNameTransform.htm @@ -18,7 +18,7 @@

Summary

Covered lines:66 Uncovered lines:11 Coverable lines:77 -Total lines:269 +Total lines:220 Line coverage:85.7% Branch coverage:67.6% @@ -42,277 +42,228 @@

#LineLine coverage - 1// ZipNameTransform.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This program is free software; you can redistribute it and/or6// modify it under the terms of the GNU General Public License7// as published by the Free Software Foundation; either version 28// of the License, or (at your option) any later version.9//10// This program is distributed in the hope that it will be useful,11// but WITHOUT ANY WARRANTY; without even the implied warranty of12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13// GNU General Public License for more details.14//15// You should have received a copy of the GNU General Public License16// along with this program; if not, write to the Free Software17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.18//19// Linking this library statically or dynamically with other modules is20// making a combined work based on this library.  Thus, the terms and21// conditions of the GNU General Public License cover the whole22// combination.23//24// As a special exception, the copyright holders of this library give you25// permission to link this library with independent modules to produce an26// executable, regardless of the license terms of these independent27// modules, and to copy and distribute the resulting executable under28// terms of your choice, provided that you also meet, for each linked29// independent module, the terms and conditions of the license of that30// module.  An independent module is a module which is not derived from31// or based on this library.  If you modify this library, you may extend32// this exception to your version of the library, but you are not33// obligated to do so.  If you do not wish to do so, delete this34// exception statement from your version.353637using System;38using System.IO;39using System.Text;4041using ICSharpCode.SharpZipLib.Core;4243namespace ICSharpCode.SharpZipLib.Zip44{45  /// <summary>46  /// ZipNameTransform transforms names as per the Zip file naming convention.47  /// </summary>48  /// <remarks>The use of absolute names is supported although its use is not valid49  /// according to Zip naming conventions, and should not be used if maximum compatability is desired.</remarks>50  public class ZipNameTransform : INameTransform51  {52    #region Constructors53    /// <summary>54    /// Initialize a new instance of <see cref="ZipNameTransform"></see>55    /// </summary> - 10656    public ZipNameTransform()57    { - 10658    }5960    /// <summary>61    /// Initialize a new instance of <see cref="ZipNameTransform"></see>62    /// </summary>63    /// <param name="trimPrefix">The string to trim from the front of paths if found.</param> - 764    public ZipNameTransform(string trimPrefix)65    { - 766      TrimPrefix = trimPrefix; - 767    }68    #endregion6970    /// <summary>71    /// Static constructor.72    /// </summary>73    static ZipNameTransform()74    {75      char[] invalidPathChars;76#if NET_1_0 || NET_1_1 || NETCF_1_077      invalidPathChars = Path.InvalidPathChars;78#else - 179      invalidPathChars = Path.GetInvalidPathChars();80#endif - 181      int howMany = invalidPathChars.Length + 2;82 - 183      InvalidEntryCharsRelaxed = new char[howMany]; - 184      Array.Copy(invalidPathChars, 0, InvalidEntryCharsRelaxed, 0, invalidPathChars.Length); - 185      InvalidEntryCharsRelaxed[howMany - 1] = '*'; - 186      InvalidEntryCharsRelaxed[howMany - 2] = '?';87 - 188      howMany = invalidPathChars.Length + 4; - 189      InvalidEntryChars = new char[howMany]; - 190      Array.Copy(invalidPathChars, 0, InvalidEntryChars, 0, invalidPathChars.Length); - 191      InvalidEntryChars[howMany - 1] = ':'; - 192      InvalidEntryChars[howMany - 2] = '\\'; - 193      InvalidEntryChars[howMany - 3] = '*'; - 194      InvalidEntryChars[howMany - 4] = '?'; - 195    }9697    /// <summary>98    /// Transform a windows directory name according to the Zip file naming conventions.99    /// </summary>100    /// <param name="name">The directory name to transform.</param>101    /// <returns>The transformed name.</returns>102    public string TransformDirectory(string name)103    { - 8104      name = TransformFile(name); - 7105       if (name.Length > 0) { - 7106         if ( !name.EndsWith("/", StringComparison.Ordinal)) { - 7107          name += "/";108        } - 7109      }110      else { - 0111        throw new ZipException("Cannot have an empty directory name");112      } - 7113      return name;114    }115116    /// <summary>117    /// Transform a windows file name according to the Zip file naming conventions.118    /// </summary>119    /// <param name="name">The file name to transform.</param>120    /// <returns>The transformed name.</returns>121    public string TransformFile(string name)122    { - 65936123       if (name != null) { - 65936124        string lowerName = name.ToLower(); - 65936125         if ( (trimPrefix_ != null) && (lowerName.IndexOf(trimPrefix_, StringComparison.Ordinal) == 0) ) { - 7126          name = name.Substring(trimPrefix_.Length);127        }1using System;2using System.IO;3using System.Text;4using ICSharpCode.SharpZipLib.Core;56namespace ICSharpCode.SharpZipLib.Zip7{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 valid12  /// according to Zip naming conventions, and should not be used if maximum compatability is desired.</remarks>13  public class ZipNameTransform : INameTransform14  {15    #region Constructors16    /// <summary>17    /// Initialize a new instance of <see cref="ZipNameTransform"></see>18    /// </summary> + 10119    public ZipNameTransform()20    { + 10121    }2223    /// <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    #endregion3233    /// <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    }5556    /// <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    }7374    /// <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);8990        // Drop any leading slashes. + 6593291         while ((name.Length > 0) && (name[0] == '/')) { + 592          name = name.Remove(0, 1);93        }9495        // Drop any trailing slashes. + 6592796         while ((name.Length > 0) && (name[name.Length - 1] == '/')) { + 097          name = name.Remove(name.Length - 1, 1);98        }99100        // 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    }113114    /// <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 from118    /// 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 - 65936129        name = name.Replace(@"\", "/"); - 65936130        name = WindowsPathUtils.DropPathRoot(name);131132        // Drop any leading slashes. - 65941133         while ((name.Length > 0) && (name[0] == '/'))134        { - 5135          name = name.Remove(0, 1);136        }137138        // Drop any trailing slashes. - 65936139         while ((name.Length > 0) && (name[name.Length - 1] == '/'))140        { - 0141          name = name.Remove(name.Length - 1, 1);142        }129    /// <summary>130    /// Force a name to be valid by replacing invalid characters with a fixed value131    /// </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;  143144        // Convert consecutive // characters to / - 65936145        int index = name.IndexOf("//", StringComparison.Ordinal); - 65936146         while (index >= 0)147        { - 0148          name = name.Remove(index, 1); - 0149          index = name.IndexOf("//", StringComparison.Ordinal);150        }151 - 65936152        name = MakeValidName(name, '_'); - 65935153      }154      else { - 0155        name = string.Empty;156      } - 65935157      return name; + 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    /// Get/set the path prefix to be trimmed from paths if present.161    /// Test a name to see if it is a valid name for a zip entry.  162    /// </summary>163    /// <remarks>The prefix is trimmed before any conversion from164    /// a windows path is done.</remarks>165    public string TrimPrefix166    { - 0167      get { return trimPrefix_; }168      set { - 7169        trimPrefix_ = value; - 7170         if (trimPrefix_ != null) { - 7171          trimPrefix_ = trimPrefix_.ToLower();172        } - 7173      }174    }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 or168    /// 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);  175176    /// <summary>177    /// Force a name to be valid by replacing invalid characters with a fixed value178    /// </summary>179    /// <param name="name">The name to force valid</param>180    /// <param name="replacement">The replacement character to use.</param>181    /// <returns>Returns a valid name</returns>182    static string MakeValidName(string name, char replacement)183    { - 65936184      int index = name.IndexOfAny(InvalidEntryChars); - 65936185       if (index >= 0) { - 5186        var builder = new StringBuilder(name);187 - 11188         while (index >= 0 ) { - 6189          builder[index] = replacement;190 - 6191           if (index >= name.Length) { - 0192            index = -1; - 0193          }194          else { - 6195            index = name.IndexOfAny(InvalidEntryChars, index + 1);196          }197        } - 5198        name = builder.ToString();199      }200 - 65936201       if (name.Length > 0xffff) { - 1202        throw new PathTooLongException();203      }204 - 65935205      return name;206    }207208    /// <summary>209    /// Test a name to see if it is a valid name for a zip entry.210    /// </summary>211    /// <param name="name">The name to test.</param>212    /// <param name="relaxed">If true checking is relaxed about windows file names and absolute paths.</param>213    /// <returns>Returns true if the name is a valid zip name; false otherwise.</returns>214    /// <remarks>Zip path names are actually in Unix format, and should only contain relative paths.215    /// This means that any path stored should not contain a drive or216    /// device letter, or a leading slash.  All slashes should forward slashes '/'.217    /// An empty name is valid for a file where the input comes from standard input.218    /// A null name is not considered valid.219    /// </remarks>220    public static bool IsValidName(string name, bool relaxed)221    { - 65916222      bool result = (name != null);223 - 65916224       if ( result ) { - 65916225         if ( relaxed ) { - 65916226          result = name.IndexOfAny(InvalidEntryCharsRelaxed) < 0; - 65916227        }228        else { - 0229          result = - 0230            (name.IndexOfAny(InvalidEntryChars) < 0) && - 0231            (name.IndexOf('/') != 0);232        }233      }234 - 65916235      return result;236    }237238    /// <summary>239    /// Test a name to see if it is a valid name for a zip entry.240    /// </summary>241    /// <param name="name">The name to test.</param>242    /// <returns>Returns true if the name is a valid zip name; false otherwise.</returns>243    /// <remarks>Zip path names are actually in unix format,244    /// and should only contain relative paths if a path is present.245    /// This means that the path stored should not contain a drive or246    /// device letter, or a leading slash.  All slashes should forward slashes '/'.247    /// An empty name is valid where the input comes from standard input.248    /// A null name is not considered valid.249    /// </remarks>250    public static bool IsValidName(string name)251    { - 2252      bool result = - 2253        (name != null) && - 2254        (name.IndexOfAny(InvalidEntryChars) < 0) && - 2255        (name.IndexOf('/') != 0) - 2256        ; - 1257      return result;258    }259260    #region Instance Fields261    string trimPrefix_;262    #endregion263264    #region Class Fields265    static readonly char[] InvalidEntryChars;266    static readonly char[] InvalidEntryCharsRelaxed;267    #endregion268  }269} + 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    }188189    /// <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 or197    /// 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    }210211    #region Instance Fields212    string trimPrefix_;213    #endregion214215    #region Class Fields216    static readonly char[] InvalidEntryChars;217    static readonly char[] InvalidEntryCharsRelaxed;218    #endregion219  }220} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipOutputStream.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipOutputStream.htm index bb8806386..92cd8d99a 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipOutputStream.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipOutputStream.htm @@ -18,7 +18,7 @@

Summary

Covered lines:285 Uncovered lines:48 Coverable lines:333 -Total lines:900 +Total lines:816 Line coverage:85.5% Branch coverage:78.4% @@ -50,908 +50,824 @@

#LineLine coverage - 1// ZipOutputStream.cs2//3// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team4//5// This file was translated from java, it was part of the GNU Classpath6// Copyright (C) 2001 Free Software Foundation, Inc.7//8// This program is free software; you can redistribute it and/or9// modify it under the terms of the GNU General Public License10// as published by the Free Software Foundation; either version 211// of the License, or (at your option) any later version.12//13// This program is distributed in the hope that it will be useful,14// but WITHOUT ANY WARRANTY; without even the implied warranty of15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the16// GNU General Public License for more details.17//18// You should have received a copy of the GNU General Public License19// along with this program; if not, write to the Free Software20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.21//22// Linking this library statically or dynamically with other modules is23// making a combined work based on this library.  Thus, the terms and24// conditions of the GNU General Public License cover the whole25// combination.26//27// As a special exception, the copyright holders of this library give you28// permission to link this library with independent modules to produce an29// executable, regardless of the license terms of these independent30// modules, and to copy and distribute the resulting executable under31// terms of your choice, provided that you also meet, for each linked32// independent module, the terms and conditions of the license of that33// module.  An independent module is a module which is not derived from34// or based on this library.  If you modify this library, you may extend35// this exception to your version of the library, but you are not36// obligated to do so.  If you do not wish to do so, delete this37// exception statement from your version.3839// HISTORY40//  22-12-2009  Z-1649  Added AES support41//  22-02-2010  Z-1648  Zero byte entries would create invalid zip files42//  27-07-2012  Z-1724  Compressed size was incorrect in local header when CRC and Size are known4344using System;45using System.IO;46using System.Collections;4748using ICSharpCode.SharpZipLib.Checksums;49using ICSharpCode.SharpZipLib.Zip.Compression;50using ICSharpCode.SharpZipLib.Zip.Compression.Streams;5152namespace ICSharpCode.SharpZipLib.Zip53{54  /// <summary>55  /// This is a DeflaterOutputStream that writes the files into a zip56  /// archive one after another.  It has a special method to start a new57  /// zip entry.  The zip entries contains information about the file name58  /// size, compressed size, CRC, etc.59  ///60  /// It includes support for Stored and Deflated entries.61  /// This class is not thread safe.62  /// <br/>63  /// <br/>Author of the original java version : Jochen Hoenicke64  /// </summary>65  /// <example> This sample shows how to create a zip file66  /// <code>67  /// using System;68  /// using System.IO;69  ///70  /// using ICSharpCode.SharpZipLib.Core;71  /// using ICSharpCode.SharpZipLib.Zip;72  ///73  /// class MainClass74  /// {75  ///   public static void Main(string[] args)76  ///   {77  ///     string[] filenames = Directory.GetFiles(args[0]);78  ///     byte[] buffer = new byte[4096];79  ///80  ///     using ( ZipOutputStream s = new ZipOutputStream(File.Create(args[1])) ) {81  ///82  ///       s.SetLevel(9); // 0 - store only to 9 - means best compression83  ///84  ///       foreach (string file in filenames) {85  ///         ZipEntry entry = new ZipEntry(file);86  ///         s.PutNextEntry(entry);87  ///88  ///         using (FileStream fs = File.OpenRead(file)) {89  ///            StreamUtils.Copy(fs, s, buffer);90  ///         }91  ///       }92  ///     }93  ///   }94  /// }95  /// </code>96  /// </example>97  public class ZipOutputStream : DeflaterOutputStream98  {99    #region Constructors100    /// <summary>101    /// Creates a new Zip output stream, writing a zip archive.102    /// </summary>103    /// <param name="baseOutputStream">104    /// The output stream to which the archive contents are written.105    /// </param>106    public ZipOutputStream(Stream baseOutputStream) - 92107      : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true))108    { - 92109    }110111        /// <summary>112        /// Creates a new Zip output stream, writing a zip archive.113        /// </summary>114        /// <param name="baseOutputStream">The output stream to which the archive contents are written.</param>115        /// <param name="bufferSize">Size of the buffer to use.</param>116        public ZipOutputStream( Stream baseOutputStream, int bufferSize ) - 0117            : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true), bufferSize)118        { - 0119        }120        #endregion1using System;2using System.IO;3using System.Collections;4using ICSharpCode.SharpZipLib.Checksum;5using ICSharpCode.SharpZipLib.Zip.Compression;6using ICSharpCode.SharpZipLib.Zip.Compression.Streams;78namespace ICSharpCode.SharpZipLib.Zip9{10  /// <summary>11  /// This is a DeflaterOutputStream that writes the files into a zip12  /// archive one after another.  It has a special method to start a new13  /// zip entry.  The zip entries contains information about the file name14  /// 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 Hoenicke20  /// </summary>21  /// <example> This sample shows how to create a zip file22  /// <code>23  /// using System;24  /// using System.IO;25  ///26  /// using ICSharpCode.SharpZipLib.Core;27  /// using ICSharpCode.SharpZipLib.Zip;28  ///29  /// class MainClass30  /// {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 compression39  ///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 : DeflaterOutputStream54  {55    #region Constructors56    /// <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    }6667    /// <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    #endregion7778    /// <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    }8788    /// <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    }106107    /// <summary>108    /// Sets the compression level.  The new level will be activated109    /// 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    /// Gets a flag value of true if the central header has been added for this archive; false if it has not been added.123    /// Get the current deflater compression level  124    /// </summary>125    /// <remarks>No further entries can be added once this has been done.</remarks>126    public bool IsFinished125    /// <returns>The current compression level</returns>126    public int GetLevel()  127    {128      get { - 1129        return entries == null;130      }131    }132133    /// <summary>134    /// Set the zip file comment.135    /// </summary>136    /// <param name="comment">137    /// The comment text for the entire archive.138    /// </param>139    /// <exception name ="ArgumentOutOfRangeException">140    /// The converted comment is longer than 0xffff bytes.141    /// </exception>142    public void SetComment(string comment)143    {144      // TODO: Its not yet clear how to handle unicode comments here. - 8145      byte[] commentBytes = ZipConstants.ConvertToArray(comment); - 8146       if (commentBytes.Length > 0xffff) { - 1147        throw new ArgumentOutOfRangeException(nameof(comment));148      } - 7149      zipComment = commentBytes; - 7150    }151152    /// <summary>153    /// Sets the compression level.  The new level will be activated154    /// immediately.155    /// </summary>156    /// <param name="level">The new compression level (1 to 9).</param>157    /// <exception cref="ArgumentOutOfRangeException">158    /// Level specified is not supported.159    /// </exception>160    /// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Deflater"/>161    public void SetLevel(int level)162    { - 57163      deflater_.SetLevel(level); - 57164      defaultCompressionLevel = level; - 57165    }166167    /// <summary>168    /// Get the current deflater compression level169    /// </summary>170    /// <returns>The current compression level</returns>171    public int GetLevel()172    { - 3173      return deflater_.GetLevel();174    } + 3128      return deflater_.GetLevel();129    }130131    /// <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 arch136    /// Setting this property to off is workable but less desirable as in those circumstances adding a file137    /// larger then 4GB will fail.</remarks>138    public UseZip64 UseZip64 { + 0139      get { return useZip64_; } + 14140      set { useZip64_ = value; }141    }142143    /// <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    }153154    /// <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    }164165    /// <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    /// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.178    /// </summary>179    /// <remarks>Older archivers may not understand Zip64 extensions.180    /// If backwards compatability is an issue be careful when adding <see cref="ZipEntry.Size">entries</see> to an arch181    /// Setting this property to off is workable but less desirable as in those circumstances adding a file182    /// larger then 4GB will fail.</remarks>183    public UseZip64 UseZip64184    { - 0185      get { return useZip64_; } - 18186      set { useZip64_ = value; }187    }188189    /// <summary>190    /// Write an unsigned short in little endian byte order.191    /// </summary>192    private void WriteLeShort(int value)193    {194      unchecked { - 6539195        baseOutputStream_.WriteByte((byte)(value & 0xff)); - 6539196        baseOutputStream_.WriteByte((byte)((value >> 8) & 0xff));197      } - 6539198    }199200    /// <summary>201    /// Write an int in little endian byte order.202    /// </summary>203    private void WriteLeInt(int value)204    {205      unchecked { - 2350206        WriteLeShort(value); - 2350207        WriteLeShort(value >> 16);177    /// Starts a new Zip entry. It automatically closes the previous178    /// 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 patchable181    /// the compression for that entry is automatically changed to deflate level 0182    /// </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 finished194    /// </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      } - 2350209    }210211    /// <summary>212    /// Write an int in little endian byte order.213    /// </summary>214    private void WriteLeLong(long value)215    {216      unchecked { - 278217        WriteLeInt((int)value); - 278218        WriteLeInt((int)(value >> 32));219      } - 278220    }221222    /// <summary>223    /// Starts a new Zip entry. It automatically closes the previous224    /// entry if present.225    /// All entry elements bar name are optional, but must be correct if present.226    /// If the compression method is stored and the output is not patchable227    /// the compression for that entry is automatically changed to deflate level 0228    /// </summary>229    /// <param name="entry">230    /// the entry.231    /// </param>232    /// <exception cref="System.ArgumentNullException">233    /// if entry passed is null.234    /// </exception>235    /// <exception cref="System.IO.IOException">236    /// if an I/O error occured.237    /// </exception>238    /// <exception cref="System.InvalidOperationException">239    /// if stream was finished240    /// </exception>241    /// <exception cref="ZipException">242    /// Too many entries in the Zip file<br/>243    /// Entry name is too long<br/>244    /// Finish has already been called<br/>245    /// </exception>246    public void PutNextEntry(ZipEntry entry)247    { - 133248       if ( entry == null ) { - 0249        throw new ArgumentNullException(nameof(entry));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;220221      // Clear flags that the library manages internally + 129222      entry.Flags &= (int)GeneralBitFlags.UnicodeText; + 129223      patchEntryHeader = false;224225      bool headerInfoAvailable;226227      // 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;235236        // 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 > 0245            { + 0246            entry.CompressedSize = entry.Size; + 0247            headerInfoAvailable = entry.HasCrc;248          }249        }  250      }  251 - 133252       if (entries == null) { - 1253        throw new InvalidOperationException("ZipOutputStream was finished");254      }255 - 132256       if (curEntry != null) { - 48257        CloseEntry();258      }259 - 132260       if (entries.Count == int.MaxValue) { - 0261        throw new ZipException("Too many entries for Zip file"); + 129252       if (headerInfoAvailable == false) { + 128253         if (CanPatchEntries == false) {254          // Only way to record size and compressed size is to append a data descriptor255          // after compressed data.256257          // Stored entries of this form have already been converted to deflating. + 32258          entry.Flags |= 8; + 32259        } else { + 96260          patchEntryHeader = true;261        }  262      }  263 - 132264      CompressionMethod method = entry.CompressionMethod; - 132265      int compressionLevel = defaultCompressionLevel;266267      // Clear flags that the library manages internally - 132268      entry.Flags &= (int)GeneralBitFlags.UnicodeText; - 132269      patchEntryHeader = false;270271      bool headerInfoAvailable;272273      // No need to compress - definitely no data. - 132274       if (entry.Size == 0)275      { - 1276        entry.CompressedSize = entry.Size; - 1277        entry.Crc = 0; - 1278        method = CompressionMethod.Stored; - 1279        headerInfoAvailable = true; - 1280      }281      else282      { - 131283        headerInfoAvailable = (entry.Size >= 0) && entry.HasCrc && entry.CompressedSize >= 0;284285        // Switch to deflation if storing isnt possible. - 131286         if (method == CompressionMethod.Stored)287        { - 13288           if (!headerInfoAvailable)289          { - 13290             if (!CanPatchEntries)291            {292              // Can't patch entries so storing is not possible. - 5293              method = CompressionMethod.Deflated; - 5294              compressionLevel = 0;295            } - 5296          }297          else // entry.size must be > 0298          { - 0299            entry.CompressedSize = entry.Size; - 0300            headerInfoAvailable = entry.HasCrc;301          }302        }303      }304 - 132305       if (headerInfoAvailable == false) { - 131306         if (CanPatchEntries == false) {307          // Only way to record size and compressed size is to append a data descriptor308          // after compressed data.309310          // Stored entries of this form have already been converted to deflating. - 33311          entry.Flags |= 8; - 33312        } else { - 98313          patchEntryHeader = true;314        }315      }316 - 132317       if (Password != null) { - 36318        entry.IsCrypted = true; - 36319         if (entry.Crc < 0) {320          // Need to append a data descriptor as the crc isnt available for use321          // with encryption, the date is used instead.  Setting the flag322          // indicates this to the decompressor. - 32323          entry.Flags |= 8;324        }325      }326 - 132327      entry.Offset = offset; - 132328      entry.CompressionMethod = (CompressionMethod)method; + 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 use268          // with encryption, the date is used instead.  Setting the flag269          // 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      }283284      // 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);291292      // 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);  // Crc307 + 128308         if (patchEntryHeader) { + 96309          sizePatchPos = baseOutputStream_.Position;310        }311312        // 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 size319        }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 - 132330      curMethod = method; - 132331      sizePatchPos = -1;332 - 132333       if ( (useZip64_ == UseZip64.On) || ((entry.Size < 0) && (useZip64_ == UseZip64.Dynamic)) ) { - 124334        entry.ForceZip64();335      }336337      // Write the local file header - 132338      WriteLeInt(ZipConstants.LocalHeaderSignature);339 - 132340      WriteLeShort(entry.Version); - 132341      WriteLeShort(entry.Flags); - 132342      WriteLeShort((byte)entry.CompressionMethodForHeader); - 132343      WriteLeInt((int)entry.DosTime); + 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        }  344345      // TODO: Refactor header writing.  Its done in several places. - 132346       if (headerInfoAvailable) { - 1347        WriteLeInt((int)entry.Crc); - 1348         if ( entry.LocalHeaderRequiresZip64 ) { - 1349          WriteLeInt(-1); - 1350          WriteLeInt(-1); - 1351        }352        else { - 0353          WriteLeInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.Compressed - 0354          WriteLeInt((int)entry.Size);355        } - 0356      } else { - 131357         if (patchEntryHeader) { - 98358          crcPatchPos = baseOutputStream_.Position;359        } - 131360        WriteLeInt(0);  // Crc361 - 131362         if ( patchEntryHeader ) { - 98363          sizePatchPos = baseOutputStream_.Position;364        }365366        // For local header both sizes appear in Zip64 Extended Information - 131367         if ( entry.LocalHeaderRequiresZip64 || patchEntryHeader ) { - 128368          WriteLeInt(-1); - 128369          WriteLeInt(-1); - 128370        }371        else { - 3372          WriteLeInt(0);  // Compressed size - 3373          WriteLeInt(0);  // Uncompressed size374        }375      } + 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 - 132377      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);378 - 132379       if (name.Length > 0xFFFF) { - 0380        throw new ZipException("Entry name too long.");381      }382 - 132383      var ed = new ZipExtraData(entry.ExtraData);384 - 132385       if (entry.LocalHeaderRequiresZip64) { - 125386        ed.StartNewEntry(); - 125387         if (headerInfoAvailable) { - 1388          ed.AddLeLong(entry.Size); - 1389          ed.AddLeLong(entry.CompressedSize); - 1390        }391        else { - 124392          ed.AddLeLong(-1); - 124393          ed.AddLeLong(-1);394        } - 125395        ed.AddNewEntry(1);396 - 125397         if ( !ed.Find(1) ) { - 0398          throw new ZipException("Internal error cant find extra data");399        }400 - 125401         if ( patchEntryHeader ) { - 94402          sizePatchPos = ed.CurrentReadIndex;403        } - 94404      }405      else { - 7406        ed.Delete(1);407      }408409#if !NET_1_1 && !NETCF_2_0 - 132410       if (entry.AESKeySize > 0) { - 0411        AddExtraDataAES(entry, ed);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    }398399    /// <summary>400    /// Closes the current entry, updating header and footer information as required401    /// </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#endif - 132414      byte[] extra = ed.GetEntryData();413 + 128414      long csize = size;  415 - 132416      WriteLeShort(name.Length); - 132417      WriteLeShort(extra.Length);418 - 132419       if ( name.Length > 0 ) { - 132420        baseOutputStream_.Write(name, 0, name.Length);421      }422 - 131423       if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) { - 93424        sizePatchPos += baseOutputStream_.Position;425      }426 - 131427       if ( extra.Length > 0 ) { - 124428        baseOutputStream_.Write(extra, 0, extra.Length);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      }425426      // 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 - 131431      offset += ZipConstants.LocalHeaderBaseSize + name.Length + extra.Length;432      // Fix offsetOfCentraldir for AES - 131433       if (entry.AESKeySize > 0) - 0434        offset += entry.AESOverheadSize;435436      // Activate the entry. - 131437      curEntry = entry; - 131438      crc.Reset(); - 131439       if (method == CompressionMethod.Deflated) { - 122440        deflater_.Reset(); - 122441        deflater_.SetLevel(compressionLevel);442      } - 131443      size = 0;444 - 131445       if (entry.IsCrypted) {446#if !NET_1_1 && !NETCF_2_0 - 36447         if (entry.AESKeySize > 0) { - 0448          WriteAESHeader(entry); - 0449        } else450#endif451        { - 36452           if (entry.Crc < 0) {      // so testing Zip will says its ok - 32453            WriteEncryptionHeader(entry.DosTime << 16); - 32454          } else { - 4455            WriteEncryptionHeader(entry.Crc);456          } + 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      } - 99459    }460461    /// <summary>462    /// Closes the current entry, updating header and footer information as required463    /// </summary>464    /// <exception cref="System.IO.IOException">465    /// An I/O error occurs.466    /// </exception>467    /// <exception cref="System.InvalidOperationException">468    /// No entry is active.469    /// </exception>470    public void CloseEntry()471    { - 131472       if (curEntry == null) { - 0473        throw new InvalidOperationException("No open entry");474      }475 - 131476      long csize = size;477478      // First finish the deflater, if appropriate - 131479       if (curMethod == CompressionMethod.Deflated) { - 122480         if (size >= 0) { - 122481          base.Finish(); - 122482          csize = deflater_.TotalOut; - 122483        }484        else { - 0485          deflater_.Reset();486        }487      }459460      // 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      }483484      // Add data descriptor if flagged as required + 128485       if ((curEntry.Flags & 8) != 0) { + 48486        WriteLeInt(ZipConstants.DataDescriptorSignature); + 48487        WriteLeInt(unchecked((int)curEntry.Crc));  488489      // Write the AES Authentication Code (a hash of the compressed and encrypted data) - 131490       if (curEntry.AESKeySize > 0) { - 0491        baseOutputStream_.Write(AESAuthCode, 0, 10);492      }493 - 131494       if (curEntry.Size < 0) { - 124495        curEntry.Size = size; - 131496       } else if (curEntry.Size != size) { - 0497        throw new ZipException("size was " + size + ", but I expected " + curEntry.Size); + 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 - 131500       if (curEntry.CompressedSize < 0) { - 130501        curEntry.CompressedSize = csize; - 131502       } else if (curEntry.CompressedSize != csize) { - 0503        throw new ZipException("compressed size was " + csize + ", but I expected " + curEntry.CompressedSize);504      }505 - 131506       if (curEntry.Crc < 0) { - 117507        curEntry.Crc = crc.Value; - 131508       } else if (curEntry.Crc != crc.Value) { - 0509        throw new ZipException("crc was " + crc.Value +  ", but I expected " + curEntry.Crc);510      }511 - 131512      offset += csize;513 - 131514       if (curEntry.IsCrypted) { - 36515         if (curEntry.AESKeySize > 0) { - 0516          curEntry.CompressedSize += curEntry.AESOverheadSize;517 - 0518        } else { - 36519          curEntry.CompressedSize += ZipConstants.CryptoHeaderSize;520        }521      }522523      // Patch the header if possible - 131524       if (patchEntryHeader) { - 97525        patchEntryHeader = false;526 - 97527        long curPos = baseOutputStream_.Position; - 97528        baseOutputStream_.Seek(crcPatchPos, SeekOrigin.Begin); - 97529        WriteLeInt((int)curEntry.Crc);530 - 97531         if ( curEntry.LocalHeaderRequiresZip64 ) {532 - 93533           if ( sizePatchPos == -1 ) { - 0534            throw new ZipException("Entry requires zip64 but this has been turned off");535          }536 - 93537          baseOutputStream_.Seek(sizePatchPos, SeekOrigin.Begin); - 93538          WriteLeLong(curEntry.Size); - 93539          WriteLeLong(curEntry.CompressedSize); - 93540        }541        else { - 4542          WriteLeInt((int)curEntry.CompressedSize); - 4543          WriteLeInt((int)curEntry.Size);544        } - 97545        baseOutputStream_.Seek(curPos, SeekOrigin.Begin);546      }547548      // Add data descriptor if flagged as required - 131549       if ((curEntry.Flags & 8) != 0) { - 51550        WriteLeInt(ZipConstants.DataDescriptorSignature); - 51551        WriteLeInt(unchecked((int)curEntry.Crc));552 - 51553         if ( curEntry.LocalHeaderRequiresZip64 ) { - 46554          WriteLeLong(curEntry.CompressedSize); - 46555          WriteLeLong(curEntry.Size); - 46556          offset += ZipConstants.Zip64DataDescriptorSize; - 46557        }558        else { - 5559          WriteLeInt((int)curEntry.CompressedSize); - 5560          WriteLeInt((int)curEntry.Size); - 5561          offset += ZipConstants.DataDescriptorSize;562        }563      }564 - 131565      entries.Add(curEntry); - 131566      curEntry = null; - 131567    }568569    void WriteEncryptionHeader(long crcValue)570    { - 36571      offset += ZipConstants.CryptoHeaderSize;572 - 36573      InitializePassword(Password);574 - 36575      byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize]; - 36576      var rnd = new Random(); - 36577      rnd.NextBytes(cryptBuffer); - 36578      cryptBuffer[11] = (byte)(crcValue >> 24); + 128500      entries.Add(curEntry); + 128501      curEntry = null; + 128502    }503504    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    }518519    private static void AddExtraDataAES(ZipEntry entry, ZipExtraData extraData)520    {521522      // 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.htm528      //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    }535536    // Replaces WriteEncryptionHeader for AES537    //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)   Content545      // ------------   -------546      // Variable       Salt value547      // 2              Password verification value548      // Variable       Encrypted file data549      // 10             Authentication code550      //551      // Value in the "compressed size" fields of the local file header and the central directory entry552      // is the total size of all the items listed above. In other words, it is the total size of the553      // 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    }557558    /// <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 - 36580      EncryptBlock(cryptBuffer, 0, cryptBuffer.Length); - 36581      baseOutputStream_.Write(cryptBuffer, 0, cryptBuffer.Length); - 36582    } + 4503580       if (count < 0) { + 0581        throw new ArgumentOutOfRangeException(nameof(count), "Cannot be negative");582      }  583584#if !NET_1_1 && !NETCF_2_0585    private static void AddExtraDataAES(ZipEntry entry, ZipExtraData extraData) {586587      // Vendor Version: AE-1 IS 1. AE-2 is 2. With AE-2 no CRC is required and 0 is stored.588      const int VENDOR_VERSION = 2;589      // Vendor ID is the two ASCII characters "AE".590      const int VENDOR_ID = 0x4541; //not 6965; - 0591      extraData.StartNewEntry();592      // Pack AES extra data field see http://www.winzip.com/aes_info.htm593      //extraData.AddLeShort(7);              // Data size (currently 7) - 0594      extraData.AddLeShort(VENDOR_VERSION);        // 2 = AE-2 - 0595      extraData.AddLeShort(VENDOR_ID);          // "AE" - 0596      extraData.AddData(entry.AESEncryptionStrength);    //  1 = 128, 2 = 192, 3 = 256 - 0597      extraData.AddLeShort((int)entry.CompressionMethod); // The actual compression method used to compress the file - 0598      extraData.AddNewEntry(0x9901); - 0599    }600601    // Replaces WriteEncryptionHeader for AES602    //603    private void WriteAESHeader(ZipEntry entry) {604      byte[] salt;605      byte[] pwdVerifier; - 0606      InitializeAESPassword(entry, Password, out salt, out pwdVerifier);607      // File format for AES:608      // Size (bytes)   Content609      // ------------   -------610      // Variable       Salt value611      // 2              Password verification value612      // Variable       Encrypted file data613      // 10             Authentication code614      //615      // Value in the "compressed size" fields of the local file header and the central directory entry616      // is the total size of all the items listed above. In other words, it is the total size of the617      // salt value, password verification value, encrypted data, and authentication code. - 0618      baseOutputStream_.Write(salt, 0, salt.Length); - 0619      baseOutputStream_.Write(pwdVerifier, 0, pwdVerifier.Length); - 0620    }621#endif622623    /// <summary>624    /// Writes the given buffer to the current entry.625    /// </summary>626    /// <param name="buffer">The buffer containing data to write.</param>627    /// <param name="offset">The offset of the first byte to write.</param>628    /// <param name="count">The number of bytes to write.</param>629    /// <exception cref="ZipException">Archive size is invalid</exception>630    /// <exception cref="System.InvalidOperationException">No entry is active.</exception>631    public override void Write(byte[] buffer, int offset, int count)632    { - 4507633       if (curEntry == null) { - 0634        throw new InvalidOperationException("No open entry.");635      }636 - 4507637       if ( buffer == null ) { - 0638        throw new ArgumentNullException(nameof(buffer)); + 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;595596        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    }605606    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    }620621    /// <summary>622    /// Finishes the stream.  This will write the central directory at the623    /// 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 length634    /// </exception>635    public override void Finish()636    { + 88637       if (entries == null) { + 2638        return;  639      }  640 - 4507641       if ( offset < 0 ) {642#if NETCF_1_0643        throw new ArgumentOutOfRangeException("offset");644#else - 0645        throw new ArgumentOutOfRangeException(nameof(offset), "Cannot be negative");646#endif647      }648 - 4507649       if ( count < 0 ) {650#if NETCF_1_0651        throw new ArgumentOutOfRangeException("count");652#else - 0653        throw new ArgumentOutOfRangeException(nameof(count), "Cannot be negative");654#endif655      } + 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 - 4507657       if ( (buffer.Length - offset) < count ) { - 0658        throw new ArgumentException("Invalid offset/count combination");659      }660 - 4507661      crc.Update(buffer, offset, count); - 4507662      size += count; + 128657         if (entry.IsZip64Forced() || + 128658          (entry.CompressedSize >= uint.MaxValue)) { + 121659          WriteLeInt(-1); + 121660        } else { + 7661          WriteLeInt((int)entry.CompressedSize);662        }  663 - 4507664       switch (curMethod) {665        case CompressionMethod.Deflated: - 4308666          base.Write(buffer, offset, count); - 4308667          break;668669        case CompressionMethod.Stored: - 199670           if (Password != null) { - 99671            CopyAndEncrypt(buffer, offset, count); - 99672          } else { - 100673            baseOutputStream_.Write(buffer, offset, count);674          }675          break;676      } - 100677    } + 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);  678679    void CopyAndEncrypt(byte[] buffer, int offset, int count)680    {681      const int CopyBufferSize = 4096; - 99682      byte[] localBuffer = new byte[CopyBufferSize]; - 198683       while ( count > 0 ) { - 99684         int bufferCount = (count < CopyBufferSize) ? count : CopyBufferSize; + 128679         if (entry.CentralHeaderRequiresZip64) { + 121680          ed.StartNewEntry(); + 121681           if (entry.IsZip64Forced() || + 121682            (entry.Size >= 0xffffffff)) { + 121683            ed.AddLeLong(entry.Size);684          }  685 - 99686        Array.Copy(buffer, offset, localBuffer, 0, bufferCount); - 99687        EncryptBlock(localBuffer, 0, bufferCount); - 99688        baseOutputStream_.Write(localBuffer, 0, bufferCount); - 99689        count -= bufferCount; - 99690        offset += bufferCount;691      } - 99692    }693694    /// <summary>695    /// Finishes the stream.  This will write the central directory at the696    /// end of the zip file and flush the stream.697    /// </summary>698    /// <remarks>699    /// This is automatically called when the stream is closed.700    /// </remarks>701    /// <exception cref="System.IO.IOException">702    /// An I/O error occurs.703    /// </exception>704    /// <exception cref="ZipException">705    /// Comment exceeds the maximum length<br/>706    /// Entry name exceeds the maximum length707    /// </exception>708    public override void Finish()709    { - 93710       if (entries == null)  { - 2711        return;712      } + 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 - 91714       if (curEntry != null) { - 79715        CloseEntry();716      }717 - 91718      long numEntries = entries.Count; - 91719      long sizeEntries = 0; + 128714        WriteLeShort(name.Length); + 128715        WriteLeShort(extra.Length); + 128716        WriteLeShort(entryComment.Length); + 128717        WriteLeShort(0);    // disk number + 128718        WriteLeShort(0);    // internal file attributes719                  // external file attributes  720 - 444721      foreach (ZipEntry entry in entries) { - 131722        WriteLeInt(ZipConstants.CentralHeaderSignature); - 131723        WriteLeShort(ZipConstants.VersionMadeBy); - 131724        WriteLeShort(entry.Version); - 131725        WriteLeShort(entry.Flags); - 131726        WriteLeShort((short)entry.CompressionMethodForHeader); - 131727        WriteLeInt((int)entry.DosTime); - 131728        WriteLeInt((int)entry.Crc);729 - 131730         if ( entry.IsZip64Forced() || - 131731          (entry.CompressedSize >= uint.MaxValue) )732        { - 124733          WriteLeInt(-1); - 124734        }735        else { - 7736          WriteLeInt((int)entry.CompressedSize);737        }738 - 131739         if ( entry.IsZip64Forced() || - 131740          (entry.Size >= uint.MaxValue) )741        { - 124742          WriteLeInt(-1); - 124743        }744        else { - 7745          WriteLeInt((int)entry.Size);746        }747 - 131748        byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);749 - 131750         if (name.Length > 0xffff) { - 0751          throw new ZipException("Name too long.");752        }753 - 131754        var ed = new ZipExtraData(entry.ExtraData); + 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 - 131756         if ( entry.CentralHeaderRequiresZip64 ) { - 124757          ed.StartNewEntry(); - 124758           if ( entry.IsZip64Forced() || - 124759            (entry.Size >= 0xffffffff) )760          { - 124761            ed.AddLeLong(entry.Size);762          }763 - 124764           if ( entry.IsZip64Forced() || - 124765            (entry.CompressedSize >= 0xffffffff) )766          { - 124767            ed.AddLeLong(entry.CompressedSize);768          } + 85756      entries = null; + 85757    }758759    #region Instance Fields760    /// <summary>761    /// The entries for the archive.762    /// </summary> + 87763    ArrayList entries = new ArrayList();764765    /// <summary>766    /// Used to track the crc of data added to entries.767    /// </summary> + 87768    Crc32 crc = new Crc32();  769 - 124770           if ( entry.Offset >= 0xffffffff )771          { - 0772            ed.AddLeLong(entry.Offset);773          }770    /// <summary>771    /// The current entry being added.772    /// </summary>773    ZipEntry curEntry;  774 - 124775          ed.AddNewEntry(1); - 124776        }777        else { - 7778          ed.Delete(1);779        }780781#if !NET_1_1 && !NETCF_2_0 - 131782         if (entry.AESKeySize > 0) { - 0783          AddExtraDataAES(entry, ed);784        }785#endif - 131786        byte[] extra = ed.GetEntryData();787 - 131788         byte[] entryComment = - 131789          (entry.Comment != null) ? - 131790          ZipConstants.ConvertToArray(entry.Flags, entry.Comment) : - 131791          new byte[0];792 - 131793         if (entryComment.Length > 0xffff) { - 0794          throw new ZipException("Comment too long.");795        }796 - 131797        WriteLeShort(name.Length); - 131798        WriteLeShort(extra.Length); - 131799        WriteLeShort(entryComment.Length); - 131800        WriteLeShort(0);  // disk number - 131801        WriteLeShort(0);  // internal file attributes802                  // external file attributes + 87775    int defaultCompressionLevel = Deflater.DEFAULT_COMPRESSION;776 + 87777    CompressionMethod curMethod = CompressionMethod.Deflated;778779    /// <summary>780    /// Used to track the size of data for an entry during writing.781    /// </summary>782    long size;783784    /// <summary>785    /// Offset to be recorded for each entry in the central header.786    /// </summary>787    long offset;788789    /// <summary>790    /// Comment for the entire archive recorded in central header.791    /// </summary> + 87792    byte[] zipComment = new byte[0];793794    /// <summary>795    /// Flag indicating that header patching is required for the current entry.796    /// </summary>797    bool patchEntryHeader;798799    /// <summary>800    /// Position to patch crc801    /// </summary> + 87802    long crcPatchPos = -1;  803 - 131804         if (entry.ExternalFileAttributes != -1) { - 4805          WriteLeInt(entry.ExternalFileAttributes); - 4806        } else { - 127807           if (entry.IsDirectory) {                         // mark entry as directory (from nikolam.AT.perfectinfo.com) - 8808            WriteLeInt(16); - 8809          } else { - 119810            WriteLeInt(0);811          }812        }813 - 131814         if ( entry.Offset >= uint.MaxValue ) { - 0815          WriteLeInt(-1); - 0816        }817        else { - 131818          WriteLeInt((int)entry.Offset);819        }820 - 131821         if ( name.Length > 0 ) { - 131822          baseOutputStream_.Write(name,    0, name.Length);823        }824 - 131825         if ( extra.Length > 0 ) { - 124826          baseOutputStream_.Write(extra,   0, extra.Length);827        }828 - 131829         if ( entryComment.Length > 0 ) { - 0830          baseOutputStream_.Write(entryComment, 0, entryComment.Length);831        }832 - 131833        sizeEntries += ZipConstants.CentralHeaderBaseSize + name.Length + extra.Length + entryComment.Length;834      }835 - 91836      using ( ZipHelperStream zhs = new ZipHelperStream(baseOutputStream_) ) { - 91837        zhs.WriteEndOfCentralDirectory(numEntries, sizeEntries, offset, zipComment); - 90838      }839 - 90840      entries = null; - 90841    }842843    #region Instance Fields844    /// <summary>845    /// The entries for the archive.846    /// </summary> - 92847    ArrayList entries  = new ArrayList();848849    /// <summary>850    /// Used to track the crc of data added to entries.851    /// </summary> - 92852    Crc32 crc = new Crc32();853854    /// <summary>855    /// The current entry being added.856    /// </summary>857    ZipEntry  curEntry;858 - 92859    int defaultCompressionLevel = Deflater.DEFAULT_COMPRESSION;860 - 92861    CompressionMethod curMethod = CompressionMethod.Deflated;862863    /// <summary>864    /// Used to track the size of data for an entry during writing.865    /// </summary>866    long size;867868    /// <summary>869    /// Offset to be recorded for each entry in the central header.870    /// </summary>871    long offset;872873    /// <summary>874    /// Comment for the entire archive recorded in central header.875    /// </summary> - 92876    byte[] zipComment = new byte[0];877878    /// <summary>879    /// Flag indicating that header patching is required for the current entry.880    /// </summary>881    bool patchEntryHeader;882883    /// <summary>884    /// Position to patch crc885    /// </summary> - 92886    long crcPatchPos = -1;887888    /// <summary>889    /// Position to patch size.890    /// </summary> - 92891    long sizePatchPos = -1;892893    // Default is dynamic which is not backwards compatible and can cause problems894    // with XP's built in compression which cant read Zip64 archives.895    // However it does avoid the situation were a large file is added and cannot be completed correctly.896    // NOTE: Setting the size for entries before they are added is the best solution! - 92897    UseZip64 useZip64_ = UseZip64.Dynamic;898    #endregion899  }900}804    /// <summary>805    /// Position to patch size.806    /// </summary> + 87807    long sizePatchPos = -1;808809    // Default is dynamic which is not backwards compatible and can cause problems810    // 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    #endregion815  }816} - + \ No newline at end of file diff --git a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipTestResultHandler.htm b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipTestResultHandler.htm index 9d7360caf..3528bdd56 100644 --- a/Documentation/opencover/ICSharpCode.SharpZipLib_ZipTestResultHandler.htm +++ b/Documentation/opencover/ICSharpCode.SharpZipLib_ZipTestResultHandler.htm @@ -24,6 +24,6 @@

Summary

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/Documentation/opencover/combined.js b/Documentation/opencover/combined.js index 79a1e8a14..e57ae7692 100644 --- a/Documentation/opencover/combined.js +++ b/Documentation/opencover/combined.js @@ -314,93 +314,94 @@ var assemblies = [ { "name" : "ICSharpCode.SharpZipLib", "classes" : [ - { "name" : "ICSharpCode.SharpZipLib.BZip2.BZip2", "reportPath" : "ICSharpCode.SharpZipLib_BZip2.htm", "coveredLines" : 0, "uncoveredLines" : 20, "coverableLines" : 20, "totalLines" : 105, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 12, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.BZip2.BZip2Constants", "reportPath" : "ICSharpCode.SharpZipLib_BZip2Constants.htm", "coveredLines" : 0, "uncoveredLines" : 56, "coverableLines" : 56, "totalLines" : 197, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.BZip2.BZip2Exception", "reportPath" : "ICSharpCode.SharpZipLib_BZip2Exception.htm", "coveredLines" : 0, "uncoveredLines" : 8, "coverableLines" : 8, "totalLines" : 90, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.BZip2.BZip2InputStream", "reportPath" : "ICSharpCode.SharpZipLib_BZip2InputStream.htm", "coveredLines" : 308, "uncoveredLines" : 118, "coverableLines" : 426, "totalLines" : 1001, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 141, "totalBranches" : 216, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream", "reportPath" : "ICSharpCode.SharpZipLib_BZip2OutputStream.htm", "coveredLines" : 616, "uncoveredLines" : 285, "coverableLines" : 901, "totalLines" : 1913, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 289, "totalBranches" : 436, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Checksums.Adler32", "reportPath" : "ICSharpCode.SharpZipLib_Adler32.htm", "coveredLines" : 25, "uncoveredLines" : 15, "coverableLines" : 40, "totalLines" : 237, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 11, "totalBranches" : 18, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Checksums.Crc32", "reportPath" : "ICSharpCode.SharpZipLib_Crc32.htm", "coveredLines" : 70, "uncoveredLines" : 9, "coverableLines" : 79, "totalLines" : 223, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 6, "totalBranches" : 12, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Checksums.StrangeCRC", "reportPath" : "ICSharpCode.SharpZipLib_StrangeCRC.htm", "coveredLines" : 77, "uncoveredLines" : 15, "coverableLines" : 92, "totalLines" : 208, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 2, "totalBranches" : 14, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.BZip2.BZip2", "reportPath" : "ICSharpCode.SharpZipLib_BZip2.htm", "coveredLines" : 0, "uncoveredLines" : 20, "coverableLines" : 20, "totalLines" : 66, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 12, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.BZip2.BZip2Constants", "reportPath" : "ICSharpCode.SharpZipLib_BZip2Constants.htm", "coveredLines" : 0, "uncoveredLines" : 56, "coverableLines" : 56, "totalLines" : 121, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.BZip2.BZip2Exception", "reportPath" : "ICSharpCode.SharpZipLib_BZip2Exception.htm", "coveredLines" : 0, "uncoveredLines" : 8, "coverableLines" : 8, "totalLines" : 48, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.BZip2.BZip2InputStream", "reportPath" : "ICSharpCode.SharpZipLib_BZip2InputStream.htm", "coveredLines" : 111, "uncoveredLines" : 315, "coverableLines" : 426, "totalLines" : 909, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 34, "totalBranches" : 216, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream", "reportPath" : "ICSharpCode.SharpZipLib_BZip2OutputStream.htm", "coveredLines" : 107, "uncoveredLines" : 794, "coverableLines" : 901, "totalLines" : 1793, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 16, "totalBranches" : 436, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Checksum.Adler32", "reportPath" : "ICSharpCode.SharpZipLib_Adler32.htm", "coveredLines" : 35, "uncoveredLines" : 6, "coverableLines" : 41, "totalLines" : 175, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 18, "totalBranches" : 18, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Checksum.BZip2Crc", "reportPath" : "ICSharpCode.SharpZipLib_BZip2Crc.htm", "coveredLines" : 93, "uncoveredLines" : 0, "coverableLines" : 93, "totalLines" : 200, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 14, "totalBranches" : 14, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Checksum.Crc32", "reportPath" : "ICSharpCode.SharpZipLib_Crc32.htm", "coveredLines" : 82, "uncoveredLines" : 0, "coverableLines" : 82, "totalLines" : 189, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 14, "totalBranches" : 14, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, { "name" : "ICSharpCode.SharpZipLib.Core.CompletedFileHandler", "reportPath" : "ICSharpCode.SharpZipLib_CompletedFileHandler.htm", "coveredLines" : 0, "uncoveredLines" : 0, "coverableLines" : 0, "totalLines" : 0, "coverageType" : "MethodCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Core.DirectoryEventArgs", "reportPath" : "ICSharpCode.SharpZipLib_DirectoryEventArgs.htm", "coveredLines" : 0, "uncoveredLines" : 4, "coverableLines" : 4, "totalLines" : 530, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Core.DirectoryEventArgs", "reportPath" : "ICSharpCode.SharpZipLib_DirectoryEventArgs.htm", "coveredLines" : 0, "uncoveredLines" : 4, "coverableLines" : 4, "totalLines" : 475, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, { "name" : "ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler", "reportPath" : "ICSharpCode.SharpZipLib_DirectoryFailureHandler.htm", "coveredLines" : 0, "uncoveredLines" : 0, "coverableLines" : 0, "totalLines" : 0, "coverageType" : "MethodCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Core.ExtendedPathFilter", "reportPath" : "ICSharpCode.SharpZipLib_ExtendedPathFilter.htm", "coveredLines" : 0, "uncoveredLines" : 47, "coverableLines" : 47, "totalLines" : 336, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 14, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Core.ExtendedPathFilter", "reportPath" : "ICSharpCode.SharpZipLib_ExtendedPathFilter.htm", "coveredLines" : 0, "uncoveredLines" : 47, "coverableLines" : 47, "totalLines" : 280, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 14, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, { "name" : "ICSharpCode.SharpZipLib.Core.FileFailureHandler", "reportPath" : "ICSharpCode.SharpZipLib_FileFailureHandler.htm", "coveredLines" : 0, "uncoveredLines" : 0, "coverableLines" : 0, "totalLines" : 0, "coverageType" : "MethodCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Core.FileSystemScanner", "reportPath" : "ICSharpCode.SharpZipLib_FileSystemScanner.htm", "coveredLines" : 47, "uncoveredLines" : 38, "coverableLines" : 85, "totalLines" : 530, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 15, "totalBranches" : 34, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Core.NameAndSizeFilter", "reportPath" : "ICSharpCode.SharpZipLib_NameAndSizeFilter.htm", "coveredLines" : 0, "uncoveredLines" : 23, "coverableLines" : 23, "totalLines" : 336, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 10, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Core.NameFilter", "reportPath" : "ICSharpCode.SharpZipLib_NameFilter.htm", "coveredLines" : 70, "uncoveredLines" : 21, "coverableLines" : 91, "totalLines" : 288, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 34, "totalBranches" : 46, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Core.PathFilter", "reportPath" : "ICSharpCode.SharpZipLib_PathFilter.htm", "coveredLines" : 8, "uncoveredLines" : 0, "coverableLines" : 8, "totalLines" : 336, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 2, "totalBranches" : 4, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Core.FileSystemScanner", "reportPath" : "ICSharpCode.SharpZipLib_FileSystemScanner.htm", "coveredLines" : 33, "uncoveredLines" : 49, "coverableLines" : 82, "totalLines" : 475, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 11, "totalBranches" : 34, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Core.NameAndSizeFilter", "reportPath" : "ICSharpCode.SharpZipLib_NameAndSizeFilter.htm", "coveredLines" : 0, "uncoveredLines" : 23, "coverableLines" : 23, "totalLines" : 280, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 10, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Core.NameFilter", "reportPath" : "ICSharpCode.SharpZipLib_NameFilter.htm", "coveredLines" : 68, "uncoveredLines" : 18, "coverableLines" : 86, "totalLines" : 235, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 34, "totalBranches" : 46, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Core.PathFilter", "reportPath" : "ICSharpCode.SharpZipLib_PathFilter.htm", "coveredLines" : 8, "uncoveredLines" : 0, "coverableLines" : 8, "totalLines" : 280, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 2, "totalBranches" : 4, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, { "name" : "ICSharpCode.SharpZipLib.Core.ProcessFileHandler", "reportPath" : "ICSharpCode.SharpZipLib_ProcessFileHandler.htm", "coveredLines" : 0, "uncoveredLines" : 0, "coverableLines" : 0, "totalLines" : 0, "coverageType" : "MethodCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Core.ProgressEventArgs", "reportPath" : "ICSharpCode.SharpZipLib_ProgressEventArgs.htm", "coveredLines" : 0, "uncoveredLines" : 16, "coverableLines" : 16, "totalLines" : 530, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 2, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Core.ProgressEventArgs", "reportPath" : "ICSharpCode.SharpZipLib_ProgressEventArgs.htm", "coveredLines" : 0, "uncoveredLines" : 16, "coverableLines" : 16, "totalLines" : 475, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 2, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, { "name" : "ICSharpCode.SharpZipLib.Core.ProgressHandler", "reportPath" : "ICSharpCode.SharpZipLib_ProgressHandler.htm", "coveredLines" : 0, "uncoveredLines" : 0, "coverableLines" : 0, "totalLines" : 0, "coverageType" : "MethodCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Core.ScanEventArgs", "reportPath" : "ICSharpCode.SharpZipLib_ScanEventArgs.htm", "coveredLines" : 6, "uncoveredLines" : 1, "coverableLines" : 7, "totalLines" : 530, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs", "reportPath" : "ICSharpCode.SharpZipLib_ScanFailureEventArgs.htm", "coveredLines" : 0, "uncoveredLines" : 9, "coverableLines" : 9, "totalLines" : 530, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Core.StreamUtils", "reportPath" : "ICSharpCode.SharpZipLib_StreamUtils.htm", "coveredLines" : 25, "uncoveredLines" : 54, "coverableLines" : 79, "totalLines" : 246, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 17, "totalBranches" : 50, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Core.WindowsPathUtils", "reportPath" : "ICSharpCode.SharpZipLib_WindowsPathUtils.htm", "coveredLines" : 19, "uncoveredLines" : 4, "coverableLines" : 23, "totalLines" : 94, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 23, "totalBranches" : 30, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Encryption.PkzipClassic", "reportPath" : "ICSharpCode.SharpZipLib_PkzipClassic.htm", "coveredLines" : 26, "uncoveredLines" : 2, "coverableLines" : 28, "totalLines" : 498, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 4, "totalBranches" : 6, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase", "reportPath" : "ICSharpCode.SharpZipLib_PkzipClassicCryptoBase.htm", "coveredLines" : 18, "uncoveredLines" : 2, "coverableLines" : 20, "totalLines" : 498, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 2, "totalBranches" : 4, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform", "reportPath" : "ICSharpCode.SharpZipLib_PkzipClassicDecryptCryptoTransform.htm", "coveredLines" : 14, "uncoveredLines" : 3, "coverableLines" : 17, "totalLines" : 498, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 2, "totalBranches" : 2, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform", "reportPath" : "ICSharpCode.SharpZipLib_PkzipClassicEncryptCryptoTransform.htm", "coveredLines" : 13, "uncoveredLines" : 4, "coverableLines" : 17, "totalLines" : 498, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 2, "totalBranches" : 2, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged", "reportPath" : "ICSharpCode.SharpZipLib_PkzipClassicManaged.htm", "coveredLines" : 6, "uncoveredLines" : 22, "coverableLines" : 28, "totalLines" : 498, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 1, "totalBranches" : 8, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Encryption.ZipAESStream", "reportPath" : "ICSharpCode.SharpZipLib_ZipAESStream.htm", "coveredLines" : 0, "uncoveredLines" : 51, "coverableLines" : 51, "totalLines" : 170, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 18, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Encryption.ZipAESTransform", "reportPath" : "ICSharpCode.SharpZipLib_ZipAESTransform.htm", "coveredLines" : 0, "uncoveredLines" : 47, "coverableLines" : 47, "totalLines" : 219, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 18, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.GZip.GZipConstants", "reportPath" : "ICSharpCode.SharpZipLib_GZipConstants.htm", "coveredLines" : 0, "uncoveredLines" : 2, "coverableLines" : 2, "totalLines" : 97, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.GZip.GZipException", "reportPath" : "ICSharpCode.SharpZipLib_GZipException.htm", "coveredLines" : 0, "uncoveredLines" : 8, "coverableLines" : 8, "totalLines" : 91, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.GZip.GZipInputStream", "reportPath" : "ICSharpCode.SharpZipLib_GZipInputStream.htm", "coveredLines" : 65, "uncoveredLines" : 43, "coverableLines" : 108, "totalLines" : 374, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 33, "totalBranches" : 72, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.GZip.GZipOutputStream", "reportPath" : "ICSharpCode.SharpZipLib_GZipOutputStream.htm", "coveredLines" : 61, "uncoveredLines" : 5, "coverableLines" : 66, "totalLines" : 261, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 13, "totalBranches" : 16, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.LZW.LzwConstants", "reportPath" : "ICSharpCode.SharpZipLib_LzwConstants.htm", "coveredLines" : 0, "uncoveredLines" : 2, "coverableLines" : 2, "totalLines" : 94, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.LZW.LzwException", "reportPath" : "ICSharpCode.SharpZipLib_LzwException.htm", "coveredLines" : 2, "uncoveredLines" : 6, "coverableLines" : 8, "totalLines" : 88, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.LZW.LzwInputStream", "reportPath" : "ICSharpCode.SharpZipLib_LzwInputStream.htm", "coveredLines" : 23, "uncoveredLines" : 168, "coverableLines" : 191, "totalLines" : 599, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 7, "totalBranches" : 62, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.SharpZipBaseException", "reportPath" : "ICSharpCode.SharpZipLib_SharpZipBaseException.htm", "coveredLines" : 2, "uncoveredLines" : 6, "coverableLines" : 8, "totalLines" : 94, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Tar.InvalidHeaderException", "reportPath" : "ICSharpCode.SharpZipLib_InvalidHeaderException.htm", "coveredLines" : 0, "uncoveredLines" : 8, "coverableLines" : 8, "totalLines" : 109, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Core.ScanEventArgs", "reportPath" : "ICSharpCode.SharpZipLib_ScanEventArgs.htm", "coveredLines" : 6, "uncoveredLines" : 1, "coverableLines" : 7, "totalLines" : 475, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs", "reportPath" : "ICSharpCode.SharpZipLib_ScanFailureEventArgs.htm", "coveredLines" : 0, "uncoveredLines" : 9, "coverableLines" : 9, "totalLines" : 475, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Core.StreamUtils", "reportPath" : "ICSharpCode.SharpZipLib_StreamUtils.htm", "coveredLines" : 25, "uncoveredLines" : 53, "coverableLines" : 78, "totalLines" : 208, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 17, "totalBranches" : 50, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Core.WindowsPathUtils", "reportPath" : "ICSharpCode.SharpZipLib_WindowsPathUtils.htm", "coveredLines" : 19, "uncoveredLines" : 3, "coverableLines" : 22, "totalLines" : 57, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 23, "totalBranches" : 30, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Encryption.PkzipClassic", "reportPath" : "ICSharpCode.SharpZipLib_PkzipClassic.htm", "coveredLines" : 26, "uncoveredLines" : 2, "coverableLines" : 28, "totalLines" : 445, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 4, "totalBranches" : 6, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase", "reportPath" : "ICSharpCode.SharpZipLib_PkzipClassicCryptoBase.htm", "coveredLines" : 18, "uncoveredLines" : 2, "coverableLines" : 20, "totalLines" : 445, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 2, "totalBranches" : 4, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform", "reportPath" : "ICSharpCode.SharpZipLib_PkzipClassicDecryptCryptoTransform.htm", "coveredLines" : 14, "uncoveredLines" : 3, "coverableLines" : 17, "totalLines" : 445, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 2, "totalBranches" : 2, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform", "reportPath" : "ICSharpCode.SharpZipLib_PkzipClassicEncryptCryptoTransform.htm", "coveredLines" : 13, "uncoveredLines" : 4, "coverableLines" : 17, "totalLines" : 445, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 2, "totalBranches" : 2, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged", "reportPath" : "ICSharpCode.SharpZipLib_PkzipClassicManaged.htm", "coveredLines" : 6, "uncoveredLines" : 22, "coverableLines" : 28, "totalLines" : 445, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 1, "totalBranches" : 8, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Encryption.ZipAESStream", "reportPath" : "ICSharpCode.SharpZipLib_ZipAESStream.htm", "coveredLines" : 0, "uncoveredLines" : 50, "coverableLines" : 50, "totalLines" : 134, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 18, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Encryption.ZipAESTransform", "reportPath" : "ICSharpCode.SharpZipLib_ZipAESTransform.htm", "coveredLines" : 0, "uncoveredLines" : 47, "coverableLines" : 47, "totalLines" : 183, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 18, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.GZip.GZip", "reportPath" : "ICSharpCode.SharpZipLib_GZip.htm", "coveredLines" : 0, "uncoveredLines" : 20, "coverableLines" : 20, "totalLines" : 66, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 12, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.GZip.GZipConstants", "reportPath" : "ICSharpCode.SharpZipLib_GZipConstants.htm", "coveredLines" : 0, "uncoveredLines" : 2, "coverableLines" : 2, "totalLines" : 58, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.GZip.GZipException", "reportPath" : "ICSharpCode.SharpZipLib_GZipException.htm", "coveredLines" : 0, "uncoveredLines" : 8, "coverableLines" : 8, "totalLines" : 48, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.GZip.GZipInputStream", "reportPath" : "ICSharpCode.SharpZipLib_GZipInputStream.htm", "coveredLines" : 4, "uncoveredLines" : 104, "coverableLines" : 108, "totalLines" : 330, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 72, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.GZip.GZipOutputStream", "reportPath" : "ICSharpCode.SharpZipLib_GZipOutputStream.htm", "coveredLines" : 63, "uncoveredLines" : 5, "coverableLines" : 68, "totalLines" : 227, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 13, "totalBranches" : 16, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Lzw.LzwConstants", "reportPath" : "ICSharpCode.SharpZipLib_LzwConstants.htm", "coveredLines" : 0, "uncoveredLines" : 2, "coverableLines" : 2, "totalLines" : 61, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Lzw.LzwException", "reportPath" : "ICSharpCode.SharpZipLib_LzwException.htm", "coveredLines" : 0, "uncoveredLines" : 8, "coverableLines" : 8, "totalLines" : 48, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Lzw.LzwInputStream", "reportPath" : "ICSharpCode.SharpZipLib_LzwInputStream.htm", "coveredLines" : 0, "uncoveredLines" : 194, "coverableLines" : 194, "totalLines" : 559, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 62, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.SharpZipBaseException", "reportPath" : "ICSharpCode.SharpZipLib_SharpZipBaseException.htm", "coveredLines" : 2, "uncoveredLines" : 6, "coverableLines" : 8, "totalLines" : 52, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Tar.InvalidHeaderException", "reportPath" : "ICSharpCode.SharpZipLib_InvalidHeaderException.htm", "coveredLines" : 0, "uncoveredLines" : 8, "coverableLines" : 8, "totalLines" : 51, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, { "name" : "ICSharpCode.SharpZipLib.Tar.ProgressMessageHandler", "reportPath" : "ICSharpCode.SharpZipLib_ProgressMessageHandler.htm", "coveredLines" : 0, "uncoveredLines" : 0, "coverableLines" : 0, "totalLines" : 0, "coverageType" : "MethodCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Tar.TarArchive", "reportPath" : "ICSharpCode.SharpZipLib_TarArchive.htm", "coveredLines" : 46, "uncoveredLines" : 223, "coverableLines" : 269, "totalLines" : 895, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 21, "totalBranches" : 150, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Tar.TarBuffer", "reportPath" : "ICSharpCode.SharpZipLib_TarBuffer.htm", "coveredLines" : 97, "uncoveredLines" : 50, "coverableLines" : 147, "totalLines" : 624, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 42, "totalBranches" : 82, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Tar.TarEntry", "reportPath" : "ICSharpCode.SharpZipLib_TarEntry.htm", "coveredLines" : 66, "uncoveredLines" : 56, "coverableLines" : 122, "totalLines" : 559, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 10, "totalBranches" : 42, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Tar.TarException", "reportPath" : "ICSharpCode.SharpZipLib_TarException.htm", "coveredLines" : 2, "uncoveredLines" : 6, "coverableLines" : 8, "totalLines" : 91, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Tar.TarHeader", "reportPath" : "ICSharpCode.SharpZipLib_TarHeader.htm", "coveredLines" : 217, "uncoveredLines" : 52, "coverableLines" : 269, "totalLines" : 1180, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 79, "totalBranches" : 114, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Tar.TarInputStream", "reportPath" : "ICSharpCode.SharpZipLib_TarInputStream.htm", "coveredLines" : 78, "uncoveredLines" : 77, "coverableLines" : 155, "totalLines" : 693, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 33, "totalBranches" : 64, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Tar.TarOutputStream", "reportPath" : "ICSharpCode.SharpZipLib_TarOutputStream.htm", "coveredLines" : 81, "uncoveredLines" : 36, "coverableLines" : 117, "totalLines" : 527, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 24, "totalBranches" : 36, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.BaseArchiveStorage", "reportPath" : "ICSharpCode.SharpZipLib_BaseArchiveStorage.htm", "coveredLines" : 4, "uncoveredLines" : 0, "coverableLines" : 4, "totalLines" : 4476, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.Deflater", "reportPath" : "ICSharpCode.SharpZipLib_Deflater.htm", "coveredLines" : 69, "uncoveredLines" : 29, "coverableLines" : 98, "totalLines" : 563, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 34, "totalBranches" : 50, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.DeflaterConstants", "reportPath" : "ICSharpCode.SharpZipLib_DeflaterConstants.htm", "coveredLines" : 6, "uncoveredLines" : 0, "coverableLines" : 6, "totalLines" : 185, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine", "reportPath" : "ICSharpCode.SharpZipLib_DeflaterEngine.htm", "coveredLines" : 238, "uncoveredLines" : 37, "coverableLines" : 275, "totalLines" : 868, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 157, "totalBranches" : 186, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman", "reportPath" : "ICSharpCode.SharpZipLib_DeflaterHuffman.htm", "coveredLines" : 349, "uncoveredLines" : 9, "coverableLines" : 358, "totalLines" : 905, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 156, "totalBranches" : 170, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.DeflaterPending", "reportPath" : "ICSharpCode.SharpZipLib_DeflaterPending.htm", "coveredLines" : 2, "uncoveredLines" : 0, "coverableLines" : 2, "totalLines" : 56, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.Inflater", "reportPath" : "ICSharpCode.SharpZipLib_Inflater.htm", "coveredLines" : 173, "uncoveredLines" : 59, "coverableLines" : 232, "totalLines" : 860, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 70, "totalBranches" : 117, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader", "reportPath" : "ICSharpCode.SharpZipLib_InflaterDynHeader.htm", "coveredLines" : 63, "uncoveredLines" : 10, "coverableLines" : 73, "totalLines" : 211, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 19, "totalBranches" : 35, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree", "reportPath" : "ICSharpCode.SharpZipLib_InflaterHuffmanTree.htm", "coveredLines" : 65, "uncoveredLines" : 23, "coverableLines" : 88, "totalLines" : 232, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 33, "totalBranches" : 44, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer", "reportPath" : "ICSharpCode.SharpZipLib_PendingBuffer.htm", "coveredLines" : 40, "uncoveredLines" : 18, "coverableLines" : 58, "totalLines" : 295, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 9, "totalBranches" : 10, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream", "reportPath" : "ICSharpCode.SharpZipLib_DeflaterOutputStream.htm", "coveredLines" : 76, "uncoveredLines" : 28, "coverableLines" : 104, "totalLines" : 602, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 30, "totalBranches" : 42, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer", "reportPath" : "ICSharpCode.SharpZipLib_InflaterInputBuffer.htm", "coveredLines" : 72, "uncoveredLines" : 14, "coverableLines" : 86, "totalLines" : 731, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 27, "totalBranches" : 38, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream", "reportPath" : "ICSharpCode.SharpZipLib_InflaterInputStream.htm", "coveredLines" : 38, "uncoveredLines" : 37, "coverableLines" : 75, "totalLines" : 731, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 16, "totalBranches" : 38, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow", "reportPath" : "ICSharpCode.SharpZipLib_OutputWindow.htm", "coveredLines" : 46, "uncoveredLines" : 20, "coverableLines" : 66, "totalLines" : 235, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 16, "totalBranches" : 30, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator", "reportPath" : "ICSharpCode.SharpZipLib_StreamManipulator.htm", "coveredLines" : 51, "uncoveredLines" : 12, "coverableLines" : 63, "totalLines" : 288, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 23, "totalBranches" : 34, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.DescriptorData", "reportPath" : "ICSharpCode.SharpZipLib_DescriptorData.htm", "coveredLines" : 6, "uncoveredLines" : 0, "coverableLines" : 6, "totalLines" : 623, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage", "reportPath" : "ICSharpCode.SharpZipLib_DiskArchiveStorage.htm", "coveredLines" : 55, "uncoveredLines" : 17, "coverableLines" : 72, "totalLines" : 4476, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 15, "totalBranches" : 24, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.DynamicDiskDataSource", "reportPath" : "ICSharpCode.SharpZipLib_DynamicDiskDataSource.htm", "coveredLines" : 4, "uncoveredLines" : 0, "coverableLines" : 4, "totalLines" : 4476, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 2, "totalBranches" : 2, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.EntryPatchData", "reportPath" : "ICSharpCode.SharpZipLib_EntryPatchData.htm", "coveredLines" : 0, "uncoveredLines" : 4, "coverableLines" : 4, "totalLines" : 623, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.ExtendedUnixData", "reportPath" : "ICSharpCode.SharpZipLib_ExtendedUnixData.htm", "coveredLines" : 34, "uncoveredLines" : 27, "coverableLines" : 61, "totalLines" : 987, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 8, "totalBranches" : 20, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.FastZip", "reportPath" : "ICSharpCode.SharpZipLib_FastZip.htm", "coveredLines" : 90, "uncoveredLines" : 99, "coverableLines" : 189, "totalLines" : 728, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 35, "totalBranches" : 120, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.FastZipEvents", "reportPath" : "ICSharpCode.SharpZipLib_FastZipEvents.htm", "coveredLines" : 0, "uncoveredLines" : 38, "coverableLines" : 38, "totalLines" : 728, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 10, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs", "reportPath" : "ICSharpCode.SharpZipLib_KeysRequiredEventArgs.htm", "coveredLines" : 0, "uncoveredLines" : 10, "coverableLines" : 10, "totalLines" : 4476, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage", "reportPath" : "ICSharpCode.SharpZipLib_MemoryArchiveStorage.htm", "coveredLines" : 15, "uncoveredLines" : 12, "coverableLines" : 27, "totalLines" : 4476, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 5, "totalBranches" : 10, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.NTTaggedData", "reportPath" : "ICSharpCode.SharpZipLib_NTTaggedData.htm", "coveredLines" : 45, "uncoveredLines" : 10, "coverableLines" : 55, "totalLines" : 987, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 6, "totalBranches" : 12, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.RawTaggedData", "reportPath" : "ICSharpCode.SharpZipLib_RawTaggedData.htm", "coveredLines" : 0, "uncoveredLines" : 13, "coverableLines" : 13, "totalLines" : 987, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 2, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.StaticDiskDataSource", "reportPath" : "ICSharpCode.SharpZipLib_StaticDiskDataSource.htm", "coveredLines" : 0, "uncoveredLines" : 4, "coverableLines" : 4, "totalLines" : 4476, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.TestStatus", "reportPath" : "ICSharpCode.SharpZipLib_TestStatus.htm", "coveredLines" : 7, "uncoveredLines" : 13, "coverableLines" : 20, "totalLines" : 4476, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.WindowsNameTransform", "reportPath" : "ICSharpCode.SharpZipLib_WindowsNameTransform.htm", "coveredLines" : 56, "uncoveredLines" : 21, "coverableLines" : 77, "totalLines" : 272, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 30, "totalBranches" : 42, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.ZipConstants", "reportPath" : "ICSharpCode.SharpZipLib_ZipConstants.htm", "coveredLines" : 29, "uncoveredLines" : 8, "coverableLines" : 37, "totalLines" : 647, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 19, "totalBranches" : 30, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.ZipEntry", "reportPath" : "ICSharpCode.SharpZipLib_ZipEntry.htm", "coveredLines" : 234, "uncoveredLines" : 69, "coverableLines" : 303, "totalLines" : 1251, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 83, "totalBranches" : 133, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.ZipEntryFactory", "reportPath" : "ICSharpCode.SharpZipLib_ZipEntryFactory.htm", "coveredLines" : 77, "uncoveredLines" : 24, "coverableLines" : 101, "totalLines" : 428, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 22, "totalBranches" : 40, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.ZipException", "reportPath" : "ICSharpCode.SharpZipLib_ZipException.htm", "coveredLines" : 2, "uncoveredLines" : 6, "coverableLines" : 8, "totalLines" : 94, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.ZipExtraData", "reportPath" : "ICSharpCode.SharpZipLib_ZipExtraData.htm", "coveredLines" : 118, "uncoveredLines" : 30, "coverableLines" : 148, "totalLines" : 987, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 38, "totalBranches" : 62, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.ZipFile", "reportPath" : "ICSharpCode.SharpZipLib_ZipFile.htm", "coveredLines" : 958, "uncoveredLines" : 360, "coverableLines" : 1318, "totalLines" : 4476, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 388, "totalBranches" : 664, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.ZipHelperStream", "reportPath" : "ICSharpCode.SharpZipLib_ZipHelperStream.htm", "coveredLines" : 106, "uncoveredLines" : 88, "coverableLines" : 194, "totalLines" : 623, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 30, "totalBranches" : 70, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.ZipInputStream", "reportPath" : "ICSharpCode.SharpZipLib_ZipInputStream.htm", "coveredLines" : 165, "uncoveredLines" : 42, "coverableLines" : 207, "totalLines" : 674, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 103, "totalBranches" : 150, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.ZipNameTransform", "reportPath" : "ICSharpCode.SharpZipLib_ZipNameTransform.htm", "coveredLines" : 66, "uncoveredLines" : 11, "coverableLines" : 77, "totalLines" : 269, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 23, "totalBranches" : 34, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, - { "name" : "ICSharpCode.SharpZipLib.Zip.ZipOutputStream", "reportPath" : "ICSharpCode.SharpZipLib_ZipOutputStream.htm", "coveredLines" : 285, "uncoveredLines" : 48, "coverableLines" : 333, "totalLines" : 900, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 135, "totalBranches" : 172, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Tar.TarArchive", "reportPath" : "ICSharpCode.SharpZipLib_TarArchive.htm", "coveredLines" : 46, "uncoveredLines" : 223, "coverableLines" : 269, "totalLines" : 830, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 21, "totalBranches" : 154, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Tar.TarBuffer", "reportPath" : "ICSharpCode.SharpZipLib_TarBuffer.htm", "coveredLines" : 96, "uncoveredLines" : 50, "coverableLines" : 146, "totalLines" : 551, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 41, "totalBranches" : 82, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Tar.TarEntry", "reportPath" : "ICSharpCode.SharpZipLib_TarEntry.htm", "coveredLines" : 61, "uncoveredLines" : 61, "coverableLines" : 122, "totalLines" : 496, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 9, "totalBranches" : 42, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Tar.TarException", "reportPath" : "ICSharpCode.SharpZipLib_TarException.htm", "coveredLines" : 2, "uncoveredLines" : 6, "coverableLines" : 8, "totalLines" : 48, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Tar.TarHeader", "reportPath" : "ICSharpCode.SharpZipLib_TarHeader.htm", "coveredLines" : 209, "uncoveredLines" : 63, "coverableLines" : 272, "totalLines" : 1077, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 79, "totalBranches" : 118, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Tar.TarInputStream", "reportPath" : "ICSharpCode.SharpZipLib_TarInputStream.htm", "coveredLines" : 40, "uncoveredLines" : 118, "coverableLines" : 158, "totalLines" : 626, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 15, "totalBranches" : 68, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Tar.TarOutputStream", "reportPath" : "ICSharpCode.SharpZipLib_TarOutputStream.htm", "coveredLines" : 64, "uncoveredLines" : 54, "coverableLines" : 118, "totalLines" : 442, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 21, "totalBranches" : 36, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.BaseArchiveStorage", "reportPath" : "ICSharpCode.SharpZipLib_BaseArchiveStorage.htm", "coveredLines" : 4, "uncoveredLines" : 0, "coverableLines" : 4, "totalLines" : 4263, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.Deflater", "reportPath" : "ICSharpCode.SharpZipLib_Deflater.htm", "coveredLines" : 69, "uncoveredLines" : 29, "coverableLines" : 98, "totalLines" : 521, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 34, "totalBranches" : 50, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.DeflaterConstants", "reportPath" : "ICSharpCode.SharpZipLib_DeflaterConstants.htm", "coveredLines" : 6, "uncoveredLines" : 0, "coverableLines" : 6, "totalLines" : 146, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine", "reportPath" : "ICSharpCode.SharpZipLib_DeflaterEngine.htm", "coveredLines" : 238, "uncoveredLines" : 37, "coverableLines" : 275, "totalLines" : 812, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 157, "totalBranches" : 186, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman", "reportPath" : "ICSharpCode.SharpZipLib_DeflaterHuffman.htm", "coveredLines" : 349, "uncoveredLines" : 9, "coverableLines" : 358, "totalLines" : 865, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 155, "totalBranches" : 170, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.DeflaterPending", "reportPath" : "ICSharpCode.SharpZipLib_DeflaterPending.htm", "coveredLines" : 2, "uncoveredLines" : 0, "coverableLines" : 2, "totalLines" : 17, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.Inflater", "reportPath" : "ICSharpCode.SharpZipLib_Inflater.htm", "coveredLines" : 173, "uncoveredLines" : 57, "coverableLines" : 230, "totalLines" : 788, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 70, "totalBranches" : 117, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader", "reportPath" : "ICSharpCode.SharpZipLib_InflaterDynHeader.htm", "coveredLines" : 63, "uncoveredLines" : 10, "coverableLines" : 73, "totalLines" : 170, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 19, "totalBranches" : 35, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree", "reportPath" : "ICSharpCode.SharpZipLib_InflaterHuffmanTree.htm", "coveredLines" : 65, "uncoveredLines" : 23, "coverableLines" : 88, "totalLines" : 193, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 33, "totalBranches" : 44, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer", "reportPath" : "ICSharpCode.SharpZipLib_PendingBuffer.htm", "coveredLines" : 40, "uncoveredLines" : 18, "coverableLines" : 58, "totalLines" : 255, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 9, "totalBranches" : 10, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream", "reportPath" : "ICSharpCode.SharpZipLib_DeflaterOutputStream.htm", "coveredLines" : 76, "uncoveredLines" : 28, "coverableLines" : 104, "totalLines" : 476, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 30, "totalBranches" : 42, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer", "reportPath" : "ICSharpCode.SharpZipLib_InflaterInputBuffer.htm", "coveredLines" : 72, "uncoveredLines" : 14, "coverableLines" : 86, "totalLines" : 662, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 27, "totalBranches" : 38, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream", "reportPath" : "ICSharpCode.SharpZipLib_InflaterInputStream.htm", "coveredLines" : 38, "uncoveredLines" : 36, "coverableLines" : 74, "totalLines" : 662, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 15, "totalBranches" : 38, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow", "reportPath" : "ICSharpCode.SharpZipLib_OutputWindow.htm", "coveredLines" : 46, "uncoveredLines" : 20, "coverableLines" : 66, "totalLines" : 195, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 16, "totalBranches" : 30, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator", "reportPath" : "ICSharpCode.SharpZipLib_StreamManipulator.htm", "coveredLines" : 51, "uncoveredLines" : 12, "coverableLines" : 63, "totalLines" : 241, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 23, "totalBranches" : 34, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.DescriptorData", "reportPath" : "ICSharpCode.SharpZipLib_DescriptorData.htm", "coveredLines" : 6, "uncoveredLines" : 0, "coverableLines" : 6, "totalLines" : 560, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage", "reportPath" : "ICSharpCode.SharpZipLib_DiskArchiveStorage.htm", "coveredLines" : 55, "uncoveredLines" : 15, "coverableLines" : 70, "totalLines" : 4263, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 15, "totalBranches" : 24, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.DynamicDiskDataSource", "reportPath" : "ICSharpCode.SharpZipLib_DynamicDiskDataSource.htm", "coveredLines" : 4, "uncoveredLines" : 0, "coverableLines" : 4, "totalLines" : 4263, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 2, "totalBranches" : 2, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.EntryPatchData", "reportPath" : "ICSharpCode.SharpZipLib_EntryPatchData.htm", "coveredLines" : 0, "uncoveredLines" : 4, "coverableLines" : 4, "totalLines" : 560, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.ExtendedUnixData", "reportPath" : "ICSharpCode.SharpZipLib_ExtendedUnixData.htm", "coveredLines" : 32, "uncoveredLines" : 30, "coverableLines" : 62, "totalLines" : 896, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 6, "totalBranches" : 20, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.FastZip", "reportPath" : "ICSharpCode.SharpZipLib_FastZip.htm", "coveredLines" : 85, "uncoveredLines" : 99, "coverableLines" : 184, "totalLines" : 648, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 34, "totalBranches" : 120, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.FastZipEvents", "reportPath" : "ICSharpCode.SharpZipLib_FastZipEvents.htm", "coveredLines" : 0, "uncoveredLines" : 38, "coverableLines" : 38, "totalLines" : 648, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 10, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs", "reportPath" : "ICSharpCode.SharpZipLib_KeysRequiredEventArgs.htm", "coveredLines" : 0, "uncoveredLines" : 10, "coverableLines" : 10, "totalLines" : 4263, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage", "reportPath" : "ICSharpCode.SharpZipLib_MemoryArchiveStorage.htm", "coveredLines" : 15, "uncoveredLines" : 12, "coverableLines" : 27, "totalLines" : 4263, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 5, "totalBranches" : 10, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.NTTaggedData", "reportPath" : "ICSharpCode.SharpZipLib_NTTaggedData.htm", "coveredLines" : 45, "uncoveredLines" : 9, "coverableLines" : 54, "totalLines" : 896, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 6, "totalBranches" : 12, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.RawTaggedData", "reportPath" : "ICSharpCode.SharpZipLib_RawTaggedData.htm", "coveredLines" : 0, "uncoveredLines" : 13, "coverableLines" : 13, "totalLines" : 896, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 2, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.StaticDiskDataSource", "reportPath" : "ICSharpCode.SharpZipLib_StaticDiskDataSource.htm", "coveredLines" : 0, "uncoveredLines" : 4, "coverableLines" : 4, "totalLines" : 4263, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.TestStatus", "reportPath" : "ICSharpCode.SharpZipLib_TestStatus.htm", "coveredLines" : 7, "uncoveredLines" : 13, "coverableLines" : 20, "totalLines" : 4263, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.WindowsNameTransform", "reportPath" : "ICSharpCode.SharpZipLib_WindowsNameTransform.htm", "coveredLines" : 42, "uncoveredLines" : 35, "coverableLines" : 77, "totalLines" : 226, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 18, "totalBranches" : 42, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.ZipConstants", "reportPath" : "ICSharpCode.SharpZipLib_ZipConstants.htm", "coveredLines" : 29, "uncoveredLines" : 8, "coverableLines" : 37, "totalLines" : 591, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 19, "totalBranches" : 30, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.ZipEntry", "reportPath" : "ICSharpCode.SharpZipLib_ZipEntry.htm", "coveredLines" : 219, "uncoveredLines" : 69, "coverableLines" : 288, "totalLines" : 1175, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 72, "totalBranches" : 121, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.ZipEntryFactory", "reportPath" : "ICSharpCode.SharpZipLib_ZipEntryFactory.htm", "coveredLines" : 51, "uncoveredLines" : 50, "coverableLines" : 101, "totalLines" : 341, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 14, "totalBranches" : 40, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.ZipException", "reportPath" : "ICSharpCode.SharpZipLib_ZipException.htm", "coveredLines" : 2, "uncoveredLines" : 6, "coverableLines" : 8, "totalLines" : 48, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.ZipExtraData", "reportPath" : "ICSharpCode.SharpZipLib_ZipExtraData.htm", "coveredLines" : 121, "uncoveredLines" : 19, "coverableLines" : 140, "totalLines" : 896, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 39, "totalBranches" : 58, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.ZipFile", "reportPath" : "ICSharpCode.SharpZipLib_ZipFile.htm", "coveredLines" : 953, "uncoveredLines" : 356, "coverableLines" : 1309, "totalLines" : 4263, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 393, "totalBranches" : 670, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.ZipHelperStream", "reportPath" : "ICSharpCode.SharpZipLib_ZipHelperStream.htm", "coveredLines" : 106, "uncoveredLines" : 88, "coverableLines" : 194, "totalLines" : 560, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 30, "totalBranches" : 70, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.ZipInputStream", "reportPath" : "ICSharpCode.SharpZipLib_ZipInputStream.htm", "coveredLines" : 162, "uncoveredLines" : 44, "coverableLines" : 206, "totalLines" : 610, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 101, "totalBranches" : 150, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.ZipNameTransform", "reportPath" : "ICSharpCode.SharpZipLib_ZipNameTransform.htm", "coveredLines" : 66, "uncoveredLines" : 11, "coverableLines" : 77, "totalLines" : 220, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 23, "totalBranches" : 34, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, + { "name" : "ICSharpCode.SharpZipLib.Zip.ZipOutputStream", "reportPath" : "ICSharpCode.SharpZipLib_ZipOutputStream.htm", "coveredLines" : 285, "uncoveredLines" : 48, "coverableLines" : 333, "totalLines" : 816, "coverageType" : "LineCoverage", "methodCoverage" : "-", "coveredBranches" : 135, "totalBranches" : 172, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, { "name" : "ICSharpCode.SharpZipLib.Zip.ZipTestResultHandler", "reportPath" : "ICSharpCode.SharpZipLib_ZipTestResultHandler.htm", "coveredLines" : 0, "uncoveredLines" : 0, "coverableLines" : 0, "totalLines" : 0, "coverageType" : "MethodCoverage", "methodCoverage" : "-", "coveredBranches" : 0, "totalBranches" : 0, "lineCoverageHistory" : [], "branchCoverageHistory" : [] }, ]}, ]; diff --git a/Documentation/opencover/index.htm b/Documentation/opencover/index.htm index 0a2f470f0..f351056fe 100644 --- a/Documentation/opencover/index.htm +++ b/Documentation/opencover/index.htm @@ -12,17 +12,17 @@

Summary

-Generated on:4/18/2016 - 1:13:14 PM +Generated on:5/17/2016 - 5:03:19 PM Parser:OpenCoverParser Assemblies:1 -Classes:88 -Files:57 -Covered lines:5732 -Uncovered lines:2872 -Coverable lines:8604 -Total lines:71893 -Line coverage:66.6% -Branch coverage:58.8% +Classes:89 +Files:58 +Covered lines:4828 +Uncovered lines:3758 +Coverable lines:8586 +Total lines:66022 +Line coverage:56.2% +Branch coverage:47.3%

Assemblies

@@ -44,97 +44,98 @@

Assemblies

NameCoveredUncoveredCoverableTotalLine coverageBranch coverage -ICSharpCode.SharpZipLib5732287286047189366.6%
  
58.8%
  
-ICSharpCode.SharpZipLib.BZip2.BZip2020201050%
 
0%
 
-ICSharpCode.SharpZipLib.BZip2.BZip2Constants056561970%
 
 
-ICSharpCode.SharpZipLib.BZip2.BZip2Exception088900%
 
 
-ICSharpCode.SharpZipLib.BZip2.BZip2InputStream308118426100172.3%
  
65.2%
  
-ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream616285901191368.3%
  
66.2%
  
-ICSharpCode.SharpZipLib.Checksums.Adler3225154023762.5%
  
61.1%
  
-ICSharpCode.SharpZipLib.Checksums.Crc327097922388.6%
  
50%
  
-ICSharpCode.SharpZipLib.Checksums.StrangeCRC77159220883.6%
  
14.2%
  
+ICSharpCode.SharpZipLib4828375885866602256.2%
  
47.3%
  
+ICSharpCode.SharpZipLib.BZip2.BZip202020660%
 
0%
 
+ICSharpCode.SharpZipLib.BZip2.BZip2Constants056561210%
 
 
+ICSharpCode.SharpZipLib.BZip2.BZip2Exception088480%
 
 
+ICSharpCode.SharpZipLib.BZip2.BZip2InputStream11131542690926%
  
15.7%
  
+ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream107794901179311.8%
  
3.6%
  
+ICSharpCode.SharpZipLib.Checksum.Adler323564117585.3%
  
100%
 
+ICSharpCode.SharpZipLib.Checksum.BZip2Crc93093200100%
 
100%
 
+ICSharpCode.SharpZipLib.Checksum.Crc3282082189100%
 
100%
 
ICSharpCode.SharpZipLib.Core.CompletedFileHandler0000
 
 
-ICSharpCode.SharpZipLib.Core.DirectoryEventArgs0445300%
 
 
+ICSharpCode.SharpZipLib.Core.DirectoryEventArgs0444750%
 
 
ICSharpCode.SharpZipLib.Core.DirectoryFailureHandler0000
 
 
-ICSharpCode.SharpZipLib.Core.ExtendedPathFilter047473360%
 
0%
 
+ICSharpCode.SharpZipLib.Core.ExtendedPathFilter047472800%
 
0%
 
ICSharpCode.SharpZipLib.Core.FileFailureHandler0000
 
 
-ICSharpCode.SharpZipLib.Core.FileSystemScanner47388553055.2%
  
44.1%
  
-ICSharpCode.SharpZipLib.Core.NameAndSizeFilter023233360%
 
0%
 
-ICSharpCode.SharpZipLib.Core.NameFilter70219128876.9%
  
73.9%
  
-ICSharpCode.SharpZipLib.Core.PathFilter808336100%
 
50%
  
+ICSharpCode.SharpZipLib.Core.FileSystemScanner33498247540.2%
  
32.3%
  
+ICSharpCode.SharpZipLib.Core.NameAndSizeFilter023232800%
 
0%
 
+ICSharpCode.SharpZipLib.Core.NameFilter68188623579%
  
73.9%
  
+ICSharpCode.SharpZipLib.Core.PathFilter808280100%
 
50%
  
ICSharpCode.SharpZipLib.Core.ProcessFileHandler0000
 
 
-ICSharpCode.SharpZipLib.Core.ProgressEventArgs016165300%
 
0%
 
+ICSharpCode.SharpZipLib.Core.ProgressEventArgs016164750%
 
0%
 
ICSharpCode.SharpZipLib.Core.ProgressHandler0000
 
 
-ICSharpCode.SharpZipLib.Core.ScanEventArgs61753085.7%
  
 
-ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs0995300%
 
 
-ICSharpCode.SharpZipLib.Core.StreamUtils25547924631.6%
  
34%
  
-ICSharpCode.SharpZipLib.Core.WindowsPathUtils194239482.6%
  
76.6%
  
-ICSharpCode.SharpZipLib.Encryption.PkzipClassic2622849892.8%
  
66.6%
  
-ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase1822049890%
  
50%
  
-ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform1431749882.3%
  
100%
 
-ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform1341749876.4%
  
100%
 
-ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged6222849821.4%
  
12.5%
  
-ICSharpCode.SharpZipLib.Encryption.ZipAESStream051511700%
 
0%
 
-ICSharpCode.SharpZipLib.Encryption.ZipAESTransform047472190%
 
0%
 
-ICSharpCode.SharpZipLib.GZip.GZipConstants022970%
 
 
-ICSharpCode.SharpZipLib.GZip.GZipException088910%
 
 
-ICSharpCode.SharpZipLib.GZip.GZipInputStream654310837460.1%
  
45.8%
  
-ICSharpCode.SharpZipLib.GZip.GZipOutputStream6156626192.4%
  
81.2%
  
-ICSharpCode.SharpZipLib.LZW.LzwConstants022940%
 
 
-ICSharpCode.SharpZipLib.LZW.LzwException2688825%
  
 
-ICSharpCode.SharpZipLib.LZW.LzwInputStream2316819159912%
  
11.2%
  
-ICSharpCode.SharpZipLib.SharpZipBaseException2689425%
  
 
-ICSharpCode.SharpZipLib.Tar.InvalidHeaderException0881090%
 
 
+ICSharpCode.SharpZipLib.Core.ScanEventArgs61747585.7%
  
 
+ICSharpCode.SharpZipLib.Core.ScanFailureEventArgs0994750%
 
 
+ICSharpCode.SharpZipLib.Core.StreamUtils25537820832%
  
34%
  
+ICSharpCode.SharpZipLib.Core.WindowsPathUtils193225786.3%
  
76.6%
  
+ICSharpCode.SharpZipLib.Encryption.PkzipClassic2622844592.8%
  
66.6%
  
+ICSharpCode.SharpZipLib.Encryption.PkzipClassicCryptoBase1822044590%
  
50%
  
+ICSharpCode.SharpZipLib.Encryption.PkzipClassicDecryptCryptoTransform1431744582.3%
  
100%
 
+ICSharpCode.SharpZipLib.Encryption.PkzipClassicEncryptCryptoTransform1341744576.4%
  
100%
 
+ICSharpCode.SharpZipLib.Encryption.PkzipClassicManaged6222844521.4%
  
12.5%
  
+ICSharpCode.SharpZipLib.Encryption.ZipAESStream050501340%
 
0%
 
+ICSharpCode.SharpZipLib.Encryption.ZipAESTransform047471830%
 
0%
 
+ICSharpCode.SharpZipLib.GZip.GZip02020660%
 
0%
 
+ICSharpCode.SharpZipLib.GZip.GZipConstants022580%
 
 
+ICSharpCode.SharpZipLib.GZip.GZipException088480%
 
 
+ICSharpCode.SharpZipLib.GZip.GZipInputStream41041083303.7%
  
0%
 
+ICSharpCode.SharpZipLib.GZip.GZipOutputStream6356822792.6%
  
81.2%
  
+ICSharpCode.SharpZipLib.Lzw.LzwConstants022610%
 
 
+ICSharpCode.SharpZipLib.Lzw.LzwException088480%
 
 
+ICSharpCode.SharpZipLib.Lzw.LzwInputStream01941945590%
 
0%
 
+ICSharpCode.SharpZipLib.SharpZipBaseException2685225%
  
 
+ICSharpCode.SharpZipLib.Tar.InvalidHeaderException088510%
 
 
ICSharpCode.SharpZipLib.Tar.ProgressMessageHandler0000
 
 
-ICSharpCode.SharpZipLib.Tar.TarArchive4622326989517.1%
  
14%
  
-ICSharpCode.SharpZipLib.Tar.TarBuffer975014762465.9%
  
51.2%
  
-ICSharpCode.SharpZipLib.Tar.TarEntry665612255954%
  
23.8%
  
-ICSharpCode.SharpZipLib.Tar.TarException2689125%
  
 
-ICSharpCode.SharpZipLib.Tar.TarHeader21752269118080.6%
  
69.2%
  
-ICSharpCode.SharpZipLib.Tar.TarInputStream787715569350.3%
  
51.5%
  
-ICSharpCode.SharpZipLib.Tar.TarOutputStream813611752769.2%
  
66.6%
  
-ICSharpCode.SharpZipLib.Zip.BaseArchiveStorage4044476100%
 
 
-ICSharpCode.SharpZipLib.Zip.Compression.Deflater69299856370.4%
  
68%
  
-ICSharpCode.SharpZipLib.Zip.Compression.DeflaterConstants606185100%
 
 
-ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine2383727586886.5%
  
84.4%
  
-ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman349935890597.4%
  
91.7%
  
-ICSharpCode.SharpZipLib.Zip.Compression.DeflaterPending20256100%
 
 
-ICSharpCode.SharpZipLib.Zip.Compression.Inflater1735923286074.5%
  
59.8%
  
-ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader63107321186.3%
  
54.2%
  
-ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree65238823273.8%
  
75%
  
-ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer40185829568.9%
  
90%
  
-ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream762810460273%
  
71.4%
  
-ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer72148673183.7%
  
71%
  
-ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream38377573150.6%
  
42.1%
  
-ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow46206623569.6%
  
53.3%
  
-ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator51126328880.9%
  
67.6%
  
-ICSharpCode.SharpZipLib.Zip.DescriptorData606623100%
 
 
-ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage551772447676.3%
  
62.5%
  
-ICSharpCode.SharpZipLib.Zip.DynamicDiskDataSource4044476100%
 
100%
 
-ICSharpCode.SharpZipLib.Zip.EntryPatchData0446230%
 
 
-ICSharpCode.SharpZipLib.Zip.ExtendedUnixData34276198755.7%
  
40%
  
-ICSharpCode.SharpZipLib.Zip.FastZip909918972847.6%
  
29.1%
  
-ICSharpCode.SharpZipLib.Zip.FastZipEvents038387280%
 
0%
 
-ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs0101044760%
 
 
-ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage151227447655.5%
  
50%
  
-ICSharpCode.SharpZipLib.Zip.NTTaggedData45105598781.8%
  
50%
  
-ICSharpCode.SharpZipLib.Zip.RawTaggedData013139870%
 
0%
 
-ICSharpCode.SharpZipLib.Zip.StaticDiskDataSource04444760%
 
 
-ICSharpCode.SharpZipLib.Zip.TestStatus71320447635%
  
 
-ICSharpCode.SharpZipLib.Zip.WindowsNameTransform56217727272.7%
  
71.4%
  
-ICSharpCode.SharpZipLib.Zip.ZipConstants2983764778.3%
  
63.3%
  
-ICSharpCode.SharpZipLib.Zip.ZipEntry23469303125177.2%
  
62.4%
  
-ICSharpCode.SharpZipLib.Zip.ZipEntryFactory772410142876.2%
  
55%
  
-ICSharpCode.SharpZipLib.Zip.ZipException2689425%
  
 
-ICSharpCode.SharpZipLib.Zip.ZipExtraData1183014898779.7%
  
61.2%
  
-ICSharpCode.SharpZipLib.Zip.ZipFile9583601318447672.6%
  
58.4%
  
-ICSharpCode.SharpZipLib.Zip.ZipHelperStream1068819462354.6%
  
42.8%
  
-ICSharpCode.SharpZipLib.Zip.ZipInputStream1654220767479.7%
  
68.6%
  
-ICSharpCode.SharpZipLib.Zip.ZipNameTransform66117726985.7%
  
67.6%
  
-ICSharpCode.SharpZipLib.Zip.ZipOutputStream2854833390085.5%
  
78.4%
  
+ICSharpCode.SharpZipLib.Tar.TarArchive4622326983017.1%
  
13.6%
  
+ICSharpCode.SharpZipLib.Tar.TarBuffer965014655165.7%
  
50%
  
+ICSharpCode.SharpZipLib.Tar.TarEntry616112249650%
  
21.4%
  
+ICSharpCode.SharpZipLib.Tar.TarException2684825%
  
 
+ICSharpCode.SharpZipLib.Tar.TarHeader20963272107776.8%
  
66.9%
  
+ICSharpCode.SharpZipLib.Tar.TarInputStream4011815862625.3%
  
22%
  
+ICSharpCode.SharpZipLib.Tar.TarOutputStream645411844254.2%
  
58.3%
  
+ICSharpCode.SharpZipLib.Zip.BaseArchiveStorage4044263100%
 
 
+ICSharpCode.SharpZipLib.Zip.Compression.Deflater69299852170.4%
  
68%
  
+ICSharpCode.SharpZipLib.Zip.Compression.DeflaterConstants606146100%
 
 
+ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine2383727581286.5%
  
84.4%
  
+ICSharpCode.SharpZipLib.Zip.Compression.DeflaterHuffman349935886597.4%
  
91.1%
  
+ICSharpCode.SharpZipLib.Zip.Compression.DeflaterPending20217100%
 
 
+ICSharpCode.SharpZipLib.Zip.Compression.Inflater1735723078875.2%
  
59.8%
  
+ICSharpCode.SharpZipLib.Zip.Compression.InflaterDynHeader63107317086.3%
  
54.2%
  
+ICSharpCode.SharpZipLib.Zip.Compression.InflaterHuffmanTree65238819373.8%
  
75%
  
+ICSharpCode.SharpZipLib.Zip.Compression.PendingBuffer40185825568.9%
  
90%
  
+ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream762810447673%
  
71.4%
  
+ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer72148666283.7%
  
71%
  
+ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream38367466251.3%
  
39.4%
  
+ICSharpCode.SharpZipLib.Zip.Compression.Streams.OutputWindow46206619569.6%
  
53.3%
  
+ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator51126324180.9%
  
67.6%
  
+ICSharpCode.SharpZipLib.Zip.DescriptorData606560100%
 
 
+ICSharpCode.SharpZipLib.Zip.DiskArchiveStorage551570426378.5%
  
62.5%
  
+ICSharpCode.SharpZipLib.Zip.DynamicDiskDataSource4044263100%
 
100%
 
+ICSharpCode.SharpZipLib.Zip.EntryPatchData0445600%
 
 
+ICSharpCode.SharpZipLib.Zip.ExtendedUnixData32306289651.6%
  
30%
  
+ICSharpCode.SharpZipLib.Zip.FastZip859918464846.1%
  
28.3%
  
+ICSharpCode.SharpZipLib.Zip.FastZipEvents038386480%
 
0%
 
+ICSharpCode.SharpZipLib.Zip.KeysRequiredEventArgs0101042630%
 
 
+ICSharpCode.SharpZipLib.Zip.MemoryArchiveStorage151227426355.5%
  
50%
  
+ICSharpCode.SharpZipLib.Zip.NTTaggedData4595489683.3%
  
50%
  
+ICSharpCode.SharpZipLib.Zip.RawTaggedData013138960%
 
0%
 
+ICSharpCode.SharpZipLib.Zip.StaticDiskDataSource04442630%
 
 
+ICSharpCode.SharpZipLib.Zip.TestStatus71320426335%
  
 
+ICSharpCode.SharpZipLib.Zip.WindowsNameTransform42357722654.5%
  
42.8%
  
+ICSharpCode.SharpZipLib.Zip.ZipConstants2983759178.3%
  
63.3%
  
+ICSharpCode.SharpZipLib.Zip.ZipEntry21969288117576%
  
59.5%
  
+ICSharpCode.SharpZipLib.Zip.ZipEntryFactory515010134150.4%
  
35%
  
+ICSharpCode.SharpZipLib.Zip.ZipException2684825%
  
 
+ICSharpCode.SharpZipLib.Zip.ZipExtraData1211914089686.4%
  
67.2%
  
+ICSharpCode.SharpZipLib.Zip.ZipFile9533561309426372.8%
  
58.6%
  
+ICSharpCode.SharpZipLib.Zip.ZipHelperStream1068819456054.6%
  
42.8%
  
+ICSharpCode.SharpZipLib.Zip.ZipInputStream1624420661078.6%
  
67.3%
  
+ICSharpCode.SharpZipLib.Zip.ZipNameTransform66117722085.7%
  
67.6%
  
+ICSharpCode.SharpZipLib.Zip.ZipOutputStream2854833381685.5%
  
78.4%
  
ICSharpCode.SharpZipLib.Zip.ZipTestResultHandler0000
 
 
- + \ No newline at end of file diff --git a/ICSharpCode.SharpZipLib.Samples/Samples.sln b/ICSharpCode.SharpZipLib.Samples/Samples.sln index ca209913a..d1e96c424 100644 --- a/ICSharpCode.SharpZipLib.Samples/Samples.sln +++ b/ICSharpCode.SharpZipLib.Samples/Samples.sln @@ -17,12 +17,12 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "minibzip2", "vb\minibzip2\m {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD} = {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD} EndProjectSection EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "viewzipfile", "vb\viewzipfile\viewzipfile.vbproj", "{DB53264C-64AD-4B43-91A9-F5325561C77B}" +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "ViewZipFile", "vb\viewzipfile\ViewZipFile.vbproj", "{DB53264C-64AD-4B43-91A9-F5325561C77B}" ProjectSection(ProjectDependencies) = postProject {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD} = {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD} EndProjectSection EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "zipfiletest", "vb\zipfiletest\zipfiletest.vbproj", "{54057AFD-35E2-48C3-8419-45D57C351C1F}" +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "ZipFileTest", "vb\zipfiletest\ZipFileTest.vbproj", "{54057AFD-35E2-48C3-8419-45D57C351C1F}" ProjectSection(ProjectDependencies) = postProject {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD} = {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD} EndProjectSection diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_BZip2/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_BZip2/AssemblyInfo.cs deleted file mode 100644 index fbb8c17ed..000000000 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_BZip2/AssemblyInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("Cmd_BZip2")] -[assembly: AssemblyDescription("bzip2 based file compression")] -[assembly: AssemblyCulture("")] - -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("")] -[assembly: AssemblyKeyName("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_BZip2/Cmd_BZip2.cs b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_BZip2/Cmd_BZip2.cs index 6aaaf6e9c..31ade65a4 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_BZip2/Cmd_BZip2.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_BZip2/Cmd_BZip2.cs @@ -1,33 +1,5 @@ -// SharpZipLib samples -// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, this list -// of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -// - Neither the name of the SharpDevelop team nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS -// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - using System; using System.IO; - using ICSharpCode.SharpZipLib.BZip2; class Cmd_BZip2 diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_BZip2/Cmd_BZip2.csproj b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_BZip2/Cmd_BZip2.csproj index ad2f98a16..61f377933 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_BZip2/Cmd_BZip2.csproj +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_BZip2/Cmd_BZip2.csproj @@ -82,10 +82,10 @@ copy Cmd_BZip2.exe bunzip2.exe - GlobalAssemblyInfo.cs + Properties\GlobalAssemblyInfo.cs - + diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_BZip2/Properties/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_BZip2/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..573f3dc45 --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_BZip2/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Cmd_BZip2")] +[assembly: AssemblyDescription("bzip2 based file compression")] +[assembly: AssemblyCulture("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Checksum/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Checksum/AssemblyInfo.cs deleted file mode 100644 index 53e99bdb0..000000000 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Checksum/AssemblyInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("Cmd_Crc")] -[assembly: AssemblyDescription("file checksum generator")] -[assembly: AssemblyCulture("")] - -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("")] -[assembly: AssemblyKeyName("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Checksum/Cmd_Checksum.cs b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Checksum/Cmd_Checksum.cs index 968cd8671..49426af69 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Checksum/Cmd_Checksum.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Checksum/Cmd_Checksum.cs @@ -1,33 +1,5 @@ -// SharpZipLib samples -// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, this list -// of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -// - Neither the name of the SharpDevelop team nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS -// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - using System; using System.IO; - using ICSharpCode.SharpZipLib.Checksum; class Cmd_Checksum diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Checksum/Cmd_Checksum.csproj b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Checksum/Cmd_Checksum.csproj index 664ff5ab4..f11eba746 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Checksum/Cmd_Checksum.csproj +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Checksum/Cmd_Checksum.csproj @@ -76,10 +76,10 @@ - GlobalAssemblyInfo.cs + Properties\GlobalAssemblyInfo.cs - + diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Checksum/Properties/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Checksum/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..fb389add6 --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Checksum/Properties/AssemblyInfo.cs @@ -0,0 +1,5 @@ +using System.Reflection; + +[assembly: AssemblyTitle("Cmd_Checksum")] +[assembly: AssemblyDescription("file checksum generator")] +[assembly: AssemblyCulture("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_GZip/Cmd_GZip.cs b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_GZip/Cmd_GZip.cs index e7813ff27..88b270fea 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_GZip/Cmd_GZip.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_GZip/Cmd_GZip.cs @@ -1,33 +1,5 @@ -// SharpZipLib samples -// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, this list -// of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -// - Neither the name of the SharpDevelop team nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS -// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - using System; using System.IO; - using ICSharpCode.SharpZipLib.GZip; class Cmd_GZip diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_GZip/Cmd_GZip.csproj b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_GZip/Cmd_GZip.csproj index f3715162a..daa1c23d6 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_GZip/Cmd_GZip.csproj +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_GZip/Cmd_GZip.csproj @@ -76,10 +76,10 @@ copy Cmd_GZip.exe gunzip.exe - GlobalAssemblyInfo.cs + Properties\GlobalAssemblyInfo.cs - + diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_GZip/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_GZip/Properties/AssemblyInfo.cs similarity index 60% rename from ICSharpCode.SharpZipLib.Samples/cs/Cmd_GZip/AssemblyInfo.cs rename to ICSharpCode.SharpZipLib.Samples/cs/Cmd_GZip/Properties/AssemblyInfo.cs index e846200fc..602eb750c 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_GZip/AssemblyInfo.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_GZip/Properties/AssemblyInfo.cs @@ -3,7 +3,3 @@ [assembly: AssemblyTitle("Cmd_GZip")] [assembly: AssemblyDescription("gzip based file compression")] [assembly: AssemblyCulture("")] - -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("")] -[assembly: AssemblyKeyName("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/AssemblyInfo.cs deleted file mode 100644 index 3379715cd..000000000 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/AssemblyInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Reflection; - -// Information about this assembly is defined by the following -// attributes. -// -// change them to the information which is associated with the assembly -// you compile. - -[assembly: AssemblyTitle("Tar Sharp Sample")] -[assembly: AssemblyDescription("A simple tar application")] -[assembly: AssemblyCulture("")] - -// The following attributes specify the key for the sign of your assembly. See the -// .NET Framework documentation for more information about signing. -// This is not required, if you don't want signing let these attributes like they're. -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("")] -[assembly: AssemblyKeyName("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/Tar.cs b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/Cmd_Tar.cs similarity index 86% rename from ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/Tar.cs rename to ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/Cmd_Tar.cs index 9ddcbbda0..4b0df6e02 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/Tar.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/Cmd_Tar.cs @@ -1,30 +1,3 @@ -// SharpZipLib samples -// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, this list -// of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -// - Neither the name of the SharpDevelop team nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS -// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - using System; using System.IO; using ICSharpCode.SharpZipLib.Zip.Compression.Streams; @@ -40,7 +13,7 @@ /// GNU long filename extensions are supported, POSIX extensions are not yet supported... /// See the help (-? or --help) for option details. ///
-public class Tar +public class Cmd_Tar { /// /// The compresion to use when creating archives. @@ -122,10 +95,10 @@ enum Operation #endregion /// - /// Initialise default instance of . + /// Initialise default instance of . /// Sets up the default userName with the system 'UserName' property. /// - public Tar() + public Cmd_Tar() { blockingFactor = TarBuffer.DefaultBlockFactor; userId = 0; @@ -142,7 +115,7 @@ public Tar() /// public static void Main(string[] argv) { - var tarApp = new Tar(); + var tarApp = new Cmd_Tar(); tarApp.InstanceMain(argv); } @@ -586,13 +559,7 @@ static void Version() Console.Error.WriteLine("tar 2.0.6.2"); Console.Error.WriteLine(""); Console.Error.WriteLine("{0}", SharpZipVersion()); - Console.Error.WriteLine("Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team"); - Console.Error.WriteLine(""); - Console.Error.WriteLine("This program is free software licensed to you under the"); - Console.Error.WriteLine("GNU General Public License. See the accompanying LICENSE"); - Console.Error.WriteLine("file, or the webpage or,"); - Console.Error.WriteLine("visit www.gnu.org for more details."); - Console.Error.WriteLine(""); + Console.Error.WriteLine("Copyright © 2000-2016 SharpZipLib Contributors"); } /// @@ -643,18 +610,3 @@ static private void ShowHelp() Environment.Exit(1); } } - -/* -** Authored by Timothy Gerard Endres -** -** -** This work has been placed into the public domain. -** You may use this work in any way and for any purpose you wish. -** -** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, -** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR -** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY -** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR -** REDISTRIBUTION OF THIS SOFTWARE. -** -*/ diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/Cmd_Tar.csproj b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/Cmd_Tar.csproj index b079107f5..bfe06d65d 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/Cmd_Tar.csproj +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/Cmd_Tar.csproj @@ -61,7 +61,7 @@ true - Tar + Cmd_Tar @@ -72,10 +72,10 @@ - GlobalAssemblyInfo.cs + Properties\GlobalAssemblyInfo.cs - - + + diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/Properties/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..c4f6ef464 --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_Tar/Properties/AssemblyInfo.cs @@ -0,0 +1,11 @@ +using System.Reflection; + +// Information about this assembly is defined by the following +// attributes. +// +// change them to the information which is associated with the assembly +// you compile. + +[assembly: AssemblyTitle("Tar Sharp Sample")] +[assembly: AssemblyDescription("A simple tar application")] +[assembly: AssemblyCulture("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_ZipInfo/Cmd_ZipInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_ZipInfo/Cmd_ZipInfo.cs index a4bb535ff..07bbc25ac 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_ZipInfo/Cmd_ZipInfo.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_ZipInfo/Cmd_ZipInfo.cs @@ -1,33 +1,5 @@ -// SharpZipLib samples -// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, this list -// of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -// - Neither the name of the SharpDevelop team nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS -// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - using System; using System.IO; - using ICSharpCode.SharpZipLib.Zip; class Cmd_ZipInfo diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_ZipInfo/Cmd_ZipInfo.csproj b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_ZipInfo/Cmd_ZipInfo.csproj index c2080657a..46dc4d57e 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_ZipInfo/Cmd_ZipInfo.csproj +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_ZipInfo/Cmd_ZipInfo.csproj @@ -75,9 +75,9 @@ - GlobalAssemblyInfo.cs + Properties\GlobalAssemblyInfo.cs - + diff --git a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_ZipInfo/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_ZipInfo/Properties/AssemblyInfo.cs similarity index 64% rename from ICSharpCode.SharpZipLib.Samples/cs/Cmd_ZipInfo/AssemblyInfo.cs rename to ICSharpCode.SharpZipLib.Samples/cs/Cmd_ZipInfo/Properties/AssemblyInfo.cs index 47348570a..7a4e92419 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/Cmd_ZipInfo/AssemblyInfo.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/Cmd_ZipInfo/Properties/AssemblyInfo.cs @@ -3,7 +3,3 @@ [assembly: AssemblyTitle("Cmd_ZipInfo")] [assembly: AssemblyDescription("list detailed information about a ZIP archive")] [assembly: AssemblyCulture("")] - -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("")] -[assembly: AssemblyKeyName("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/CreateZipFile/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/CreateZipFile/AssemblyInfo.cs deleted file mode 100644 index ce41e72da..000000000 --- a/ICSharpCode.SharpZipLib.Samples/cs/CreateZipFile/AssemblyInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("CreateZipFile")] -[assembly: AssemblyDescription("Free C# IDE")] -[assembly: AssemblyCulture("")] - -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("")] -[assembly: AssemblyKeyName("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/CreateZipFile/CreateZipFile.cs b/ICSharpCode.SharpZipLib.Samples/cs/CreateZipFile/CreateZipFile.cs index e6da71819..00e800b90 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/CreateZipFile/CreateZipFile.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/CreateZipFile/CreateZipFile.cs @@ -1,37 +1,9 @@ -// SharpZipLib samples -// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, this list -// of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -// - Neither the name of the SharpDevelop team nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS -// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - using System; using System.IO; using ICSharpCode.SharpZipLib.Zip; class CreateZipFile { - public static void Main(string[] args) { // Perform some simple parameter checking. More could be done diff --git a/ICSharpCode.SharpZipLib.Samples/cs/CreateZipFile/CreateZipFile.csproj b/ICSharpCode.SharpZipLib.Samples/cs/CreateZipFile/CreateZipFile.csproj index 5a3840097..0ddde07bb 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/CreateZipFile/CreateZipFile.csproj +++ b/ICSharpCode.SharpZipLib.Samples/cs/CreateZipFile/CreateZipFile.csproj @@ -83,10 +83,10 @@ - GlobalAssemblyInfo.cs + Properties\GlobalAssemblyInfo.cs - + diff --git a/ICSharpCode.SharpZipLib.Samples/cs/CreateZipFile/Properties/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/CreateZipFile/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..39cbac5d9 --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/cs/CreateZipFile/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CreateZipFile")] +[assembly: AssemblyDescription("A SharpZipLib sample program")] +[assembly: AssemblyCulture("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/FastZip/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/FastZip/AssemblyInfo.cs deleted file mode 100644 index 54bc51f21..000000000 --- a/ICSharpCode.SharpZipLib.Samples/cs/FastZip/AssemblyInfo.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -// Information about this assembly is defined by the following -// attributes. -// -// change them to the information which is associated with the assembly -// you compile. - -[assembly: AssemblyTitle("FastZip sample")] -[assembly: AssemblyDescription("A SharpZip library sample.")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("")] -[assembly: AssemblyCopyright("Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// The assembly version has following format : -// -// Major.Minor.Build.Revision -// -// You can specify all values by your own or you can build default build and revision -// numbers with the '*' character (the default): - -[assembly: AssemblyVersion("0.85.4.369")] - -// The following attributes specify the key for the sign of your assembly. See the -// .NET Framework documentation for more information about signing. -// This is not required, if you don't want signing let these attributes like they're. -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/FastZip/FastZip.cs b/ICSharpCode.SharpZipLib.Samples/cs/FastZip/FastZip.cs index 56408d791..28c3eeb17 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/FastZip/FastZip.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/FastZip/FastZip.cs @@ -1,35 +1,7 @@ -// SharpZipLib samples -// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, this list -// of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -// - Neither the name of the SharpDevelop team nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS -// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - using System; using System.IO; - -using ICSharpCode.SharpZipLib.Zip; using ICSharpCode.SharpZipLib.Core; +using ICSharpCode.SharpZipLib.Zip; class FastZipDemo { diff --git a/ICSharpCode.SharpZipLib.Samples/cs/FastZip/FastZip.csproj b/ICSharpCode.SharpZipLib.Samples/cs/FastZip/FastZip.csproj index 77bbbc3b6..442366ab6 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/FastZip/FastZip.csproj +++ b/ICSharpCode.SharpZipLib.Samples/cs/FastZip/FastZip.csproj @@ -68,8 +68,11 @@ + + Properties\GlobalAssemblyInfo.cs + - + diff --git a/ICSharpCode.SharpZipLib.Samples/cs/FastZip/Properties/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/FastZip/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..070e54484 --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/cs/FastZip/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("FastZip sample")] +[assembly: AssemblyDescription("A SharpZipLib sample program")] +[assembly: AssemblyCulture("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/zf/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/SampleAssemblyInfo.cs similarity index 100% rename from ICSharpCode.SharpZipLib.Samples/cs/zf/AssemblyInfo.cs rename to ICSharpCode.SharpZipLib.Samples/cs/SampleAssemblyInfo.cs diff --git a/ICSharpCode.SharpZipLib.Samples/cs/sz/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/sz/AssemblyInfo.cs deleted file mode 100644 index 74fb0b5f3..000000000 --- a/ICSharpCode.SharpZipLib.Samples/cs/sz/AssemblyInfo.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -// Information about this assembly is defined by the following -// attributes. -// -// change them to the information which is associated with the assembly -// you compile. - -[assembly: AssemblyTitle("SZ Sharp Sample")] -[assembly: AssemblyDescription("A free C# compression library")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("#ZipLibrary")] -[assembly: AssemblyCopyright("Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// The assembly version has following format : -// -// Major.Minor.Build.Revision -// -// You can specify all values by your own or you can build default build and revision -// numbers with the '*' character (the default): - -[assembly: AssemblyVersion("0.85.4.369")] - -// The following attributes specify the key for the sign of your assembly. See the -// .NET Framework documentation for more information about signing. -// This is not required, if you don't want signing let these attributes like they're. -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/sz/Properties/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/sz/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..38fd02d39 --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/cs/sz/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SZ")] +[assembly: AssemblyDescription("A SharpZipLib sample program")] +[assembly: AssemblyCulture("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/sz/sz.cs b/ICSharpCode.SharpZipLib.Samples/cs/sz/sz.cs index 18a27d338..d928f8907 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/sz/sz.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/sz/sz.cs @@ -1,54 +1,19 @@ -// SharpZipLib samples -// -// $Id$ -// $URL$ -// -// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, this list -// of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -// - Neither the name of the SharpDevelop team nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS -// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Define test to add more detailed Console.WriteLine style information -// #define TEST - using System; -using System.IO; using System.Collections; -using System.Text; using System.Globalization; +using System.IO; using System.Reflection; - +using System.Text; using ICSharpCode.SharpZipLib.Core; using ICSharpCode.SharpZipLib.Zip; using ICSharpCode.SharpZipLib.Zip.Compression; namespace ICSharpCode.SharpZipLib.Samples.SZ { - /// - /// A command line archiver using the SharpZipLib compression library - /// - public class SharpZipArchiver { + /// + /// A command line archiver using the SharpZipLib compression library + /// + public class SharpZipArchiver { /// /// Options for handling overwriting of files. @@ -1374,4 +1339,4 @@ public static void Main(string[] args) { #endregion } -} \ No newline at end of file +} diff --git a/ICSharpCode.SharpZipLib.Samples/cs/sz/sz.csproj b/ICSharpCode.SharpZipLib.Samples/cs/sz/sz.csproj index 766a64baa..307073fd1 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/sz/sz.csproj +++ b/ICSharpCode.SharpZipLib.Samples/cs/sz/sz.csproj @@ -63,7 +63,10 @@ - + + Properties\GlobalAssemblyInfo.cs + + diff --git a/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/Program.cs b/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/Program.cs deleted file mode 100644 index 7cfb2684c..000000000 --- a/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/Program.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace unzipfile -{ - class Program - { - static void Main(string[] args) - { - } - } -} diff --git a/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/Properties/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/Properties/AssemblyInfo.cs index 98dce2770..12c8fa697 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/Properties/AssemblyInfo.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/Properties/AssemblyInfo.cs @@ -1,36 +1,8 @@ using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("unzipfile")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("unzipfile")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] +[assembly: AssemblyTitle("UnZipFile")] +[assembly: AssemblyDescription("A SharpZipLib sample program")] [assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("de6aa83b-1efa-41b0-85d9-49da1b0202bc")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/UnZipFile.cs b/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/UnZipFile.cs index e148ddaba..46c7d69f9 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/UnZipFile.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/UnZipFile.cs @@ -1,37 +1,6 @@ -// SharpZipLib samples -// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, this list -// of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -// - Neither the name of the SharpDevelop team nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS -// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - using System; -using System.Text; -using System.Collections; using System.IO; - using ICSharpCode.SharpZipLib.Zip; -using ICSharpCode.SharpZipLib.Zip.Compression.Streams; class UnZipFileClass diff --git a/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/unzipfile.csproj b/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/unzipfile.csproj index 21666aadf..34beb77ba 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/unzipfile.csproj +++ b/ICSharpCode.SharpZipLib.Samples/cs/unzipfile/unzipfile.csproj @@ -46,6 +46,9 @@ + + Properties\GlobalAssemblyInfo.cs + diff --git a/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/Program.cs b/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/Program.cs deleted file mode 100644 index b42ea0c7e..000000000 --- a/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/Program.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace viewzipfile -{ - class Program - { - static void Main(string[] args) - { - } - } -} diff --git a/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/Properties/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/Properties/AssemblyInfo.cs index 1fecfcb75..155e43183 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/Properties/AssemblyInfo.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/Properties/AssemblyInfo.cs @@ -1,36 +1,8 @@ using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("viewzipfile")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("viewzipfile")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] +[assembly: AssemblyTitle("ViewZipFile")] +[assembly: AssemblyDescription("A SharpZipLib sample program")] [assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("f356b460-0dea-4f7d-9cd8-7475b9bec1f7")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/ViewZipFile.cs b/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/ViewZipFile.cs index 64e807f27..ac9ef390c 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/ViewZipFile.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/ViewZipFile.cs @@ -1,16 +1,7 @@ -// project created on 10.11.2001 at 13:09 using System; -using System.Text; -using System.Collections; using System.IO; -using System.Diagnostics; -using System.Runtime.Serialization.Formatters.Binary; - -using ICSharpCode.SharpZipLib.BZip2; +using System.Text; using ICSharpCode.SharpZipLib.Zip; -using ICSharpCode.SharpZipLib.Zip.Compression; -using ICSharpCode.SharpZipLib.Zip.Compression.Streams; -using ICSharpCode.SharpZipLib.GZip; class ViewZipFileClass diff --git a/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/viewzipfile.csproj b/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/viewzipfile.csproj index 34507c0b0..92a9f2746 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/viewzipfile.csproj +++ b/ICSharpCode.SharpZipLib.Samples/cs/viewzipfile/viewzipfile.csproj @@ -46,6 +46,9 @@ + + Properties\GlobalAssemblyInfo.cs + diff --git a/ICSharpCode.SharpZipLib.Samples/cs/zf/Properties/AssemblyInfo.cs b/ICSharpCode.SharpZipLib.Samples/cs/zf/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..11a6f5b5a --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/cs/zf/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ZF")] +[assembly: AssemblyDescription("A SharpZipLib sample program")] +[assembly: AssemblyCulture("")] diff --git a/ICSharpCode.SharpZipLib.Samples/cs/zf/zf.cs b/ICSharpCode.SharpZipLib.Samples/cs/zf/zf.cs index 8abe53165..88cd628ea 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/zf/zf.cs +++ b/ICSharpCode.SharpZipLib.Samples/cs/zf/zf.cs @@ -3,7 +3,7 @@ // zf - A command line archiver using the ZipFile class from SharpZipLib // for compression // -// Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team +// Copyright © 2000-2016 SharpZipLib Contributors // //------------------------------------------------------------------------------ // Version History diff --git a/ICSharpCode.SharpZipLib.Samples/cs/zf/zf.csproj b/ICSharpCode.SharpZipLib.Samples/cs/zf/zf.csproj index 1695a915b..13524660c 100644 --- a/ICSharpCode.SharpZipLib.Samples/cs/zf/zf.csproj +++ b/ICSharpCode.SharpZipLib.Samples/cs/zf/zf.csproj @@ -63,7 +63,10 @@ - + + Properties\GlobalAssemblyInfo.cs + + diff --git a/ICSharpCode.SharpZipLib.Samples/vb/CreateZipFile/AssemblyInfo.vb b/ICSharpCode.SharpZipLib.Samples/vb/CreateZipFile/AssemblyInfo.vb deleted file mode 100644 index a54654475..000000000 --- a/ICSharpCode.SharpZipLib.Samples/vb/CreateZipFile/AssemblyInfo.vb +++ /dev/null @@ -1,33 +0,0 @@ -Imports System.Reflection -Imports System.Runtime.InteropServices - -' Information about this assembly is defined by the following -' attributes. -' -' change them to the information which is associated with the assembly -' you compile. - - - - - - - - - - -' The assembly version has following format : -' -' Major.Minor.Build.Revision -' -' You can specify all values by your own or you can build default build and revision -' numbers with the '*' character (the default): - - - -' The following attributes specify the key for the sign of your assembly. See the -' .NET Framework documentation for more information about signing. -' This is not required, if you don't want signing let these attributes like they're. - - - diff --git a/ICSharpCode.SharpZipLib.Samples/vb/CreateZipFile/CreateZipFile.vbproj b/ICSharpCode.SharpZipLib.Samples/vb/CreateZipFile/CreateZipFile.vbproj index 5bbe44e9a..bb94d39c6 100644 --- a/ICSharpCode.SharpZipLib.Samples/vb/CreateZipFile/CreateZipFile.vbproj +++ b/ICSharpCode.SharpZipLib.Samples/vb/CreateZipFile/CreateZipFile.vbproj @@ -70,10 +70,13 @@ + + SampleAssemblyInfo.vb + Form - + Designer @@ -84,9 +87,7 @@ - - - + False diff --git a/ICSharpCode.SharpZipLib.Samples/vb/CreateZipFile/CreateZipFileForm.vb b/ICSharpCode.SharpZipLib.Samples/vb/CreateZipFile/CreateZipFileForm.vb index 60168698a..9df25d477 100644 --- a/ICSharpCode.SharpZipLib.Samples/vb/CreateZipFile/CreateZipFileForm.vb +++ b/ICSharpCode.SharpZipLib.Samples/vb/CreateZipFile/CreateZipFileForm.vb @@ -1,30 +1,3 @@ -' SharpZipLib samples -' Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team -' All rights reserved. -' -' Redistribution and use in source and binary forms, with or without modification, are -' permitted provided that the following conditions are met: -' -' - Redistributions of source code must retain the above copyright notice, this list -' of conditions and the following disclaimer. -' -' - Redistributions in binary form must reproduce the above copyright notice, this list -' of conditions and the following disclaimer in the documentation and/or other materials -' provided with the distribution. -' -' - Neither the name of the SharpDevelop team nor the names of its contributors may be used to -' endorse or promote products derived from this software without specific prior written -' permission. -' -' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS -' OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -' AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -' CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -' DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -' IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -' OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - Imports System Imports System.IO Imports System.Drawing diff --git a/ICSharpCode.SharpZipLib.Samples/vb/CreateZipFile/My Project/AssemblyInfo.vb b/ICSharpCode.SharpZipLib.Samples/vb/CreateZipFile/My Project/AssemblyInfo.vb new file mode 100644 index 000000000..af333e614 --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/vb/CreateZipFile/My Project/AssemblyInfo.vb @@ -0,0 +1,14 @@ +Imports System.Reflection +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + +' Review the values of the assembly attributes + + + + +'The following GUID is for the ID of the typelib if this project is exposed to COM + diff --git a/ICSharpCode.SharpZipLib.Samples/vb/viewzipfile/AssemblyInfo.vb b/ICSharpCode.SharpZipLib.Samples/vb/SampleAssemblyInfo.vb similarity index 56% rename from ICSharpCode.SharpZipLib.Samples/vb/viewzipfile/AssemblyInfo.vb rename to ICSharpCode.SharpZipLib.Samples/vb/SampleAssemblyInfo.vb index 0f915990c..0b17604b4 100644 --- a/ICSharpCode.SharpZipLib.Samples/vb/viewzipfile/AssemblyInfo.vb +++ b/ICSharpCode.SharpZipLib.Samples/vb/SampleAssemblyInfo.vb @@ -7,15 +7,13 @@ Imports System.Runtime.InteropServices ' Review the values of the assembly attributes - - - - - - + + + + + -'The following GUID is for the ID of the typelib if this project is exposed to COM - + ' Version information for an assembly consists of the following four values: ' @@ -26,5 +24,7 @@ Imports System.Runtime.InteropServices ' ' You can specify all the values or you can default the Build and Revision Numbers ' by using the '*' as shown below: +' - + + diff --git a/ICSharpCode.SharpZipLib.Samples/vb/WpfCreateZipFile/My Project/AssemblyInfo.vb b/ICSharpCode.SharpZipLib.Samples/vb/WpfCreateZipFile/My Project/AssemblyInfo.vb index 56cd80e3f..798a0f93a 100644 --- a/ICSharpCode.SharpZipLib.Samples/vb/WpfCreateZipFile/My Project/AssemblyInfo.vb +++ b/ICSharpCode.SharpZipLib.Samples/vb/WpfCreateZipFile/My Project/AssemblyInfo.vb @@ -1,9 +1,6 @@ -Imports System -Imports System.Reflection -Imports System.Runtime.InteropServices -Imports System.Globalization +Imports System.Reflection Imports System.Resources -Imports System.Windows +Imports System.Runtime.InteropServices ' General Information about an assembly is controlled through the following ' set of attributes. Change these attribute values to modify the information @@ -12,12 +9,7 @@ Imports System.Windows ' Review the values of the assembly attributes - - - - - - + 'In order to begin building localizable applications, set 'CultureYouAreCodingWith in your .vbproj file @@ -26,7 +18,7 @@ Imports System.Windows 'NeutralResourceLanguage attribute below. Update the "en-US" in the line 'below to match the UICulture setting in the project file. -' + 'The ThemeInfo attribute describes where any theme specific and generic resource dictionaries can be found. @@ -43,17 +35,3 @@ Imports System.Windows 'The following GUID is for the ID of the typelib if this project is exposed to COM - -' Version information for an assembly consists of the following four values: -' -' Major Version -' Minor Version -' Build Number -' Revision -' -' You can specify all the values or you can default the Build and Revision Numbers -' by using the '*' as shown below: -' - - - diff --git a/ICSharpCode.SharpZipLib.Samples/vb/WpfCreateZipFile/WpfCreateZipFile.vbproj b/ICSharpCode.SharpZipLib.Samples/vb/WpfCreateZipFile/WpfCreateZipFile.vbproj index 73e21d670..f56b548c9 100644 --- a/ICSharpCode.SharpZipLib.Samples/vb/WpfCreateZipFile/WpfCreateZipFile.vbproj +++ b/ICSharpCode.SharpZipLib.Samples/vb/WpfCreateZipFile/WpfCreateZipFile.vbproj @@ -92,6 +92,9 @@ MSBuild:Compile Designer + + SampleAssemblyInfo.vb + Application.xaml Code diff --git a/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/AssemblyInfo.vb b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/AssemblyInfo.vb deleted file mode 100644 index c12d89455..000000000 --- a/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/AssemblyInfo.vb +++ /dev/null @@ -1,30 +0,0 @@ -Imports System.Reflection -Imports System.Runtime.InteropServices - -' General Information about an assembly is controlled through the following -' set of attributes. Change these attribute values to modify the information -' associated with an assembly. - -' Review the values of the assembly attributes - - - - - - - - -'The following GUID is for the ID of the typelib if this project is exposed to COM - - -' Version information for an assembly consists of the following four values: -' -' Major Version -' Minor Version -' Build Number -' Revision -' -' You can specify all the values or you can default the Build and Revision Numbers -' by using the '*' as shown below: - - diff --git a/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/Main.vb b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/Main.vb index 9238749bf..f7c09bf83 100644 --- a/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/Main.vb +++ b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/Main.vb @@ -1,30 +1,3 @@ -' SharpZipLib samples -' Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team -' All rights reserved. -' -' Redistribution and use in source and binary forms, with or without modification, are -' permitted provided that the following conditions are met: -' -' - Redistributions of source code must retain the above copyright notice, this list -' of conditions and the following disclaimer. -' -' - Redistributions in binary form must reproduce the above copyright notice, this list -' of conditions and the following disclaimer in the documentation and/or other materials -' provided with the distribution. -' -' - Neither the name of the SharpDevelop team nor the names of its contributors may be used to -' endorse or promote products derived from this software without specific prior written -' permission. -' -' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS -' OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -' AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -' CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -' DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -' IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -' OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - Imports System Imports System.Windows.Forms Imports System.IO diff --git a/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/Application.Designer.vb b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/Application.Designer.vb new file mode 100644 index 000000000..88dd01c78 --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/Application.Designer.vb @@ -0,0 +1,13 @@ +'------------------------------------------------------------------------------ +' +' This code was generated by a tool. +' Runtime Version:4.0.30319.42000 +' +' Changes to this file may cause incorrect behavior and will be lost if +' the code is regenerated. +' +'------------------------------------------------------------------------------ + +Option Strict On +Option Explicit On + diff --git a/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/Application.myapp b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/Application.myapp new file mode 100644 index 000000000..c5e5a3b37 --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/Application.myapp @@ -0,0 +1,10 @@ + + + false + MainForm + false + 0 + true + 0 + true + \ No newline at end of file diff --git a/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/AssemblyInfo.vb b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/AssemblyInfo.vb new file mode 100644 index 000000000..e1aa4b239 --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/AssemblyInfo.vb @@ -0,0 +1,14 @@ +Imports System.Reflection +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + +' Review the values of the assembly attributes + + + + +'The following GUID is for the ID of the typelib if this project is exposed to COM + diff --git a/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/Resources.Designer.vb b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/Resources.Designer.vb new file mode 100644 index 000000000..5ea8ce991 --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/Resources.Designer.vb @@ -0,0 +1,63 @@ +'------------------------------------------------------------------------------ +' +' This code was generated by a tool. +' Runtime Version:4.0.30319.42000 +' +' Changes to this file may cause incorrect behavior and will be lost if +' the code is regenerated. +' +'------------------------------------------------------------------------------ + +Option Strict On +Option Explicit On + +Imports System + +Namespace My.Resources + + 'This class was auto-generated by the StronglyTypedResourceBuilder + 'class via a tool like ResGen or Visual Studio. + 'To add or remove a member, edit your .ResX file then rerun ResGen + 'with the /str option, or rebuild your VS project. + ''' + ''' A strongly-typed resource class, for looking up localized strings, etc. + ''' + _ + Friend Module Resources + + Private resourceMan As Global.System.Resources.ResourceManager + + Private resourceCulture As Global.System.Globalization.CultureInfo + + ''' + ''' Returns the cached ResourceManager instance used by this class. + ''' + _ + Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager + Get + If Object.ReferenceEquals(resourceMan, Nothing) Then + Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("ICSharpCode.SharpZipLib.Samples.Resources", GetType(Resources).Assembly) + resourceMan = temp + End If + Return resourceMan + End Get + End Property + + ''' + ''' Overrides the current thread's CurrentUICulture property for all + ''' resource lookups using this strongly typed resource class. + ''' + _ + Friend Property Culture() As Global.System.Globalization.CultureInfo + Get + Return resourceCulture + End Get + Set + resourceCulture = value + End Set + End Property + End Module +End Namespace diff --git a/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/Resources.resx b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/Resources.resx new file mode 100644 index 000000000..26a50bdc6 --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/Resources.resx @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/app.manifest b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/app.manifest new file mode 100644 index 000000000..a6b46bb75 --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/My Project/app.manifest @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/minibzip2.vbproj b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/minibzip2.vbproj index abc6713d1..4003110da 100644 --- a/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/minibzip2.vbproj +++ b/ICSharpCode.SharpZipLib.Samples/vb/minibzip2/minibzip2.vbproj @@ -11,7 +11,7 @@ - + ICSharpCode.SharpZipLib.Samples.MainForm OnSuccessfulBuild @@ -23,6 +23,8 @@ 2.0 + false + publish\ true Disk @@ -35,10 +37,8 @@ true 0 1.0.0.%2a - false false true - True @@ -65,6 +65,12 @@ false true + + WindowsFormsWithCustomSubMain + + + My Project\app.manifest + @@ -72,19 +78,34 @@ + + SampleAssemblyInfo.vb + Form - + + True + Application.myapp + + + + True + True + Resources.resx + Main.vb Designer + + My.Resources + VbMyResourcesResXFileCodeGenerator + Resources.Designer.vb + - - - + False @@ -94,6 +115,7 @@ + @@ -101,5 +123,11 @@ ICSharpCode.SharpZipLib + + + MyApplicationCodeGenerator + Application.Designer.vb + + \ No newline at end of file diff --git a/ICSharpCode.SharpZipLib.Samples/vb/viewzipfile/Main.vb b/ICSharpCode.SharpZipLib.Samples/vb/viewzipfile/Main.vb index e6e14c1e5..638afcd40 100644 --- a/ICSharpCode.SharpZipLib.Samples/vb/viewzipfile/Main.vb +++ b/ICSharpCode.SharpZipLib.Samples/vb/viewzipfile/Main.vb @@ -1,30 +1,3 @@ -' SharpZipLib samples -' Copyright © 2000-2016 AlphaSierraPapa for the SharpZipLib Team -' All rights reserved. -' -' Redistribution and use in source and binary forms, with or without modification, are -' permitted provided that the following conditions are met: -' -' - Redistributions of source code must retain the above copyright notice, this list -' of conditions and the following disclaimer. -' -' - Redistributions in binary form must reproduce the above copyright notice, this list -' of conditions and the following disclaimer in the documentation and/or other materials -' provided with the distribution. -' -' - Neither the name of the SharpDevelop team nor the names of its contributors may be used to -' endorse or promote products derived from this software without specific prior written -' permission. -' -' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS -' OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -' AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -' CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -' DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -' IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -' OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - Imports System Imports System.IO Imports System.Text diff --git a/ICSharpCode.SharpZipLib.Samples/vb/viewzipfile/My Project/AssemblyInfo.vb b/ICSharpCode.SharpZipLib.Samples/vb/viewzipfile/My Project/AssemblyInfo.vb new file mode 100644 index 000000000..d1d40f5e0 --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/vb/viewzipfile/My Project/AssemblyInfo.vb @@ -0,0 +1,14 @@ +Imports System.Reflection +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + +' Review the values of the assembly attributes + + + + +'The following GUID is for the ID of the typelib if this project is exposed to COM + diff --git a/ICSharpCode.SharpZipLib.Samples/vb/viewzipfile/viewzipfile.vbproj b/ICSharpCode.SharpZipLib.Samples/vb/viewzipfile/viewzipfile.vbproj index 55041b31b..71eddac3d 100644 --- a/ICSharpCode.SharpZipLib.Samples/vb/viewzipfile/viewzipfile.vbproj +++ b/ICSharpCode.SharpZipLib.Samples/vb/viewzipfile/viewzipfile.vbproj @@ -70,19 +70,20 @@ + + SampleAssemblyInfo.vb + Form - + Main.vb Designer - - - + False diff --git a/ICSharpCode.SharpZipLib.Samples/vb/zipfiletest/AssemblyInfo.vb b/ICSharpCode.SharpZipLib.Samples/vb/zipfiletest/AssemblyInfo.vb deleted file mode 100644 index f60c2246c..000000000 --- a/ICSharpCode.SharpZipLib.Samples/vb/zipfiletest/AssemblyInfo.vb +++ /dev/null @@ -1,27 +0,0 @@ -Imports System.Reflection -Imports System.Runtime.InteropServices - -' General Information about an assembly is controlled through the following -' set of attributes. Change these attribute values to modify the information -' associated with an assembly. - -' Review the values of the assembly attributes - - - - - - - - -' Version information for an assembly consists of the following four values: -' -' Major Version -' Minor Version -' Build Number -' Revision -' -' You can specify all the values or you can default the Build and Revision Numbers -' by using the '*' as shown below: - - diff --git a/ICSharpCode.SharpZipLib.Samples/vb/zipfiletest/My Project/AssemblyInfo.vb b/ICSharpCode.SharpZipLib.Samples/vb/zipfiletest/My Project/AssemblyInfo.vb new file mode 100644 index 000000000..9b7c7697a --- /dev/null +++ b/ICSharpCode.SharpZipLib.Samples/vb/zipfiletest/My Project/AssemblyInfo.vb @@ -0,0 +1,14 @@ +Imports System.Reflection +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + +' Review the values of the assembly attributes + + + + +'The following GUID is for the ID of the typelib if this project is exposed to COM + diff --git a/ICSharpCode.SharpZipLib.Samples/vb/zipfiletest/zipfiletest.vbproj b/ICSharpCode.SharpZipLib.Samples/vb/zipfiletest/zipfiletest.vbproj index 129c323ee..8336ef360 100644 --- a/ICSharpCode.SharpZipLib.Samples/vb/zipfiletest/zipfiletest.vbproj +++ b/ICSharpCode.SharpZipLib.Samples/vb/zipfiletest/zipfiletest.vbproj @@ -79,18 +79,19 @@ - + + SampleAssemblyInfo.vb + Form + Main.vb Designer - - - + False diff --git a/ICSharpCode.SharpZipLib.Tests/Core/Core.cs b/ICSharpCode.SharpZipLib.Tests/Core/CoreTests.cs similarity index 93% rename from ICSharpCode.SharpZipLib.Tests/Core/Core.cs rename to ICSharpCode.SharpZipLib.Tests/Core/CoreTests.cs index cc8706463..4d49862c5 100644 --- a/ICSharpCode.SharpZipLib.Tests/Core/Core.cs +++ b/ICSharpCode.SharpZipLib.Tests/Core/CoreTests.cs @@ -4,10 +4,10 @@ namespace ICSharpCode.SharpZipLib.Tests.Core { [TestFixture] - public class Core + public class CoreTestSuite { - [Test] + [Category("Core")] public void FilterQuoting() { string[] filters = NameFilter.SplitQuoted(""); @@ -33,6 +33,7 @@ public void FilterQuoting() } [Test] + [Category("Core")] public void NullFilter() { var nf = new NameFilter(null); @@ -40,6 +41,7 @@ public void NullFilter() } [Test] + [Category("Core")] public void ValidFilter() { Assert.IsTrue(NameFilter.IsValidFilterExpression(null)); diff --git a/ICSharpCode.SharpZipLib.Tests/ICSharpCode.SharpZipLib.Tests.csproj b/ICSharpCode.SharpZipLib.Tests/ICSharpCode.SharpZipLib.Tests.csproj index 263743499..534721568 100644 --- a/ICSharpCode.SharpZipLib.Tests/ICSharpCode.SharpZipLib.Tests.csproj +++ b/ICSharpCode.SharpZipLib.Tests/ICSharpCode.SharpZipLib.Tests.csproj @@ -89,7 +89,7 @@ - + diff --git a/ICSharpCode.SharpZipLib.Tests/PassingTests.txt b/ICSharpCode.SharpZipLib.Tests/PassingTests.txt index 2fe844cab..32e1d93ae 100644 --- a/ICSharpCode.SharpZipLib.Tests/PassingTests.txt +++ b/ICSharpCode.SharpZipLib.Tests/PassingTests.txt @@ -38,7 +38,6 @@ 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.Tar.TarTestSuite.ValuesPreserved ICSharpCode.SharpZipLib.Tests.TestSupport.ExerciseBuffer.Basic ICSharpCode.SharpZipLib.Tests.TestSupport.ExerciseBuffer.Buffered ICSharpCode.SharpZipLib.Tests.TestSupport.ExerciseBuffer.Threaded @@ -61,7 +60,6 @@ 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.PasswordCheckingWithDateInExtraData ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.SerializedObject ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.SerializedObjectZeroLength ICSharpCode.SharpZipLib.Tests.Zip.GeneralHandling.SetCommentOversize diff --git a/ICSharpCode.SharpZipLib.Tests/packages.config b/ICSharpCode.SharpZipLib.Tests/packages.config index 46eb857d7..01304db01 100644 --- a/ICSharpCode.SharpZipLib.Tests/packages.config +++ b/ICSharpCode.SharpZipLib.Tests/packages.config @@ -11,5 +11,6 @@ + \ No newline at end of file diff --git a/ICSharpCode.SharpZipLib/BZip2/BZip2Exception.cs b/ICSharpCode.SharpZipLib/BZip2/BZip2Exception.cs index 2ef20c32f..716c5ae36 100644 --- a/ICSharpCode.SharpZipLib/BZip2/BZip2Exception.cs +++ b/ICSharpCode.SharpZipLib/BZip2/BZip2Exception.cs @@ -4,12 +4,11 @@ namespace ICSharpCode.SharpZipLib.BZip2 { /// - /// BZip2Exception represents exceptions specific to Bzip2 algorithm + /// BZip2Exception represents exceptions specific to BZip2 classes and code. /// [Serializable] public class BZip2Exception : SharpZipBaseException { - /// /// Deserialization constructor /// @@ -17,31 +16,32 @@ public class BZip2Exception : SharpZipBaseException /// for this constructor protected BZip2Exception(SerializationInfo info, StreamingContext context) : base(info, context) - { } + /// - /// Initialise a new instance of BZip2Exception. + /// Initialise a new instance of . /// public BZip2Exception() { } /// - /// Initialise a new instance of BZip2Exception with its message set to message. + /// Initialise a new instance of with its message string. /// - /// The message describing the error. - public BZip2Exception(string message) : base(message) + /// A that describes the error. + public BZip2Exception(string message) + : base(message) { } /// - /// Initialise an instance of BZip2Exception + /// Initialise a new instance of . /// - /// A message describing the error. - /// The exception that is the cause of the current exception. - public BZip2Exception(string message, Exception exception) - : base(message, exception) + /// A that describes the error. + /// The that caused this exception. + public BZip2Exception(string message, Exception innerException) + : base(message, innerException) { } } diff --git a/ICSharpCode.SharpZipLib/GZip/GZipException.cs b/ICSharpCode.SharpZipLib/GZip/GZipException.cs index cde0cec25..1abc3c2c3 100644 --- a/ICSharpCode.SharpZipLib/GZip/GZipException.cs +++ b/ICSharpCode.SharpZipLib/GZip/GZipException.cs @@ -4,7 +4,7 @@ namespace ICSharpCode.SharpZipLib.GZip { /// - /// GZipException represents a Gzip specific exception + /// GZipException represents exceptions specific to GZip classes and code. /// [Serializable] public class GZipException : SharpZipBaseException @@ -16,19 +16,18 @@ public class GZipException : SharpZipBaseException /// for this constructor protected GZipException(SerializationInfo info, StreamingContext context) : base(info, context) - { } /// - /// Initialise a new instance of GZipException + /// Initialise a new instance of . /// public GZipException() { } /// - /// Initialise a new instance of GZipException with its message string. + /// Initialise a new instance of with its message string. /// /// A that describes the error. public GZipException(string message) @@ -37,7 +36,7 @@ public GZipException(string message) } /// - /// Initialise a new instance of . + /// Initialise a new instance of . /// /// A that describes the error. /// The that caused this exception. diff --git a/ICSharpCode.SharpZipLib/Lzw/LzwException.cs b/ICSharpCode.SharpZipLib/Lzw/LzwException.cs index 41db05b7c..32f0c3197 100644 --- a/ICSharpCode.SharpZipLib/Lzw/LzwException.cs +++ b/ICSharpCode.SharpZipLib/Lzw/LzwException.cs @@ -4,12 +4,11 @@ namespace ICSharpCode.SharpZipLib.Lzw { /// - /// LzwException represents a LZW specific exception + /// LzwException represents exceptions specific to LZW classes and code. /// [Serializable] public class LzwException : SharpZipBaseException { - /// /// Deserialization constructor /// @@ -21,14 +20,14 @@ protected LzwException(SerializationInfo info, StreamingContext context) } /// - /// Initialise a new instance of LzwException + /// Initialise a new instance of . /// public LzwException() { } /// - /// Initialise a new instance of LzwException with its message string. + /// Initialise a new instance of with its message string. /// /// A that describes the error. public LzwException(string message) @@ -37,7 +36,7 @@ public LzwException(string message) } /// - /// Initialise a new instance of . + /// Initialise a new instance of . /// /// A that describes the error. /// The that caused this exception. diff --git a/ICSharpCode.SharpZipLib/Tar/TarException.cs b/ICSharpCode.SharpZipLib/Tar/TarException.cs index fb426c5f5..2fca8bf64 100644 --- a/ICSharpCode.SharpZipLib/Tar/TarException.cs +++ b/ICSharpCode.SharpZipLib/Tar/TarException.cs @@ -4,7 +4,7 @@ namespace ICSharpCode.SharpZipLib.Tar { /// - /// TarExceptions are used for exceptions specific to tar classes and code. + /// TarException represents exceptions specific to Tar classes and code. /// [Serializable] public class TarException : SharpZipBaseException @@ -16,33 +16,32 @@ public class TarException : SharpZipBaseException /// for this constructor protected TarException(SerializationInfo info, StreamingContext context) : base(info, context) - { } /// - /// Initialises a new instance of the TarException class. + /// Initialise a new instance of . /// public TarException() { } /// - /// Initialises a new instance of the TarException class with a specified message. + /// Initialise a new instance of with its message string. /// - /// The message that describes the error. + /// A that describes the error. public TarException(string message) : base(message) { } /// - /// + /// Initialise a new instance of . /// - /// A message describing the error. - /// The exception that is the cause of the current exception. - public TarException(string message, Exception exception) - : base(message, exception) + /// A that describes the error. + /// The that caused this exception. + public TarException(string message, Exception innerException) + : base(message, innerException) { } } diff --git a/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs b/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs index 07645b589..32c644820 100644 --- a/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs +++ b/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs @@ -212,7 +212,6 @@ public ZipEntry(ZipEntry entry) compressedSize = entry.compressedSize; crc = entry.crc; dosTime = entry.dosTime; - dateTime = entry.dateTime; method = entry.method; comment = entry.comment; versionToExtract = entry.versionToExtract; @@ -621,7 +620,16 @@ public long DosTime { /// public DateTime DateTime { - get { return dateTime; } + get + { + uint sec = Math.Min(59, 2 * (dosTime & 0x1f)); + uint min = Math.Min(59, (dosTime >> 5) & 0x3f); + uint hrs = Math.Min(23, (dosTime >> 11) & 0x1f); + uint mon = Math.Max(1, Math.Min(12, ((dosTime >> 21) & 0xf))); + uint year = ((dosTime >> 25) & 0x7f) + 1980; + int day = Math.Max(1, Math.Min(DateTime.DaysInMonth((int)year, (int)mon), (int)((dosTime >> 16) & 0x1f))); + return new System.DateTime((int)year, (int)mon, day, (int)hrs, (int)min, (int)sec); + } set { var year = (uint)value.Year; @@ -930,7 +938,7 @@ internal void ProcessExtraData(bool localHeader) } } - dateTime = GetDateTime(extraData); + DateTime = GetDateTime(extraData); if (method == CompressionMethod.WinZipAES) { ProcessAESExtraData(extraData); } @@ -1155,7 +1163,6 @@ public static string CleanName(string name) ushort versionToExtract; // Version required to extract (library handles <= 2.0) uint crc; uint dosTime; - DateTime dateTime; CompressionMethod method = CompressionMethod.Deflated; byte[] extra; diff --git a/ICSharpCode.SharpZipLib/Zip/ZipException.cs b/ICSharpCode.SharpZipLib/Zip/ZipException.cs index ebd8f1739..f149965e3 100644 --- a/ICSharpCode.SharpZipLib/Zip/ZipException.cs +++ b/ICSharpCode.SharpZipLib/Zip/ZipException.cs @@ -4,7 +4,7 @@ namespace ICSharpCode.SharpZipLib.Zip { /// - /// Represents exception conditions specific to Zip archive handling + /// ZipException represents exceptions specific to Zip classes and code. /// [Serializable] public class ZipException : SharpZipBaseException @@ -20,28 +20,28 @@ protected ZipException(SerializationInfo info, StreamingContext context) } /// - /// Initializes a new instance of the ZipException class. + /// Initialise a new instance of . /// public ZipException() { } /// - /// Initializes a new instance of the ZipException class with a specified error message. + /// Initialise a new instance of with its message string. /// - /// The error message that explains the reason for the exception. + /// A that describes the error. public ZipException(string message) : base(message) { } /// - /// Initialise a new instance of ZipException. + /// Initialise a new instance of . /// - /// A message describing the error. - /// The exception that is the cause of the current exception. - public ZipException(string message, Exception exception) - : base(message, exception) + /// A that describes the error. + /// The that caused this exception. + public ZipException(string message, Exception innerException) + : base(message, innerException) { } } diff --git a/README.md b/README.md index fb5a54740..8ee630200 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,4 @@ -[![Stories in Ready](https://badge.waffle.io/McNeight/SharpZipLib.png?label=ready&title=Ready)](https://waffle.io/McNeight/SharpZipLib) -# SharpZipLib - -[![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) +# SharpZipLib [![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) [![Stories in Ready](https://badge.waffle.io/icsharpcode/SharpZipLib.svg?label=ready&title=Ready)](http://waffle.io/icsharpcode/SharpZipLib) [![Coverage Status](https://coveralls.io/repos/github/McNeight/SharpZipLib/badge.svg?branch=master)](https://coveralls.io/github/McNeight/SharpZipLib?branch=master) [![Coverity Scan Build Status](https://scan.coverity.com/projects/8519/badge.svg)](https://scan.coverity.com/projects/mcneight-sharpziplib) @@ -28,10 +25,11 @@ - + - + @@ -55,9 +53,9 @@ The [SharpZipLib homepage](http://icsharpcode.github.io/SharpZipLib/) has precom License ------- -This software is now released under the [MIT License](https://opensource.org/licenses/MIT) +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. +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 ---------------- @@ -69,6 +67,7 @@ Namespace layout |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.\*| @@ -80,3 +79,7 @@ Credits SharpZipLib was initially developed by [Mike Krüger](http://www.icsharpcode.net/pub/relations/krueger.aspx). Past maintainers are John Reilly and David Pierson. The current maintainer is Neil McNeight. And thanks to all the people that contributed features, bug fixes and issue reports. + +Metrics +------- +[![Throughput Graph](https://graphs.waffle.io/icsharpcode/SharpZipLib/throughput.svg)](https://waffle.io/icsharpcode/SharpZipLib/metrics/throughput) diff --git a/appveyor.yml b/appveyor.yml index 97a4ce3ea..59eae6924 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -101,15 +101,22 @@ configuration: Release # ios: true build: - parallel: true - project: ICSharpCode.SharpZipLib.sln - publish_nuget: true - publish_nuget_symbols: true - include_nuget_references: true +# parallel: true +# project: ICSharpCode.SharpZipLib.sln +# publish_nuget: true +# publish_nuget_symbols: true +# include_nuget_references: true # MSBuild verbosity level - verbosity: normal - +# verbosity: normal + +environment: + COVERALLS_REPO_TOKEN: + secure: B/NQfoRYUnKLGS5KJSJrGBvcYD0Jv+coudjJMY2jf+gqvqDWral9CDmv2i0WovY7 + COVERITY_TOKEN: + secure: n9NA/kasTqxUc8UBfQ2cBlZcDyFJvko1gcMzVTDvZq8= + COVERITY_EMAIL: + secure: j/N0ZmnUZYKnS2nGocKyNsXoKQBfWTBOg+VI4q7yMn4= # scripts to run before build before_build: - cmd: nuget restore ICSharpCode.SharpZipLib.sln @@ -122,6 +129,7 @@ after_build: # to run your custom scripts instead of automatic MSBuild build_script: +- ps: Build\run-appveyor-build.ps1 # to disable automatic builds #build: off @@ -153,11 +161,13 @@ before_test: # scripts to run after tests after_test: - - cmd: nuget pack Build\ICSharpCode.SharpZipLib.nuspec -BasePath Build -OutputDirectory bin\Release + - 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% # to run your custom scripts instead of automatic tests test_script: - - cmd: nunit3-console --framework=net-4.5 --labels=All --testlist=./ICSharpCode.SharpZipLib.Tests/PassingTests.txt --result=./bin/Release/nunit3-test-results-appveyor.xml;format=AppVeyor ./bin/Release/ICSharpCode.SharpZipLib.Tests.dll + - 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 # to disable automatic tests #test: off @@ -173,8 +183,10 @@ artifacts: name: BuildRelease - path: bin\**\*.nupkg name: NuGet -- path: bin\Release\nunit3-test-results-appveyor.xml +- path: Documentation\*.xml name: TestResults +- path: Documentation\coverity.zip + name: Coverity #---------------------------------# # deployment configuration # @@ -184,7 +196,7 @@ artifacts: # provider names are case-sensitive! deploy: - provider: GitHub - release: sharpziplib-dogfood-$(appveyor_build_version) + release: sharpziplib-dogfood-{version} description: 'Something To Eat' auth_token: secure: pZ5zHJ/2mZsmqQH0gPke0LMqSgUhz79wbcCjdDTCEIl6hRJYlYhkaPianw2hz26k # your encrypted token from GitHub @@ -193,8 +205,10 @@ deploy: prerelease: true on: branch: master # release from master branch only - appveyor_repo_tag: true # deploy on tag push only +# 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
Mono 4.2.3
Bitrise (Soon)Bitrise OSX Xamarin.iOS + Bitrise Build Status
OSX