Use System.IO.Compression instead of custom ZIP library for EPPlus.
Change-Id: I4dc2d0c7889d885efdce1d786551414295b0e9c5
Reviewed-on: https://gnocchi-internal-review.git.corp.google.com/c/third_party/epplus/+/207480
Reviewed-by: Hughes Hilton <hugheshilton@google.com>
diff --git a/EPPlus/EPPlusSDK.csproj b/EPPlus/EPPlusSDK.csproj
index 9b5f21b..9203ac9 100644
--- a/EPPlus/EPPlusSDK.csproj
+++ b/EPPlus/EPPlusSDK.csproj
@@ -4,7 +4,7 @@
<RootNamespace>OfficeOpenXml</RootNamespace>
<AssemblyName>EPPlus</AssemblyName>
<PackageId>Appsheet.EPPlus</PackageId>
- <Version>1.0.3</Version>
+ <Version>1.0.4</Version>
<DefaultItemExcludes>$(DefaultItemExcludes);Properties/AssemblyInfo.cs;FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/**;FormulaParsing/LexicalAnalysis/TokenHandler.cs;FormulaParsing/Excel/Functions/Math/Rank.cs</DefaultItemExcludes>
<DefineConstants>Core;STANDARD20</DefineConstants>
<ImplicitUsings>disable</ImplicitUsings>
diff --git a/EPPlus/ExcelWorkbook.cs b/EPPlus/ExcelWorkbook.cs
index e47b791..ba02560 100644
--- a/EPPlus/ExcelWorkbook.cs
+++ b/EPPlus/ExcelWorkbook.cs
@@ -31,7 +31,6 @@
* Richard Tallent Fix escaping of quotes 2012-10-31
*******************************************************************************/
using System;
-using System.Linq;
using System.Xml;
using System.IO;
using System.Collections.Generic;
@@ -40,7 +39,6 @@
using OfficeOpenXml.Utils;
using OfficeOpenXml.FormulaParsing;
using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-using OfficeOpenXml.Packaging.Ionic.Zip;
using System.Drawing;
namespace OfficeOpenXml
@@ -794,26 +792,9 @@
}
}
- private void SaveSharedStringHandler(ZipOutputStream stream, CompressionLevel compressionLevel, string fileName)
+ private void SaveSharedStringHandler(StreamWriter sw)
{
- //Packaging.ZipPackagePart stringPart;
- //if (_package.Package.PartExists(SharedStringsUri))
- //{
- // stringPart=_package.Package.GetPart(SharedStringsUri);
- //}
- //else
- //{
- // stringPart = _package.Package.CreatePart(SharedStringsUri, @"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml", _package.Compression);
- //Part.CreateRelationship(UriHelper.GetRelativeUri(WorkbookUri, SharedStringsUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/sharedStrings");
- //}
-
- //StreamWriter sw = new StreamWriter(stringPart.GetStream(FileMode.Create, FileAccess.Write));
- //Init Zip
- stream.CompressionLevel = (OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel)compressionLevel;
- stream.PutNextEntry(fileName);
-
var cache = new StringBuilder();
- var sw = new StreamWriter(stream);
cache.AppendFormat("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><sst xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" count=\"{0}\" uniqueCount=\"{0}\">", _sharedStrings.Count);
foreach (string t in _sharedStrings.Keys)
{
diff --git a/EPPlus/ExcelWorksheet.cs b/EPPlus/ExcelWorksheet.cs
index 6ee3dd1..f8b6aeb 100644
--- a/EPPlus/ExcelWorksheet.cs
+++ b/EPPlus/ExcelWorksheet.cs
@@ -44,10 +44,10 @@
using OfficeOpenXml.DataValidation;
using OfficeOpenXml.Table.PivotTable;
using System.ComponentModel;
+using System.IO.Compression;
using OfficeOpenXml.ConditionalFormatting;
using OfficeOpenXml.Utils;
using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-using OfficeOpenXml.Packaging.Ionic.Zip;
namespace OfficeOpenXml
{
@@ -2878,80 +2878,79 @@
}
}
}
- internal void SaveHandler(ZipOutputStream stream, CompressionLevel compressionLevel, string fileName)
+ internal void SaveHandler(StreamWriter streamWriter)
{
- //Init Zip
- stream.CodecBufferSize = 8096;
- stream.CompressionLevel = (OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel)compressionLevel;
- stream.PutNextEntry(fileName);
+ //Create the nodes if they do not exist.
+ if (this is ExcelChartsheet)
+ {
+ streamWriter.Write(_worksheetXml.OuterXml);
+ }
+ else
+ {
+ CreateNode("d:cols");
+ CreateNode("d:sheetData");
+ CreateNode("d:mergeCells");
+ CreateNode("d:hyperlinks");
+ CreateNode("d:rowBreaks");
+ CreateNode("d:colBreaks");
-
- SaveXml(stream);
+ //StreamWriter sw=new StreamWriter(Part.GetStream(FileMode.Create, FileAccess.Write));
+ var xml = _worksheetXml.OuterXml;
+ int colStart = 0, colEnd = 0;
+ GetBlockPos(xml, "cols", ref colStart, ref colEnd);
+
+ streamWriter.Write(xml.Substring(0, colStart));
+ var colBreaks = new List<int>();
+ //if (_columns.Count > 0)
+ //{
+ UpdateColumnData(streamWriter);
+ //}
+
+ int cellStart = colEnd, cellEnd = colEnd;
+ GetBlockPos(xml, "sheetData", ref cellStart, ref cellEnd);
+
+ streamWriter.Write(xml.Substring(colEnd, cellStart - colEnd));
+ var rowBreaks = new List<int>();
+ UpdateRowCellData(streamWriter);
+
+ int mergeStart = cellEnd, mergeEnd = cellEnd;
+
+ GetBlockPos(xml, "mergeCells", ref mergeStart, ref mergeEnd);
+ streamWriter.Write(xml.Substring(cellEnd, mergeStart - cellEnd));
+
+ CleanupMergedCells(_mergedCells);
+ if (_mergedCells.Count > 0)
+ {
+ UpdateMergedCells(streamWriter);
+ }
+
+ int hyperStart = mergeEnd, hyperEnd = mergeEnd;
+ GetBlockPos(xml, "hyperlinks", ref hyperStart, ref hyperEnd);
+ streamWriter.Write(xml.Substring(mergeEnd, hyperStart - mergeEnd));
+ //if (_hyperLinkCells.Count > 0)
+ //{
+ UpdateHyperLinks(streamWriter);
+ // }
+
+ int rowBreakStart = hyperEnd, rowBreakEnd = hyperEnd;
+ GetBlockPos(xml, "rowBreaks", ref rowBreakStart, ref rowBreakEnd);
+ streamWriter.Write(xml.Substring(hyperEnd, rowBreakStart - hyperEnd));
+ //if (rowBreaks.Count > 0)
+ //{
+ UpdateRowBreaks(streamWriter);
+ //}
+
+ int colBreakStart = rowBreakEnd, colBreakEnd = rowBreakEnd;
+ GetBlockPos(xml, "colBreaks", ref colBreakStart, ref colBreakEnd);
+ streamWriter.Write(xml.Substring(rowBreakEnd, colBreakStart - rowBreakEnd));
+ //if (colBreaks.Count > 0)
+ //{
+ UpdateColBreaks(streamWriter);
+ //}
+ streamWriter.Write(xml.Substring(colBreakEnd, xml.Length - colBreakEnd));
+ }
}
-
-
- ///// <summary>
- ///// Saves the worksheet to the package.
- ///// </summary>
- //internal void Save() // Worksheet Save
- //{
- // DeletePrinterSettings();
-
- // if (_worksheetXml != null)
- // {
-
- // // save the header & footer (if defined)
- // if (_headerFooter != null)
- // HeaderFooter.Save();
-
- // var d = Dimension;
- // if (d == null)
- // {
- // this.DeleteAllNode("d:dimension/@ref");
- // }
- // else
- // {
- // this.SetXmlNodeString("d:dimension/@ref", d.Address);
- // }
-
-
- // if (_drawings != null && _drawings.Count == 0)
- // {
- // //Remove node if no drawings exists.
- // DeleteNode("d:drawing");
- // }
-
- // SaveComments();
- // HeaderFooter.SaveHeaderFooterImages();
- // SaveTables();
- // SavePivotTables();
- // SaveXml();
- // }
-
- // if (Drawings.UriDrawing!=null)
- // {
- // if (Drawings.Count == 0)
- // {
- // Part.DeleteRelationship(Drawings._drawingRelation.Id);
- // _package.Package.DeletePart(Drawings.UriDrawing);
- // }
- // else
- // {
- // Packaging.ZipPackagePart partPack = Drawings.Part;
- // Drawings.DrawingXml.Save(partPack.GetStream(FileMode.Create, FileAccess.Write));
- // foreach (ExcelDrawing d in Drawings)
- // {
- // if (d is ExcelChart)
- // {
- // ExcelChart c = (ExcelChart)d;
- // c.ChartXml.Save(c.Part.GetStream(FileMode.Create, FileAccess.Write));
- // }
- // }
- // }
- // }
- //}
-
/// <summary>
/// Delete the printersettings relationship and part.
/// </summary>
@@ -3285,81 +3284,6 @@
{
return string.Format("SUBTOTAL({0},{1}[{2}])", FunctionNum, col._tbl.Name, col.Name);
}
- private void SaveXml(Stream stream)
- {
- //Create the nodes if they do not exist.
- StreamWriter sw = new StreamWriter(stream, System.Text.Encoding.UTF8, 65536);
- if (this is ExcelChartsheet)
- {
- sw.Write(_worksheetXml.OuterXml);
- }
- else
- {
- CreateNode("d:cols");
- CreateNode("d:sheetData");
- CreateNode("d:mergeCells");
- CreateNode("d:hyperlinks");
- CreateNode("d:rowBreaks");
- CreateNode("d:colBreaks");
-
- //StreamWriter sw=new StreamWriter(Part.GetStream(FileMode.Create, FileAccess.Write));
- var xml = _worksheetXml.OuterXml;
- int colStart = 0, colEnd = 0;
- GetBlockPos(xml, "cols", ref colStart, ref colEnd);
-
- sw.Write(xml.Substring(0, colStart));
- var colBreaks = new List<int>();
- //if (_columns.Count > 0)
- //{
- UpdateColumnData(sw);
- //}
-
- int cellStart = colEnd, cellEnd = colEnd;
- GetBlockPos(xml, "sheetData", ref cellStart, ref cellEnd);
-
- sw.Write(xml.Substring(colEnd, cellStart - colEnd));
- var rowBreaks = new List<int>();
- UpdateRowCellData(sw);
-
- int mergeStart = cellEnd, mergeEnd = cellEnd;
-
- GetBlockPos(xml, "mergeCells", ref mergeStart, ref mergeEnd);
- sw.Write(xml.Substring(cellEnd, mergeStart - cellEnd));
-
- CleanupMergedCells(_mergedCells);
- if (_mergedCells.Count > 0)
- {
- UpdateMergedCells(sw);
- }
-
- int hyperStart = mergeEnd, hyperEnd = mergeEnd;
- GetBlockPos(xml, "hyperlinks", ref hyperStart, ref hyperEnd);
- sw.Write(xml.Substring(mergeEnd, hyperStart - mergeEnd));
- //if (_hyperLinkCells.Count > 0)
- //{
- UpdateHyperLinks(sw);
- // }
-
- int rowBreakStart = hyperEnd, rowBreakEnd = hyperEnd;
- GetBlockPos(xml, "rowBreaks", ref rowBreakStart, ref rowBreakEnd);
- sw.Write(xml.Substring(hyperEnd, rowBreakStart - hyperEnd));
- //if (rowBreaks.Count > 0)
- //{
- UpdateRowBreaks(sw);
- //}
-
- int colBreakStart = rowBreakEnd, colBreakEnd = rowBreakEnd;
- GetBlockPos(xml, "colBreaks", ref colBreakStart, ref colBreakEnd);
- sw.Write(xml.Substring(rowBreakEnd, colBreakStart - rowBreakEnd));
- //if (colBreaks.Count > 0)
- //{
- UpdateColBreaks(sw);
- //}
- sw.Write(xml.Substring(colBreakEnd, xml.Length - colBreakEnd));
- }
- sw.Flush();
- //sw.Close();
- }
private void CleanupMergedCells(MergeCellsCollection _mergedCells)
{
diff --git a/EPPlus/Packaging/DotNetZip/CRC32.cs b/EPPlus/Packaging/DotNetZip/CRC32.cs
deleted file mode 100644
index cf9574d..0000000
--- a/EPPlus/Packaging/DotNetZip/CRC32.cs
+++ /dev/null
@@ -1,814 +0,0 @@
-// CRC32.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2011 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// Last Saved: <2011-August-02 18:25:54>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the CRC32 class, which can do the CRC32 algorithm, using
-// arbitrary starting polynomials, and bit reversal. The bit reversal is what
-// distinguishes this CRC-32 used in BZip2 from the CRC-32 that is used in PKZIP
-// files, or GZIP files. This class does both.
-//
-// ------------------------------------------------------------------
-
-
-using System;
-using Interop = System.Runtime.InteropServices;
-
-namespace OfficeOpenXml.Packaging.Ionic.Crc
-{
- /// <summary>
- /// Computes a CRC-32. The CRC-32 algorithm is parameterized - you
- /// can set the polynomial and enable or disable bit
- /// reversal. This can be used for GZIP, BZip2, or ZIP.
- /// </summary>
- /// <remarks>
- /// This type is used internally by DotNetZip; it is generally not used
- /// directly by applications wishing to create, read, or manipulate zip
- /// archive files.
- /// </remarks>
-
- [Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000C")]
- [Interop.ComVisible(true)]
-#if !NETCF
- [Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)]
-#endif
- internal class CRC32
- {
- /// <summary>
- /// Indicates the total number of bytes applied to the CRC.
- /// </summary>
- public Int64 TotalBytesRead
- {
- get
- {
- return _TotalBytesRead;
- }
- }
-
- /// <summary>
- /// Indicates the current CRC for all blocks slurped in.
- /// </summary>
- public Int32 Crc32Result
- {
- get
- {
- return unchecked((Int32)(~_register));
- }
- }
-
- /// <summary>
- /// Returns the CRC32 for the specified stream.
- /// </summary>
- /// <param name="input">The stream over which to calculate the CRC32</param>
- /// <returns>the CRC32 calculation</returns>
- public Int32 GetCrc32(System.IO.Stream input)
- {
- return GetCrc32AndCopy(input, null);
- }
-
- /// <summary>
- /// Returns the CRC32 for the specified stream, and writes the input into the
- /// output stream.
- /// </summary>
- /// <param name="input">The stream over which to calculate the CRC32</param>
- /// <param name="output">The stream into which to deflate the input</param>
- /// <returns>the CRC32 calculation</returns>
- public Int32 GetCrc32AndCopy(System.IO.Stream input, System.IO.Stream output)
- {
- if (input == null)
- throw new Exception("The input stream must not be null.");
-
- unchecked
- {
- byte[] buffer = new byte[BUFFER_SIZE];
- int readSize = BUFFER_SIZE;
-
- _TotalBytesRead = 0;
- int count = input.Read(buffer, 0, readSize);
- if (output != null) output.Write(buffer, 0, count);
- _TotalBytesRead += count;
- while (count > 0)
- {
- SlurpBlock(buffer, 0, count);
- count = input.Read(buffer, 0, readSize);
- if (output != null) output.Write(buffer, 0, count);
- _TotalBytesRead += count;
- }
-
- return (Int32)(~_register);
- }
- }
-
-
- /// <summary>
- /// Get the CRC32 for the given (word,byte) combo. This is a
- /// computation defined by PKzip for PKZIP 2.0 (weak) encryption.
- /// </summary>
- /// <param name="W">The word to start with.</param>
- /// <param name="B">The byte to combine it with.</param>
- /// <returns>The CRC-ized result.</returns>
- public Int32 ComputeCrc32(Int32 W, byte B)
- {
- return _InternalComputeCrc32((UInt32)W, B);
- }
-
- internal Int32 _InternalComputeCrc32(UInt32 W, byte B)
- {
- return (Int32)(crc32Table[(W ^ B) & 0xFF] ^ (W >> 8));
- }
-
-
- /// <summary>
- /// Update the value for the running CRC32 using the given block of bytes.
- /// This is useful when using the CRC32() class in a Stream.
- /// </summary>
- /// <param name="block">block of bytes to slurp</param>
- /// <param name="offset">starting point in the block</param>
- /// <param name="count">how many bytes within the block to slurp</param>
- public void SlurpBlock(byte[] block, int offset, int count)
- {
- if (block == null)
- throw new Exception("The data buffer must not be null.");
-
- // bzip algorithm
- for (int i = 0; i < count; i++)
- {
- int x = offset + i;
- byte b = block[x];
- if (this.reverseBits)
- {
- UInt32 temp = (_register >> 24) ^ b;
- _register = (_register << 8) ^ crc32Table[temp];
- }
- else
- {
- UInt32 temp = (_register & 0x000000FF) ^ b;
- _register = (_register >> 8) ^ crc32Table[temp];
- }
- }
- _TotalBytesRead += count;
- }
-
-
- /// <summary>
- /// Process one byte in the CRC.
- /// </summary>
- /// <param name = "b">the byte to include into the CRC . </param>
- public void UpdateCRC(byte b)
- {
- if (this.reverseBits)
- {
- UInt32 temp = (_register >> 24) ^ b;
- _register = (_register << 8) ^ crc32Table[temp];
- }
- else
- {
- UInt32 temp = (_register & 0x000000FF) ^ b;
- _register = (_register >> 8) ^ crc32Table[temp];
- }
- }
-
- /// <summary>
- /// Process a run of N identical bytes into the CRC.
- /// </summary>
- /// <remarks>
- /// <para>
- /// This method serves as an optimization for updating the CRC when a
- /// run of identical bytes is found. Rather than passing in a buffer of
- /// length n, containing all identical bytes b, this method accepts the
- /// byte value and the length of the (virtual) buffer - the length of
- /// the run.
- /// </para>
- /// </remarks>
- /// <param name = "b">the byte to include into the CRC. </param>
- /// <param name = "n">the number of times that byte should be repeated. </param>
- public void UpdateCRC(byte b, int n)
- {
- while (n-- > 0)
- {
- if (this.reverseBits)
- {
- uint temp = (_register >> 24) ^ b;
- _register = (_register << 8) ^ crc32Table[(temp >= 0)
- ? temp
- : (temp + 256)];
- }
- else
- {
- UInt32 temp = (_register & 0x000000FF) ^ b;
- _register = (_register >> 8) ^ crc32Table[(temp >= 0)
- ? temp
- : (temp + 256)];
-
- }
- }
- }
-
-
-
- private static uint ReverseBits(uint data)
- {
- unchecked
- {
- uint ret = data;
- ret = (ret & 0x55555555) << 1 | (ret >> 1) & 0x55555555;
- ret = (ret & 0x33333333) << 2 | (ret >> 2) & 0x33333333;
- ret = (ret & 0x0F0F0F0F) << 4 | (ret >> 4) & 0x0F0F0F0F;
- ret = (ret << 24) | ((ret & 0xFF00) << 8) | ((ret >> 8) & 0xFF00) | (ret >> 24);
- return ret;
- }
- }
-
- private static byte ReverseBits(byte data)
- {
- unchecked
- {
- uint u = (uint)data * 0x00020202;
- uint m = 0x01044010;
- uint s = u & m;
- uint t = (u << 2) & (m << 1);
- return (byte)((0x01001001 * (s + t)) >> 24);
- }
- }
-
-
-
- private void GenerateLookupTable()
- {
- crc32Table = new UInt32[256];
- unchecked
- {
- UInt32 dwCrc;
- byte i = 0;
- do
- {
- dwCrc = i;
- for (byte j = 8; j > 0; j--)
- {
- if ((dwCrc & 1) == 1)
- {
- dwCrc = (dwCrc >> 1) ^ dwPolynomial;
- }
- else
- {
- dwCrc >>= 1;
- }
- }
- if (reverseBits)
- {
- crc32Table[ReverseBits(i)] = ReverseBits(dwCrc);
- }
- else
- {
- crc32Table[i] = dwCrc;
- }
- i++;
- } while (i!=0);
- }
-
-#if VERBOSE
- Console.WriteLine();
- Console.WriteLine("private static readonly UInt32[] crc32Table = {");
- for (int i = 0; i < crc32Table.Length; i+=4)
- {
- Console.Write(" ");
- for (int j=0; j < 4; j++)
- {
- Console.Write(" 0x{0:X8}U,", crc32Table[i+j]);
- }
- Console.WriteLine();
- }
- Console.WriteLine("};");
- Console.WriteLine();
-#endif
- }
-
-
- private uint gf2_matrix_times(uint[] matrix, uint vec)
- {
- uint sum = 0;
- int i=0;
- while (vec != 0)
- {
- if ((vec & 0x01)== 0x01)
- sum ^= matrix[i];
- vec >>= 1;
- i++;
- }
- return sum;
- }
-
- private void gf2_matrix_square(uint[] square, uint[] mat)
- {
- for (int i = 0; i < 32; i++)
- square[i] = gf2_matrix_times(mat, mat[i]);
- }
-
-
-
- /// <summary>
- /// Combines the given CRC32 value with the current running total.
- /// </summary>
- /// <remarks>
- /// This is useful when using a divide-and-conquer approach to
- /// calculating a CRC. Multiple threads can each calculate a
- /// CRC32 on a segment of the data, and then combine the
- /// individual CRC32 values at the end.
- /// </remarks>
- /// <param name="crc">the crc value to be combined with this one</param>
- /// <param name="length">the length of data the CRC value was calculated on</param>
- public void Combine(int crc, int length)
- {
- uint[] even = new uint[32]; // even-power-of-two zeros operator
- uint[] odd = new uint[32]; // odd-power-of-two zeros operator
-
- if (length == 0)
- return;
-
- uint crc1= ~_register;
- uint crc2= (uint) crc;
-
- // put operator for one zero bit in odd
- odd[0] = this.dwPolynomial; // the CRC-32 polynomial
- uint row = 1;
- for (int i = 1; i < 32; i++)
- {
- odd[i] = row;
- row <<= 1;
- }
-
- // put operator for two zero bits in even
- gf2_matrix_square(even, odd);
-
- // put operator for four zero bits in odd
- gf2_matrix_square(odd, even);
-
- uint len2 = (uint) length;
-
- // apply len2 zeros to crc1 (first square will put the operator for one
- // zero byte, eight zero bits, in even)
- do {
- // apply zeros operator for this bit of len2
- gf2_matrix_square(even, odd);
-
- if ((len2 & 1)== 1)
- crc1 = gf2_matrix_times(even, crc1);
- len2 >>= 1;
-
- if (len2 == 0)
- break;
-
- // another iteration of the loop with odd and even swapped
- gf2_matrix_square(odd, even);
- if ((len2 & 1)==1)
- crc1 = gf2_matrix_times(odd, crc1);
- len2 >>= 1;
-
-
- } while (len2 != 0);
-
- crc1 ^= crc2;
-
- _register= ~crc1;
-
- //return (int) crc1;
- return;
- }
-
-
- /// <summary>
- /// Create an instance of the CRC32 class using the default settings: no
- /// bit reversal, and a polynomial of 0xEDB88320.
- /// </summary>
- public CRC32() : this(false)
- {
- }
-
- /// <summary>
- /// Create an instance of the CRC32 class, specifying whether to reverse
- /// data bits or not.
- /// </summary>
- /// <param name='reverseBits'>
- /// specify true if the instance should reverse data bits.
- /// </param>
- /// <remarks>
- /// <para>
- /// In the CRC-32 used by BZip2, the bits are reversed. Therefore if you
- /// want a CRC32 with compatibility with BZip2, you should pass true
- /// here. In the CRC-32 used by GZIP and PKZIP, the bits are not
- /// reversed; Therefore if you want a CRC32 with compatibility with
- /// those, you should pass false.
- /// </para>
- /// </remarks>
- public CRC32(bool reverseBits) :
- this( unchecked((int)0xEDB88320), reverseBits)
- {
- }
-
-
- /// <summary>
- /// Create an instance of the CRC32 class, specifying the polynomial and
- /// whether to reverse data bits or not.
- /// </summary>
- /// <param name='polynomial'>
- /// The polynomial to use for the CRC, expressed in the reversed (LSB)
- /// format: the highest ordered bit in the polynomial value is the
- /// coefficient of the 0th power; the second-highest order bit is the
- /// coefficient of the 1 power, and so on. Expressed this way, the
- /// polynomial for the CRC-32C used in IEEE 802.3, is 0xEDB88320.
- /// </param>
- /// <param name='reverseBits'>
- /// specify true if the instance should reverse data bits.
- /// </param>
- ///
- /// <remarks>
- /// <para>
- /// In the CRC-32 used by BZip2, the bits are reversed. Therefore if you
- /// want a CRC32 with compatibility with BZip2, you should pass true
- /// here for the <c>reverseBits</c> parameter. In the CRC-32 used by
- /// GZIP and PKZIP, the bits are not reversed; Therefore if you want a
- /// CRC32 with compatibility with those, you should pass false for the
- /// <c>reverseBits</c> parameter.
- /// </para>
- /// </remarks>
- public CRC32(int polynomial, bool reverseBits)
- {
- this.reverseBits = reverseBits;
- this.dwPolynomial = (uint) polynomial;
- this.GenerateLookupTable();
- }
-
- /// <summary>
- /// Reset the CRC-32 class - clear the CRC "remainder register."
- /// </summary>
- /// <remarks>
- /// <para>
- /// Use this when employing a single instance of this class to compute
- /// multiple, distinct CRCs on multiple, distinct data blocks.
- /// </para>
- /// </remarks>
- public void Reset()
- {
- _register = 0xFFFFFFFFU;
- }
-
- // private member vars
- private UInt32 dwPolynomial;
- private Int64 _TotalBytesRead;
- private bool reverseBits;
- private UInt32[] crc32Table;
- private const int BUFFER_SIZE = 8192;
- private UInt32 _register = 0xFFFFFFFFU;
- }
-
-
- /// <summary>
- /// A Stream that calculates a CRC32 (a checksum) on all bytes read,
- /// or on all bytes written.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This class can be used to verify the CRC of a ZipEntry when
- /// reading from a stream, or to calculate a CRC when writing to a
- /// stream. The stream should be used to either read, or write, but
- /// not both. If you intermix reads and writes, the results are not
- /// defined.
- /// </para>
- ///
- /// <para>
- /// This class is intended primarily for use internally by the
- /// DotNetZip library.
- /// </para>
- /// </remarks>
- internal class CrcCalculatorStream : System.IO.Stream, System.IDisposable
- {
- private static readonly Int64 UnsetLengthLimit = -99;
-
- internal System.IO.Stream _innerStream;
- private CRC32 _Crc32;
- private Int64 _lengthLimit = -99;
- private bool _leaveOpen;
-
- /// <summary>
- /// The default constructor.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Instances returned from this constructor will leave the underlying
- /// stream open upon Close(). The stream uses the default CRC32
- /// algorithm, which implies a polynomial of 0xEDB88320.
- /// </para>
- /// </remarks>
- /// <param name="stream">The underlying stream</param>
- public CrcCalculatorStream(System.IO.Stream stream)
- : this(true, CrcCalculatorStream.UnsetLengthLimit, stream, null)
- {
- }
-
- /// <summary>
- /// The constructor allows the caller to specify how to handle the
- /// underlying stream at close.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The stream uses the default CRC32 algorithm, which implies a
- /// polynomial of 0xEDB88320.
- /// </para>
- /// </remarks>
- /// <param name="stream">The underlying stream</param>
- /// <param name="leaveOpen">true to leave the underlying stream
- /// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
- public CrcCalculatorStream(System.IO.Stream stream, bool leaveOpen)
- : this(leaveOpen, CrcCalculatorStream.UnsetLengthLimit, stream, null)
- {
- }
-
- /// <summary>
- /// A constructor allowing the specification of the length of the stream
- /// to read.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The stream uses the default CRC32 algorithm, which implies a
- /// polynomial of 0xEDB88320.
- /// </para>
- /// <para>
- /// Instances returned from this constructor will leave the underlying
- /// stream open upon Close().
- /// </para>
- /// </remarks>
- /// <param name="stream">The underlying stream</param>
- /// <param name="length">The length of the stream to slurp</param>
- public CrcCalculatorStream(System.IO.Stream stream, Int64 length)
- : this(true, length, stream, null)
- {
- if (length < 0)
- throw new ArgumentException("length");
- }
-
- /// <summary>
- /// A constructor allowing the specification of the length of the stream
- /// to read, as well as whether to keep the underlying stream open upon
- /// Close().
- /// </summary>
- /// <remarks>
- /// <para>
- /// The stream uses the default CRC32 algorithm, which implies a
- /// polynomial of 0xEDB88320.
- /// </para>
- /// </remarks>
- /// <param name="stream">The underlying stream</param>
- /// <param name="length">The length of the stream to slurp</param>
- /// <param name="leaveOpen">true to leave the underlying stream
- /// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
- public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen)
- : this(leaveOpen, length, stream, null)
- {
- if (length < 0)
- throw new ArgumentException("length");
- }
-
- /// <summary>
- /// A constructor allowing the specification of the length of the stream
- /// to read, as well as whether to keep the underlying stream open upon
- /// Close(), and the CRC32 instance to use.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The stream uses the specified CRC32 instance, which allows the
- /// application to specify how the CRC gets calculated.
- /// </para>
- /// </remarks>
- /// <param name="stream">The underlying stream</param>
- /// <param name="length">The length of the stream to slurp</param>
- /// <param name="leaveOpen">true to leave the underlying stream
- /// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
- /// <param name="crc32">the CRC32 instance to use to calculate the CRC32</param>
- public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen,
- CRC32 crc32)
- : this(leaveOpen, length, stream, crc32)
- {
- if (length < 0)
- throw new ArgumentException("length");
- }
-
-
- // This ctor is private - no validation is done here. This is to allow the use
- // of a (specific) negative value for the _lengthLimit, to indicate that there
- // is no length set. So we validate the length limit in those ctors that use an
- // explicit param, otherwise we don't validate, because it could be our special
- // value.
- private CrcCalculatorStream
- (bool leaveOpen, Int64 length, System.IO.Stream stream, CRC32 crc32)
- : base()
- {
- _innerStream = stream;
- _Crc32 = crc32 ?? new CRC32();
- _lengthLimit = length;
- _leaveOpen = leaveOpen;
- }
-
-
- /// <summary>
- /// Gets the total number of bytes run through the CRC32 calculator.
- /// </summary>
- ///
- /// <remarks>
- /// This is either the total number of bytes read, or the total number of
- /// bytes written, depending on the direction of this stream.
- /// </remarks>
- public Int64 TotalBytesSlurped
- {
- get { return _Crc32.TotalBytesRead; }
- }
-
- /// <summary>
- /// Provides the current CRC for all blocks slurped in.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The running total of the CRC is kept as data is written or read
- /// through the stream. read this property after all reads or writes to
- /// get an accurate CRC for the entire stream.
- /// </para>
- /// </remarks>
- public Int32 Crc
- {
- get { return _Crc32.Crc32Result; }
- }
-
- /// <summary>
- /// Indicates whether the underlying stream will be left open when the
- /// <c>CrcCalculatorStream</c> is Closed.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Set this at any point before calling <see cref="Close()"/>.
- /// </para>
- /// </remarks>
- public bool LeaveOpen
- {
- get { return _leaveOpen; }
- set { _leaveOpen = value; }
- }
-
- /// <summary>
- /// Read from the stream
- /// </summary>
- /// <param name="buffer">the buffer to read</param>
- /// <param name="offset">the offset at which to start</param>
- /// <param name="count">the number of bytes to read</param>
- /// <returns>the number of bytes actually read</returns>
- public override int Read(byte[] buffer, int offset, int count)
- {
- int bytesToRead = count;
-
- // Need to limit the # of bytes returned, if the stream is intended to have
- // a definite length. This is especially useful when returning a stream for
- // the uncompressed data directly to the application. The app won't
- // necessarily read only the UncompressedSize number of bytes. For example
- // wrapping the stream returned from OpenReader() into a StreadReader() and
- // calling ReadToEnd() on it, We can "over-read" the zip data and get a
- // corrupt string. The length limits that, prevents that problem.
-
- if (_lengthLimit != CrcCalculatorStream.UnsetLengthLimit)
- {
- if (_Crc32.TotalBytesRead >= _lengthLimit) return 0; // EOF
- Int64 bytesRemaining = _lengthLimit - _Crc32.TotalBytesRead;
- if (bytesRemaining < count) bytesToRead = (int)bytesRemaining;
- }
- int n = _innerStream.Read(buffer, offset, bytesToRead);
- if (n > 0) _Crc32.SlurpBlock(buffer, offset, n);
- return n;
- }
-
- /// <summary>
- /// Write to the stream.
- /// </summary>
- /// <param name="buffer">the buffer from which to write</param>
- /// <param name="offset">the offset at which to start writing</param>
- /// <param name="count">the number of bytes to write</param>
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (count > 0) _Crc32.SlurpBlock(buffer, offset, count);
- _innerStream.Write(buffer, offset, count);
- }
-
- /// <summary>
- /// Indicates whether the stream supports reading.
- /// </summary>
- public override bool CanRead
- {
- get { return _innerStream.CanRead; }
- }
-
- /// <summary>
- /// Indicates whether the stream supports seeking.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Always returns false.
- /// </para>
- /// </remarks>
- public override bool CanSeek
- {
- get { return false; }
- }
-
- /// <summary>
- /// Indicates whether the stream supports writing.
- /// </summary>
- public override bool CanWrite
- {
- get { return _innerStream.CanWrite; }
- }
-
- /// <summary>
- /// Flush the stream.
- /// </summary>
- public override void Flush()
- {
- _innerStream.Flush();
- }
-
- /// <summary>
- /// Returns the length of the underlying stream.
- /// </summary>
- public override long Length
- {
- get
- {
- if (_lengthLimit == CrcCalculatorStream.UnsetLengthLimit)
- return _innerStream.Length;
- else return _lengthLimit;
- }
- }
-
- /// <summary>
- /// The getter for this property returns the total bytes read.
- /// If you use the setter, it will throw
- /// <see cref="NotSupportedException"/>.
- /// </summary>
- public override long Position
- {
- get { return _Crc32.TotalBytesRead; }
- set { throw new NotSupportedException(); }
- }
-
- /// <summary>
- /// Seeking is not supported on this stream. This method always throws
- /// <see cref="NotSupportedException"/>
- /// </summary>
- /// <param name="offset">N/A</param>
- /// <param name="origin">N/A</param>
- /// <returns>N/A</returns>
- public override long Seek(long offset, System.IO.SeekOrigin origin)
- {
- throw new NotSupportedException();
- }
-
- /// <summary>
- /// This method always throws
- /// <see cref="NotSupportedException"/>
- /// </summary>
- /// <param name="value">N/A</param>
- public override void SetLength(long value)
- {
- throw new NotSupportedException();
- }
-
-
- void IDisposable.Dispose()
- {
- Close();
- }
-
- /// <summary>
- /// Closes the stream.
- /// </summary>
- public override void Close()
- {
- base.Close();
- if (!_leaveOpen)
- _innerStream.Close();
- }
-
- }
-
-}
\ No newline at end of file
diff --git a/EPPlus/Packaging/DotNetZip/ComHelper.cs b/EPPlus/Packaging/DotNetZip/ComHelper.cs
deleted file mode 100644
index fe2dfdb..0000000
--- a/EPPlus/Packaging/DotNetZip/ComHelper.cs
+++ /dev/null
@@ -1,116 +0,0 @@
-// ComHelper.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-June-13 17:04:06>
-//
-// ------------------------------------------------------------------
-//
-// This module defines a COM Helper class.
-//
-// Created: Tue, 08 Sep 2009 22:03
-//
-
-using Interop=System.Runtime.InteropServices;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- /// <summary>
- /// This class exposes a set of COM-accessible wrappers for static
- /// methods available on the ZipFile class. You don't need this
- /// class unless you are using DotNetZip from a COM environment.
- /// </summary>
- [System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000F")]
- [System.Runtime.InteropServices.ComVisible(true)]
-#if !NETCF
- [System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.AutoDispatch)]
-#endif
-
- internal class ComHelper
- {
- /// <summary>
- /// A wrapper for <see cref="ZipFile.IsZipFile(string)">ZipFile.IsZipFile(string)</see>
- /// </summary>
- /// <param name="filename">The filename to of the zip file to check.</param>
- /// <returns>true if the file contains a valid zip file.</returns>
- public bool IsZipFile(string filename)
- {
- return ZipFile.IsZipFile(filename);
- }
-
- /// <summary>
- /// A wrapper for <see cref="ZipFile.IsZipFile(string, bool)">ZipFile.IsZipFile(string, bool)</see>
- /// </summary>
- /// <remarks>
- /// We cannot use "overloaded" Method names in COM interop.
- /// So, here, we use a unique name.
- /// </remarks>
- /// <param name="filename">The filename to of the zip file to check.</param>
- /// <returns>true if the file contains a valid zip file.</returns>
- public bool IsZipFileWithExtract(string filename)
- {
- return ZipFile.IsZipFile(filename, true);
- }
-
-#if !NETCF
- /// <summary>
- /// A wrapper for <see cref="ZipFile.CheckZip(string)">ZipFile.CheckZip(string)</see>
- /// </summary>
- /// <param name="filename">The filename to of the zip file to check.</param>
- ///
- /// <returns>true if the named zip file checks OK. Otherwise, false. </returns>
- public bool CheckZip(string filename)
- {
- return ZipFile.CheckZip(filename);
- }
-
- /// <summary>
- /// A COM-friendly wrapper for the static method <see cref="ZipFile.CheckZipPassword(string,string)"/>.
- /// </summary>
- ///
- /// <param name="filename">The filename to of the zip file to check.</param>
- ///
- /// <param name="password">The password to check.</param>
- ///
- /// <returns>true if the named zip file checks OK. Otherwise, false. </returns>
- public bool CheckZipPassword(string filename, string password)
- {
- return ZipFile.CheckZipPassword(filename, password);
- }
-
- /// <summary>
- /// A wrapper for <see cref="ZipFile.FixZipDirectory(string)">ZipFile.FixZipDirectory(string)</see>
- /// </summary>
- /// <param name="filename">The filename to of the zip file to fix.</param>
- public void FixZipDirectory(string filename)
- {
- ZipFile.FixZipDirectory(filename);
- }
-#endif
-
- /// <summary>
- /// A wrapper for <see cref="ZipFile.LibraryVersion">ZipFile.LibraryVersion</see>
- /// </summary>
- /// <returns>
- /// the version number on the DotNetZip assembly, formatted as a string.
- /// </returns>
- public string GetZipLibraryVersion()
- {
- return ZipFile.LibraryVersion.ToString();
- }
-
- }
-}
\ No newline at end of file
diff --git a/EPPlus/Packaging/DotNetZip/EncryptionAlgorithm.cs b/EPPlus/Packaging/DotNetZip/EncryptionAlgorithm.cs
deleted file mode 100644
index 1247432..0000000
--- a/EPPlus/Packaging/DotNetZip/EncryptionAlgorithm.cs
+++ /dev/null
@@ -1,135 +0,0 @@
-// EncryptionAlgorithm.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2009-October-21 17:24:45>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the EncryptionAgorithm enum
-//
-//
-// ------------------------------------------------------------------
-
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- /// <summary>
- /// An enum that provides the various encryption algorithms supported by this
- /// library.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// <c>PkzipWeak</c> implies the use of Zip 2.0 encryption, which is known to be
- /// weak and subvertible.
- /// </para>
- ///
- /// <para>
- /// A note on interoperability: Values of <c>PkzipWeak</c> and <c>None</c> are
- /// specified in <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's zip
- /// specification</see>, and are considered to be "standard". Zip archives
- /// produced using these options will be interoperable with many other zip tools
- /// and libraries, including Windows Explorer.
- /// </para>
- ///
- /// <para>
- /// Values of <c>WinZipAes128</c> and <c>WinZipAes256</c> are not part of the Zip
- /// specification, but rather imply the use of a vendor-specific extension from
- /// WinZip. If you want to produce interoperable Zip archives, do not use these
- /// values. For example, if you produce a zip archive using WinZipAes256, you
- /// will be able to open it in Windows Explorer on Windows XP and Vista, but you
- /// will not be able to extract entries; trying this will lead to an "unspecified
- /// error". For this reason, some people have said that a zip archive that uses
- /// WinZip's AES encryption is not actually a zip archive at all. A zip archive
- /// produced this way will be readable with the WinZip tool (Version 11 and
- /// beyond).
- /// </para>
- ///
- /// <para>
- /// There are other third-party tools and libraries, both commercial and
- /// otherwise, that support WinZip's AES encryption. These will be able to read
- /// AES-encrypted zip archives produced by DotNetZip, and conversely applications
- /// that use DotNetZip to read zip archives will be able to read AES-encrypted
- /// archives produced by those tools or libraries. Consult the documentation for
- /// those other tools and libraries to find out if WinZip's AES encryption is
- /// supported.
- /// </para>
- ///
- /// <para>
- /// In case you care: According to <see
- /// href="http://www.winzip.com/aes_info.htm">the WinZip specification</see>, the
- /// actual AES key used is derived from the <see cref="ZipEntry.Password"/> via an
- /// algorithm that complies with <see
- /// href="http://www.ietf.org/rfc/rfc2898.txt">RFC 2898</see>, using an iteration
- /// count of 1000. The algorithm is sometimes referred to as PBKDF2, which stands
- /// for "Password Based Key Derivation Function #2".
- /// </para>
- ///
- /// <para>
- /// A word about password strength and length: The AES encryption technology is
- /// very good, but any system is only as secure as the weakest link. If you want
- /// to secure your data, be sure to use a password that is hard to guess. To make
- /// it harder to guess (increase its "entropy"), you should make it longer. If
- /// you use normal characters from an ASCII keyboard, a password of length 20 will
- /// be strong enough that it will be impossible to guess. For more information on
- /// that, I'd encourage you to read <see
- /// href="http://www.redkestrel.co.uk/Articles/RandomPasswordStrength.html">this
- /// article.</see>
- /// </para>
- ///
- /// <para>
- /// The WinZip AES algorithms are not supported with the version of DotNetZip that
- /// runs on the .NET Compact Framework. This is because .NET CF lacks the
- /// HMACSHA1 class that is required for producing the archive.
- /// </para>
- /// </remarks>
- internal enum EncryptionAlgorithm
- {
- /// <summary>
- /// No encryption at all.
- /// </summary>
- None = 0,
-
- /// <summary>
- /// Traditional or Classic pkzip encryption.
- /// </summary>
- PkzipWeak,
-
-#if AESCRYPTO
- /// <summary>
- /// WinZip AES encryption (128 key bits).
- /// </summary>
- WinZipAes128,
-
- /// <summary>
- /// WinZip AES encryption (256 key bits).
- /// </summary>
- WinZipAes256,
-#endif
-
- /// <summary>
- /// An encryption algorithm that is not supported by DotNetZip.
- /// </summary>
- Unsupported = 4,
-
-
- // others... not implemented (yet?)
- }
-
-}
diff --git a/EPPlus/Packaging/DotNetZip/Events.cs b/EPPlus/Packaging/DotNetZip/Events.cs
deleted file mode 100644
index 7ba296c..0000000
--- a/EPPlus/Packaging/DotNetZip/Events.cs
+++ /dev/null
@@ -1,684 +0,0 @@
-// Events.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2006, 2007, 2008, 2009 Dino Chiesa and Microsoft Corporation.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-August-06 12:26:24>
-//
-// ------------------------------------------------------------------
-//
-// This module defines events used by the ZipFile class.
-//
-//
-
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- /// <summary>
- /// Delegate in which the application writes the <c>ZipEntry</c> content for the named entry.
- /// </summary>
- ///
- /// <param name="entryName">The name of the entry that must be written.</param>
- /// <param name="stream">The stream to which the entry data should be written.</param>
- ///
- /// <remarks>
- /// When you add an entry and specify a <c>WriteDelegate</c>, via <see
- /// cref="Ionic.Zip.ZipFile.AddEntry(string, WriteDelegate)"/>, the application
- /// code provides the logic that writes the entry data directly into the zip file.
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example shows how to define a WriteDelegate that obtains a DataSet, and then
- /// writes the XML for the DataSet into the zip archive. There's no need to
- /// save the XML to a disk file first.
- ///
- /// <code lang="C#">
- /// private void WriteEntry (String filename, Stream output)
- /// {
- /// DataSet ds1 = ObtainDataSet();
- /// ds1.WriteXml(output);
- /// }
- ///
- /// private void Run()
- /// {
- /// using (var zip = new ZipFile())
- /// {
- /// zip.AddEntry(zipEntryName, WriteEntry);
- /// zip.Save(zipFileName);
- /// }
- /// }
- /// </code>
- ///
- /// <code lang="vb">
- /// Private Sub WriteEntry (ByVal filename As String, ByVal output As Stream)
- /// DataSet ds1 = ObtainDataSet()
- /// ds1.WriteXml(stream)
- /// End Sub
- ///
- /// Public Sub Run()
- /// Using zip = New ZipFile
- /// zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry))
- /// zip.Save(zipFileName)
- /// End Using
- /// End Sub
- /// </code>
- /// </example>
- /// <seealso cref="Ionic.Zip.ZipFile.AddEntry(string, WriteDelegate)"/>
- public delegate void WriteDelegate(string entryName, System.IO.Stream stream);
-
-
- /// <summary>
- /// Delegate in which the application opens the stream, just-in-time, for the named entry.
- /// </summary>
- ///
- /// <param name="entryName">
- /// The name of the ZipEntry that the application should open the stream for.
- /// </param>
- ///
- /// <remarks>
- /// When you add an entry via <see cref="Ionic.Zip.ZipFile.AddEntry(string,
- /// OpenDelegate, CloseDelegate)"/>, the application code provides the logic that
- /// opens and closes the stream for the given ZipEntry.
- /// </remarks>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddEntry(string, OpenDelegate, CloseDelegate)"/>
- public delegate System.IO.Stream OpenDelegate(string entryName);
-
- /// <summary>
- /// Delegate in which the application closes the stream, just-in-time, for the named entry.
- /// </summary>
- ///
- /// <param name="entryName">
- /// The name of the ZipEntry that the application should close the stream for.
- /// </param>
- ///
- /// <param name="stream">The stream to be closed.</param>
- ///
- /// <remarks>
- /// When you add an entry via <see cref="Ionic.Zip.ZipFile.AddEntry(string,
- /// OpenDelegate, CloseDelegate)"/>, the application code provides the logic that
- /// opens and closes the stream for the given ZipEntry.
- /// </remarks>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddEntry(string, OpenDelegate, CloseDelegate)"/>
- public delegate void CloseDelegate(string entryName, System.IO.Stream stream);
-
- /// <summary>
- /// Delegate for the callback by which the application tells the
- /// library the CompressionLevel to use for a file.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Using this callback, the application can, for example, specify that
- /// previously-compressed files (.mp3, .png, .docx, etc) should use a
- /// <c>CompressionLevel</c> of <c>None</c>, or can set the compression level based
- /// on any other factor.
- /// </para>
- /// </remarks>
- /// <seealso cref="Ionic.Zip.ZipFile.SetCompression"/>
- public delegate OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel SetCompressionCallback(string localFileName, string fileNameInArchive);
-
- /// <summary>
- /// In an EventArgs type, indicates which sort of progress event is being
- /// reported.
- /// </summary>
- /// <remarks>
- /// There are events for reading, events for saving, and events for
- /// extracting. This enumeration allows a single EventArgs type to be sued to
- /// describe one of multiple subevents. For example, a SaveProgress event is
- /// invoked before, after, and during the saving of a single entry. The value
- /// of an enum with this type, specifies which event is being triggered. The
- /// same applies to Extraction, Reading and Adding events.
- /// </remarks>
- internal enum ZipProgressEventType
- {
- /// <summary>
- /// Indicates that a Add() operation has started.
- /// </summary>
- Adding_Started,
-
- /// <summary>
- /// Indicates that an individual entry in the archive has been added.
- /// </summary>
- Adding_AfterAddEntry,
-
- /// <summary>
- /// Indicates that a Add() operation has completed.
- /// </summary>
- Adding_Completed,
-
- /// <summary>
- /// Indicates that a Read() operation has started.
- /// </summary>
- Reading_Started,
-
- /// <summary>
- /// Indicates that an individual entry in the archive is about to be read.
- /// </summary>
- Reading_BeforeReadEntry,
-
- /// <summary>
- /// Indicates that an individual entry in the archive has just been read.
- /// </summary>
- Reading_AfterReadEntry,
-
- /// <summary>
- /// Indicates that a Read() operation has completed.
- /// </summary>
- Reading_Completed,
-
- /// <summary>
- /// The given event reports the number of bytes read so far
- /// during a Read() operation.
- /// </summary>
- Reading_ArchiveBytesRead,
-
- /// <summary>
- /// Indicates that a Save() operation has started.
- /// </summary>
- Saving_Started,
-
- /// <summary>
- /// Indicates that an individual entry in the archive is about to be written.
- /// </summary>
- Saving_BeforeWriteEntry,
-
- /// <summary>
- /// Indicates that an individual entry in the archive has just been saved.
- /// </summary>
- Saving_AfterWriteEntry,
-
- /// <summary>
- /// Indicates that a Save() operation has completed.
- /// </summary>
- Saving_Completed,
-
- /// <summary>
- /// Indicates that the zip archive has been created in a
- /// temporary location during a Save() operation.
- /// </summary>
- Saving_AfterSaveTempArchive,
-
- /// <summary>
- /// Indicates that the temporary file is about to be renamed to the final archive
- /// name during a Save() operation.
- /// </summary>
- Saving_BeforeRenameTempArchive,
-
- /// <summary>
- /// Indicates that the temporary file is has just been renamed to the final archive
- /// name during a Save() operation.
- /// </summary>
- Saving_AfterRenameTempArchive,
-
- /// <summary>
- /// Indicates that the self-extracting archive has been compiled
- /// during a Save() operation.
- /// </summary>
- Saving_AfterCompileSelfExtractor,
-
- /// <summary>
- /// The given event is reporting the number of source bytes that have run through the compressor so far
- /// during a Save() operation.
- /// </summary>
- Saving_EntryBytesRead,
-
- /// <summary>
- /// Indicates that an entry is about to be extracted.
- /// </summary>
- Extracting_BeforeExtractEntry,
-
- /// <summary>
- /// Indicates that an entry has just been extracted.
- /// </summary>
- Extracting_AfterExtractEntry,
-
- /// <summary>
- /// Indicates that extraction of an entry would overwrite an existing
- /// filesystem file. You must use
- /// <see cref="ExtractExistingFileAction.InvokeExtractProgressEvent">
- /// ExtractExistingFileAction.InvokeExtractProgressEvent</see> in the call
- /// to <c>ZipEntry.Extract()</c> in order to receive this event.
- /// </summary>
- Extracting_ExtractEntryWouldOverwrite,
-
- /// <summary>
- /// The given event is reporting the number of bytes written so far for
- /// the current entry during an Extract() operation.
- /// </summary>
- Extracting_EntryBytesWritten,
-
- /// <summary>
- /// Indicates that an ExtractAll operation is about to begin.
- /// </summary>
- Extracting_BeforeExtractAll,
-
- /// <summary>
- /// Indicates that an ExtractAll operation has completed.
- /// </summary>
- Extracting_AfterExtractAll,
-
- /// <summary>
- /// Indicates that an error has occurred while saving a zip file.
- /// This generally means the file cannot be opened, because it has been
- /// removed, or because it is locked by another process. It can also
- /// mean that the file cannot be Read, because of a range lock conflict.
- /// </summary>
- Error_Saving,
- }
-
-
- /// <summary>
- /// Provides information about the progress of a save, read, or extract operation.
- /// This is a base class; you will probably use one of the classes derived from this one.
- /// </summary>
- internal class ZipProgressEventArgs : EventArgs
- {
- private int _entriesTotal;
- private bool _cancel;
- private ZipEntry _latestEntry;
- private ZipProgressEventType _flavor;
- private String _archiveName;
- private Int64 _bytesTransferred;
- private Int64 _totalBytesToTransfer;
-
-
- internal ZipProgressEventArgs() { }
-
- internal ZipProgressEventArgs(string archiveName, ZipProgressEventType flavor)
- {
- this._archiveName = archiveName;
- this._flavor = flavor;
- }
-
- /// <summary>
- /// The total number of entries to be saved or extracted.
- /// </summary>
- public int EntriesTotal
- {
- get { return _entriesTotal; }
- set { _entriesTotal = value; }
- }
-
- /// <summary>
- /// The name of the last entry saved or extracted.
- /// </summary>
- public ZipEntry CurrentEntry
- {
- get { return _latestEntry; }
- set { _latestEntry = value; }
- }
-
- /// <summary>
- /// In an event handler, set this to cancel the save or extract
- /// operation that is in progress.
- /// </summary>
- public bool Cancel
- {
- get { return _cancel; }
- set { _cancel = _cancel || value; }
- }
-
- /// <summary>
- /// The type of event being reported.
- /// </summary>
- public ZipProgressEventType EventType
- {
- get { return _flavor; }
- set { _flavor = value; }
- }
-
- /// <summary>
- /// Returns the archive name associated to this event.
- /// </summary>
- public String ArchiveName
- {
- get { return _archiveName; }
- set { _archiveName = value; }
- }
-
-
- /// <summary>
- /// The number of bytes read or written so far for this entry.
- /// </summary>
- public Int64 BytesTransferred
- {
- get { return _bytesTransferred; }
- set { _bytesTransferred = value; }
- }
-
-
-
- /// <summary>
- /// Total number of bytes that will be read or written for this entry.
- /// This number will be -1 if the value cannot be determined.
- /// </summary>
- public Int64 TotalBytesToTransfer
- {
- get { return _totalBytesToTransfer; }
- set { _totalBytesToTransfer = value; }
- }
- }
-
-
-
- /// <summary>
- /// Provides information about the progress of a Read operation.
- /// </summary>
- internal class ReadProgressEventArgs : ZipProgressEventArgs
- {
-
- internal ReadProgressEventArgs() { }
-
- private ReadProgressEventArgs(string archiveName, ZipProgressEventType flavor)
- : base(archiveName, flavor)
- { }
-
- internal static ReadProgressEventArgs Before(string archiveName, int entriesTotal)
- {
- var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_BeforeReadEntry);
- x.EntriesTotal = entriesTotal;
- return x;
- }
-
- internal static ReadProgressEventArgs After(string archiveName, ZipEntry entry, int entriesTotal)
- {
- var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_AfterReadEntry);
- x.EntriesTotal = entriesTotal;
- x.CurrentEntry = entry;
- return x;
- }
-
- internal static ReadProgressEventArgs Started(string archiveName)
- {
- var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_Started);
- return x;
- }
-
- internal static ReadProgressEventArgs ByteUpdate(string archiveName, ZipEntry entry, Int64 bytesXferred, Int64 totalBytes)
- {
- var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_ArchiveBytesRead);
- x.CurrentEntry = entry;
- x.BytesTransferred = bytesXferred;
- x.TotalBytesToTransfer = totalBytes;
- return x;
- }
-
- internal static ReadProgressEventArgs Completed(string archiveName)
- {
- var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_Completed);
- return x;
- }
-
- }
-
-
- /// <summary>
- /// Provides information about the progress of a Add operation.
- /// </summary>
- internal class AddProgressEventArgs : ZipProgressEventArgs
- {
- internal AddProgressEventArgs() { }
-
- private AddProgressEventArgs(string archiveName, ZipProgressEventType flavor)
- : base(archiveName, flavor)
- { }
-
- internal static AddProgressEventArgs AfterEntry(string archiveName, ZipEntry entry, int entriesTotal)
- {
- var x = new AddProgressEventArgs(archiveName, ZipProgressEventType.Adding_AfterAddEntry);
- x.EntriesTotal = entriesTotal;
- x.CurrentEntry = entry;
- return x;
- }
-
- internal static AddProgressEventArgs Started(string archiveName)
- {
- var x = new AddProgressEventArgs(archiveName, ZipProgressEventType.Adding_Started);
- return x;
- }
-
- internal static AddProgressEventArgs Completed(string archiveName)
- {
- var x = new AddProgressEventArgs(archiveName, ZipProgressEventType.Adding_Completed);
- return x;
- }
-
- }
-
- /// <summary>
- /// Provides information about the progress of a save operation.
- /// </summary>
- internal class SaveProgressEventArgs : ZipProgressEventArgs
- {
- private int _entriesSaved;
-
- /// <summary>
- /// Constructor for the SaveProgressEventArgs.
- /// </summary>
- /// <param name="archiveName">the name of the zip archive.</param>
- /// <param name="before">whether this is before saving the entry, or after</param>
- /// <param name="entriesTotal">The total number of entries in the zip archive.</param>
- /// <param name="entriesSaved">Number of entries that have been saved.</param>
- /// <param name="entry">The entry involved in the event.</param>
- internal SaveProgressEventArgs(string archiveName, bool before, int entriesTotal, int entriesSaved, ZipEntry entry)
- : base(archiveName, (before) ? ZipProgressEventType.Saving_BeforeWriteEntry : ZipProgressEventType.Saving_AfterWriteEntry)
- {
- this.EntriesTotal = entriesTotal;
- this.CurrentEntry = entry;
- this._entriesSaved = entriesSaved;
- }
-
- internal SaveProgressEventArgs() { }
-
- internal SaveProgressEventArgs(string archiveName, ZipProgressEventType flavor)
- : base(archiveName, flavor)
- { }
-
-
- internal static SaveProgressEventArgs ByteUpdate(string archiveName, ZipEntry entry, Int64 bytesXferred, Int64 totalBytes)
- {
- var x = new SaveProgressEventArgs(archiveName, ZipProgressEventType.Saving_EntryBytesRead);
- x.ArchiveName = archiveName;
- x.CurrentEntry = entry;
- x.BytesTransferred = bytesXferred;
- x.TotalBytesToTransfer = totalBytes;
- return x;
- }
-
- internal static SaveProgressEventArgs Started(string archiveName)
- {
- var x = new SaveProgressEventArgs(archiveName, ZipProgressEventType.Saving_Started);
- return x;
- }
-
- internal static SaveProgressEventArgs Completed(string archiveName)
- {
- var x = new SaveProgressEventArgs(archiveName, ZipProgressEventType.Saving_Completed);
- return x;
- }
-
- /// <summary>
- /// Number of entries saved so far.
- /// </summary>
- public int EntriesSaved
- {
- get { return _entriesSaved; }
- }
- }
-
-
- /// <summary>
- /// Provides information about the progress of the extract operation.
- /// </summary>
- internal class ExtractProgressEventArgs : ZipProgressEventArgs
- {
- private int _entriesExtracted;
- private string _target;
-
- /// <summary>
- /// Constructor for the ExtractProgressEventArgs.
- /// </summary>
- /// <param name="archiveName">the name of the zip archive.</param>
- /// <param name="before">whether this is before saving the entry, or after</param>
- /// <param name="entriesTotal">The total number of entries in the zip archive.</param>
- /// <param name="entriesExtracted">Number of entries that have been extracted.</param>
- /// <param name="entry">The entry involved in the event.</param>
- /// <param name="extractLocation">The location to which entries are extracted.</param>
- internal ExtractProgressEventArgs(string archiveName, bool before, int entriesTotal, int entriesExtracted, ZipEntry entry, string extractLocation)
- : base(archiveName, (before) ? ZipProgressEventType.Extracting_BeforeExtractEntry : ZipProgressEventType.Extracting_AfterExtractEntry)
- {
- this.EntriesTotal = entriesTotal;
- this.CurrentEntry = entry;
- this._entriesExtracted = entriesExtracted;
- this._target = extractLocation;
- }
-
- internal ExtractProgressEventArgs(string archiveName, ZipProgressEventType flavor)
- : base(archiveName, flavor)
- { }
-
- internal ExtractProgressEventArgs()
- { }
-
-
- internal static ExtractProgressEventArgs BeforeExtractEntry(string archiveName, ZipEntry entry, string extractLocation)
- {
- var x = new ExtractProgressEventArgs
- {
- ArchiveName = archiveName,
- EventType = ZipProgressEventType.Extracting_BeforeExtractEntry,
- CurrentEntry = entry,
- _target = extractLocation,
- };
- return x;
- }
-
- internal static ExtractProgressEventArgs ExtractExisting(string archiveName, ZipEntry entry, string extractLocation)
- {
- var x = new ExtractProgressEventArgs
- {
- ArchiveName = archiveName,
- EventType = ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite,
- CurrentEntry = entry,
- _target = extractLocation,
- };
- return x;
- }
-
- internal static ExtractProgressEventArgs AfterExtractEntry(string archiveName, ZipEntry entry, string extractLocation)
- {
- var x = new ExtractProgressEventArgs
- {
- ArchiveName = archiveName,
- EventType = ZipProgressEventType.Extracting_AfterExtractEntry,
- CurrentEntry = entry,
- _target = extractLocation,
- };
- return x;
- }
-
- internal static ExtractProgressEventArgs ExtractAllStarted(string archiveName, string extractLocation)
- {
- var x = new ExtractProgressEventArgs(archiveName, ZipProgressEventType.Extracting_BeforeExtractAll);
- x._target = extractLocation;
- return x;
- }
-
- internal static ExtractProgressEventArgs ExtractAllCompleted(string archiveName, string extractLocation)
- {
- var x = new ExtractProgressEventArgs(archiveName, ZipProgressEventType.Extracting_AfterExtractAll);
- x._target = extractLocation;
- return x;
- }
-
-
- internal static ExtractProgressEventArgs ByteUpdate(string archiveName, ZipEntry entry, Int64 bytesWritten, Int64 totalBytes)
- {
- var x = new ExtractProgressEventArgs(archiveName, ZipProgressEventType.Extracting_EntryBytesWritten);
- x.ArchiveName = archiveName;
- x.CurrentEntry = entry;
- x.BytesTransferred = bytesWritten;
- x.TotalBytesToTransfer = totalBytes;
- return x;
- }
-
-
-
- /// <summary>
- /// Number of entries extracted so far. This is set only if the
- /// EventType is Extracting_BeforeExtractEntry or Extracting_AfterExtractEntry, and
- /// the Extract() is occurring witin the scope of a call to ExtractAll().
- /// </summary>
- public int EntriesExtracted
- {
- get { return _entriesExtracted; }
- }
-
- /// <summary>
- /// Returns the extraction target location, a filesystem path.
- /// </summary>
- public String ExtractLocation
- {
- get { return _target; }
- }
-
- }
-
-
-
- /// <summary>
- /// Provides information about the an error that occurred while zipping.
- /// </summary>
- internal class ZipErrorEventArgs : ZipProgressEventArgs
- {
- private Exception _exc;
- private ZipErrorEventArgs() { }
- internal static ZipErrorEventArgs Saving(string archiveName, ZipEntry entry, Exception exception)
- {
- var x = new ZipErrorEventArgs
- {
- EventType = ZipProgressEventType.Error_Saving,
- ArchiveName = archiveName,
- CurrentEntry = entry,
- _exc = exception
- };
- return x;
- }
-
- /// <summary>
- /// Returns the exception that occurred, if any.
- /// </summary>
- public Exception @Exception
- {
- get { return _exc; }
- }
-
- /// <summary>
- /// Returns the name of the file that caused the exception, if any.
- /// </summary>
- public String FileName
- {
- get { return CurrentEntry.LocalFileName; }
- }
- }
-
-
-}
diff --git a/EPPlus/Packaging/DotNetZip/Exceptions.cs b/EPPlus/Packaging/DotNetZip/Exceptions.cs
deleted file mode 100644
index a5a2c81..0000000
--- a/EPPlus/Packaging/DotNetZip/Exceptions.cs
+++ /dev/null
@@ -1,300 +0,0 @@
-// Exceptions.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2008, 2009 Dino Chiesa and Microsoft Corporation.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-July-12 12:19:10>
-//
-// ------------------------------------------------------------------
-//
-// This module defines exceptions used in the class library.
-//
-
-
-
-using System;
-using System.Collections.Generic;
-using System.Text;
-#if !NETCF
-using System.Runtime.Serialization;
-#endif
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- ///// <summary>
- ///// Base exception type for all custom exceptions in the Zip library. It acts as a marker class.
- ///// </summary>
- //[AttributeUsage(AttributeTargets.Class)]
- //public class ZipExceptionAttribute : Attribute { }
-
-
-
- /// <summary>
- /// Issued when an <c>ZipEntry.ExtractWithPassword()</c> method is invoked
- /// with an incorrect password.
- /// </summary>
-#if !SILVERLIGHT
- [Serializable]
-#endif
- [System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000B")]
- public class BadPasswordException : ZipException
- {
- /// <summary>
- /// Default ctor.
- /// </summary>
- public BadPasswordException() { }
-
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="message">The message in the exception.</param>
- public BadPasswordException(String message)
- : base(message)
- { }
-
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="message">The message in the exception.</param>
- /// <param name="innerException">The innerException for this exception.</param>
- public BadPasswordException(String message, Exception innerException)
- : base(message, innerException)
- {
- }
-
-
-#if ! (NETCF || SILVERLIGHT)
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="info">The serialization info for the exception.</param>
- /// <param name="context">The streaming context from which to deserialize.</param>
- protected BadPasswordException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- { }
-#endif
-
- }
-
- /// <summary>
- /// Indicates that a read was attempted on a stream, and bad or incomplete data was
- /// received.
- /// </summary>
-#if !SILVERLIGHT
- [Serializable]
-#endif
- [System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000A")]
- public class BadReadException : ZipException
- {
- /// <summary>
- /// Default ctor.
- /// </summary>
- public BadReadException() { }
-
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="message">The message in the exception.</param>
- public BadReadException(String message)
- : base(message)
- { }
-
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="message">The message in the exception.</param>
- /// <param name="innerException">The innerException for this exception.</param>
- public BadReadException(String message, Exception innerException)
- : base(message, innerException)
- {
- }
-
-#if ! (NETCF || SILVERLIGHT)
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="info">The serialization info for the exception.</param>
- /// <param name="context">The streaming context from which to deserialize.</param>
- protected BadReadException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- { }
-#endif
-
- }
-
-
-
- /// <summary>
- /// Issued when an CRC check fails upon extracting an entry from a zip archive.
- /// </summary>
-#if !SILVERLIGHT
- [Serializable]
-#endif
- [System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00009")]
- public class BadCrcException : ZipException
- {
- /// <summary>
- /// Default ctor.
- /// </summary>
- public BadCrcException() { }
-
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="message">The message in the exception.</param>
- public BadCrcException(String message)
- : base(message)
- { }
-
-
-#if ! (NETCF || SILVERLIGHT)
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="info">The serialization info for the exception.</param>
- /// <param name="context">The streaming context from which to deserialize.</param>
- protected BadCrcException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- { }
-#endif
-
- }
-
-
- /// <summary>
- /// Issued when errors occur saving a self-extracting archive.
- /// </summary>
-#if !SILVERLIGHT
- [Serializable]
-#endif
- [System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00008")]
- public class SfxGenerationException : ZipException
- {
- /// <summary>
- /// Default ctor.
- /// </summary>
- public SfxGenerationException() { }
-
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="message">The message in the exception.</param>
- public SfxGenerationException(String message)
- : base(message)
- { }
-
-#if ! (NETCF || SILVERLIGHT)
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="info">The serialization info for the exception.</param>
- /// <param name="context">The streaming context from which to deserialize.</param>
- protected SfxGenerationException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- { }
-#endif
-
- }
-
-
- /// <summary>
- /// Indicates that an operation was attempted on a ZipFile which was not possible
- /// given the state of the instance. For example, if you call <c>Save()</c> on a ZipFile
- /// which has no filename set, you can get this exception.
- /// </summary>
-#if !SILVERLIGHT
- [Serializable]
-#endif
- [System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00007")]
- public class BadStateException : ZipException
- {
- /// <summary>
- /// Default ctor.
- /// </summary>
- public BadStateException() { }
-
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="message">The message in the exception.</param>
- public BadStateException(String message)
- : base(message)
- { }
-
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="message">The message in the exception.</param>
- /// <param name="innerException">The innerException for this exception.</param>
- public BadStateException(String message, Exception innerException)
- : base(message, innerException)
- {}
-
-#if ! (NETCF || SILVERLIGHT)
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="info">The serialization info for the exception.</param>
- /// <param name="context">The streaming context from which to deserialize.</param>
- protected BadStateException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- { }
-#endif
-
- }
-
- /// <summary>
- /// Base class for all exceptions defined by and throw by the Zip library.
- /// </summary>
-#if !SILVERLIGHT
- [Serializable]
-#endif
- [System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00006")]
- public class ZipException : Exception
- {
- /// <summary>
- /// Default ctor.
- /// </summary>
- public ZipException() { }
-
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="message">The message in the exception.</param>
- public ZipException(String message) : base(message) { }
-
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="message">The message in the exception.</param>
- /// <param name="innerException">The innerException for this exception.</param>
- public ZipException(String message, Exception innerException)
- : base(message, innerException)
- { }
-
-#if ! (NETCF || SILVERLIGHT)
- /// <summary>
- /// Come on, you know how exceptions work. Why are you looking at this documentation?
- /// </summary>
- /// <param name="info">The serialization info for the exception.</param>
- /// <param name="context">The streaming context from which to deserialize.</param>
- protected ZipException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- { }
-#endif
-
- }
-
-}
diff --git a/EPPlus/Packaging/DotNetZip/ExtractExistingFileAction.cs b/EPPlus/Packaging/DotNetZip/ExtractExistingFileAction.cs
deleted file mode 100644
index 3b4af1a..0000000
--- a/EPPlus/Packaging/DotNetZip/ExtractExistingFileAction.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-// ExtractExistingFileAction.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2009-August-25 08:44:37>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the ExtractExistingFileAction enum
-//
-//
-// ------------------------------------------------------------------
-
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
-
- /// <summary>
- /// An enum for the options when extracting an entry would overwrite an existing file.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This enum describes the actions that the library can take when an
- /// <c>Extract()</c> or <c>ExtractWithPassword()</c> method is called to extract an
- /// entry to a filesystem, and the extraction would overwrite an existing filesystem
- /// file.
- /// </para>
- /// </remarks>
- ///
- internal enum ExtractExistingFileAction
- {
- /// <summary>
- /// Throw an exception when extraction would overwrite an existing file. (For
- /// COM clients, this is a 0 (zero).)
- /// </summary>
- Throw,
-
- /// <summary>
- /// When extraction would overwrite an existing file, overwrite the file silently.
- /// The overwrite will happen even if the target file is marked as read-only.
- /// (For COM clients, this is a 1.)
- /// </summary>
- OverwriteSilently,
-
- /// <summary>
- /// When extraction would overwrite an existing file, don't overwrite the file, silently.
- /// (For COM clients, this is a 2.)
- /// </summary>
- DoNotOverwrite,
-
- /// <summary>
- /// When extraction would overwrite an existing file, invoke the ExtractProgress
- /// event, using an event type of <see
- /// cref="ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite"/>. In
- /// this way, the application can decide, just-in-time, whether to overwrite the
- /// file. For example, a GUI application may wish to pop up a dialog to allow
- /// the user to choose. You may want to examine the <see
- /// cref="ExtractProgressEventArgs.ExtractLocation"/> property before making
- /// the decision. If, after your processing in the Extract progress event, you
- /// want to NOT extract the file, set <see cref="ZipEntry.ExtractExistingFile"/>
- /// on the <c>ZipProgressEventArgs.CurrentEntry</c> to <c>DoNotOverwrite</c>.
- /// If you do want to extract the file, set <c>ZipEntry.ExtractExistingFile</c>
- /// to <c>OverwriteSilently</c>. If you want to cancel the Extraction, set
- /// <c>ZipProgressEventArgs.Cancel</c> to true. Cancelling differs from using
- /// DoNotOverwrite in that a cancel will not extract any further entries, if
- /// there are any. (For COM clients, the value of this enum is a 3.)
- /// </summary>
- InvokeExtractProgressEvent,
- }
-
-}
diff --git a/EPPlus/Packaging/DotNetZip/FileSelector.cs b/EPPlus/Packaging/DotNetZip/FileSelector.cs
deleted file mode 100644
index 85d5fcc..0000000
--- a/EPPlus/Packaging/DotNetZip/FileSelector.cs
+++ /dev/null
@@ -1,1609 +0,0 @@
-//#define SelectorTrace
-
-// FileSelector.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2008-2011 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved: <2011-August-05 11:03:11>
-//
-// ------------------------------------------------------------------
-//
-// This module implements a "file selector" that finds files based on a
-// set of inclusion criteria, including filename, size, file time, and
-// potentially file attributes. The criteria are given in a string with
-// a simple expression language. Examples:
-//
-// find all .txt files:
-// name = *.txt
-//
-// shorthand for the above
-// *.txt
-//
-// all files modified after January 1st, 2009
-// mtime > 2009-01-01
-//
-// All .txt files modified after the first of the year
-// name = *.txt AND mtime > 2009-01-01
-//
-// All .txt files modified after the first of the year, or any file with the archive bit set
-// (name = *.txt AND mtime > 2009-01-01) or (attribtues = A)
-//
-// All .txt files or any file greater than 1mb in size
-// (name = *.txt or size > 1mb)
-//
-// and so on.
-// ------------------------------------------------------------------
-
-
-using System;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using System.Reflection;
-using System.ComponentModel;
-using System.Text.RegularExpressions;
-using System.Collections.Generic;
-#if SILVERLIGHT
-using System.Linq;
-#endif
-
-namespace OfficeOpenXml.Packaging.Ionic
-{
-
- /// <summary>
- /// Enumerates the options for a logical conjunction. This enum is intended for use
- /// internally by the FileSelector class.
- /// </summary>
- internal enum LogicalConjunction
- {
- NONE,
- AND,
- OR,
- XOR,
- }
-
- internal enum WhichTime
- {
- atime,
- mtime,
- ctime,
- }
-
-
- internal enum ComparisonOperator
- {
- [Description(">")]
- GreaterThan,
- [Description(">=")]
- GreaterThanOrEqualTo,
- [Description("<")]
- LesserThan,
- [Description("<=")]
- LesserThanOrEqualTo,
- [Description("=")]
- EqualTo,
- [Description("!=")]
- NotEqualTo
- }
-
-
- internal abstract partial class SelectionCriterion
- {
- internal virtual bool Verbose
- {
- get;set;
- }
- internal abstract bool Evaluate(string filename);
-
- [System.Diagnostics.Conditional("SelectorTrace")]
- protected static void CriterionTrace(string format, params object[] args)
- {
- //System.Console.WriteLine(" " + format, args);
- }
- }
-
-
- internal partial class SizeCriterion : SelectionCriterion
- {
- internal ComparisonOperator Operator;
- internal Int64 Size;
-
- public override String ToString()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append("size ").Append(EnumUtil.GetDescription(Operator)).Append(" ").Append(Size.ToString());
- return sb.ToString();
- }
-
- internal override bool Evaluate(string filename)
- {
- System.IO.FileInfo fi = new System.IO.FileInfo(filename);
- CriterionTrace("SizeCriterion::Evaluate('{0}' [{1}])",
- filename, this.ToString());
- return _Evaluate(fi.Length);
- }
-
- private bool _Evaluate(Int64 Length)
- {
- bool result = false;
- switch (Operator)
- {
- case ComparisonOperator.GreaterThanOrEqualTo:
- result = Length >= Size;
- break;
- case ComparisonOperator.GreaterThan:
- result = Length > Size;
- break;
- case ComparisonOperator.LesserThanOrEqualTo:
- result = Length <= Size;
- break;
- case ComparisonOperator.LesserThan:
- result = Length < Size;
- break;
- case ComparisonOperator.EqualTo:
- result = Length == Size;
- break;
- case ComparisonOperator.NotEqualTo:
- result = Length != Size;
- break;
- default:
- throw new ArgumentException("Operator");
- }
- return result;
- }
-
- }
-
-
-
- internal partial class TimeCriterion : SelectionCriterion
- {
- internal ComparisonOperator Operator;
- internal WhichTime Which;
- internal DateTime Time;
-
- public override String ToString()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append(Which.ToString()).Append(" ").Append(EnumUtil.GetDescription(Operator)).Append(" ").Append(Time.ToString("yyyy-MM-dd-HH:mm:ss"));
- return sb.ToString();
- }
-
- internal override bool Evaluate(string filename)
- {
- DateTime x;
- switch (Which)
- {
- case WhichTime.atime:
- x = System.IO.File.GetLastAccessTime(filename).ToUniversalTime();
- break;
- case WhichTime.mtime:
- x = System.IO.File.GetLastWriteTime(filename).ToUniversalTime();
- break;
- case WhichTime.ctime:
- x = System.IO.File.GetCreationTime(filename).ToUniversalTime();
- break;
- default:
- throw new ArgumentException("Operator");
- }
- CriterionTrace("TimeCriterion({0},{1})= {2}", filename, Which.ToString(), x);
- return _Evaluate(x);
- }
-
-
- private bool _Evaluate(DateTime x)
- {
- bool result = false;
- switch (Operator)
- {
- case ComparisonOperator.GreaterThanOrEqualTo:
- result = (x >= Time);
- break;
- case ComparisonOperator.GreaterThan:
- result = (x > Time);
- break;
- case ComparisonOperator.LesserThanOrEqualTo:
- result = (x <= Time);
- break;
- case ComparisonOperator.LesserThan:
- result = (x < Time);
- break;
- case ComparisonOperator.EqualTo:
- result = (x == Time);
- break;
- case ComparisonOperator.NotEqualTo:
- result = (x != Time);
- break;
- default:
- throw new ArgumentException("Operator");
- }
-
- CriterionTrace("TimeCriterion: {0}", result);
- return result;
- }
- }
-
-
-
- internal partial class NameCriterion : SelectionCriterion
- {
- private Regex _re;
- private String _regexString;
- internal ComparisonOperator Operator;
- private string _MatchingFileSpec;
- internal virtual string MatchingFileSpec
- {
- set
- {
- // workitem 8245
- if (Directory.Exists(value))
- {
- _MatchingFileSpec = ".\\" + value + "\\*.*";
- }
- else
- {
- _MatchingFileSpec = value;
- }
-
- _regexString = "^" +
- Regex.Escape(_MatchingFileSpec)
- .Replace(@"\\\*\.\*", @"\\([^\.]+|.*\.[^\\\.]*)")
- .Replace(@"\.\*", @"\.[^\\\.]*")
- .Replace(@"\*", @".*")
- //.Replace(@"\*", @"[^\\\.]*") // ill-conceived
- .Replace(@"\?", @"[^\\\.]")
- + "$";
-
- CriterionTrace("NameCriterion regexString({0})", _regexString);
-
- _re = new Regex(_regexString, RegexOptions.IgnoreCase);
- }
- }
-
-
- public override String ToString()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append("name ").Append(EnumUtil.GetDescription(Operator))
- .Append(" '")
- .Append(_MatchingFileSpec)
- .Append("'");
- return sb.ToString();
- }
-
-
- internal override bool Evaluate(string filename)
- {
- CriterionTrace("NameCriterion::Evaluate('{0}' pattern[{1}])",
- filename, _MatchingFileSpec);
- return _Evaluate(filename);
- }
-
- private bool _Evaluate(string fullpath)
- {
- CriterionTrace("NameCriterion::Evaluate({0})", fullpath);
- // No slash in the pattern implicitly means recurse, which means compare to
- // filename only, not full path.
- String f = (_MatchingFileSpec.IndexOf('\\') == -1)
- ? System.IO.Path.GetFileName(fullpath)
- : fullpath; // compare to fullpath
-
- bool result = _re.IsMatch(f);
-
- if (Operator != ComparisonOperator.EqualTo)
- result = !result;
- return result;
- }
- }
-
-
- internal partial class TypeCriterion : SelectionCriterion
- {
- private char ObjectType; // 'D' = Directory, 'F' = File
- internal ComparisonOperator Operator;
- internal string AttributeString
- {
- get
- {
- return ObjectType.ToString();
- }
- set
- {
- if (value.Length != 1 ||
- (value[0]!='D' && value[0]!='F'))
- throw new ArgumentException("Specify a single character: either D or F");
- ObjectType = value[0];
- }
- }
-
- public override String ToString()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append("type ").Append(EnumUtil.GetDescription(Operator)).Append(" ").Append(AttributeString);
- return sb.ToString();
- }
-
- internal override bool Evaluate(string filename)
- {
- CriterionTrace("TypeCriterion::Evaluate({0})", filename);
-
- bool result = (ObjectType == 'D')
- ? Directory.Exists(filename)
- : File.Exists(filename);
-
- if (Operator != ComparisonOperator.EqualTo)
- result = !result;
- return result;
- }
- }
-
-
-#if !SILVERLIGHT
- internal partial class AttributesCriterion : SelectionCriterion
- {
- private FileAttributes _Attributes;
- internal ComparisonOperator Operator;
- internal string AttributeString
- {
- get
- {
- string result = "";
- if ((_Attributes & FileAttributes.Hidden) != 0)
- result += "H";
- if ((_Attributes & FileAttributes.System) != 0)
- result += "S";
- if ((_Attributes & FileAttributes.ReadOnly) != 0)
- result += "R";
- if ((_Attributes & FileAttributes.Archive) != 0)
- result += "A";
- if ((_Attributes & FileAttributes.ReparsePoint) != 0)
- result += "L";
- if ((_Attributes & FileAttributes.NotContentIndexed) != 0)
- result += "I";
- return result;
- }
-
- set
- {
- _Attributes = FileAttributes.Normal;
- foreach (char c in value.ToUpper(CultureInfo.InvariantCulture))
- {
- switch (c)
- {
- case 'H':
- if ((_Attributes & FileAttributes.Hidden) != 0)
- throw new ArgumentException(String.Format("Repeated flag. ({0})", c), "value");
- _Attributes |= FileAttributes.Hidden;
- break;
-
- case 'R':
- if ((_Attributes & FileAttributes.ReadOnly) != 0)
- throw new ArgumentException(String.Format("Repeated flag. ({0})", c), "value");
- _Attributes |= FileAttributes.ReadOnly;
- break;
-
- case 'S':
- if ((_Attributes & FileAttributes.System) != 0)
- throw new ArgumentException(String.Format("Repeated flag. ({0})", c), "value");
- _Attributes |= FileAttributes.System;
- break;
-
- case 'A':
- if ((_Attributes & FileAttributes.Archive) != 0)
- throw new ArgumentException(String.Format("Repeated flag. ({0})", c), "value");
- _Attributes |= FileAttributes.Archive;
- break;
-
- case 'I':
- if ((_Attributes & FileAttributes.NotContentIndexed) != 0)
- throw new ArgumentException(String.Format("Repeated flag. ({0})", c), "value");
- _Attributes |= FileAttributes.NotContentIndexed;
- break;
-
- case 'L':
- if ((_Attributes & FileAttributes.ReparsePoint) != 0)
- throw new ArgumentException(String.Format("Repeated flag. ({0})", c), "value");
- _Attributes |= FileAttributes.ReparsePoint;
- break;
-
- default:
- throw new ArgumentException(value);
- }
- }
- }
- }
-
-
- public override String ToString()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append("attributes ").Append(EnumUtil.GetDescription(Operator)).Append(" ").Append(AttributeString);
- return sb.ToString();
- }
-
- private bool _EvaluateOne(FileAttributes fileAttrs, FileAttributes criterionAttrs)
- {
- bool result = false;
- if ((_Attributes & criterionAttrs) == criterionAttrs)
- result = ((fileAttrs & criterionAttrs) == criterionAttrs);
- else
- result = true;
- return result;
- }
-
-
-
- internal override bool Evaluate(string filename)
- {
- // workitem 10191
- if (Directory.Exists(filename))
- {
- // Directories don't have file attributes, so the result
- // of an evaluation is always NO. This gets negated if
- // the operator is NotEqualTo.
- return (Operator != ComparisonOperator.EqualTo);
- }
-#if NETCF
- FileAttributes fileAttrs = NetCfFile.GetAttributes(filename);
-#else
- FileAttributes fileAttrs = System.IO.File.GetAttributes(filename);
-#endif
-
- return _Evaluate(fileAttrs);
- }
-
- private bool _Evaluate(FileAttributes fileAttrs)
- {
- bool result = _EvaluateOne(fileAttrs, FileAttributes.Hidden);
- if (result)
- result = _EvaluateOne(fileAttrs, FileAttributes.System);
- if (result)
- result = _EvaluateOne(fileAttrs, FileAttributes.ReadOnly);
- if (result)
- result = _EvaluateOne(fileAttrs, FileAttributes.Archive);
- if (result)
- result = _EvaluateOne(fileAttrs, FileAttributes.NotContentIndexed);
- if (result)
- result = _EvaluateOne(fileAttrs, FileAttributes.ReparsePoint);
-
- if (Operator != ComparisonOperator.EqualTo)
- result = !result;
-
- return result;
- }
- }
-#endif
-
-
- internal partial class CompoundCriterion : SelectionCriterion
- {
- internal LogicalConjunction Conjunction;
- internal SelectionCriterion Left;
-
- private SelectionCriterion _Right;
- internal SelectionCriterion Right
- {
- get { return _Right; }
- set
- {
- _Right = value;
- if (value == null)
- Conjunction = LogicalConjunction.NONE;
- else if (Conjunction == LogicalConjunction.NONE)
- Conjunction = LogicalConjunction.AND;
- }
- }
-
-
- internal override bool Evaluate(string filename)
- {
- bool result = Left.Evaluate(filename);
- switch (Conjunction)
- {
- case LogicalConjunction.AND:
- if (result)
- result = Right.Evaluate(filename);
- break;
- case LogicalConjunction.OR:
- if (!result)
- result = Right.Evaluate(filename);
- break;
- case LogicalConjunction.XOR:
- result ^= Right.Evaluate(filename);
- break;
- default:
- throw new ArgumentException("Conjunction");
- }
- return result;
- }
-
-
- public override String ToString()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append("(")
- .Append((Left != null) ? Left.ToString() : "null")
- .Append(" ")
- .Append(Conjunction.ToString())
- .Append(" ")
- .Append((Right != null) ? Right.ToString() : "null")
- .Append(")");
- return sb.ToString();
- }
- }
-
-
-
- /// <summary>
- /// FileSelector encapsulates logic that selects files from a source - a zip file
- /// or the filesystem - based on a set of criteria. This class is used internally
- /// by the DotNetZip library, in particular for the AddSelectedFiles() methods.
- /// This class can also be used independently of the zip capability in DotNetZip.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// The FileSelector class is used internally by the ZipFile class for selecting
- /// files for inclusion into the ZipFile, when the <see
- /// cref="Ionic.Zip.ZipFile.AddSelectedFiles(String,String)"/> method, or one of
- /// its overloads, is called. It's also used for the <see
- /// cref="Ionic.Zip.ZipFile.ExtractSelectedEntries(String)"/> methods. Typically, an
- /// application that creates or manipulates Zip archives will not directly
- /// interact with the FileSelector class.
- /// </para>
- ///
- /// <para>
- /// Some applications may wish to use the FileSelector class directly, to
- /// select files from disk volumes based on a set of criteria, without creating or
- /// querying Zip archives. The file selection criteria include: a pattern to
- /// match the filename; the last modified, created, or last accessed time of the
- /// file; the size of the file; and the attributes of the file.
- /// </para>
- ///
- /// <para>
- /// Consult the documentation for <see cref="SelectionCriteria"/>
- /// for more information on specifying the selection criteria.
- /// </para>
- ///
- /// </remarks>
- internal partial class FileSelector
- {
- internal SelectionCriterion _Criterion;
-
-#if NOTUSED
- /// <summary>
- /// The default constructor.
- /// </summary>
- /// <remarks>
- /// Typically, applications won't use this constructor. Instead they'll
- /// call the constructor that accepts a selectionCriteria string. If you
- /// use this constructor, you'll want to set the SelectionCriteria
- /// property on the instance before calling SelectFiles().
- /// </remarks>
- protected FileSelector() { }
-#endif
- /// <summary>
- /// Constructor that allows the caller to specify file selection criteria.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This constructor allows the caller to specify a set of criteria for
- /// selection of files.
- /// </para>
- ///
- /// <para>
- /// See <see cref="FileSelector.SelectionCriteria"/> for a description of
- /// the syntax of the selectionCriteria string.
- /// </para>
- ///
- /// <para>
- /// By default the FileSelector will traverse NTFS Reparse Points. To
- /// change this, use <see cref="FileSelector(String,
- /// bool)">FileSelector(String, bool)</see>.
- /// </para>
- /// </remarks>
- ///
- /// <param name="selectionCriteria">The criteria for file selection.</param>
- public FileSelector(String selectionCriteria)
- : this(selectionCriteria, true)
- {
- }
-
- /// <summary>
- /// Constructor that allows the caller to specify file selection criteria.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This constructor allows the caller to specify a set of criteria for
- /// selection of files.
- /// </para>
- ///
- /// <para>
- /// See <see cref="FileSelector.SelectionCriteria"/> for a description of
- /// the syntax of the selectionCriteria string.
- /// </para>
- /// </remarks>
- ///
- /// <param name="selectionCriteria">The criteria for file selection.</param>
- /// <param name="traverseDirectoryReparsePoints">
- /// whether to traverse NTFS reparse points (junctions).
- /// </param>
- public FileSelector(String selectionCriteria, bool traverseDirectoryReparsePoints)
- {
- if (!String.IsNullOrEmpty(selectionCriteria))
- _Criterion = _ParseCriterion(selectionCriteria);
- TraverseReparsePoints = traverseDirectoryReparsePoints;
- }
-
-
-
- /// <summary>
- /// The string specifying which files to include when retrieving.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// Specify the criteria in statements of 3 elements: a noun, an operator,
- /// and a value. Consider the string "name != *.doc" . The noun is
- /// "name". The operator is "!=", implying "Not Equal". The value is
- /// "*.doc". That criterion, in English, says "all files with a name that
- /// does not end in the .doc extension."
- /// </para>
- ///
- /// <para>
- /// Supported nouns include "name" (or "filename") for the filename;
- /// "atime", "mtime", and "ctime" for last access time, last modfied time,
- /// and created time of the file, respectively; "attributes" (or "attrs")
- /// for the file attributes; "size" (or "length") for the file length
- /// (uncompressed); and "type" for the type of object, either a file or a
- /// directory. The "attributes", "type", and "name" nouns all support =
- /// and != as operators. The "size", "atime", "mtime", and "ctime" nouns
- /// support = and !=, and >, >=, <, <= as well. The times are
- /// taken to be expressed in local time.
- /// </para>
- ///
- /// <para>
- /// Specify values for the file attributes as a string with one or more of
- /// the characters H,R,S,A,I,L in any order, implying file attributes of
- /// Hidden, ReadOnly, System, Archive, NotContextIndexed, and ReparsePoint
- /// (symbolic link) respectively.
- /// </para>
- ///
- /// <para>
- /// To specify a time, use YYYY-MM-DD-HH:mm:ss or YYYY/MM/DD-HH:mm:ss as
- /// the format. If you omit the HH:mm:ss portion, it is assumed to be
- /// 00:00:00 (midnight).
- /// </para>
- ///
- /// <para>
- /// The value for a size criterion is expressed in integer quantities of
- /// bytes, kilobytes (use k or kb after the number), megabytes (m or mb),
- /// or gigabytes (g or gb).
- /// </para>
- ///
- /// <para>
- /// The value for a name is a pattern to match against the filename,
- /// potentially including wildcards. The pattern follows CMD.exe glob
- /// rules: * implies one or more of any character, while ? implies one
- /// character. If the name pattern contains any slashes, it is matched to
- /// the entire filename, including the path; otherwise, it is matched
- /// against only the filename without the path. This means a pattern of
- /// "*\*.*" matches all files one directory level deep, while a pattern of
- /// "*.*" matches all files in all directories.
- /// </para>
- ///
- /// <para>
- /// To specify a name pattern that includes spaces, use single quotes
- /// around the pattern. A pattern of "'* *.*'" will match all files that
- /// have spaces in the filename. The full criteria string for that would
- /// be "name = '* *.*'" .
- /// </para>
- ///
- /// <para>
- /// The value for a type criterion is either F (implying a file) or D
- /// (implying a directory).
- /// </para>
- ///
- /// <para>
- /// Some examples:
- /// </para>
- ///
- /// <list type="table">
- /// <listheader>
- /// <term>criteria</term>
- /// <description>Files retrieved</description>
- /// </listheader>
- ///
- /// <item>
- /// <term>name != *.xls </term>
- /// <description>any file with an extension that is not .xls
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>name = *.mp3 </term>
- /// <description>any file with a .mp3 extension.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>*.mp3</term>
- /// <description>(same as above) any file with a .mp3 extension.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>attributes = A </term>
- /// <description>all files whose attributes include the Archive bit.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>attributes != H </term>
- /// <description>all files whose attributes do not include the Hidden bit.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>mtime > 2009-01-01</term>
- /// <description>all files with a last modified time after January 1st, 2009.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ctime > 2009/01/01-03:00:00</term>
- /// <description>all files with a created time after 3am (local time),
- /// on January 1st, 2009.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>size > 2gb</term>
- /// <description>all files whose uncompressed size is greater than 2gb.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>type = D</term>
- /// <description>all directories in the filesystem. </description>
- /// </item>
- ///
- /// </list>
- ///
- /// <para>
- /// You can combine criteria with the conjunctions AND, OR, and XOR. Using
- /// a string like "name = *.txt AND size >= 100k" for the
- /// selectionCriteria retrieves entries whose names end in .txt, and whose
- /// uncompressed size is greater than or equal to 100 kilobytes.
- /// </para>
- ///
- /// <para>
- /// For more complex combinations of criteria, you can use parenthesis to
- /// group clauses in the boolean logic. Absent parenthesis, the
- /// precedence of the criterion atoms is determined by order of
- /// appearance. Unlike the C# language, the AND conjunction does not take
- /// precendence over the logical OR. This is important only in strings
- /// that contain 3 or more criterion atoms. In other words, "name = *.txt
- /// and size > 1000 or attributes = H" implies "((name = *.txt AND size
- /// > 1000) OR attributes = H)" while "attributes = H OR name = *.txt
- /// and size > 1000" evaluates to "((attributes = H OR name = *.txt)
- /// AND size > 1000)". When in doubt, use parenthesis.
- /// </para>
- ///
- /// <para>
- /// Using time properties requires some extra care. If you want to
- /// retrieve all entries that were last updated on 2009 February 14,
- /// specify "mtime >= 2009-02-14 AND mtime < 2009-02-15". Read this
- /// to say: all files updated after 12:00am on February 14th, until
- /// 12:00am on February 15th. You can use the same bracketing approach to
- /// specify any time period - a year, a month, a week, and so on.
- /// </para>
- ///
- /// <para>
- /// The syntax allows one special case: if you provide a string with no
- /// spaces, it is treated as a pattern to match for the filename.
- /// Therefore a string like "*.xls" will be equivalent to specifying "name
- /// = *.xls". This "shorthand" notation does not work with compound
- /// criteria.
- /// </para>
- ///
- /// <para>
- /// There is no logic in this class that insures that the inclusion
- /// criteria are internally consistent. For example, it's possible to
- /// specify criteria that says the file must have a size of less than 100
- /// bytes, as well as a size that is greater than 1000 bytes. Obviously
- /// no file will ever satisfy such criteria, but this class does not check
- /// for or detect such inconsistencies.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <exception cref="System.Exception">
- /// Thrown in the setter if the value has an invalid syntax.
- /// </exception>
- public String SelectionCriteria
- {
- get
- {
- if (_Criterion == null) return null;
- return _Criterion.ToString();
- }
- set
- {
- if (value == null) _Criterion = null;
- else if (value.Trim() == "") _Criterion = null;
- else
- _Criterion = _ParseCriterion(value);
- }
- }
-
- /// <summary>
- /// Indicates whether searches will traverse NTFS reparse points, like Junctions.
- /// </summary>
- public bool TraverseReparsePoints
- {
- get; set;
- }
-
-
- private enum ParseState
- {
- Start,
- OpenParen,
- CriterionDone,
- ConjunctionPending,
- Whitespace,
- }
-
-
- private static class RegexAssertions
- {
- public static readonly String PrecededByOddNumberOfSingleQuotes = "(?<=(?:[^']*'[^']*')*'[^']*)";
- public static readonly String FollowedByOddNumberOfSingleQuotesAndLineEnd = "(?=[^']*'(?:[^']*'[^']*')*[^']*$)";
-
- public static readonly String PrecededByEvenNumberOfSingleQuotes = "(?<=(?:[^']*'[^']*')*[^']*)";
- public static readonly String FollowedByEvenNumberOfSingleQuotesAndLineEnd = "(?=(?:[^']*'[^']*')*[^']*$)";
- }
-
-
- private static string NormalizeCriteriaExpression(string source)
- {
- // The goal here is to normalize the criterion expression. At output, in
- // the transformed criterion string, every significant syntactic element
- // - a property element, grouping paren for the boolean logic, operator
- // ( = < > != ), conjunction, or property value - will be separated from
- // its neighbors by at least one space. Thus,
- //
- // before after
- // -------------------------------------------------------------------
- // name=*.txt name = *.txt
- // (size>100)AND(name=*.txt) ( size > 100 ) AND ( name = *.txt )
- //
- // This is relatively straightforward using regular expression
- // replacement. This method applies a distinct regex pattern and
- // corresponding replacement string for each one of a number of cases:
- // an open paren followed by a word; a word followed by a close-paren; a
- // pair of open parens; a close paren followed by a word (which should
- // then be followed by an open paren). And so on. These patterns and
- // replacements are all stored in prPairs. By applying each of these
- // regex replacements in turn, we get the transformed string. Easy.
- //
- // The resulting "normalized" criterion string, is then used as the
- // subject that gets parsed, by splitting the string into tokens that
- // are separated by spaces. Here, there's a twist. The spaces within
- // single-quote delimiters do not delimit distinct tokens. So, this
- // normalization method temporarily replaces those spaces with
- // ASCII 6 (0x06), a control character which is not a legal
- // character in a filename. The parsing logic that happens later will
- // revert that change, restoring the original value of the filename
- // specification.
- //
- // To illustrate, for a "before" string of [(size>100)AND(name='Name
- // (with Parens).txt')] , the "after" string is [( size > 100 ) AND
- // ( name = 'Name\u0006(with\u0006Parens).txt' )].
- //
-
- string[][] prPairs =
- {
- // A. opening double parens - insert a space between them
- new string[] { @"([^']*)\(\(([^']+)", "$1( ($2" },
-
- // B. closing double parens - insert a space between
- new string[] { @"(.)\)\)", "$1) )" },
-
- // C. single open paren with a following word - insert a space between
- new string[] { @"\((\S)", "( $1" },
-
- // D. single close paren with a preceding word - insert a space between the two
- new string[] { @"(\S)\)", "$1 )" },
-
- // E. close paren at line start?, insert a space before the close paren
- // this seems like a degenerate case. I don't recall why it's here.
- new string[] { @"^\)", " )" },
-
- // F. a word (likely a conjunction) followed by an open paren - insert a space between
- new string[] { @"(\S)\(", "$1 (" },
-
- // G. single close paren followed by word - insert a paren after close paren
- new string[] { @"\)(\S)", ") $1" },
-
- // H. insert space between = and a following single quote
- //new string[] { @"(=|!=)('[^']*')", "$1 $2" },
- new string[] { @"(=)('[^']*')", "$1 $2" },
-
- // I. insert space between property names and the following operator
- //new string[] { @"([^ ])([><(?:!=)=])", "$1 $2" },
- new string[] { @"([^ !><])(>|<|!=|=)", "$1 $2" },
-
- // J. insert spaces between operators and the following values
- //new string[] { @"([><(?:!=)=])([^ ])", "$1 $2" },
- new string[] { @"(>|<|!=|=)([^ =])", "$1 $2" },
-
- // K. replace fwd slash with backslash
- new string[] { @"/", "\\" },
- };
-
- string interim = source;
-
- for (int i=0; i < prPairs.Length; i++)
- {
- //char caseIdx = (char)('A' + i);
- string pattern = RegexAssertions.PrecededByEvenNumberOfSingleQuotes +
- prPairs[i][0] +
- RegexAssertions.FollowedByEvenNumberOfSingleQuotesAndLineEnd;
-
- interim = Regex.Replace(interim, pattern, prPairs[i][1]);
- }
-
- // match a fwd slash, followed by an odd number of single quotes.
- // This matches fwd slashes only inside a pair of single quote delimiters,
- // eg, a filename. This must be done as well as the case above, to handle
- // filenames specified inside quotes as well as filenames without quotes.
- var regexPattern = @"/" +
- RegexAssertions.FollowedByOddNumberOfSingleQuotesAndLineEnd;
- // replace with backslash
- interim = Regex.Replace(interim, regexPattern, "\\");
-
- // match a space, followed by an odd number of single quotes.
- // This matches spaces only inside a pair of single quote delimiters.
- regexPattern = " " +
- RegexAssertions.FollowedByOddNumberOfSingleQuotesAndLineEnd;
-
- // Replace all spaces that appear inside single quotes, with
- // ascii 6. This allows a split on spaces to get tokens in
- // the expression. The split will not split any filename or
- // wildcard that appears within single quotes. After tokenizing, we
- // need to replace ascii 6 with ascii 32 to revert the
- // spaces within quotes.
- return Regex.Replace(interim, regexPattern, "\u0006");
- }
-
-
- private static SelectionCriterion _ParseCriterion(String s)
- {
- if (s == null) return null;
-
- // inject spaces after open paren and before close paren, etc
- s = NormalizeCriteriaExpression(s);
-
- // no spaces in the criteria is shorthand for filename glob
- if (s.IndexOf(" ") == -1)
- s = "name = " + s;
-
- // split the expression into tokens
- string[] tokens = s.Trim().Split(' ', '\t');
-
- if (tokens.Length < 3) throw new ArgumentException(s);
-
- SelectionCriterion current = null;
-
- LogicalConjunction pendingConjunction = LogicalConjunction.NONE;
-
- ParseState state;
- var stateStack = new System.Collections.Generic.Stack<ParseState>();
- var critStack = new System.Collections.Generic.Stack<SelectionCriterion>();
- stateStack.Push(ParseState.Start);
-
- for (int i = 0; i < tokens.Length; i++)
- {
- string tok1 = tokens[i].ToLower(CultureInfo.InvariantCulture);
- switch (tok1)
- {
- case "and":
- case "xor":
- case "or":
- state = stateStack.Peek();
- if (state != ParseState.CriterionDone)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
-
- if (tokens.Length <= i + 3)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
-
- pendingConjunction = (LogicalConjunction)Enum.Parse(typeof(LogicalConjunction), tokens[i].ToUpper(CultureInfo.InvariantCulture), true);
- current = new CompoundCriterion { Left = current, Right = null, Conjunction = pendingConjunction };
- stateStack.Push(state);
- stateStack.Push(ParseState.ConjunctionPending);
- critStack.Push(current);
- break;
-
- case "(":
- state = stateStack.Peek();
- if (state != ParseState.Start && state != ParseState.ConjunctionPending && state != ParseState.OpenParen)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
-
- if (tokens.Length <= i + 4)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
-
- stateStack.Push(ParseState.OpenParen);
- break;
-
- case ")":
- state = stateStack.Pop();
- if (stateStack.Peek() != ParseState.OpenParen)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
-
- stateStack.Pop();
- stateStack.Push(ParseState.CriterionDone);
- break;
-
- case "atime":
- case "ctime":
- case "mtime":
- if (tokens.Length <= i + 2)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
-
- DateTime t;
- try
- {
- t = DateTime.ParseExact(tokens[i + 2], "yyyy-MM-dd-HH:mm:ss", null);
- }
- catch (FormatException)
- {
- try
- {
- t = DateTime.ParseExact(tokens[i + 2], "yyyy/MM/dd-HH:mm:ss", null);
- }
- catch (FormatException)
- {
- try
- {
- t = DateTime.ParseExact(tokens[i + 2], "yyyy/MM/dd", null);
- }
- catch (FormatException)
- {
- try
- {
- t = DateTime.ParseExact(tokens[i + 2], "MM/dd/yyyy", null);
- }
- catch (FormatException)
- {
- t = DateTime.ParseExact(tokens[i + 2], "yyyy-MM-dd", null);
- }
- }
- }
- }
- t= DateTime.SpecifyKind(t, DateTimeKind.Local).ToUniversalTime();
- current = new TimeCriterion
- {
- Which = (WhichTime)Enum.Parse(typeof(WhichTime), tokens[i], true),
- Operator = (ComparisonOperator)EnumUtil.Parse(typeof(ComparisonOperator), tokens[i + 1]),
- Time = t
- };
- i += 2;
- stateStack.Push(ParseState.CriterionDone);
- break;
-
-
- case "length":
- case "size":
- if (tokens.Length <= i + 2)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
-
- Int64 sz = 0;
- string v = tokens[i + 2];
- if (v.EndsWith("K", StringComparison.InvariantCultureIgnoreCase))
- sz = Int64.Parse(v.Substring(0, v.Length - 1)) * 1024;
- else if (v.EndsWith("KB", StringComparison.InvariantCultureIgnoreCase))
- sz = Int64.Parse(v.Substring(0, v.Length - 2)) * 1024;
- else if (v.EndsWith("M", StringComparison.InvariantCultureIgnoreCase))
- sz = Int64.Parse(v.Substring(0, v.Length - 1)) * 1024 * 1024;
- else if (v.EndsWith("MB", StringComparison.InvariantCultureIgnoreCase))
- sz = Int64.Parse(v.Substring(0, v.Length - 2)) * 1024 * 1024;
- else if (v.EndsWith("G", StringComparison.InvariantCultureIgnoreCase))
- sz = Int64.Parse(v.Substring(0, v.Length - 1)) * 1024 * 1024 * 1024;
- else if (v.EndsWith("GB", StringComparison.InvariantCultureIgnoreCase))
- sz = Int64.Parse(v.Substring(0, v.Length - 2)) * 1024 * 1024 * 1024;
- else sz = Int64.Parse(tokens[i + 2]);
-
- current = new SizeCriterion
- {
- Size = sz,
- Operator = (ComparisonOperator)EnumUtil.Parse(typeof(ComparisonOperator), tokens[i + 1])
- };
- i += 2;
- stateStack.Push(ParseState.CriterionDone);
- break;
-
- case "filename":
- case "name":
- {
- if (tokens.Length <= i + 2)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
-
- ComparisonOperator c =
- (ComparisonOperator)EnumUtil.Parse(typeof(ComparisonOperator), tokens[i + 1]);
-
- if (c != ComparisonOperator.NotEqualTo && c != ComparisonOperator.EqualTo)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
-
- string m = tokens[i + 2];
-
- // handle single-quoted filespecs (used to include
- // spaces in filename patterns)
- if (m.StartsWith("'") && m.EndsWith("'"))
- {
- // trim off leading and trailing single quotes and
- // revert the control characters to spaces.
- m = m.Substring(1, m.Length - 2)
- .Replace("\u0006", " ");
- }
-
- // if (m.StartsWith("'"))
- // m = m.Replace("\u0006", " ");
-
- current = new NameCriterion
- {
- MatchingFileSpec = m,
- Operator = c
- };
- i += 2;
- stateStack.Push(ParseState.CriterionDone);
- }
- break;
-
-#if !SILVERLIGHT
- case "attrs":
- case "attributes":
-#endif
- case "type":
- {
- if (tokens.Length <= i + 2)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
-
- ComparisonOperator c =
- (ComparisonOperator)EnumUtil.Parse(typeof(ComparisonOperator), tokens[i + 1]);
-
- if (c != ComparisonOperator.NotEqualTo && c != ComparisonOperator.EqualTo)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
-
-#if SILVERLIGHT
- current = (SelectionCriterion) new TypeCriterion
- {
- AttributeString = tokens[i + 2],
- Operator = c
- };
-#else
- current = (tok1 == "type")
- ? (SelectionCriterion) new TypeCriterion
- {
- AttributeString = tokens[i + 2],
- Operator = c
- }
- : (SelectionCriterion) new AttributesCriterion
- {
- AttributeString = tokens[i + 2],
- Operator = c
- };
-#endif
- i += 2;
- stateStack.Push(ParseState.CriterionDone);
- }
- break;
-
- case "":
- // NOP
- stateStack.Push(ParseState.Whitespace);
- break;
-
- default:
- throw new ArgumentException("'" + tokens[i] + "'");
- }
-
- state = stateStack.Peek();
- if (state == ParseState.CriterionDone)
- {
- stateStack.Pop();
- if (stateStack.Peek() == ParseState.ConjunctionPending)
- {
- while (stateStack.Peek() == ParseState.ConjunctionPending)
- {
- var cc = critStack.Pop() as CompoundCriterion;
- cc.Right = current;
- current = cc; // mark the parent as current (walk up the tree)
- stateStack.Pop(); // the conjunction is no longer pending
-
- state = stateStack.Pop();
- if (state != ParseState.CriterionDone)
- throw new ArgumentException("??");
- }
- }
- else stateStack.Push(ParseState.CriterionDone); // not sure?
- }
-
- if (state == ParseState.Whitespace)
- stateStack.Pop();
- }
-
- return current;
- }
-
-
- /// <summary>
- /// Returns a string representation of the FileSelector object.
- /// </summary>
- /// <returns>The string representation of the boolean logic statement of the file
- /// selection criteria for this instance. </returns>
- public override String ToString()
- {
- return "FileSelector("+_Criterion.ToString()+")";
- }
-
-
- private bool Evaluate(string filename)
- {
- // dinoch - Thu, 11 Feb 2010 18:34
- SelectorTrace("Evaluate({0})", filename);
- bool result = _Criterion.Evaluate(filename);
- return result;
- }
-
- [System.Diagnostics.Conditional("SelectorTrace")]
- private void SelectorTrace(string format, params object[] args)
- {
- if (_Criterion != null && _Criterion.Verbose)
- System.Console.WriteLine(format, args);
- }
-
- /// <summary>
- /// Returns the names of the files in the specified directory
- /// that fit the selection criteria specified in the FileSelector.
- /// </summary>
- ///
- /// <remarks>
- /// This is equivalent to calling <see cref="SelectFiles(String, bool)"/>
- /// with recurseDirectories = false.
- /// </remarks>
- ///
- /// <param name="directory">
- /// The name of the directory over which to apply the FileSelector
- /// criteria.
- /// </param>
- ///
- /// <returns>
- /// A collection of strings containing fully-qualified pathnames of files
- /// that match the criteria specified in the FileSelector instance.
- /// </returns>
- public System.Collections.Generic.ICollection<String> SelectFiles(String directory)
- {
- return SelectFiles(directory, false);
- }
-
-
- /// <summary>
- /// Returns the names of the files in the specified directory that fit the
- /// selection criteria specified in the FileSelector, optionally recursing
- /// through subdirectories.
- /// </summary>
- ///
- /// <remarks>
- /// This method applies the file selection criteria contained in the
- /// FileSelector to the files contained in the given directory, and
- /// returns the names of files that conform to the criteria.
- /// </remarks>
- ///
- /// <param name="directory">
- /// The name of the directory over which to apply the FileSelector
- /// criteria.
- /// </param>
- ///
- /// <param name="recurseDirectories">
- /// Whether to recurse through subdirectories when applying the file
- /// selection criteria.
- /// </param>
- ///
- /// <returns>
- /// A collection of strings containing fully-qualified pathnames of files
- /// that match the criteria specified in the FileSelector instance.
- /// </returns>
- public System.Collections.ObjectModel.ReadOnlyCollection<String>
- SelectFiles(String directory,
- bool recurseDirectories)
- {
- if (_Criterion == null)
- throw new ArgumentException("SelectionCriteria has not been set");
-
- var list = new List<String>();
- try
- {
- if (Directory.Exists(directory))
- {
- String[] filenames = Directory.GetFiles(directory);
-
- // add the files:
- foreach (String filename in filenames)
- {
- if (Evaluate(filename))
- list.Add(filename);
- }
-
- if (recurseDirectories)
- {
- // add the subdirectories:
- String[] dirnames = Directory.GetDirectories(directory);
- foreach (String dir in dirnames)
- {
- if (this.TraverseReparsePoints
-#if !SILVERLIGHT
- || ((File.GetAttributes(dir) & FileAttributes.ReparsePoint) == 0)
-#endif
- )
- {
- // workitem 10191
- if (Evaluate(dir)) list.Add(dir);
- list.AddRange(this.SelectFiles(dir, recurseDirectories));
- }
- }
- }
- }
- }
- // can get System.UnauthorizedAccessException here
- catch (System.UnauthorizedAccessException)
- {
- }
- catch (System.IO.IOException)
- {
- }
-
- return list.AsReadOnly();
- }
- }
-
-
-
- /// <summary>
- /// Summary description for EnumUtil.
- /// </summary>
- internal sealed class EnumUtil
- {
- private EnumUtil() { }
- /// <summary>
- /// Returns the value of the DescriptionAttribute if the specified Enum
- /// value has one. If not, returns the ToString() representation of the
- /// Enum value.
- /// </summary>
- /// <param name="value">The Enum to get the description for</param>
- /// <returns></returns>
- internal static string GetDescription(System.Enum value)
- {
- FieldInfo fi = value.GetType().GetField(value.ToString());
- var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
- if (attributes.Length > 0)
- return attributes[0].Description;
- else
- return value.ToString();
- }
-
- /// <summary>
- /// Converts the string representation of the name or numeric value of one
- /// or more enumerated constants to an equivalent enumerated object.
- /// Note: use the DescriptionAttribute on enum values to enable this.
- /// </summary>
- /// <param name="enumType">The System.Type of the enumeration.</param>
- /// <param name="stringRepresentation">
- /// A string containing the name or value to convert.
- /// </param>
- /// <returns></returns>
- internal static object Parse(Type enumType, string stringRepresentation)
- {
- return Parse(enumType, stringRepresentation, false);
- }
-
-
-#if SILVERLIGHT
- public static System.Enum[] GetEnumValues(Type type)
- {
- if (!type.IsEnum)
- throw new ArgumentException("not an enum");
-
- return (
- from field in type.GetFields(BindingFlags.Public | BindingFlags.Static)
- where field.IsLiteral
- select (System.Enum)field.GetValue(null)
- ).ToArray();
- }
-
- public static string[] GetEnumStrings<T>()
- {
- var type = typeof(T);
- if (!type.IsEnum)
- throw new ArgumentException("not an enum");
-
- return (
- from field in type.GetFields(BindingFlags.Public | BindingFlags.Static)
- where field.IsLiteral
- select field.Name
- ).ToArray();
- }
-#endif
-
- /// <summary>
- /// Converts the string representation of the name or numeric value of one
- /// or more enumerated constants to an equivalent enumerated object. A
- /// parameter specified whether the operation is case-sensitive. Note:
- /// use the DescriptionAttribute on enum values to enable this.
- /// </summary>
- /// <param name="enumType">The System.Type of the enumeration.</param>
- /// <param name="stringRepresentation">
- /// A string containing the name or value to convert.
- /// </param>
- /// <param name="ignoreCase">
- /// Whether the operation is case-sensitive or not.</param>
- /// <returns></returns>
- internal static object Parse(Type enumType, string stringRepresentation, bool ignoreCase)
- {
- if (ignoreCase)
- stringRepresentation = stringRepresentation.ToLower(CultureInfo.InvariantCulture);
-
-#if SILVERLIGHT
- foreach (System.Enum enumVal in GetEnumValues(enumType))
-#else
- foreach (System.Enum enumVal in System.Enum.GetValues(enumType))
-#endif
- {
- string description = GetDescription(enumVal);
- if (ignoreCase)
- description = description.ToLower(CultureInfo.InvariantCulture);
- if (description == stringRepresentation)
- return enumVal;
- }
-
- return System.Enum.Parse(enumType, stringRepresentation, ignoreCase);
- }
- }
-
-
-#if DEMO
- internal class DemonstrateFileSelector
- {
- private string _directory;
- private bool _recurse;
- private bool _traverse;
- private bool _verbose;
- private string _selectionCriteria;
- private FileSelector f;
-
- public DemonstrateFileSelector()
- {
- this._directory = ".";
- this._recurse = true;
- }
-
- public DemonstrateFileSelector(string[] args) : this()
- {
- for (int i = 0; i < args.Length; i++)
- {
- switch(args[i])
- {
- case"-?":
- Usage();
- Environment.Exit(0);
- break;
- case "-d":
- i++;
- if (args.Length <= i)
- throw new ArgumentException("-directory");
- this._directory = args[i];
- break;
- case "-norecurse":
- this._recurse = false;
- break;
-
- case "-j-":
- this._traverse = false;
- break;
-
- case "-j+":
- this._traverse = true;
- break;
-
- case "-v":
- this._verbose = true;
- break;
-
- default:
- if (this._selectionCriteria != null)
- throw new ArgumentException(args[i]);
- this._selectionCriteria = args[i];
- break;
- }
-
- if (this._selectionCriteria != null)
- this.f = new FileSelector(this._selectionCriteria);
- }
- }
-
-
- public static void Main(string[] args)
- {
- try
- {
- Console.WriteLine();
- new DemonstrateFileSelector(args).Run();
- }
- catch (Exception exc1)
- {
- Console.WriteLine("Exception: {0}", exc1.ToString());
- Usage();
- }
- }
-
-
- public void Run()
- {
- if (this.f == null)
- this.f = new FileSelector("name = *.jpg AND (size > 1000 OR atime < 2009-02-14-01:00:00)");
-
- this.f.TraverseReparsePoints = _traverse;
- this.f.Verbose = this._verbose;
- Console.WriteLine();
- Console.WriteLine(new String(':', 88));
- Console.WriteLine("Selecting files:\n" + this.f.ToString());
- var files = this.f.SelectFiles(this._directory, this._recurse);
- if (files.Count == 0)
- {
- Console.WriteLine("no files.");
- }
- else
- {
- Console.WriteLine("files: {0}", files.Count);
- foreach (string file in files)
- {
- Console.WriteLine(" " + file);
- }
- }
- }
-
- public static void Usage()
- {
- Console.WriteLine("FileSelector: select files based on selection criteria.\n");
- Console.WriteLine("Usage:\n FileSelector <selectionCriteria> [options]\n" +
- "\n" +
- " -d <dir> directory to select from (Default .)\n" +
- " -norecurse don't recurse into subdirs\n" +
- " -j- don't traverse junctions\n" +
- " -v verbose output\n");
- }
- }
-
-#endif
-
-
-
-}
-
-
diff --git a/EPPlus/Packaging/DotNetZip/OffsetStream.cs b/EPPlus/Packaging/DotNetZip/OffsetStream.cs
deleted file mode 100644
index c1156d0..0000000
--- a/EPPlus/Packaging/DotNetZip/OffsetStream.cs
+++ /dev/null
@@ -1,114 +0,0 @@
-// OffsetStream.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2009-August-27 12:50:35>
-//
-// ------------------------------------------------------------------
-//
-// This module defines logic for handling reading of zip archives embedded
-// into larger streams. The initial position of the stream serves as
-// the base offset for all future Seek() operations.
-//
-// ------------------------------------------------------------------
-
-
-using System;
-using System.IO;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- internal class OffsetStream : System.IO.Stream, System.IDisposable
- {
- private Int64 _originalPosition;
- private Stream _innerStream;
-
- public OffsetStream(Stream s)
- : base()
- {
- _originalPosition = s.Position;
- _innerStream = s;
- }
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- return _innerStream.Read(buffer, offset, count);
- }
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- throw new NotImplementedException();
- }
-
- public override bool CanRead
- {
- get { return _innerStream.CanRead; }
- }
-
- public override bool CanSeek
- {
- get { return _innerStream.CanSeek; }
- }
-
- public override bool CanWrite
- {
- get { return false; }
- }
-
- public override void Flush()
- {
- _innerStream.Flush();
- }
-
- public override long Length
- {
- get
- {
- return _innerStream.Length;
- }
- }
-
- public override long Position
- {
- get { return _innerStream.Position - _originalPosition; }
- set { _innerStream.Position = _originalPosition + value; }
- }
-
-
- public override long Seek(long offset, System.IO.SeekOrigin origin)
- {
- return _innerStream.Seek(_originalPosition + offset, origin) - _originalPosition;
- }
-
-
- public override void SetLength(long value)
- {
- throw new NotImplementedException();
- }
-
- void IDisposable.Dispose()
- {
- Close();
- }
-
- public override void Close()
- {
- base.Close();
- }
-
- }
-
-}
\ No newline at end of file
diff --git a/EPPlus/Packaging/DotNetZip/Shared.cs b/EPPlus/Packaging/DotNetZip/Shared.cs
deleted file mode 100644
index ca8f18c..0000000
--- a/EPPlus/Packaging/DotNetZip/Shared.cs
+++ /dev/null
@@ -1,901 +0,0 @@
-// Shared.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2006-2011 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// Last Saved: <2011-August-02 19:41:01>
-//
-// ------------------------------------------------------------------
-//
-// This module defines some shared utility classes and methods.
-//
-// Created: Tue, 27 Mar 2007 15:30
-//
-
-using System;
-using System.IO;
-using System.Security.Permissions;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- /// <summary>
- /// Collects general purpose utility methods.
- /// </summary>
- internal static class SharedUtilities
- {
- /// private null constructor
- //private SharedUtilities() { }
-
- // workitem 8423
- public static Int64 GetFileLength(string fileName)
- {
- if (!File.Exists(fileName))
- throw new System.IO.FileNotFoundException(fileName);
-
- long fileLength = 0L;
- FileShare fs = FileShare.ReadWrite;
-#if !NETCF
- // FileShare.Delete is not defined for the Compact Framework
- fs |= FileShare.Delete;
-#endif
- using (var s = File.Open(fileName, FileMode.Open, FileAccess.Read, fs))
- {
- fileLength = s.Length;
- }
- return fileLength;
- }
-
-
- [System.Diagnostics.Conditional("NETCF")]
- public static void Workaround_Ladybug318918(Stream s)
- {
- // This is a workaround for this issue:
- // https://connect.microsoft.com/VisualStudio/feedback/details/318918
- // It's required only on NETCF.
- s.Flush();
- }
-
-
-#if LEGACY
- /// <summary>
- /// Round the given DateTime value to an even second value.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Round up in the case of an odd second value. The rounding does not consider
- /// fractional seconds.
- /// </para>
- /// <para>
- /// This is useful because the Zip spec allows storage of time only to the nearest
- /// even second. So if you want to compare the time of an entry in the archive with
- /// it's actual time in the filesystem, you need to round the actual filesystem
- /// time, or use a 2-second threshold for the comparison.
- /// </para>
- /// <para>
- /// This is most nautrally an extension method for the DateTime class but this
- /// library is built for .NET 2.0, not for .NET 3.5; This means extension methods
- /// are a no-no.
- /// </para>
- /// </remarks>
- /// <param name="source">The DateTime value to round</param>
- /// <returns>The ruonded DateTime value</returns>
- public static DateTime RoundToEvenSecond(DateTime source)
- {
- // round to nearest second:
- if ((source.Second % 2) == 1)
- source += new TimeSpan(0, 0, 1);
-
- DateTime dtRounded = new DateTime(source.Year, source.Month, source.Day, source.Hour, source.Minute, source.Second);
- //if (source.Millisecond >= 500) dtRounded = dtRounded.AddSeconds(1);
- return dtRounded;
- }
-#endif
-
-#if YOU_LIKE_REDUNDANT_CODE
- internal static string NormalizePath(string path)
- {
- // remove leading single dot slash
- if (path.StartsWith(".\\")) path = path.Substring(2);
-
- // remove intervening dot-slash
- path = path.Replace("\\.\\", "\\");
-
- // remove double dot when preceded by a directory name
- var re = new System.Text.RegularExpressions.Regex(@"^(.*\\)?([^\\\.]+\\\.\.\\)(.+)$");
- path = re.Replace(path, "$1$3");
- return path;
- }
-#endif
-
- private static System.Text.RegularExpressions.Regex doubleDotRegex1 =
- new System.Text.RegularExpressions.Regex(@"^(.*/)?([^/\\.]+/\\.\\./)(.+)$");
-
- private static string SimplifyFwdSlashPath(string path)
- {
- if (path.StartsWith("./")) path = path.Substring(2);
- path = path.Replace("/./", "/");
-
- // Replace foo/anything/../bar with foo/bar
- path = doubleDotRegex1.Replace(path, "$1$3");
- return path;
- }
-
-
- /// <summary>
- /// Utility routine for transforming path names from filesystem format (on Windows that means backslashes) to
- /// a format suitable for use within zipfiles. This means trimming the volume letter and colon (if any) And
- /// swapping backslashes for forward slashes.
- /// </summary>
- /// <param name="pathName">source path.</param>
- /// <returns>transformed path</returns>
- public static string NormalizePathForUseInZipFile(string pathName)
- {
- // boundary case
- if (String.IsNullOrEmpty(pathName)) return pathName;
-
- // trim volume if necessary
- if ((pathName.Length >= 2) && ((pathName[1] == ':') && (pathName[2] == '\\')))
- pathName = pathName.Substring(3);
-
- // swap slashes
- pathName = pathName.Replace('\\', '/');
-
- // trim all leading slashes
- while (pathName.StartsWith("/")) pathName = pathName.Substring(1);
-
- return SimplifyFwdSlashPath(pathName);
- }
-
-
- static System.Text.Encoding ibm437 = System.Text.Encoding.ASCII;
- static System.Text.Encoding utf8 = System.Text.Encoding.GetEncoding("UTF-8");
-
- internal static byte[] StringToByteArray(string value, System.Text.Encoding encoding)
- {
- byte[] a = encoding.GetBytes(value);
- return a;
- }
- internal static byte[] StringToByteArray(string value)
- {
- return StringToByteArray(value, ibm437);
- }
-
- //internal static byte[] Utf8StringToByteArray(string value)
- //{
- // return StringToByteArray(value, utf8);
- //}
-
- //internal static string StringFromBuffer(byte[] buf, int maxlength)
- //{
- // return StringFromBuffer(buf, maxlength, ibm437);
- //}
-
- internal static string Utf8StringFromBuffer(byte[] buf)
- {
- return StringFromBuffer(buf, utf8);
- }
-
- internal static string StringFromBuffer(byte[] buf, System.Text.Encoding encoding)
- {
- // this form of the GetString() method is required for .NET CF compatibility
- string s = encoding.GetString(buf, 0, buf.Length);
- return s;
- }
-
-
- internal static int ReadSignature(System.IO.Stream s)
- {
- int x = 0;
- try { x = _ReadFourBytes(s, "n/a"); }
- catch (BadReadException) { }
- return x;
- }
-
-
- internal static int ReadEntrySignature(System.IO.Stream s)
- {
- // handle the case of ill-formatted zip archives - includes a data descriptor
- // when none is expected.
- int x = 0;
- try
- {
- x = _ReadFourBytes(s, "n/a");
- if (x == ZipConstants.ZipEntryDataDescriptorSignature)
- {
- // advance past data descriptor - 12 bytes if not zip64
- s.Seek(12, SeekOrigin.Current);
- // workitem 10178
- Workaround_Ladybug318918(s);
- x = _ReadFourBytes(s, "n/a");
- if (x != ZipConstants.ZipEntrySignature)
- {
- // Maybe zip64 was in use for the prior entry.
- // Therefore, skip another 8 bytes.
- s.Seek(8, SeekOrigin.Current);
- // workitem 10178
- Workaround_Ladybug318918(s);
- x = _ReadFourBytes(s, "n/a");
- if (x != ZipConstants.ZipEntrySignature)
- {
- // seek back to the first spot
- s.Seek(-24, SeekOrigin.Current);
- // workitem 10178
- Workaround_Ladybug318918(s);
- x = _ReadFourBytes(s, "n/a");
- }
- }
- }
- }
- catch (BadReadException) { }
- return x;
- }
-
-
- internal static int ReadInt(System.IO.Stream s)
- {
- return _ReadFourBytes(s, "Could not read block - no data! (position 0x{0:X8})");
- }
-
- private static int _ReadFourBytes(System.IO.Stream s, string message)
- {
- int n = 0;
- byte[] block = new byte[4];
-#if NETCF
- // workitem 9181
- // Reading here in NETCF sometimes reads "backwards". Seems to happen for
- // larger files. Not sure why. Maybe an error in caching. If the data is:
- //
- // 00100210: 9efa 0f00 7072 6f6a 6563 742e 6963 7750 ....project.icwP
- // 00100220: 4b05 0600 0000 0006 0006 0091 0100 008e K...............
- // 00100230: 0010 0000 00 .....
- //
- // ...and the stream Position is 10021F, then a Read of 4 bytes is returning
- // 50776369, instead of 06054b50. This seems to happen the 2nd time Read()
- // is called from that Position..
- //
- // submitted to connect.microsoft.com
- // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=318918#tabs
- //
- for (int i = 0; i < block.Length; i++)
- {
- n+= s.Read(block, i, 1);
- }
-#else
- n = s.Read(block, 0, block.Length);
-#endif
- if (n != block.Length) throw new BadReadException(String.Format(message, s.Position));
- int data = unchecked((((block[3] * 256 + block[2]) * 256) + block[1]) * 256 + block[0]);
- return data;
- }
-
-
-
- /// <summary>
- /// Finds a signature in the zip stream. This is useful for finding
- /// the end of a zip entry, for example, or the beginning of the next ZipEntry.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Scans through 64k at a time.
- /// </para>
- ///
- /// <para>
- /// If the method fails to find the requested signature, the stream Position
- /// after completion of this method is unchanged. If the method succeeds in
- /// finding the requested signature, the stream position after completion is
- /// direct AFTER the signature found in the stream.
- /// </para>
- /// </remarks>
- ///
- /// <param name="stream">The stream to search</param>
- /// <param name="SignatureToFind">The 4-byte signature to find</param>
- /// <returns>The number of bytes read</returns>
- internal static long FindSignature(System.IO.Stream stream, int SignatureToFind)
- {
- long startingPosition = stream.Position;
-
- int BATCH_SIZE = 65536; // 8192;
- byte[] targetBytes = new byte[4];
- targetBytes[0] = (byte)(SignatureToFind >> 24);
- targetBytes[1] = (byte)((SignatureToFind & 0x00FF0000) >> 16);
- targetBytes[2] = (byte)((SignatureToFind & 0x0000FF00) >> 8);
- targetBytes[3] = (byte)(SignatureToFind & 0x000000FF);
- byte[] batch = new byte[BATCH_SIZE];
- int n = 0;
- bool success = false;
- do
- {
- n = stream.Read(batch, 0, batch.Length);
- if (n != 0)
- {
- for (int i = 0; i < n; i++)
- {
- if (batch[i] == targetBytes[3])
- {
- long curPosition = stream.Position;
- stream.Seek(i - n, System.IO.SeekOrigin.Current);
- // workitem 10178
- Workaround_Ladybug318918(stream);
-
- // workitem 7711
- int sig = ReadSignature(stream);
-
- success = (sig == SignatureToFind);
- if (!success)
- {
- stream.Seek(curPosition, System.IO.SeekOrigin.Begin);
- // workitem 10178
- Workaround_Ladybug318918(stream);
- }
- else
- break; // out of for loop
- }
- }
- }
- else break;
- if (success) break;
-
- } while (true);
-
- if (!success)
- {
- stream.Seek(startingPosition, System.IO.SeekOrigin.Begin);
- // workitem 10178
- Workaround_Ladybug318918(stream);
- return -1; // or throw?
- }
-
- // subtract 4 for the signature.
- long bytesRead = (stream.Position - startingPosition) - 4;
-
- return bytesRead;
- }
-
-
- // If I have a time in the .NET environment, and I want to use it for
- // SetWastWriteTime() etc, then I need to adjust it for Win32.
- internal static DateTime AdjustTime_Reverse(DateTime time)
- {
- if (time.Kind == DateTimeKind.Utc) return time;
- DateTime adjusted = time;
- if (DateTime.Now.IsDaylightSavingTime() && !time.IsDaylightSavingTime())
- adjusted = time - new System.TimeSpan(1, 0, 0);
-
- else if (!DateTime.Now.IsDaylightSavingTime() && time.IsDaylightSavingTime())
- adjusted = time + new System.TimeSpan(1, 0, 0);
-
- return adjusted;
- }
-
-#if NECESSARY
- // If I read a time from a file with GetLastWriteTime() (etc), I need
- // to adjust it for display in the .NET environment.
- internal static DateTime AdjustTime_Forward(DateTime time)
- {
- if (time.Kind == DateTimeKind.Utc) return time;
- DateTime adjusted = time;
- if (DateTime.Now.IsDaylightSavingTime() && !time.IsDaylightSavingTime())
- adjusted = time + new System.TimeSpan(1, 0, 0);
-
- else if (!DateTime.Now.IsDaylightSavingTime() && time.IsDaylightSavingTime())
- adjusted = time - new System.TimeSpan(1, 0, 0);
-
- return adjusted;
- }
-#endif
-
-
- internal static DateTime PackedToDateTime(Int32 packedDateTime)
- {
- // workitem 7074 & workitem 7170
- if (packedDateTime == 0xFFFF || packedDateTime == 0)
- return new System.DateTime(1995, 1, 1, 0, 0, 0, 0); // return a fixed date when none is supplied.
-
- Int16 packedTime = unchecked((Int16)(packedDateTime & 0x0000ffff));
- Int16 packedDate = unchecked((Int16)((packedDateTime & 0xffff0000) >> 16));
-
- int year = 1980 + ((packedDate & 0xFE00) >> 9);
- int month = (packedDate & 0x01E0) >> 5;
- int day = packedDate & 0x001F;
-
- int hour = (packedTime & 0xF800) >> 11;
- int minute = (packedTime & 0x07E0) >> 5;
- //int second = packedTime & 0x001F;
- int second = (packedTime & 0x001F) * 2;
-
- // validation and error checking.
- // this is not foolproof but will catch most errors.
- if (second >= 60) { minute++; second = 0; }
- if (minute >= 60) { hour++; minute = 0; }
- if (hour >= 24) { day++; hour = 0; }
-
- DateTime d = System.DateTime.Now;
- bool success= false;
- try
- {
- d = new System.DateTime(year, month, day, hour, minute, second, 0);
- success= true;
- }
- catch (System.ArgumentOutOfRangeException)
- {
- if (year == 1980 && (month == 0 || day == 0))
- {
- try
- {
- d = new System.DateTime(1980, 1, 1, hour, minute, second, 0);
- success= true;
- }
- catch (System.ArgumentOutOfRangeException)
- {
- try
- {
- d = new System.DateTime(1980, 1, 1, 0, 0, 0, 0);
- success= true;
- }
- catch (System.ArgumentOutOfRangeException) { }
-
- }
- }
- // workitem 8814
- // my god, I can't believe how many different ways applications
- // can mess up a simple date format.
- else
- {
- try
- {
- while (year < 1980) year++;
- while (year > 2030) year--;
- while (month < 1) month++;
- while (month > 12) month--;
- while (day < 1) day++;
- while (day > 28) day--;
- while (minute < 0) minute++;
- while (minute > 59) minute--;
- while (second < 0) second++;
- while (second > 59) second--;
- d = new System.DateTime(year, month, day, hour, minute, second, 0);
- success= true;
- }
- catch (System.ArgumentOutOfRangeException) { }
- }
- }
- if (!success)
- {
- string msg = String.Format("y({0}) m({1}) d({2}) h({3}) m({4}) s({5})", year, month, day, hour, minute, second);
- throw new ZipException(String.Format("Bad date/time format in the zip file. ({0})", msg));
-
- }
- // workitem 6191
- //d = AdjustTime_Reverse(d);
- d = DateTime.SpecifyKind(d, DateTimeKind.Local);
- return d;
- }
-
-
- internal
- static Int32 DateTimeToPacked(DateTime time)
- {
- // The time is passed in here only for purposes of writing LastModified to the
- // zip archive. It should always be LocalTime, but we convert anyway. And,
- // since the time is being written out, it needs to be adjusted.
-
- time = time.ToLocalTime();
- // workitem 7966
- //time = AdjustTime_Forward(time);
-
- // see http://www.vsft.com/hal/dostime.htm for the format
- UInt16 packedDate = (UInt16)((time.Day & 0x0000001F) | ((time.Month << 5) & 0x000001E0) | (((time.Year - 1980) << 9) & 0x0000FE00));
- UInt16 packedTime = (UInt16)((time.Second / 2 & 0x0000001F) | ((time.Minute << 5) & 0x000007E0) | ((time.Hour << 11) & 0x0000F800));
-
- Int32 result = (Int32)(((UInt32)(packedDate << 16)) | packedTime);
- return result;
- }
-
-
- /// <summary>
- /// Create a pseudo-random filename, suitable for use as a temporary
- /// file, and open it.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The System.IO.Path.GetRandomFileName() method is not available on
- /// the Compact Framework, so this library provides its own substitute
- /// on NETCF.
- /// </para>
- /// <para>
- /// This method produces a filename of the form
- /// DotNetZip-xxxxxxxx.tmp, where xxxxxxxx is replaced by randomly
- /// chosen characters, and creates that file.
- /// </para>
- /// </remarks>
- public static void CreateAndOpenUniqueTempFile(string dir,
- out Stream fs,
- out string filename)
- {
- // workitem 9763
- // http://dotnet.org.za/markn/archive/2006/04/15/51594.aspx
- // try 3 times:
- for (int i = 0; i < 3; i++)
- {
- try
- {
- filename = Path.Combine(dir, InternalGetTempFileName());
- fs = new FileStream(filename, FileMode.CreateNew);
- return;
- }
- catch (IOException)
- {
- if (i == 2) throw;
- }
- }
- throw new IOException();
- }
-
-#if NETCF || SILVERLIGHT
- public static string InternalGetTempFileName()
- {
- return "DotNetZip-" + GenerateRandomStringImpl(8,0) + ".tmp";
- }
-
- internal static string GenerateRandomStringImpl(int length, int delta)
- {
- bool WantMixedCase = (delta == 0);
- System.Random rnd = new System.Random();
-
- string result = "";
- char[] a = new char[length];
-
- for (int i = 0; i < length; i++)
- {
- // delta == 65 means uppercase
- // delta == 97 means lowercase
- if (WantMixedCase)
- delta = (rnd.Next(2) == 0) ? 65 : 97;
- a[i] = (char)(rnd.Next(26) + delta);
- }
-
- result = new System.String(a);
- return result;
- }
-#else
- public static string InternalGetTempFileName()
- {
- return "DotNetZip-" + Path.GetRandomFileName().Substring(0, 8) + ".tmp";
- }
-
-#endif
-
-
- /// <summary>
- /// Workitem 7889: handle ERROR_LOCK_VIOLATION during read
- /// </summary>
- /// <remarks>
- /// This could be gracefully handled with an extension attribute, but
- /// This assembly is built for .NET 2.0, so I cannot use them.
- /// </remarks>
- internal static int ReadWithRetry(System.IO.Stream s, byte[] buffer, int offset, int count, string FileName)
- {
- int n = 0;
- bool done = false;
-#if !NETCF && !SILVERLIGHT
- int retries = 0;
-#endif
- do
- {
- try
- {
- n = s.Read(buffer, offset, count);
- done = true;
- }
-#if NETCF || SILVERLIGHT
- catch (System.IO.IOException)
- {
- throw;
- }
-#else
- catch (System.IO.IOException ioexc1)
- {
- // Check if we can call GetHRForException,
- // which makes unmanaged code calls.
- var p = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
- if (p.IsUnrestricted())
- {
- uint hresult = _HRForException(ioexc1);
- if (hresult != 0x80070021) // ERROR_LOCK_VIOLATION
- throw new System.IO.IOException(String.Format("Cannot read file {0}", FileName), ioexc1);
- retries++;
- if (retries > 10)
- throw new System.IO.IOException(String.Format("Cannot read file {0}, at offset 0x{1:X8} after 10 retries", FileName, offset), ioexc1);
-
- // max time waited on last retry = 250 + 10*550 = 5.75s
- // aggregate time waited after 10 retries: 250 + 55*550 = 30.5s
- System.Threading.Thread.Sleep(250 + retries * 550);
- }
- else
- {
- // The permission.Demand() failed. Therefore, we cannot call
- // GetHRForException, and cannot do the subtle handling of
- // ERROR_LOCK_VIOLATION. Just bail.
- throw;
- }
- }
-#endif
- }
- while (!done);
-
- return n;
- }
-
-
-#if !NETCF
- // workitem 8009
- //
- // This method must remain separate.
- //
- // Marshal.GetHRForException() is needed to do special exception handling for
- // the read. But, that method requires UnmanagedCode permissions, and is marked
- // with LinkDemand for UnmanagedCode. In an ASP.NET medium trust environment,
- // where UnmanagedCode is restricted, will generate a SecurityException at the
- // time of JIT of the method that calls a method that is marked with LinkDemand
- // for UnmanagedCode. The SecurityException, if it is restricted, will occur
- // when this method is JITed.
- //
- // The Marshal.GetHRForException() is factored out of ReadWithRetry in order to
- // avoid the SecurityException at JIT compile time. Because _HRForException is
- // called only when the UnmanagedCode is allowed. This means .NET never
- // JIT-compiles this method when UnmanagedCode is disallowed, and thus never
- // generates the JIT-compile time exception.
- //
-#endif
- private static uint _HRForException(System.Exception ex1)
- {
- return unchecked((uint)System.Runtime.InteropServices.Marshal.GetHRForException(ex1));
- }
-
- }
-
-
-
- /// <summary>
- /// A decorator stream. It wraps another stream, and performs bookkeeping
- /// to keep track of the stream Position.
- /// </summary>
- /// <remarks>
- /// <para>
- /// In some cases, it is not possible to get the Position of a stream, let's
- /// say, on a write-only output stream like ASP.NET's
- /// <c>Response.OutputStream</c>, or on a different write-only stream
- /// provided as the destination for the zip by the application. In this
- /// case, programmers can use this counting stream to count the bytes read
- /// or written.
- /// </para>
- /// <para>
- /// Consider the scenario of an application that saves a self-extracting
- /// archive (SFX), that uses a custom SFX stub.
- /// </para>
- /// <para>
- /// Saving to a filesystem file, the application would open the
- /// filesystem file (getting a <c>FileStream</c>), save the custom sfx stub
- /// into it, and then call <c>ZipFile.Save()</c>, specifying the same
- /// FileStream. <c>ZipFile.Save()</c> does the right thing for the zipentry
- /// offsets, by inquiring the Position of the <c>FileStream</c> before writing
- /// any data, and then adding that initial offset into any ZipEntry
- /// offsets in the zip directory. Everything works fine.
- /// </para>
- /// <para>
- /// Now suppose the application is an ASPNET application and it saves
- /// directly to <c>Response.OutputStream</c>. It's not possible for DotNetZip to
- /// inquire the <c>Position</c>, so the offsets for the SFX will be wrong.
- /// </para>
- /// <para>
- /// The workaround is for the application to use this class to wrap
- /// <c>HttpResponse.OutputStream</c>, then write the SFX stub and the ZipFile
- /// into that wrapper stream. Because <c>ZipFile.Save()</c> can inquire the
- /// <c>Position</c>, it will then do the right thing with the offsets.
- /// </para>
- /// </remarks>
- internal class CountingStream : System.IO.Stream
- {
- // workitem 12374: this class is now public
- private System.IO.Stream _s;
- private Int64 _bytesWritten;
- private Int64 _bytesRead;
- private Int64 _initialOffset;
-
- /// <summary>
- /// The constructor.
- /// </summary>
- /// <param name="stream">The underlying stream</param>
- public CountingStream(System.IO.Stream stream)
- : base()
- {
- _s = stream;
- try
- {
- _initialOffset = _s.Position;
- }
- catch
- {
- _initialOffset = 0L;
- }
- }
-
- /// <summary>
- /// Gets the wrapped stream.
- /// </summary>
- public Stream WrappedStream
- {
- get
- {
- return _s;
- }
- }
-
- /// <summary>
- /// The count of bytes written out to the stream.
- /// </summary>
- public Int64 BytesWritten
- {
- get { return _bytesWritten; }
- }
-
- /// <summary>
- /// the count of bytes that have been read from the stream.
- /// </summary>
- public Int64 BytesRead
- {
- get { return _bytesRead; }
- }
-
- /// <summary>
- /// Adjust the byte count on the stream.
- /// </summary>
- ///
- /// <param name='delta'>
- /// the number of bytes to subtract from the count.
- /// </param>
- ///
- /// <remarks>
- /// <para>
- /// Subtract delta from the count of bytes written to the stream.
- /// This is necessary when seeking back, and writing additional data,
- /// as happens in some cases when saving Zip files.
- /// </para>
- /// </remarks>
- public void Adjust(Int64 delta)
- {
- _bytesWritten -= delta;
- if (_bytesWritten < 0)
- throw new InvalidOperationException();
- if (_s as CountingStream != null)
- ((CountingStream)_s).Adjust(delta);
- }
-
- /// <summary>
- /// The read method.
- /// </summary>
- /// <param name="buffer">The buffer to hold the data read from the stream.</param>
- /// <param name="offset">the offset within the buffer to copy the first byte read.</param>
- /// <param name="count">the number of bytes to read.</param>
- /// <returns>the number of bytes read, after decryption and decompression.</returns>
- public override int Read(byte[] buffer, int offset, int count)
- {
- int n = _s.Read(buffer, offset, count);
- _bytesRead += n;
- return n;
- }
-
- /// <summary>
- /// Write data into the stream.
- /// </summary>
- /// <param name="buffer">The buffer holding data to write to the stream.</param>
- /// <param name="offset">the offset within that data array to find the first byte to write.</param>
- /// <param name="count">the number of bytes to write.</param>
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (count == 0) return;
- _s.Write(buffer, offset, count);
- _bytesWritten += count;
- }
-
- /// <summary>
- /// Whether the stream can be read.
- /// </summary>
- public override bool CanRead
- {
- get { return _s.CanRead; }
- }
-
- /// <summary>
- /// Whether it is possible to call Seek() on the stream.
- /// </summary>
- public override bool CanSeek
- {
- get { return _s.CanSeek; }
- }
-
- /// <summary>
- /// Whether it is possible to call Write() on the stream.
- /// </summary>
- public override bool CanWrite
- {
- get { return _s.CanWrite; }
- }
-
- /// <summary>
- /// Flushes the underlying stream.
- /// </summary>
- public override void Flush()
- {
- _s.Flush();
- }
-
- /// <summary>
- /// The length of the underlying stream.
- /// </summary>
- public override long Length
- {
- get { return _s.Length; } // bytesWritten??
- }
-
- /// <summary>
- /// Returns the sum of number of bytes written, plus the initial
- /// offset before writing.
- /// </summary>
- public long ComputedPosition
- {
- get { return _initialOffset + _bytesWritten; }
- }
-
-
- /// <summary>
- /// The Position of the stream.
- /// </summary>
- public override long Position
- {
- get { return _s.Position; }
- set
- {
- _s.Seek(value, System.IO.SeekOrigin.Begin);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_s);
- }
- }
-
- /// <summary>
- /// Seek in the stream.
- /// </summary>
- /// <param name="offset">the offset point to seek to</param>
- /// <param name="origin">the reference point from which to seek</param>
- /// <returns>The new position</returns>
- public override long Seek(long offset, System.IO.SeekOrigin origin)
- {
- return _s.Seek(offset, origin);
- }
-
- /// <summary>
- /// Set the length of the underlying stream. Be careful with this!
- /// </summary>
- ///
- /// <param name='value'>the length to set on the underlying stream.</param>
- public override void SetLength(long value)
- {
- _s.SetLength(value);
- }
- }
-
-
-}
diff --git a/EPPlus/Packaging/DotNetZip/WinZipAes.cs b/EPPlus/Packaging/DotNetZip/WinZipAes.cs
deleted file mode 100644
index f45eea4..0000000
--- a/EPPlus/Packaging/DotNetZip/WinZipAes.cs
+++ /dev/null
@@ -1,941 +0,0 @@
-//#define Trace
-
-// WinZipAes.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009-2011 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-July-12 13:42:06>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the classes for dealing with WinZip's AES encryption,
-// according to the specifications for the format available on WinZip's website.
-//
-// Created: January 2009
-//
-// ------------------------------------------------------------------
-
-using System;
-using System.IO;
-using System.Collections.Generic;
-using System.Security.Cryptography;
-
-#if AESCRYPTO
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- /// <summary>
- /// This is a helper class supporting WinZip AES encryption.
- /// This class is intended for use only by the DotNetZip library.
- /// </summary>
- ///
- /// <remarks>
- /// Most uses of the DotNetZip library will not involve direct calls into
- /// the WinZipAesCrypto class. Instead, the WinZipAesCrypto class is
- /// instantiated and used by the ZipEntry() class when WinZip AES
- /// encryption or decryption on an entry is employed.
- /// </remarks>
- internal class WinZipAesCrypto
- {
- internal byte[] _Salt;
- internal byte[] _providedPv;
- internal byte[] _generatedPv;
- internal int _KeyStrengthInBits;
- private byte[] _MacInitializationVector;
- private byte[] _StoredMac;
- private byte[] _keyBytes;
- private Int16 PasswordVerificationStored;
- private Int16 PasswordVerificationGenerated;
- private int Rfc2898KeygenIterations = 1000;
- private string _Password;
- private bool _cryptoGenerated ;
-
- private WinZipAesCrypto(string password, int KeyStrengthInBits)
- {
- _Password = password;
- _KeyStrengthInBits = KeyStrengthInBits;
- }
-
- public static WinZipAesCrypto Generate(string password, int KeyStrengthInBits)
- {
- WinZipAesCrypto c = new WinZipAesCrypto(password, KeyStrengthInBits);
-
- int saltSizeInBytes = c._KeyStrengthInBytes / 2;
- c._Salt = new byte[saltSizeInBytes];
- Random rnd = new Random();
- rnd.NextBytes(c._Salt);
- return c;
- }
-
-
-
- public static WinZipAesCrypto ReadFromStream(string password, int KeyStrengthInBits, Stream s)
- {
- // from http://www.winzip.com/aes_info.htm
- //
- // Size(bytes) Content
- // -----------------------------------
- // Variable Salt value
- // 2 Password verification value
- // Variable Encrypted file data
- // 10 Authentication code
- //
- // ZipEntry.CompressedSize represents the size of all of those elements.
-
- // salt size varies with key length:
- // 128 bit key => 8 bytes salt
- // 192 bits => 12 bytes salt
- // 256 bits => 16 bytes salt
-
- WinZipAesCrypto c = new WinZipAesCrypto(password, KeyStrengthInBits);
-
- int saltSizeInBytes = c._KeyStrengthInBytes / 2;
- c._Salt = new byte[saltSizeInBytes];
- c._providedPv = new byte[2];
-
- s.Read(c._Salt, 0, c._Salt.Length);
- s.Read(c._providedPv, 0, c._providedPv.Length);
-
- c.PasswordVerificationStored = (Int16)(c._providedPv[0] + c._providedPv[1] * 256);
- if (password != null)
- {
- c.PasswordVerificationGenerated = (Int16)(c.GeneratedPV[0] + c.GeneratedPV[1] * 256);
- if (c.PasswordVerificationGenerated != c.PasswordVerificationStored)
- throw new BadPasswordException("bad password");
- }
-
- return c;
- }
-
- public byte[] GeneratedPV
- {
- get
- {
- if (!_cryptoGenerated) _GenerateCryptoBytes();
- return _generatedPv;
- }
- }
-
-
- public byte[] Salt
- {
- get
- {
- return _Salt;
- }
- }
-
-
- private int _KeyStrengthInBytes
- {
- get
- {
- return _KeyStrengthInBits / 8;
-
- }
- }
-
- public int SizeOfEncryptionMetadata
- {
- get
- {
- // 10 bytes after, (n-10) before the compressed data
- return _KeyStrengthInBytes / 2 + 10 + 2;
- }
- }
-
- public string Password
- {
- set
- {
- _Password = value;
- if (_Password != null)
- {
- PasswordVerificationGenerated = (Int16)(GeneratedPV[0] + GeneratedPV[1] * 256);
- if (PasswordVerificationGenerated != PasswordVerificationStored)
- throw new Ionic.Zip.BadPasswordException();
- }
- }
- private get
- {
- return _Password;
- }
- }
-
-
- private void _GenerateCryptoBytes()
- {
- //Console.WriteLine(" provided password: '{0}'", _Password);
-
- System.Security.Cryptography.Rfc2898DeriveBytes rfc2898 =
- new System.Security.Cryptography.Rfc2898DeriveBytes(_Password, Salt, Rfc2898KeygenIterations);
-
- _keyBytes = rfc2898.GetBytes(_KeyStrengthInBytes); // 16 or 24 or 32 ???
- _MacInitializationVector = rfc2898.GetBytes(_KeyStrengthInBytes);
- _generatedPv = rfc2898.GetBytes(2);
-
- _cryptoGenerated = true;
- }
-
-
- public byte[] KeyBytes
- {
- get
- {
- if (!_cryptoGenerated) _GenerateCryptoBytes();
- return _keyBytes;
- }
- }
-
-
- public byte[] MacIv
- {
- get
- {
- if (!_cryptoGenerated) _GenerateCryptoBytes();
- return _MacInitializationVector;
- }
- }
-
- public byte[] CalculatedMac;
-
-
- public void ReadAndVerifyMac(System.IO.Stream s)
- {
- bool invalid = false;
-
- // read integrityCheckVector.
- // caller must ensure that the file pointer is in the right spot!
- _StoredMac = new byte[10]; // aka "authentication code"
- s.Read(_StoredMac, 0, _StoredMac.Length);
-
- if (_StoredMac.Length != CalculatedMac.Length)
- invalid = true;
-
- if (!invalid)
- {
- for (int i = 0; i < _StoredMac.Length; i++)
- {
- if (_StoredMac[i] != CalculatedMac[i])
- invalid = true;
- }
- }
-
- if (invalid)
- throw new Ionic.Zip.BadStateException("The MAC does not match.");
- }
-
- }
-
-
- #region DONT_COMPILE_BUT_KEEP_FOR_POTENTIAL_FUTURE_USE
-#if NO
- internal class Util
- {
- private static void _Format(System.Text.StringBuilder sb1,
- byte[] b,
- int offset,
- int length)
- {
-
- System.Text.StringBuilder sb2 = new System.Text.StringBuilder();
- sb1.Append("0000 ");
- int i;
- for (i = 0; i < length; i++)
- {
- int x = offset+i;
- if (i != 0 && i % 16 == 0)
- {
- sb1.Append(" ")
- .Append(sb2)
- .Append("\n")
- .Append(String.Format("{0:X4} ", i));
- sb2.Remove(0,sb2.Length);
- }
- sb1.Append(System.String.Format("{0:X2} ", b[x]));
- if (b[x] >=32 && b[x] <= 126)
- sb2.Append((char)b[x]);
- else
- sb2.Append(".");
- }
- if (sb2.Length > 0)
- {
- sb1.Append(new String(' ', ((16 - i%16) * 3) + 4))
- .Append(sb2);
- }
- }
-
-
-
- internal static string FormatByteArray(byte[] b, int limit)
- {
- System.Text.StringBuilder sb1 = new System.Text.StringBuilder();
-
- if ((limit * 2 > b.Length) || limit == 0)
- {
- _Format(sb1, b, 0, b.Length);
- }
- else
- {
- // first N bytes of the buffer
- _Format(sb1, b, 0, limit);
-
- if (b.Length > limit * 2)
- sb1.Append(String.Format("\n ...({0} other bytes here)....\n", b.Length - limit * 2));
-
- // last N bytes of the buffer
- _Format(sb1, b, b.Length - limit, limit);
- }
-
- return sb1.ToString();
- }
-
-
- internal static string FormatByteArray(byte[] b)
- {
- return FormatByteArray(b, 0);
- }
- }
-
-#endif
- #endregion
-
-
-
-
- /// <summary>
- /// A stream that encrypts as it writes, or decrypts as it reads. The
- /// Crypto is AES in CTR (counter) mode, which is compatible with the AES
- /// encryption employed by WinZip 12.0.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The AES/CTR encryption protocol used by WinZip works like this:
- ///
- /// - start with a counter, initialized to zero.
- ///
- /// - to encrypt, take the data by 16-byte blocks. For each block:
- /// - apply the transform to the counter
- /// - increement the counter
- /// - XOR the result of the transform with the plaintext to
- /// get the ciphertext.
- /// - compute the mac on the encrypted bytes
- /// - when finished with all blocks, store the computed MAC.
- ///
- /// - to decrypt, take the data by 16-byte blocks. For each block:
- /// - compute the mac on the encrypted bytes,
- /// - apply the transform to the counter
- /// - increement the counter
- /// - XOR the result of the transform with the ciphertext to
- /// get the plaintext.
- /// - when finished with all blocks, compare the computed MAC against
- /// the stored MAC
- ///
- /// </para>
- /// </remarks>
- //
- internal class WinZipAesCipherStream : Stream
- {
- private WinZipAesCrypto _params;
- private System.IO.Stream _s;
- private CryptoMode _mode;
- private int _nonce;
- private bool _finalBlock;
-
- internal HMACSHA1 _mac;
-
- // Use RijndaelManaged from .NET 2.0.
- // AesManaged came in .NET 3.5, but we want to limit
- // dependency to .NET 2.0. AES is just a restricted form
- // of Rijndael (fixed block size of 128, some crypto modes not supported).
-
- internal RijndaelManaged _aesCipher;
- internal ICryptoTransform _xform;
-
- private const int BLOCK_SIZE_IN_BYTES = 16;
-
- private byte[] counter = new byte[BLOCK_SIZE_IN_BYTES];
- private byte[] counterOut = new byte[BLOCK_SIZE_IN_BYTES];
-
- // I've had a problem when wrapping a WinZipAesCipherStream inside
- // a DeflateStream. Calling Read() on the DeflateStream results in
- // a Read() on the WinZipAesCipherStream, but the buffer is larger
- // than the total size of the encrypted data, and larger than the
- // initial Read() on the DeflateStream! When the encrypted
- // bytestream is embedded within a larger stream (As in a zip
- // archive), the Read() doesn't fail with EOF. This causes bad
- // data to be returned, and it messes up the MAC.
-
- // This field is used to provide a hard-stop to the size of
- // data that can be read from the stream. In Read(), if the buffer or
- // read request goes beyond the stop, we truncate it.
-
- private long _length;
- private long _totalBytesXferred;
- private byte[] _PendingWriteBlock;
- private int _pendingCount;
- private byte[] _iobuf;
-
- /// <summary>
- /// The constructor.
- /// </summary>
- /// <param name="s">The underlying stream</param>
- /// <param name="mode">To either encrypt or decrypt.</param>
- /// <param name="cryptoParams">The pre-initialized WinZipAesCrypto object.</param>
- /// <param name="length">The maximum number of bytes to read from the stream.</param>
- internal WinZipAesCipherStream(System.IO.Stream s, WinZipAesCrypto cryptoParams, long length, CryptoMode mode)
- : this(s, cryptoParams, mode)
- {
- // don't read beyond this limit!
- _length = length;
- //Console.WriteLine("max length of AES stream: {0}", _length);
- }
-
-
-#if WANT_TRACE
- Stream untransformed;
- String traceFileUntransformed;
- Stream transformed;
- String traceFileTransformed;
-#endif
-
-
- internal WinZipAesCipherStream(System.IO.Stream s, WinZipAesCrypto cryptoParams, CryptoMode mode)
- : base()
- {
- TraceOutput("-------------------------------------------------------");
- TraceOutput("Create {0:X8}", this.GetHashCode());
-
- _params = cryptoParams;
- _s = s;
- _mode = mode;
- _nonce = 1;
-
- if (_params == null)
- throw new BadPasswordException("Supply a password to use AES encryption.");
-
- int keySizeInBits = _params.KeyBytes.Length * 8;
- if (keySizeInBits != 256 && keySizeInBits != 128 && keySizeInBits != 192)
- throw new ArgumentOutOfRangeException("keysize",
- "size of key must be 128, 192, or 256");
-
- _mac = new HMACSHA1(_params.MacIv);
-
- _aesCipher = new System.Security.Cryptography.RijndaelManaged();
- _aesCipher.BlockSize = 128;
- _aesCipher.KeySize = keySizeInBits; // 128, 192, 256
- _aesCipher.Mode = CipherMode.ECB;
- _aesCipher.Padding = PaddingMode.None;
-
- byte[] iv = new byte[BLOCK_SIZE_IN_BYTES]; // all zeroes
-
- // Create an ENCRYPTOR, regardless whether doing decryption or encryption.
- // It is reflexive.
- _xform = _aesCipher.CreateEncryptor(_params.KeyBytes, iv);
-
- if (_mode == CryptoMode.Encrypt)
- {
- _iobuf = new byte[2048];
- _PendingWriteBlock = new byte[BLOCK_SIZE_IN_BYTES];
- }
-
-
-#if WANT_TRACE
- traceFileUntransformed = "unpack\\WinZipAesCipherStream.trace.untransformed.out";
- traceFileTransformed = "unpack\\WinZipAesCipherStream.trace.transformed.out";
-
- untransformed = System.IO.File.Create(traceFileUntransformed);
- transformed = System.IO.File.Create(traceFileTransformed);
-#endif
- }
-
- private void XorInPlace(byte[] buffer, int offset, int count)
- {
- for (int i = 0; i < count; i++)
- {
- buffer[offset + i] = (byte)(counterOut[i] ^ buffer[offset + i]);
- }
- }
-
- private void WriteTransformOneBlock(byte[] buffer, int offset)
- {
- System.Array.Copy(BitConverter.GetBytes(_nonce++), 0, counter, 0, 4);
- _xform.TransformBlock(counter,
- 0,
- BLOCK_SIZE_IN_BYTES,
- counterOut,
- 0);
- XorInPlace(buffer, offset, BLOCK_SIZE_IN_BYTES);
- _mac.TransformBlock(buffer, offset, BLOCK_SIZE_IN_BYTES, null, 0);
- }
-
-
- private void WriteTransformBlocks(byte[] buffer, int offset, int count)
- {
- int posn = offset;
- int last = count + offset;
-
- while (posn < buffer.Length && posn < last)
- {
- WriteTransformOneBlock (buffer, posn);
- posn += BLOCK_SIZE_IN_BYTES;
- }
- }
-
-
- private void WriteTransformFinalBlock()
- {
- if (_pendingCount == 0)
- throw new InvalidOperationException("No bytes available.");
-
- if (_finalBlock)
- throw new InvalidOperationException("The final block has already been transformed.");
-
- System.Array.Copy(BitConverter.GetBytes(_nonce++), 0, counter, 0, 4);
- counterOut = _xform.TransformFinalBlock(counter,
- 0,
- BLOCK_SIZE_IN_BYTES);
- XorInPlace(_PendingWriteBlock, 0, _pendingCount);
- _mac.TransformFinalBlock(_PendingWriteBlock, 0, _pendingCount);
- _finalBlock = true;
- }
-
-
-
-
-
- private int ReadTransformOneBlock(byte[] buffer, int offset, int last)
- {
- if (_finalBlock)
- throw new NotSupportedException();
-
- int bytesRemaining = last - offset;
- int bytesToRead = (bytesRemaining > BLOCK_SIZE_IN_BYTES)
- ? BLOCK_SIZE_IN_BYTES
- : bytesRemaining;
-
- // update the counter
- System.Array.Copy(BitConverter.GetBytes(_nonce++), 0, counter, 0, 4);
-
- // Determine if this is the final block
- if ((bytesToRead == bytesRemaining) &&
- (_length > 0) &&
- (_totalBytesXferred + last == _length))
- {
- _mac.TransformFinalBlock(buffer, offset, bytesToRead);
- counterOut = _xform.TransformFinalBlock(counter,
- 0,
- BLOCK_SIZE_IN_BYTES);
- _finalBlock = true;
- }
- else
- {
- _mac.TransformBlock(buffer, offset, bytesToRead, null, 0);
- _xform.TransformBlock(counter,
- 0, // offset
- BLOCK_SIZE_IN_BYTES,
- counterOut,
- 0); // offset
- }
-
- XorInPlace(buffer, offset, bytesToRead);
- return bytesToRead;
- }
-
-
-
- private void ReadTransformBlocks(byte[] buffer, int offset, int count)
- {
- int posn = offset;
- int last = count + offset;
-
- while (posn < buffer.Length && posn < last )
- {
- int n = ReadTransformOneBlock (buffer, posn, last);
- posn += n;
- }
- }
-
-
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- if (_mode == CryptoMode.Encrypt)
- throw new NotSupportedException();
-
- if (buffer == null)
- throw new ArgumentNullException("buffer");
-
- if (offset < 0)
- throw new ArgumentOutOfRangeException("offset",
- "Must not be less than zero.");
- if (count < 0)
- throw new ArgumentOutOfRangeException("count",
- "Must not be less than zero.");
-
- if (buffer.Length < offset + count)
- throw new ArgumentException("The buffer is too small");
-
- // When I wrap a WinZipAesStream in a DeflateStream, the
- // DeflateStream asks its captive to read 4k blocks, even if the
- // encrypted bytestream is smaller than that. This is a way to
- // limit the number of bytes read.
-
- int bytesToRead = count;
-
- if (_totalBytesXferred >= _length)
- {
- return 0; // EOF
- }
-
- long bytesRemaining = _length - _totalBytesXferred;
- if (bytesRemaining < count) bytesToRead = (int)bytesRemaining;
-
- int n = _s.Read(buffer, offset, bytesToRead);
-
-
-#if WANT_TRACE
- untransformed.Write(buffer, offset, bytesToRead);
-#endif
-
- ReadTransformBlocks(buffer, offset, bytesToRead);
-
-#if WANT_TRACE
- transformed.Write(buffer, offset, bytesToRead);
-#endif
- _totalBytesXferred += n;
- return n;
- }
-
-
-
- /// <summary>
- /// Returns the final HMAC-SHA1-80 for the data that was encrypted.
- /// </summary>
- public byte[] FinalAuthentication
- {
- get
- {
- if (!_finalBlock)
- {
- // special-case zero-byte files
- if ( _totalBytesXferred != 0)
- throw new BadStateException("The final hash has not been computed.");
-
- // Must call ComputeHash on an empty byte array when no data
- // has run through the MAC.
-
- byte[] b = { };
- _mac.ComputeHash(b);
- // fall through
- }
- byte[] macBytes10 = new byte[10];
- System.Array.Copy(_mac.Hash, 0, macBytes10, 0, 10);
- return macBytes10;
- }
- }
-
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (_finalBlock)
- throw new InvalidOperationException("The final block has already been transformed.");
-
- if (_mode == CryptoMode.Decrypt)
- throw new NotSupportedException();
-
- if (buffer == null)
- throw new ArgumentNullException("buffer");
-
- if (offset < 0)
- throw new ArgumentOutOfRangeException("offset",
- "Must not be less than zero.");
- if (count < 0)
- throw new ArgumentOutOfRangeException("count",
- "Must not be less than zero.");
- if (buffer.Length < offset + count)
- throw new ArgumentException("The offset and count are too large");
-
- if (count == 0)
- return;
-
- TraceOutput("Write off({0}) count({1})", offset, count);
-
-#if WANT_TRACE
- untransformed.Write(buffer, offset, count);
-#endif
-
- // For proper AES encryption, an AES encryptor application calls
- // TransformBlock repeatedly for all 16-byte blocks except the
- // last. For the last block, it then calls TransformFinalBlock().
- //
- // This class is a stream that encrypts via Write(). But, it's not
- // possible to recognize which are the "last" bytes from within the call
- // to Write(). The caller can call Write() several times in succession,
- // with varying buffers. This class only "knows" that the last bytes
- // have been written when the app calls Close().
- //
- // Therefore, this class buffers writes: After completion every Write(),
- // a 16-byte "pending" block (_PendingWriteBlock) must hold between 1
- // and 16 bytes, which will be used in TransformFinalBlock if the app
- // calls Close() immediately thereafter. Also, every write must
- // transform any pending bytes, before transforming the data passed in
- // to the current call.
- //
- // In operation, after the first call to Write() and before the call to
- // Close(), one full or partial block of bytes is always available,
- // pending. At time of Close(), this class calls
- // WriteTransformFinalBlock() to flush the pending bytes.
- //
- // This approach works whether the caller writes in odd-sized batches,
- // for example 5000 bytes, or in batches that are neat multiples of the
- // blocksize (16).
- //
- // Logicaly, what we do is this:
- //
- // 1. if there are fewer than 16 bytes (pending + current), then
- // just copy them into th pending buffer and return.
- //
- // 2. there are more than 16 bytes to write. So, take the leading slice
- // of bytes from the current buffer, enough to fill the pending
- // buffer. Transform the pending block, and write it out.
- //
- // 3. Take the trailing slice of bytes (a full block or a partial block),
- // and copy it to the pending block for next time.
- //
- // 4. transform and write all the other blocks, the middle slice.
- //
-
- // There are 16 or fewer bytes, so just buffer the bytes.
- if (count + _pendingCount <= BLOCK_SIZE_IN_BYTES)
- {
- Buffer.BlockCopy(buffer,
- offset,
- _PendingWriteBlock,
- _pendingCount,
- count);
- _pendingCount += count;
-
- // At this point, _PendingWriteBlock contains up to
- // BLOCK_SIZE_IN_BYTES bytes, and _pendingCount ranges from 0 to
- // BLOCK_SIZE_IN_BYTES. We don't want to xform+write them yet,
- // because this may have been the last block. The last block gets
- // written at Close().
- return;
- }
-
- // We know there are at least 17 bytes, counting those in the current
- // buffer, along with the (possibly empty) pending block.
-
- int bytesRemaining = count;
- int curOffset = offset;
-
- // workitem 12815
- //
- // xform chunkwise ... Cannot transform in place using the original
- // buffer because that is user-maintained.
-
- if (_pendingCount != 0)
- {
- // We have more than one block of data to write, therefore it is safe
- // to xform+write.
- int fillCount = BLOCK_SIZE_IN_BYTES - _pendingCount;
-
- // fillCount is possibly zero here. That happens when the pending
- // buffer held 16 bytes (one complete block) before this call to
- // Write.
- if (fillCount > 0)
- {
- Buffer.BlockCopy(buffer,
- offset,
- _PendingWriteBlock,
- _pendingCount,
- fillCount);
-
- // adjust counts:
- bytesRemaining -= fillCount;
- curOffset += fillCount;
- }
-
- // xform and write:
- WriteTransformOneBlock(_PendingWriteBlock, 0);
- _s.Write(_PendingWriteBlock, 0, BLOCK_SIZE_IN_BYTES);
- _totalBytesXferred += BLOCK_SIZE_IN_BYTES;
- _pendingCount = 0;
- }
-
- // At this point _PendingWriteBlock is empty, and bytesRemaining is
- // always greater than 0.
-
- // Now, xform N blocks, where N = floor((bytesRemaining-1)/16). If
- // writing 32 bytes, then xform 1 block, and stage the remaining 16. If
- // writing 10037 bytes, xform 627 blocks of 16 bytes, then stage the
- // remaining 5 bytes.
-
- int blocksToXform = (bytesRemaining-1)/BLOCK_SIZE_IN_BYTES;
- _pendingCount = bytesRemaining - (blocksToXform * BLOCK_SIZE_IN_BYTES);
-
- // _pendingCount is ALWAYS between 1 and 16.
- // Put the last _pendingCount bytes into the pending block.
- Buffer.BlockCopy(buffer,
- curOffset + bytesRemaining - _pendingCount,
- _PendingWriteBlock,
- 0,
- _pendingCount);
- bytesRemaining -= _pendingCount;
- _totalBytesXferred += bytesRemaining; // will be true after the loop
-
- // now, transform all the full blocks preceding that.
- // bytesRemaining is always a multiple of 16 .
- if (blocksToXform > 0)
- {
- do
- {
- int c = _iobuf.Length;
- if (c > bytesRemaining) c = bytesRemaining;
- Buffer.BlockCopy(buffer,
- curOffset,
- _iobuf,
- 0,
- c);
-
- WriteTransformBlocks(_iobuf, 0, c);
- _s.Write(_iobuf, 0, c);
- bytesRemaining -= c;
- curOffset += c;
- } while(bytesRemaining > 0);
- }
- }
-
-
-
- /// <summary>
- /// Close the stream.
- /// </summary>
- public override void Close()
- {
- TraceOutput("Close {0:X8}", this.GetHashCode());
-
- // In the degenerate case, no bytes have been written to the
- // stream at all. Need to check here, and NOT emit the
- // final block if Write has not been called.
- if (_pendingCount > 0)
- {
- WriteTransformFinalBlock();
- _s.Write(_PendingWriteBlock, 0, _pendingCount);
- _totalBytesXferred += _pendingCount;
- _pendingCount = 0;
- }
- _s.Close();
-
-#if WANT_TRACE
- untransformed.Close();
- transformed.Close();
- Console.WriteLine("\nuntransformed bytestream is in {0}", traceFileUntransformed);
- Console.WriteLine("\ntransformed bytestream is in {0}", traceFileTransformed);
-#endif
- TraceOutput("-------------------------------------------------------");
- }
-
-
- /// <summary>
- /// Returns true if the stream can be read.
- /// </summary>
- public override bool CanRead
- {
- get
- {
- if (_mode != CryptoMode.Decrypt) return false;
- return true;
- }
- }
-
-
- /// <summary>
- /// Always returns false.
- /// </summary>
- public override bool CanSeek
- {
- get { return false; }
- }
-
- /// <summary>
- /// Returns true if the CryptoMode is Encrypt.
- /// </summary>
- public override bool CanWrite
- {
- get { return (_mode == CryptoMode.Encrypt); }
- }
-
- /// <summary>
- /// Flush the content in the stream.
- /// </summary>
- public override void Flush()
- {
- _s.Flush();
- }
-
- /// <summary>
- /// Getting this property throws a NotImplementedException.
- /// </summary>
- public override long Length
- {
- get { throw new NotImplementedException(); }
- }
-
- /// <summary>
- /// Getting or Setting this property throws a NotImplementedException.
- /// </summary>
- public override long Position
- {
- get { throw new NotImplementedException(); }
- set { throw new NotImplementedException(); }
- }
-
- /// <summary>
- /// This method throws a NotImplementedException.
- /// </summary>
- public override long Seek(long offset, System.IO.SeekOrigin origin)
- {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// This method throws a NotImplementedException.
- /// </summary>
- public override void SetLength(long value)
- {
- throw new NotImplementedException();
- }
-
-
-
- [System.Diagnostics.ConditionalAttribute("Trace")]
- private void TraceOutput(string format, params object[] varParams)
- {
- lock(_outputLock)
- {
- int tid = System.Threading.Thread.CurrentThread.GetHashCode();
- Console.ForegroundColor = (ConsoleColor) (tid % 8 + 8);
- Console.Write("{0:000} WZACS ", tid);
- Console.WriteLine(format, varParams);
- Console.ResetColor();
- }
- }
-
- private object _outputLock = new Object();
- }
-}
-#endif
diff --git a/EPPlus/Packaging/DotNetZip/ZipConstants.cs b/EPPlus/Packaging/DotNetZip/ZipConstants.cs
deleted file mode 100644
index 5852a29..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipConstants.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-// ZipConstants.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2006, 2007, 2008, 2009 Dino Chiesa and Microsoft Corporation.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2009-August-27 23:22:32>
-//
-// ------------------------------------------------------------------
-//
-// This module defines a few constants that are used in the project.
-//
-// ------------------------------------------------------------------
-
-using System;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- static class ZipConstants
- {
- public const UInt32 PackedToRemovableMedia = 0x30304b50;
- public const UInt32 Zip64EndOfCentralDirectoryRecordSignature = 0x06064b50;
- public const UInt32 Zip64EndOfCentralDirectoryLocatorSignature = 0x07064b50;
- public const UInt32 EndOfCentralDirectorySignature = 0x06054b50;
- public const int ZipEntrySignature = 0x04034b50;
- public const int ZipEntryDataDescriptorSignature = 0x08074b50;
- public const int SplitArchiveSignature = 0x08074b50;
- public const int ZipDirEntrySignature = 0x02014b50;
-
-
- // These are dictated by the Zip Spec.See APPNOTE.txt
- public const int AesKeySize = 192; // 128, 192, 256
- public const int AesBlockSize = 128; // ???
-
- public const UInt16 AesAlgId128 = 0x660E;
- public const UInt16 AesAlgId192 = 0x660F;
- public const UInt16 AesAlgId256 = 0x6610;
-
- }
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipCrypto.cs b/EPPlus/Packaging/DotNetZip/ZipCrypto.cs
deleted file mode 100644
index 6e7f625..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipCrypto.cs
+++ /dev/null
@@ -1,455 +0,0 @@
-// ZipCrypto.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2008, 2009, 2011 Dino Chiesa
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-July-28 06:30:59>
-//
-// ------------------------------------------------------------------
-//
-// This module provides the implementation for "traditional" Zip encryption.
-//
-// Created Tue Apr 15 17:39:56 2008
-//
-// ------------------------------------------------------------------
-
-using System;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- /// <summary>
- /// This class implements the "traditional" or "classic" PKZip encryption,
- /// which today is considered to be weak. On the other hand it is
- /// ubiquitous. This class is intended for use only by the DotNetZip
- /// library.
- /// </summary>
- ///
- /// <remarks>
- /// Most uses of the DotNetZip library will not involve direct calls into
- /// the ZipCrypto class. Instead, the ZipCrypto class is instantiated and
- /// used by the ZipEntry() class when encryption or decryption on an entry
- /// is employed. If for some reason you really wanted to use a weak
- /// encryption algorithm in some other application, you might use this
- /// library. But you would be much better off using one of the built-in
- /// strong encryption libraries in the .NET Framework, like the AES
- /// algorithm or SHA.
- /// </remarks>
- internal class ZipCrypto
- {
- /// <summary>
- /// The default constructor for ZipCrypto.
- /// </summary>
- ///
- /// <remarks>
- /// This class is intended for internal use by the library only. It's
- /// probably not useful to you. Seriously. Stop reading this
- /// documentation. It's a waste of your time. Go do something else.
- /// Check the football scores. Go get an ice cream with a friend.
- /// Seriously.
- /// </remarks>
- ///
- private ZipCrypto() { }
-
- public static ZipCrypto ForWrite(string password)
- {
- ZipCrypto z = new ZipCrypto();
- if (password == null)
- throw new BadPasswordException("This entry requires a password.");
- z.InitCipher(password);
- return z;
- }
-
-
- public static ZipCrypto ForRead(string password, ZipEntry e)
- {
- System.IO.Stream s = e._archiveStream;
- e._WeakEncryptionHeader = new byte[12];
- byte[] eh = e._WeakEncryptionHeader;
- ZipCrypto z = new ZipCrypto();
-
- if (password == null)
- throw new BadPasswordException("This entry requires a password.");
-
- z.InitCipher(password);
-
- ZipEntry.ReadWeakEncryptionHeader(s, eh);
-
- // Decrypt the header. This has a side effect of "further initializing the
- // encryption keys" in the traditional zip encryption.
- byte[] DecryptedHeader = z.DecryptMessage(eh, eh.Length);
-
- // CRC check
- // According to the pkzip spec, the final byte in the decrypted header
- // is the highest-order byte in the CRC. We check it here.
- if (DecryptedHeader[11] != (byte)((e._Crc32 >> 24) & 0xff))
- {
- // In the case that bit 3 of the general purpose bit flag is set to
- // indicate the presence of an 'Extended File Header' or a 'data
- // descriptor' (signature 0x08074b50), the last byte of the decrypted
- // header is sometimes compared with the high-order byte of the
- // lastmodified time, rather than the high-order byte of the CRC, to
- // verify the password.
- //
- // This is not documented in the PKWare Appnote.txt. It was
- // discovered this by analysis of the Crypt.c source file in the
- // InfoZip library http://www.info-zip.org/pub/infozip/
- //
- // The reason for this is that the CRC for a file cannot be known
- // until the entire contents of the file have been streamed. This
- // means a tool would have to read the file content TWICE in its
- // entirety in order to perform PKZIP encryption - once to compute
- // the CRC, and again to actually encrypt.
- //
- // This is so important for performance that using the timeblob as
- // the verification should be the standard practice for DotNetZip
- // when using PKZIP encryption. This implies that bit 3 must be
- // set. The downside is that some tools still cannot cope with ZIP
- // files that use bit 3. Therefore, DotNetZip DOES NOT force bit 3
- // when PKZIP encryption is in use, and instead, reads the stream
- // twice.
- //
-
- if ((e._BitField & 0x0008) != 0x0008)
- {
- throw new BadPasswordException("The password did not match.");
- }
- else if (DecryptedHeader[11] != (byte)((e._TimeBlob >> 8) & 0xff))
- {
- throw new BadPasswordException("The password did not match.");
- }
-
- // We have a good password.
- }
- else
- {
- // A-OK
- }
- return z;
- }
-
-
-
-
- /// <summary>
- /// From AppNote.txt:
- /// unsigned char decrypt_byte()
- /// local unsigned short temp
- /// temp :=- Key(2) | 2
- /// decrypt_byte := (temp * (temp ^ 1)) bitshift-right 8
- /// end decrypt_byte
- /// </summary>
- private byte MagicByte
- {
- get
- {
- UInt16 t = (UInt16)((UInt16)(_Keys[2] & 0xFFFF) | 2);
- return (byte)((t * (t ^ 1)) >> 8);
- }
- }
-
- // Decrypting:
- // From AppNote.txt:
- // loop for i from 0 to 11
- // C := buffer(i) ^ decrypt_byte()
- // update_keys(C)
- // buffer(i) := C
- // end loop
-
-
- /// <summary>
- /// Call this method on a cipher text to render the plaintext. You must
- /// first initialize the cipher with a call to InitCipher.
- /// </summary>
- ///
- /// <example>
- /// <code>
- /// var cipher = new ZipCrypto();
- /// cipher.InitCipher(Password);
- /// // Decrypt the header. This has a side effect of "further initializing the
- /// // encryption keys" in the traditional zip encryption.
- /// byte[] DecryptedMessage = cipher.DecryptMessage(EncryptedMessage);
- /// </code>
- /// </example>
- ///
- /// <param name="cipherText">The encrypted buffer.</param>
- /// <param name="length">
- /// The number of bytes to encrypt.
- /// Should be less than or equal to CipherText.Length.
- /// </param>
- ///
- /// <returns>The plaintext.</returns>
- public byte[] DecryptMessage(byte[] cipherText, int length)
- {
- if (cipherText == null)
- throw new ArgumentNullException("cipherText");
-
- if (length > cipherText.Length)
- throw new ArgumentOutOfRangeException("length",
- "Bad length during Decryption: the length parameter must be smaller than or equal to the size of the destination array.");
-
- byte[] plainText = new byte[length];
- for (int i = 0; i < length; i++)
- {
- byte C = (byte)(cipherText[i] ^ MagicByte);
- UpdateKeys(C);
- plainText[i] = C;
- }
- return plainText;
- }
-
- /// <summary>
- /// This is the converse of DecryptMessage. It encrypts the plaintext
- /// and produces a ciphertext.
- /// </summary>
- ///
- /// <param name="plainText">The plain text buffer.</param>
- ///
- /// <param name="length">
- /// The number of bytes to encrypt.
- /// Should be less than or equal to plainText.Length.
- /// </param>
- ///
- /// <returns>The ciphertext.</returns>
- public byte[] EncryptMessage(byte[] plainText, int length)
- {
- if (plainText == null)
- throw new ArgumentNullException("plaintext");
-
- if (length > plainText.Length)
- throw new ArgumentOutOfRangeException("length",
- "Bad length during Encryption: The length parameter must be smaller than or equal to the size of the destination array.");
-
- byte[] cipherText = new byte[length];
- for (int i = 0; i < length; i++)
- {
- byte C = plainText[i];
- cipherText[i] = (byte)(plainText[i] ^ MagicByte);
- UpdateKeys(C);
- }
- return cipherText;
- }
-
-
- /// <summary>
- /// This initializes the cipher with the given password.
- /// See AppNote.txt for details.
- /// </summary>
- ///
- /// <param name="passphrase">
- /// The passphrase for encrypting or decrypting with this cipher.
- /// </param>
- ///
- /// <remarks>
- /// <code>
- /// Step 1 - Initializing the encryption keys
- /// -----------------------------------------
- /// Start with these keys:
- /// Key(0) := 305419896 (0x12345678)
- /// Key(1) := 591751049 (0x23456789)
- /// Key(2) := 878082192 (0x34567890)
- ///
- /// Then, initialize the keys with a password:
- ///
- /// loop for i from 0 to length(password)-1
- /// update_keys(password(i))
- /// end loop
- ///
- /// Where update_keys() is defined as:
- ///
- /// update_keys(char):
- /// Key(0) := crc32(key(0),char)
- /// Key(1) := Key(1) + (Key(0) bitwiseAND 000000ffH)
- /// Key(1) := Key(1) * 134775813 + 1
- /// Key(2) := crc32(key(2),key(1) rightshift 24)
- /// end update_keys
- ///
- /// Where crc32(old_crc,char) is a routine that given a CRC value and a
- /// character, returns an updated CRC value after applying the CRC-32
- /// algorithm described elsewhere in this document.
- ///
- /// </code>
- ///
- /// <para>
- /// After the keys are initialized, then you can use the cipher to
- /// encrypt the plaintext.
- /// </para>
- ///
- /// <para>
- /// Essentially we encrypt the password with the keys, then discard the
- /// ciphertext for the password. This initializes the keys for later use.
- /// </para>
- ///
- /// </remarks>
- public void InitCipher(string passphrase)
- {
- byte[] p = SharedUtilities.StringToByteArray(passphrase);
- for (int i = 0; i < passphrase.Length; i++)
- UpdateKeys(p[i]);
- }
-
-
- private void UpdateKeys(byte byteValue)
- {
- _Keys[0] = (UInt32)crc32.ComputeCrc32((int)_Keys[0], byteValue);
- _Keys[1] = _Keys[1] + (byte)_Keys[0];
- _Keys[1] = _Keys[1] * 0x08088405 + 1;
- _Keys[2] = (UInt32)crc32.ComputeCrc32((int)_Keys[2], (byte)(_Keys[1] >> 24));
- }
-
- ///// <summary>
- ///// The byte array representing the seed keys used.
- ///// Get this after calling InitCipher. The 12 bytes represents
- ///// what the zip spec calls the "EncryptionHeader".
- ///// </summary>
- //public byte[] KeyHeader
- //{
- // get
- // {
- // byte[] result = new byte[12];
- // result[0] = (byte)(_Keys[0] & 0xff);
- // result[1] = (byte)((_Keys[0] >> 8) & 0xff);
- // result[2] = (byte)((_Keys[0] >> 16) & 0xff);
- // result[3] = (byte)((_Keys[0] >> 24) & 0xff);
- // result[4] = (byte)(_Keys[1] & 0xff);
- // result[5] = (byte)((_Keys[1] >> 8) & 0xff);
- // result[6] = (byte)((_Keys[1] >> 16) & 0xff);
- // result[7] = (byte)((_Keys[1] >> 24) & 0xff);
- // result[8] = (byte)(_Keys[2] & 0xff);
- // result[9] = (byte)((_Keys[2] >> 8) & 0xff);
- // result[10] = (byte)((_Keys[2] >> 16) & 0xff);
- // result[11] = (byte)((_Keys[2] >> 24) & 0xff);
- // return result;
- // }
- //}
-
- // private fields for the crypto stuff:
- private UInt32[] _Keys = { 0x12345678, 0x23456789, 0x34567890 };
- private Ionic.Crc.CRC32 crc32 = new Ionic.Crc.CRC32();
-
- }
-
- internal enum CryptoMode
- {
- Encrypt,
- Decrypt
- }
-
- /// <summary>
- /// A Stream for reading and concurrently decrypting data from a zip file,
- /// or for writing and concurrently encrypting data to a zip file.
- /// </summary>
- internal class ZipCipherStream : System.IO.Stream
- {
- private ZipCrypto _cipher;
- private System.IO.Stream _s;
- private CryptoMode _mode;
-
- /// <summary> The constructor. </summary>
- /// <param name="s">The underlying stream</param>
- /// <param name="mode">To either encrypt or decrypt.</param>
- /// <param name="cipher">The pre-initialized ZipCrypto object.</param>
- public ZipCipherStream(System.IO.Stream s, ZipCrypto cipher, CryptoMode mode)
- : base()
- {
- _cipher = cipher;
- _s = s;
- _mode = mode;
- }
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- if (_mode == CryptoMode.Encrypt)
- throw new NotSupportedException("This stream does not encrypt via Read()");
-
- if (buffer == null)
- throw new ArgumentNullException("buffer");
-
- byte[] db = new byte[count];
- int n = _s.Read(db, 0, count);
- byte[] decrypted = _cipher.DecryptMessage(db, n);
- for (int i = 0; i < n; i++)
- {
- buffer[offset + i] = decrypted[i];
- }
- return n;
- }
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (_mode == CryptoMode.Decrypt)
- throw new NotSupportedException("This stream does not Decrypt via Write()");
-
- if (buffer == null)
- throw new ArgumentNullException("buffer");
-
- // workitem 7696
- if (count == 0) return;
-
- byte[] plaintext = null;
- if (offset != 0)
- {
- plaintext = new byte[count];
- for (int i = 0; i < count; i++)
- {
- plaintext[i] = buffer[offset + i];
- }
- }
- else plaintext = buffer;
-
- byte[] encrypted = _cipher.EncryptMessage(plaintext, count);
- _s.Write(encrypted, 0, encrypted.Length);
- }
-
-
- public override bool CanRead
- {
- get { return (_mode == CryptoMode.Decrypt); }
- }
- public override bool CanSeek
- {
- get { return false; }
- }
-
- public override bool CanWrite
- {
- get { return (_mode == CryptoMode.Encrypt); }
- }
-
- public override void Flush()
- {
- //throw new NotSupportedException();
- }
-
- public override long Length
- {
- get { throw new NotSupportedException(); }
- }
-
- public override long Position
- {
- get { throw new NotSupportedException(); }
- set { throw new NotSupportedException(); }
- }
- public override long Seek(long offset, System.IO.SeekOrigin origin)
- {
- throw new NotSupportedException();
- }
-
- public override void SetLength(long value)
- {
- throw new NotSupportedException();
- }
- }
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipDirEntry.cs b/EPPlus/Packaging/DotNetZip/ZipDirEntry.cs
deleted file mode 100644
index ddc2447..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipDirEntry.cs
+++ /dev/null
@@ -1,381 +0,0 @@
-// ZipDirEntry.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2006-2011 Dino Chiesa .
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-July-11 12:03:03>
-//
-// ------------------------------------------------------------------
-//
-// This module defines members of the ZipEntry class for reading the
-// Zip file central directory.
-//
-// Created: Tue, 27 Mar 2007 15:30
-//
-// ------------------------------------------------------------------
-
-
-using System;
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
-
- partial class ZipEntry
- {
- /// <summary>
- /// True if the referenced entry is a directory.
- /// </summary>
- internal bool AttributesIndicateDirectory
- {
- get { return ((_InternalFileAttrs == 0) && ((_ExternalFileAttrs & 0x0010) == 0x0010)); }
- }
-
-
- internal void ResetDirEntry()
- {
- // __FileDataPosition is the position of the file data for an entry.
- // It is _RelativeOffsetOfLocalHeader + size of local header.
-
- // We cannot know the __FileDataPosition until we read the local
- // header.
-
- // The local header is not necessarily the same length as the record
- // in the central directory.
-
- // Set to -1, to indicate we need to read this later.
- this.__FileDataPosition = -1;
-
- // set _LengthOfHeader to 0, to indicate we need to read later.
- this._LengthOfHeader = 0;
- }
-
- /// <summary>
- /// Provides a human-readable string with information about the ZipEntry.
- /// </summary>
- public string Info
- {
- get
- {
- var builder = new System.Text.StringBuilder();
- builder
- .Append(string.Format(" ZipEntry: {0}\n", this.FileName))
- .Append(string.Format(" Version Made By: {0}\n", this._VersionMadeBy))
- .Append(string.Format(" Needed to extract: {0}\n", this.VersionNeeded));
-
- if (this._IsDirectory)
- builder.Append(" Entry type: directory\n");
- else
- {
- builder.Append(string.Format(" File type: {0}\n", this._IsText? "text":"binary"))
- .Append(string.Format(" Compression: {0}\n", this.CompressionMethod))
- .Append(string.Format(" Compressed: 0x{0:X}\n", this.CompressedSize))
- .Append(string.Format(" Uncompressed: 0x{0:X}\n", this.UncompressedSize))
- .Append(string.Format(" CRC32: 0x{0:X8}\n", this._Crc32));
- }
- builder.Append(string.Format(" Disk Number: {0}\n", this._diskNumber));
- if (this._RelativeOffsetOfLocalHeader > 0xFFFFFFFF)
- builder
- .Append(string.Format(" Relative Offset: 0x{0:X16}\n", this._RelativeOffsetOfLocalHeader));
- else
- builder
- .Append(string.Format(" Relative Offset: 0x{0:X8}\n", this._RelativeOffsetOfLocalHeader));
-
- builder
- .Append(string.Format(" Bit Field: 0x{0:X4}\n", this._BitField))
- .Append(string.Format(" Encrypted?: {0}\n", this._sourceIsEncrypted))
- .Append(string.Format(" Timeblob: 0x{0:X8}\n", this._TimeBlob))
- .Append(string.Format(" Time: {0}\n", Ionic.Zip.SharedUtilities.PackedToDateTime(this._TimeBlob)));
-
- builder.Append(string.Format(" Is Zip64?: {0}\n", this._InputUsesZip64));
- if (!string.IsNullOrEmpty(this._Comment))
- {
- builder.Append(string.Format(" Comment: {0}\n", this._Comment));
- }
- builder.Append("\n");
- return builder.ToString();
- }
- }
-
-
- // workitem 10330
- private class CopyHelper
- {
- private static System.Text.RegularExpressions.Regex re =
- new System.Text.RegularExpressions.Regex(" \\(copy (\\d+)\\)$");
-
- private static int callCount = 0;
-
- internal static string AppendCopyToFileName(string f)
- {
- callCount++;
- if (callCount > 25)
- throw new OverflowException("overflow while creating filename");
-
- int n = 1;
- int r = f.LastIndexOf(".");
-
- if (r == -1)
- {
- // there is no extension
- System.Text.RegularExpressions.Match m = re.Match(f);
- if (m.Success)
- {
- n = Int32.Parse(m.Groups[1].Value) + 1;
- string copy = String.Format(" (copy {0})", n);
- f = f.Substring(0, m.Index) + copy;
- }
- else
- {
- string copy = String.Format(" (copy {0})", n);
- f = f + copy;
- }
- }
- else
- {
- //System.Console.WriteLine("HasExtension");
- System.Text.RegularExpressions.Match m = re.Match(f.Substring(0, r));
- if (m.Success)
- {
- n = Int32.Parse(m.Groups[1].Value) + 1;
- string copy = String.Format(" (copy {0})", n);
- f = f.Substring(0, m.Index) + copy + f.Substring(r);
- }
- else
- {
- string copy = String.Format(" (copy {0})", n);
- f = f.Substring(0, r) + copy + f.Substring(r);
- }
-
- //System.Console.WriteLine("returning f({0})", f);
- }
- return f;
- }
- }
-
-
-
- /// <summary>
- /// Reads one entry from the zip directory structure in the zip file.
- /// </summary>
- ///
- /// <param name="zf">
- /// The zipfile for which a directory entry will be read. From this param, the
- /// method gets the ReadStream and the expected text encoding
- /// (ProvisionalAlternateEncoding) which is used if the entry is not marked
- /// UTF-8.
- /// </param>
- ///
- /// <param name="previouslySeen">
- /// a list of previously seen entry names; used to prevent duplicates.
- /// </param>
- ///
- /// <returns>the entry read from the archive.</returns>
- internal static ZipEntry ReadDirEntry(ZipFile zf,
- Dictionary<String,Object> previouslySeen)
- {
- System.IO.Stream s = zf.ReadStream;
- System.Text.Encoding expectedEncoding = (zf.AlternateEncodingUsage == ZipOption.Always)
- ? zf.AlternateEncoding
- : ZipFile.DefaultEncoding;
-
- int signature = Ionic.Zip.SharedUtilities.ReadSignature(s);
- // return null if this is not a local file header signature
- if (IsNotValidZipDirEntrySig(signature))
- {
- s.Seek(-4, System.IO.SeekOrigin.Current);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(s);
-
- // Getting "not a ZipDirEntry signature" here is not always wrong or an
- // error. This can happen when walking through a zipfile. After the
- // last ZipDirEntry, we expect to read an
- // EndOfCentralDirectorySignature. When we get this is how we know
- // we've reached the end of the central directory.
- if (signature != ZipConstants.EndOfCentralDirectorySignature &&
- signature != ZipConstants.Zip64EndOfCentralDirectoryRecordSignature &&
- signature != ZipConstants.ZipEntrySignature // workitem 8299
- )
- {
- throw new BadReadException(String.Format(" Bad signature (0x{0:X8}) at position 0x{1:X8}", signature, s.Position));
- }
- return null;
- }
-
- int bytesRead = 42 + 4;
- byte[] block = new byte[42];
- int n = s.Read(block, 0, block.Length);
- if (n != block.Length) return null;
-
- int i = 0;
- ZipEntry zde = new ZipEntry();
- zde.AlternateEncoding = expectedEncoding;
- zde._Source = ZipEntrySource.ZipFile;
- zde._container = new ZipContainer(zf);
-
- unchecked
- {
- zde._VersionMadeBy = (short)(block[i++] + block[i++] * 256);
- zde._VersionNeeded = (short)(block[i++] + block[i++] * 256);
- zde._BitField = (short)(block[i++] + block[i++] * 256);
- zde._CompressionMethod = (Int16)(block[i++] + block[i++] * 256);
- zde._TimeBlob = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
- zde._LastModified = Ionic.Zip.SharedUtilities.PackedToDateTime(zde._TimeBlob);
- zde._timestamp |= ZipEntryTimestamp.DOS;
-
- zde._Crc32 = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
- zde._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
- zde._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
- }
-
- // preserve
- zde._CompressionMethod_FromZipFile = zde._CompressionMethod;
-
- zde._filenameLength = (short)(block[i++] + block[i++] * 256);
- zde._extraFieldLength = (short)(block[i++] + block[i++] * 256);
- zde._commentLength = (short)(block[i++] + block[i++] * 256);
- zde._diskNumber = (UInt32)(block[i++] + block[i++] * 256);
-
- zde._InternalFileAttrs = (short)(block[i++] + block[i++] * 256);
- zde._ExternalFileAttrs = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
-
- zde._RelativeOffsetOfLocalHeader = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
-
- // workitem 7801
- zde.IsText = ((zde._InternalFileAttrs & 0x01) == 0x01);
-
- block = new byte[zde._filenameLength];
- n = s.Read(block, 0, block.Length);
- bytesRead += n;
- if ((zde._BitField & 0x0800) == 0x0800)
- {
- // UTF-8 is in use
- zde._FileNameInArchive = Ionic.Zip.SharedUtilities.Utf8StringFromBuffer(block);
- }
- else
- {
- zde._FileNameInArchive = Ionic.Zip.SharedUtilities.StringFromBuffer(block, expectedEncoding);
- }
-
- // workitem 10330
- // insure unique entry names
- while (previouslySeen.ContainsKey(zde._FileNameInArchive))
- {
- zde._FileNameInArchive = CopyHelper.AppendCopyToFileName(zde._FileNameInArchive);
- zde._metadataChanged = true;
- }
-
- if (zde.AttributesIndicateDirectory)
- zde.MarkAsDirectory(); // may append a slash to filename if nec.
- // workitem 6898
- else if (zde._FileNameInArchive.EndsWith("/")) zde.MarkAsDirectory();
-
- zde._CompressedFileDataSize = zde._CompressedSize;
- if ((zde._BitField & 0x01) == 0x01)
- {
- // this may change after processing the Extra field
- zde._Encryption_FromZipFile = zde._Encryption =
- EncryptionAlgorithm.PkzipWeak;
- zde._sourceIsEncrypted = true;
- }
-
- if (zde._extraFieldLength > 0)
- {
- zde._InputUsesZip64 = (zde._CompressedSize == 0xFFFFFFFF ||
- zde._UncompressedSize == 0xFFFFFFFF ||
- zde._RelativeOffsetOfLocalHeader == 0xFFFFFFFF);
-
- // Console.WriteLine(" Input uses Z64?: {0}", zde._InputUsesZip64);
-
- bytesRead += zde.ProcessExtraField(s, zde._extraFieldLength);
- zde._CompressedFileDataSize = zde._CompressedSize;
- }
-
- // we've processed the extra field, so we know the encryption method is set now.
- if (zde._Encryption == EncryptionAlgorithm.PkzipWeak)
- {
- // the "encryption header" of 12 bytes precedes the file data
- zde._CompressedFileDataSize -= 12;
- }
-#if AESCRYPTO
- else if (zde.Encryption == EncryptionAlgorithm.WinZipAes128 ||
- zde.Encryption == EncryptionAlgorithm.WinZipAes256)
- {
- zde._CompressedFileDataSize = zde.CompressedSize -
- (ZipEntry.GetLengthOfCryptoHeaderBytes(zde.Encryption) + 10);
- zde._LengthOfTrailer = 10;
- }
-#endif
-
- // tally the trailing descriptor
- if ((zde._BitField & 0x0008) == 0x0008)
- {
- // sig, CRC, Comp and Uncomp sizes
- if (zde._InputUsesZip64)
- zde._LengthOfTrailer += 24;
- else
- zde._LengthOfTrailer += 16;
- }
-
- // workitem 12744
- zde.AlternateEncoding = ((zde._BitField & 0x0800) == 0x0800)
- ? System.Text.Encoding.UTF8
- :expectedEncoding;
-
- zde.AlternateEncodingUsage = ZipOption.Always;
-
- if (zde._commentLength > 0)
- {
- block = new byte[zde._commentLength];
- n = s.Read(block, 0, block.Length);
- bytesRead += n;
- if ((zde._BitField & 0x0800) == 0x0800)
- {
- // UTF-8 is in use
- zde._Comment = Ionic.Zip.SharedUtilities.Utf8StringFromBuffer(block);
- }
- else
- {
- zde._Comment = Ionic.Zip.SharedUtilities.StringFromBuffer(block, expectedEncoding);
- }
- }
- //zde._LengthOfDirEntry = bytesRead;
- return zde;
- }
-
-
- /// <summary>
- /// Returns true if the passed-in value is a valid signature for a ZipDirEntry.
- /// </summary>
- /// <param name="signature">the candidate 4-byte signature value.</param>
- /// <returns>true, if the signature is valid according to the PKWare spec.</returns>
- internal static bool IsNotValidZipDirEntrySig(int signature)
- {
- return (signature != ZipConstants.ZipDirEntrySignature);
- }
-
-
- private Int16 _VersionMadeBy;
- private Int16 _InternalFileAttrs;
- private Int32 _ExternalFileAttrs;
-
- //private Int32 _LengthOfDirEntry;
- private Int16 _filenameLength;
- private Int16 _extraFieldLength;
- private Int16 _commentLength;
- }
-
-
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipEntry.Extract.cs b/EPPlus/Packaging/DotNetZip/ZipEntry.Extract.cs
deleted file mode 100644
index eb92b4c..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipEntry.Extract.cs
+++ /dev/null
@@ -1,1455 +0,0 @@
-// ZipEntry.Extract.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009-2011 Dino Chiesa
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-August-06 18:08:21>
-//
-// ------------------------------------------------------------------
-//
-// This module defines logic for Extract methods on the ZipEntry class.
-//
-// ------------------------------------------------------------------
-
-
-using System;
-using System.IO;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
-
- internal partial class ZipEntry
- {
- /// <summary>
- /// Extract the entry to the filesystem, starting at the current
- /// working directory.
- /// </summary>
- ///
- /// <overloads>
- /// This method has a bunch of overloads! One of them is sure to
- /// be the right one for you... If you don't like these, check
- /// out the <c>ExtractWithPassword()</c> methods.
- /// </overloads>
- ///
- /// <seealso cref="ZipEntry.ExtractExistingFile"/>
- /// <seealso cref="ZipEntry.Extract(ExtractExistingFileAction)"/>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This method extracts an entry from a zip file into the current
- /// working directory. The path of the entry as extracted is the full
- /// path as specified in the zip archive, relative to the current
- /// working directory. After the file is extracted successfully, the
- /// file attributes and timestamps are set.
- /// </para>
- ///
- /// <para>
- /// The action taken when extraction an entry would overwrite an
- /// existing file is determined by the <see cref="ExtractExistingFile"
- /// /> property.
- /// </para>
- ///
- /// <para>
- /// Within the call to <c>Extract()</c>, the content for the entry is
- /// written into a filesystem file, and then the last modified time of the
- /// file is set according to the <see cref="LastModified"/> property on
- /// the entry. See the remarks the <see cref="LastModified"/> property for
- /// some details about the last modified time.
- /// </para>
- ///
- /// </remarks>
- internal void Extract()
- {
- InternalExtract(".", null, null);
- }
-
-
- /// <summary>
- /// Extract the entry to a file in the filesystem, using the specified
- /// behavior when extraction would overwrite an existing file.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// See the remarks on the <see cref="LastModified"/> property, for some
- /// details about how the last modified time of the file is set after
- /// extraction.
- /// </para>
- /// </remarks>
- ///
- /// <param name="extractExistingFile">
- /// The action to take if extraction would overwrite an existing file.
- /// </param>
- internal void Extract(ExtractExistingFileAction extractExistingFile)
- {
- ExtractExistingFile = extractExistingFile;
- InternalExtract(".", null, null);
- }
-
- /// <summary>
- /// Extracts the entry to the specified stream.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The caller can specify any write-able stream, for example a <see
- /// cref="System.IO.FileStream"/>, a <see
- /// cref="System.IO.MemoryStream"/>, or ASP.NET's
- /// <c>Response.OutputStream</c>. The content will be decrypted and
- /// decompressed as necessary. If the entry is encrypted and no password
- /// is provided, this method will throw.
- /// </para>
- /// <para>
- /// The position on the stream is not reset by this method before it extracts.
- /// You may want to call stream.Seek() before calling ZipEntry.Extract().
- /// </para>
- /// </remarks>
- ///
- /// <param name="stream">
- /// the stream to which the entry should be extracted.
- /// </param>
- ///
- public void Extract(Stream stream)
- {
- InternalExtract(null, stream, null);
- }
-
- /// <summary>
- /// Extract the entry to the filesystem, starting at the specified base
- /// directory.
- /// </summary>
- ///
- /// <param name="baseDirectory">the pathname of the base directory</param>
- ///
- /// <seealso cref="ZipEntry.ExtractExistingFile"/>
- /// <seealso cref="ZipEntry.Extract(string, ExtractExistingFileAction)"/>
- ///
- /// <example>
- /// This example extracts only the entries in a zip file that are .txt files,
- /// into a directory called "textfiles".
- /// <code lang="C#">
- /// using (ZipFile zip = ZipFile.Read("PackedDocuments.zip"))
- /// {
- /// foreach (string s1 in zip.EntryFilenames)
- /// {
- /// if (s1.EndsWith(".txt"))
- /// {
- /// zip[s1].Extract("textfiles");
- /// }
- /// }
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip")
- /// Dim s1 As String
- /// For Each s1 In zip.EntryFilenames
- /// If s1.EndsWith(".txt") Then
- /// zip(s1).Extract("textfiles")
- /// End If
- /// Next
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <remarks>
- ///
- /// <para>
- /// Using this method, existing entries in the filesystem will not be
- /// overwritten. If you would like to force the overwrite of existing
- /// files, see the <see cref="ExtractExistingFile"/> property, or call
- /// <see cref="Extract(string, ExtractExistingFileAction)"/>.
- /// </para>
- ///
- /// <para>
- /// See the remarks on the <see cref="LastModified"/> property, for some
- /// details about how the last modified time of the created file is set.
- /// </para>
- /// </remarks>
- public void Extract(string baseDirectory)
- {
- InternalExtract(baseDirectory, null, null);
- }
-
-
-
-
-
- /// <summary>
- /// Extract the entry to the filesystem, starting at the specified base
- /// directory, and using the specified behavior when extraction would
- /// overwrite an existing file.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// See the remarks on the <see cref="LastModified"/> property, for some
- /// details about how the last modified time of the created file is set.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// <code lang="C#">
- /// String sZipPath = "Airborne.zip";
- /// String sFilePath = "Readme.txt";
- /// String sRootFolder = "Digado";
- /// using (ZipFile zip = ZipFile.Read(sZipPath))
- /// {
- /// if (zip.EntryFileNames.Contains(sFilePath))
- /// {
- /// // use the string indexer on the zip file
- /// zip[sFileName].Extract(sRootFolder,
- /// ExtractExistingFileAction.OverwriteSilently);
- /// }
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Dim sZipPath as String = "Airborne.zip"
- /// Dim sFilePath As String = "Readme.txt"
- /// Dim sRootFolder As String = "Digado"
- /// Using zip As ZipFile = ZipFile.Read(sZipPath)
- /// If zip.EntryFileNames.Contains(sFilePath)
- /// ' use the string indexer on the zip file
- /// zip(sFilePath).Extract(sRootFolder, _
- /// ExtractExistingFileAction.OverwriteSilently)
- /// End If
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="baseDirectory">the pathname of the base directory</param>
- /// <param name="extractExistingFile">
- /// The action to take if extraction would overwrite an existing file.
- /// </param>
- internal void Extract(string baseDirectory, ExtractExistingFileAction extractExistingFile)
- {
- ExtractExistingFile = extractExistingFile;
- InternalExtract(baseDirectory, null, null);
- }
-
-
- /// <summary>
- /// Extract the entry to the filesystem, using the current working directory
- /// and the specified password.
- /// </summary>
- ///
- /// <overloads>
- /// This method has a bunch of overloads! One of them is sure to be
- /// the right one for you...
- /// </overloads>
- ///
- /// <seealso cref="ZipEntry.ExtractExistingFile"/>
- /// <seealso cref="ZipEntry.ExtractWithPassword(ExtractExistingFileAction, string)"/>
- ///
- /// <remarks>
- ///
- /// <para>
- /// Existing entries in the filesystem will not be overwritten. If you
- /// would like to force the overwrite of existing files, see the <see
- /// cref="ZipEntry.ExtractExistingFile"/>property, or call
- /// <see
- /// cref="ExtractWithPassword(ExtractExistingFileAction,string)"/>.
- /// </para>
- ///
- /// <para>
- /// See the remarks on the <see cref="LastModified"/> property for some
- /// details about how the "last modified" time of the created file is
- /// set.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// In this example, entries that use encryption are extracted using a
- /// particular password.
- /// <code>
- /// using (var zip = ZipFile.Read(FilePath))
- /// {
- /// foreach (ZipEntry e in zip)
- /// {
- /// if (e.UsesEncryption)
- /// e.ExtractWithPassword("Secret!");
- /// else
- /// e.Extract();
- /// }
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using zip As ZipFile = ZipFile.Read(FilePath)
- /// Dim e As ZipEntry
- /// For Each e In zip
- /// If (e.UsesEncryption)
- /// e.ExtractWithPassword("Secret!")
- /// Else
- /// e.Extract
- /// End If
- /// Next
- /// End Using
- /// </code>
- /// </example>
- /// <param name="password">The Password to use for decrypting the entry.</param>
- public void ExtractWithPassword(string password)
- {
- InternalExtract(".", null, password);
- }
-
- /// <summary>
- /// Extract the entry to the filesystem, starting at the specified base
- /// directory, and using the specified password.
- /// </summary>
- ///
- /// <seealso cref="ZipEntry.ExtractExistingFile"/>
- /// <seealso cref="ZipEntry.ExtractWithPassword(string, ExtractExistingFileAction, string)"/>
- ///
- /// <remarks>
- /// <para>
- /// Existing entries in the filesystem will not be overwritten. If you
- /// would like to force the overwrite of existing files, see the <see
- /// cref="ZipEntry.ExtractExistingFile"/>property, or call
- /// <see
- /// cref="ExtractWithPassword(ExtractExistingFileAction,string)"/>.
- /// </para>
- ///
- /// <para>
- /// See the remarks on the <see cref="LastModified"/> property, for some
- /// details about how the last modified time of the created file is set.
- /// </para>
- /// </remarks>
- ///
- /// <param name="baseDirectory">The pathname of the base directory.</param>
- /// <param name="password">The Password to use for decrypting the entry.</param>
- public void ExtractWithPassword(string baseDirectory, string password)
- {
- InternalExtract(baseDirectory, null, password);
- }
-
-
-
-
- /// <summary>
- /// Extract the entry to a file in the filesystem, relative to the
- /// current directory, using the specified behavior when extraction
- /// would overwrite an existing file.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// See the remarks on the <see cref="LastModified"/> property, for some
- /// details about how the last modified time of the created file is set.
- /// </para>
- /// </remarks>
- ///
- /// <param name="password">The Password to use for decrypting the entry.</param>
- ///
- /// <param name="extractExistingFile">
- /// The action to take if extraction would overwrite an existing file.
- /// </param>
- internal void ExtractWithPassword(ExtractExistingFileAction extractExistingFile, string password)
- {
- ExtractExistingFile = extractExistingFile;
- InternalExtract(".", null, password);
- }
-
-
-
- /// <summary>
- /// Extract the entry to the filesystem, starting at the specified base
- /// directory, and using the specified behavior when extraction would
- /// overwrite an existing file.
- /// </summary>
- ///
- /// <remarks>
- /// See the remarks on the <see cref="LastModified"/> property, for some
- /// details about how the last modified time of the created file is set.
- /// </remarks>
- ///
- /// <param name="baseDirectory">the pathname of the base directory</param>
- ///
- /// <param name="extractExistingFile">The action to take if extraction would
- /// overwrite an existing file.</param>
- ///
- /// <param name="password">The Password to use for decrypting the entry.</param>
- internal void ExtractWithPassword(string baseDirectory, ExtractExistingFileAction extractExistingFile, string password)
- {
- ExtractExistingFile = extractExistingFile;
- InternalExtract(baseDirectory, null, password);
- }
-
- /// <summary>
- /// Extracts the entry to the specified stream, using the specified
- /// Password. For example, the caller could extract to Console.Out, or
- /// to a MemoryStream.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The caller can specify any write-able stream, for example a <see
- /// cref="System.IO.FileStream"/>, a <see
- /// cref="System.IO.MemoryStream"/>, or ASP.NET's
- /// <c>Response.OutputStream</c>. The content will be decrypted and
- /// decompressed as necessary. If the entry is encrypted and no password
- /// is provided, this method will throw.
- /// </para>
- /// <para>
- /// The position on the stream is not reset by this method before it extracts.
- /// You may want to call stream.Seek() before calling ZipEntry.Extract().
- /// </para>
- /// </remarks>
- ///
- ///
- /// <param name="stream">
- /// the stream to which the entry should be extracted.
- /// </param>
- /// <param name="password">
- /// The password to use for decrypting the entry.
- /// </param>
- public void ExtractWithPassword(Stream stream, string password)
- {
- InternalExtract(null, stream, password);
- }
-
-
- /// <summary>
- /// Opens a readable stream corresponding to the zip entry in the
- /// archive. The stream decompresses and decrypts as necessary, as it
- /// is read.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// DotNetZip offers a variety of ways to extract entries from a zip
- /// file. This method allows an application to extract an entry by
- /// reading a <see cref="System.IO.Stream"/>.
- /// </para>
- ///
- /// <para>
- /// The return value is of type <see
- /// cref="Ionic.Crc.CrcCalculatorStream"/>. Use it as you would any
- /// stream for reading. When an application calls <see
- /// cref="Stream.Read(byte[], int, int)"/> on that stream, it will
- /// receive data from the zip entry that is decrypted and decompressed
- /// as necessary.
- /// </para>
- ///
- /// <para>
- /// <c>CrcCalculatorStream</c> adds one additional feature: it keeps a
- /// CRC32 checksum on the bytes of the stream as it is read. The CRC
- /// value is available in the <see
- /// cref="Ionic.Crc.CrcCalculatorStream.Crc"/> property on the
- /// <c>CrcCalculatorStream</c>. When the read is complete, your
- /// application
- /// <em>should</em> check this CRC against the <see cref="ZipEntry.Crc"/>
- /// property on the <c>ZipEntry</c> to validate the content of the
- /// ZipEntry. You don't have to validate the entry using the CRC, but
- /// you should, to verify integrity. Check the example for how to do
- /// this.
- /// </para>
- ///
- /// <para>
- /// If the entry is protected with a password, then you need to provide
- /// a password prior to calling <see cref="OpenReader()"/>, either by
- /// setting the <see cref="Password"/> property on the entry, or the
- /// <see cref="ZipFile.Password"/> property on the <c>ZipFile</c>
- /// itself. Or, you can use <see cref="OpenReader(String)" />, the
- /// overload of OpenReader that accepts a password parameter.
- /// </para>
- ///
- /// <para>
- /// If you want to extract entry data into a write-able stream that is
- /// already opened, like a <see cref="System.IO.FileStream"/>, do not
- /// use this method. Instead, use <see cref="Extract(Stream)"/>.
- /// </para>
- ///
- /// <para>
- /// Your application may use only one stream created by OpenReader() at
- /// a time, and you should not call other Extract methods before
- /// completing your reads on a stream obtained from OpenReader(). This
- /// is because there is really only one source stream for the compressed
- /// content. A call to OpenReader() seeks in the source stream, to the
- /// beginning of the compressed content. A subsequent call to
- /// OpenReader() on a different entry will seek to a different position
- /// in the source stream, as will a call to Extract() or one of its
- /// overloads. This will corrupt the state for the decompressing stream
- /// from the original call to OpenReader().
- /// </para>
- ///
- /// <para>
- /// The <c>OpenReader()</c> method works only when the ZipEntry is
- /// obtained from an instance of <c>ZipFile</c>. This method will throw
- /// an exception if the ZipEntry is obtained from a ZipInputStream.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// This example shows how to open a zip archive, then read in a named
- /// entry via a stream. After the read loop is complete, the code
- /// compares the calculated during the read loop with the expected CRC
- /// on the <c>ZipEntry</c>, to verify the extraction.
- /// <code>
- /// using (ZipFile zip = new ZipFile(ZipFileToRead))
- /// {
- /// ZipEntry e1= zip["Elevation.mp3"];
- /// using (Ionic.Zlib.CrcCalculatorStream s = e1.OpenReader())
- /// {
- /// byte[] buffer = new byte[4096];
- /// int n, totalBytesRead= 0;
- /// do {
- /// n = s.Read(buffer,0, buffer.Length);
- /// totalBytesRead+=n;
- /// } while (n>0);
- /// if (s.Crc32 != e1.Crc32)
- /// throw new Exception(string.Format("The Zip Entry failed the CRC Check. (0x{0:X8}!=0x{1:X8})", s.Crc32, e1.Crc32));
- /// if (totalBytesRead != e1.UncompressedSize)
- /// throw new Exception(string.Format("We read an unexpected number of bytes. ({0}!={1})", totalBytesRead, e1.UncompressedSize));
- /// }
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using zip As New ZipFile(ZipFileToRead)
- /// Dim e1 As ZipEntry = zip.Item("Elevation.mp3")
- /// Using s As Ionic.Zlib.CrcCalculatorStream = e1.OpenReader
- /// Dim n As Integer
- /// Dim buffer As Byte() = New Byte(4096) {}
- /// Dim totalBytesRead As Integer = 0
- /// Do
- /// n = s.Read(buffer, 0, buffer.Length)
- /// totalBytesRead = (totalBytesRead + n)
- /// Loop While (n > 0)
- /// If (s.Crc32 <> e1.Crc32) Then
- /// Throw New Exception(String.Format("The Zip Entry failed the CRC Check. (0x{0:X8}!=0x{1:X8})", s.Crc32, e1.Crc32))
- /// End If
- /// If (totalBytesRead <> e1.UncompressedSize) Then
- /// Throw New Exception(String.Format("We read an unexpected number of bytes. ({0}!={1})", totalBytesRead, e1.UncompressedSize))
- /// End If
- /// End Using
- /// End Using
- /// </code>
- /// </example>
- /// <seealso cref="ZipEntry.Extract(System.IO.Stream)"/>
- /// <returns>The Stream for reading.</returns>
- internal Ionic.Crc.CrcCalculatorStream OpenReader()
- {
- // workitem 10923
- if (_container.ZipFile == null)
- throw new InvalidOperationException("Use OpenReader() only with ZipFile.");
-
- // use the entry password if it is non-null,
- // else use the zipfile password, which is possibly null
- return InternalOpenReader(this._Password ?? this._container.Password);
- }
-
- /// <summary>
- /// Opens a readable stream for an encrypted zip entry in the archive.
- /// The stream decompresses and decrypts as necessary, as it is read.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// See the documentation on the <see cref="OpenReader()"/> method for
- /// full details. This overload allows the application to specify a
- /// password for the <c>ZipEntry</c> to be read.
- /// </para>
- /// </remarks>
- ///
- /// <param name="password">The password to use for decrypting the entry.</param>
- /// <returns>The Stream for reading.</returns>
- internal Ionic.Crc.CrcCalculatorStream OpenReader(string password)
- {
- // workitem 10923
- if (_container.ZipFile == null)
- throw new InvalidOperationException("Use OpenReader() only with ZipFile.");
-
- return InternalOpenReader(password);
- }
-
-
-
- internal Ionic.Crc.CrcCalculatorStream InternalOpenReader(string password)
- {
- ValidateCompression();
- ValidateEncryption();
- SetupCryptoForExtract(password);
-
- // workitem 7958
- if (this._Source != ZipEntrySource.ZipFile)
- throw new BadStateException("You must call ZipFile.Save before calling OpenReader");
-
- // LeftToRead is a count of bytes remaining to be read (out)
- // from the stream AFTER decompression and decryption.
- // It is the uncompressed size, unless ... there is no compression in which
- // case ...? :< I'm not sure why it's not always UncompressedSize
- Int64 LeftToRead = (_CompressionMethod_FromZipFile == (short)CompressionMethod.None)
- ? this._CompressedFileDataSize
- : this.UncompressedSize;
-
- Stream input = this.ArchiveStream;
-
- this.ArchiveStream.Seek(this.FileDataPosition, SeekOrigin.Begin);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream);
-
- _inputDecryptorStream = GetExtractDecryptor(input);
- Stream input3 = GetExtractDecompressor(_inputDecryptorStream);
-
- return new Ionic.Crc.CrcCalculatorStream(input3, LeftToRead);
- }
-
-
-
- private void OnExtractProgress(Int64 bytesWritten, Int64 totalBytesToWrite)
- {
- if (_container.ZipFile != null)
- _ioOperationCanceled = _container.ZipFile.OnExtractBlock(this, bytesWritten, totalBytesToWrite);
- }
-
-
- private void OnBeforeExtract(string path)
- {
- // When in the context of a ZipFile.ExtractAll, the events are generated from
- // the ZipFile method, not from within the ZipEntry instance. (why?)
- // Therefore we suppress the events originating from the ZipEntry method.
- if (_container.ZipFile != null)
- {
- if (!_container.ZipFile._inExtractAll)
- {
- _ioOperationCanceled = _container.ZipFile.OnSingleEntryExtract(this, path, true);
- }
- }
- }
-
- private void OnAfterExtract(string path)
- {
- // When in the context of a ZipFile.ExtractAll, the events are generated from
- // the ZipFile method, not from within the ZipEntry instance. (why?)
- // Therefore we suppress the events originating from the ZipEntry method.
- if (_container.ZipFile != null)
- {
- if (!_container.ZipFile._inExtractAll)
- {
- _container.ZipFile.OnSingleEntryExtract(this, path, false);
- }
- }
- }
-
- private void OnExtractExisting(string path)
- {
- if (_container.ZipFile != null)
- _ioOperationCanceled = _container.ZipFile.OnExtractExisting(this, path);
- }
-
- private static void ReallyDelete(string fileName)
- {
- // workitem 7881
- // reset ReadOnly bit if necessary
-#if NETCF
- if ( (NetCfFile.GetAttributes(fileName) & (uint)FileAttributes.ReadOnly) == (uint)FileAttributes.ReadOnly)
- NetCfFile.SetAttributes(fileName, (uint)FileAttributes.Normal);
-#elif SILVERLIGHT
-#else
- if ((File.GetAttributes(fileName) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
- File.SetAttributes(fileName, FileAttributes.Normal);
-#endif
- File.Delete(fileName);
- }
-
-
- private void WriteStatus(string format, params Object[] args)
- {
- if (_container.ZipFile != null && _container.ZipFile.Verbose) _container.ZipFile.StatusMessageTextWriter.WriteLine(format, args);
- }
-
-
- // Pass in either basedir or s, but not both.
- // In other words, you can extract to a stream or to a directory (filesystem), but not both!
- // The Password param is required for encrypted entries.
- private void InternalExtract(string baseDir, Stream outstream, string password)
- {
- // workitem 7958
- if (_container == null)
- throw new BadStateException("This entry is an orphan");
-
- // workitem 10355
- if (_container.ZipFile == null)
- throw new InvalidOperationException("Use Extract() only with ZipFile.");
-
- _container.ZipFile.Reset(false);
-
- if (this._Source != ZipEntrySource.ZipFile)
- throw new BadStateException("You must call ZipFile.Save before calling any Extract method");
-
- OnBeforeExtract(baseDir);
- _ioOperationCanceled = false;
- string targetFileName = null;
- Stream output = null;
- bool fileExistsBeforeExtraction = false;
- bool checkLaterForResetDirTimes = false;
- try
- {
- ValidateCompression();
- ValidateEncryption();
-
- if (ValidateOutput(baseDir, outstream, out targetFileName))
- {
- WriteStatus("extract dir {0}...", targetFileName);
- // if true, then the entry was a directory and has been created.
- // We need to fire the Extract Event.
- OnAfterExtract(baseDir);
- return;
- }
-
- // workitem 10639
- // do we want to extract to a regular filesystem file?
- if (targetFileName != null)
- {
- // Check for extracting to a previously extant file. The user
- // can specify bejavior for that case: overwrite, don't
- // overwrite, and throw. Also, if the file exists prior to
- // extraction, it affects exception handling: whether to delete
- // the target of extraction or not. This check needs to be done
- // before the password check is done, because password check may
- // throw a BadPasswordException, which triggers the catch,
- // wherein the extant file may be deleted if not flagged as
- // pre-existing.
- if (File.Exists(targetFileName))
- {
- fileExistsBeforeExtraction = true;
- int rc = CheckExtractExistingFile(baseDir, targetFileName);
- if (rc == 2) goto ExitTry; // cancel
- if (rc == 1) return; // do not overwrite
- }
- }
-
- // If no password explicitly specified, use the password on the entry itself,
- // or on the zipfile itself.
- string p = password ?? this._Password ?? this._container.Password;
- if (_Encryption_FromZipFile != EncryptionAlgorithm.None)
- {
- if (p == null)
- throw new BadPasswordException();
- SetupCryptoForExtract(p);
- }
-
-
- // set up the output stream
- if (targetFileName != null)
- {
- WriteStatus("extract file {0}...", targetFileName);
- targetFileName += ".tmp";
- var dirName = Path.GetDirectoryName(targetFileName);
- // ensure the target path exists
- if (!Directory.Exists(dirName))
- {
- // we create the directory here, but we do not set the
- // create/modified/accessed times on it because it is being
- // created implicitly, not explcitly. There's no entry in the
- // zip archive for the directory.
- Directory.CreateDirectory(dirName);
- }
- else
- {
- // workitem 8264
- if (_container.ZipFile != null)
- checkLaterForResetDirTimes = _container.ZipFile._inExtractAll;
- }
-
- // File.Create(CreateNew) will overwrite any existing file.
- output = new FileStream(targetFileName, FileMode.CreateNew);
- }
- else
- {
- WriteStatus("extract entry {0} to stream...", FileName);
- output = outstream;
- }
-
-
- if (_ioOperationCanceled)
- goto ExitTry;
-
- Int32 ActualCrc32 = ExtractOne(output);
-
- if (_ioOperationCanceled)
- goto ExitTry;
-
- VerifyCrcAfterExtract(ActualCrc32);
-
- if (targetFileName != null)
- {
- output.Close();
- output = null;
-
- // workitem 10639
- // move file to permanent home
- string tmpName = targetFileName;
- string zombie = null;
- targetFileName = tmpName.Substring(0,tmpName.Length-4);
-
- if (fileExistsBeforeExtraction)
- {
- // An AV program may hold the target file open, which means
- // File.Delete() will succeed, though the actual deletion
- // remains pending. This will prevent a subsequent
- // File.Move() from succeeding. To avoid this, when the file
- // already exists, we need to replace it in 3 steps:
- //
- // 1. rename the existing file to a zombie name;
- // 2. rename the extracted file from the temp name to
- // the target file name;
- // 3. delete the zombie.
- //
- zombie = targetFileName + ".PendingOverwrite";
- File.Move(targetFileName, zombie);
- }
-
- File.Move(tmpName, targetFileName);
- _SetTimes(targetFileName, true);
-
- if (zombie != null && File.Exists(zombie))
- ReallyDelete(zombie);
-
- // workitem 8264
- if (checkLaterForResetDirTimes)
- {
- // This is sort of a hack. What I do here is set the time on
- // the parent directory, every time a file is extracted into
- // it. If there is a directory with 1000 files, then I set
- // the time on the dir, 1000 times. This allows the directory
- // to have times that reflect the actual time on the entry in
- // the zip archive.
-
- // String.Contains is not available on .NET CF 2.0
- if (this.FileName.IndexOf('/') != -1)
- {
- string dirname = Path.GetDirectoryName(this.FileName);
- if (this._container.ZipFile[dirname] == null)
- {
- _SetTimes(Path.GetDirectoryName(targetFileName), false);
- }
- }
- }
-
-#if NETCF
- // workitem 7926 - version made by OS can be zero or 10
- if ((_VersionMadeBy & 0xFF00) == 0x0a00 || (_VersionMadeBy & 0xFF00) == 0x0000)
- NetCfFile.SetAttributes(targetFileName, (uint)_ExternalFileAttrs);
-
-#else
- // workitem 7071
- //
- // We can only apply attributes if they are relevant to the NTFS
- // OS. Must do this LAST because it may involve a ReadOnly bit,
- // which would prevent us from setting the time, etc.
- //
- // workitem 7926 - version made by OS can be zero (FAT) or 10
- // (NTFS)
- if ((_VersionMadeBy & 0xFF00) == 0x0a00 || (_VersionMadeBy & 0xFF00) == 0x0000)
- File.SetAttributes(targetFileName, (FileAttributes)_ExternalFileAttrs);
-#endif
- }
-
- OnAfterExtract(baseDir);
-
- ExitTry: ;
- }
- catch (Exception)
- {
- _ioOperationCanceled = true;
- throw;
- }
- finally
- {
- if (_ioOperationCanceled)
- {
- if (targetFileName != null)
- {
- try
- {
- if (output != null) output.Close();
- // An exception has occurred. If the file exists, check
- // to see if it existed before we tried extracting. If
- // it did not, attempt to remove the target file. There
- // is a small possibility that the existing file has
- // been extracted successfully, overwriting a previously
- // existing file, and an exception was thrown after that
- // but before final completion (setting times, etc). In
- // that case the file will remain, even though some
- // error occurred. Nothing to be done about it.
- if (File.Exists(targetFileName) && !fileExistsBeforeExtraction)
- File.Delete(targetFileName);
-
- }
- finally { }
- }
- }
- }
- }
-
-
-#if NOT
- internal void CalcWinZipAesMac(Stream input)
- {
- if (Encryption == EncryptionAlgorithm.WinZipAes128 ||
- Encryption == EncryptionAlgorithm.WinZipAes256)
- {
- if (input is WinZipAesCipherStream)
- wzs = input as WinZipAesCipherStream;
-
- else if (input is Ionic.Zlib.CrcCalculatorStream)
- {
- xxx;
- }
-
- }
- }
-#endif
-
-
- internal void VerifyCrcAfterExtract(Int32 actualCrc32)
- {
-
-#if AESCRYPTO
- // After extracting, Validate the CRC32
- if (actualCrc32 != _Crc32)
- {
- // CRC is not meaningful with WinZipAES and AES method 2 (AE-2)
- if ((Encryption != EncryptionAlgorithm.WinZipAes128 &&
- Encryption != EncryptionAlgorithm.WinZipAes256)
- || _WinZipAesMethod != 0x02)
- throw new BadCrcException("CRC error: the file being extracted appears to be corrupted. " +
- String.Format("Expected 0x{0:X8}, Actual 0x{1:X8}", _Crc32, actualCrc32));
- }
-
- // ignore MAC if the size of the file is zero
- if (this.UncompressedSize == 0)
- return;
-
- // calculate the MAC
- if (Encryption == EncryptionAlgorithm.WinZipAes128 ||
- Encryption == EncryptionAlgorithm.WinZipAes256)
- {
- WinZipAesCipherStream wzs = _inputDecryptorStream as WinZipAesCipherStream;
- _aesCrypto_forExtract.CalculatedMac = wzs.FinalAuthentication;
-
- _aesCrypto_forExtract.ReadAndVerifyMac(this.ArchiveStream); // throws if MAC is bad
- // side effect: advances file position.
- }
-
-
-
-
-#else
- if (actualCrc32 != _Crc32)
- throw new BadCrcException("CRC error: the file being extracted appears to be corrupted. " +
- String.Format("Expected 0x{0:X8}, Actual 0x{1:X8}", _Crc32, actualCrc32));
-#endif
- }
-
-
-
-
- private int CheckExtractExistingFile(string baseDir, string targetFileName)
- {
- int loop = 0;
- // returns: 0 == extract, 1 = don't, 2 = cancel
- do
- {
- switch (ExtractExistingFile)
- {
- case ExtractExistingFileAction.OverwriteSilently:
- WriteStatus("the file {0} exists; will overwrite it...", targetFileName);
- return 0;
-
- case ExtractExistingFileAction.DoNotOverwrite:
- WriteStatus("the file {0} exists; not extracting entry...", FileName);
- OnAfterExtract(baseDir);
- return 1;
-
- case ExtractExistingFileAction.InvokeExtractProgressEvent:
- if (loop>0)
- throw new ZipException(String.Format("The file {0} already exists.", targetFileName));
- OnExtractExisting(baseDir);
- if (_ioOperationCanceled)
- return 2;
-
- // loop around
- break;
-
- case ExtractExistingFileAction.Throw:
- default:
- throw new ZipException(String.Format("The file {0} already exists.", targetFileName));
- }
- loop++;
- }
- while (true);
- }
-
-
-
-
- private void _CheckRead(int nbytes)
- {
- if (nbytes == 0)
- throw new BadReadException(String.Format("bad read of entry {0} from compressed archive.",
- this.FileName));
- }
-
-
- private Stream _inputDecryptorStream;
-
- private Int32 ExtractOne(Stream output)
- {
- Int32 CrcResult = 0;
- Stream input = this.ArchiveStream;
-
- try
- {
- // change for workitem 8098
- input.Seek(this.FileDataPosition, SeekOrigin.Begin);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(input);
-
- byte[] bytes = new byte[BufferSize];
-
- // The extraction process varies depending on how the entry was
- // stored. It could have been encrypted, and it coould have
- // been compressed, or both, or neither. So we need to check
- // both the encryption flag and the compression flag, and take
- // the proper action in all cases.
-
- Int64 LeftToRead = (_CompressionMethod_FromZipFile != (short)CompressionMethod.None)
- ? this.UncompressedSize
- : this._CompressedFileDataSize;
-
- // Get a stream that either decrypts or not.
- _inputDecryptorStream = GetExtractDecryptor(input);
-
- Stream input3 = GetExtractDecompressor( _inputDecryptorStream );
-
- Int64 bytesWritten = 0;
- // As we read, we maybe decrypt, and then we maybe decompress. Then we write.
- using (var s1 = new Ionic.Crc.CrcCalculatorStream(input3))
- {
- while (LeftToRead > 0)
- {
- //Console.WriteLine("ExtractOne: LeftToRead {0}", LeftToRead);
-
- // Casting LeftToRead down to an int is ok here in the else clause,
- // because that only happens when it is less than bytes.Length,
- // which is much less than MAX_INT.
- int len = (LeftToRead > bytes.Length) ? bytes.Length : (int)LeftToRead;
- int n = s1.Read(bytes, 0, len);
-
- // must check data read - essential for detecting corrupt zip files
- _CheckRead(n);
-
- output.Write(bytes, 0, n);
- LeftToRead -= n;
- bytesWritten += n;
-
- // fire the progress event, check for cancels
- OnExtractProgress(bytesWritten, UncompressedSize);
- if (_ioOperationCanceled)
- {
- break;
- }
- }
-
- CrcResult = s1.Crc;
- }
- }
- finally
- {
- var zss = input as ZipSegmentedStream;
- if (zss != null)
- {
-#if NETCF
- zss.Close();
-#else
- // need to dispose it
- zss.Dispose();
-#endif
- _archiveStream = null;
- }
- }
-
- return CrcResult;
- }
-
-
-
- internal Stream GetExtractDecompressor(Stream input2)
- {
- // get a stream that either decompresses or not.
- switch (_CompressionMethod_FromZipFile)
- {
- case (short)CompressionMethod.None:
- return input2;
- case (short)CompressionMethod.Deflate:
- return new Ionic.Zlib.DeflateStream(input2, Ionic.Zlib.CompressionMode.Decompress, true);
-#if BZIP
- case (short)CompressionMethod.BZip2:
- return new Ionic.BZip2.BZip2InputStream(input2, true);
-#endif
- }
-
- return null;
- }
-
-
-
- internal Stream GetExtractDecryptor(Stream input)
- {
- Stream input2 = null;
- if (_Encryption_FromZipFile == EncryptionAlgorithm.PkzipWeak)
- input2 = new ZipCipherStream(input, _zipCrypto_forExtract, CryptoMode.Decrypt);
-
-#if AESCRYPTO
- else if (_Encryption_FromZipFile == EncryptionAlgorithm.WinZipAes128 ||
- _Encryption_FromZipFile == EncryptionAlgorithm.WinZipAes256)
- input2 = new WinZipAesCipherStream(input, _aesCrypto_forExtract, _CompressedFileDataSize, CryptoMode.Decrypt);
-#endif
-
- else
- input2 = input;
-
- return input2;
- }
-
-
-
-
- internal void _SetTimes(string fileOrDirectory, bool isFile)
- {
-#if SILVERLIGHT
- // punt on setting file times
-#else
- // workitem 8807:
- // Because setting the time is not considered to be a fatal error,
- // and because other applications can interfere with the setting
- // of a time on a directory, we're going to swallow IO exceptions
- // in this method.
-
- try
- {
- if (_ntfsTimesAreSet)
- {
-#if NETCF
- // workitem 7944: set time should not be a fatal error on CF
- int rc = NetCfFile.SetTimes(fileOrDirectory, _Ctime, _Atime, _Mtime);
- if ( rc != 0)
- {
- WriteStatus("Warning: SetTimes failed. entry({0}) file({1}) rc({2})",
- FileName, fileOrDirectory, rc);
- }
-#else
- if (isFile)
- {
- // It's possible that the extract was cancelled, in which case,
- // the file does not exist.
- if (File.Exists(fileOrDirectory))
- {
- File.SetCreationTimeUtc(fileOrDirectory, _Ctime);
- File.SetLastAccessTimeUtc(fileOrDirectory, _Atime);
- File.SetLastWriteTimeUtc(fileOrDirectory, _Mtime);
- }
- }
- else
- {
- // It's possible that the extract was cancelled, in which case,
- // the directory does not exist.
- if (Directory.Exists(fileOrDirectory))
- {
- Directory.SetCreationTimeUtc(fileOrDirectory, _Ctime);
- Directory.SetLastAccessTimeUtc(fileOrDirectory, _Atime);
- Directory.SetLastWriteTimeUtc(fileOrDirectory, _Mtime);
- }
- }
-#endif
- }
- else
- {
- // workitem 6191
- DateTime AdjustedLastModified = Ionic.Zip.SharedUtilities.AdjustTime_Reverse(LastModified);
-
-#if NETCF
- int rc = NetCfFile.SetLastWriteTime(fileOrDirectory, AdjustedLastModified);
-
- if ( rc != 0)
- {
- WriteStatus("Warning: SetLastWriteTime failed. entry({0}) file({1}) rc({2})",
- FileName, fileOrDirectory, rc);
- }
-#else
- if (isFile)
- File.SetLastWriteTime(fileOrDirectory, AdjustedLastModified);
- else
- Directory.SetLastWriteTime(fileOrDirectory, AdjustedLastModified);
-#endif
- }
- }
- catch (System.IO.IOException ioexc1)
- {
- WriteStatus("failed to set time on {0}: {1}", fileOrDirectory, ioexc1.Message);
- }
-#endif
- }
-
-
- #region Support methods
-
-
- // workitem 7968
- private string UnsupportedAlgorithm
- {
- get
- {
- string alg = String.Empty;
- switch (_UnsupportedAlgorithmId)
- {
- case 0:
- alg = "--";
- break;
- case 0x6601:
- alg = "DES";
- break;
- case 0x6602: // - RC2 (version needed to extract < 5.2)
- alg = "RC2";
- break;
- case 0x6603: // - 3DES 168
- alg = "3DES-168";
- break;
- case 0x6609: // - 3DES 112
- alg = "3DES-112";
- break;
- case 0x660E: // - AES 128
- alg = "PKWare AES128";
- break;
- case 0x660F: // - AES 192
- alg = "PKWare AES192";
- break;
- case 0x6610: // - AES 256
- alg = "PKWare AES256";
- break;
- case 0x6702: // - RC2 (version needed to extract >= 5.2)
- alg = "RC2";
- break;
- case 0x6720: // - Blowfish
- alg = "Blowfish";
- break;
- case 0x6721: // - Twofish
- alg = "Twofish";
- break;
- case 0x6801: // - RC4
- alg = "RC4";
- break;
- case 0xFFFF: // - Unknown algorithm
- default:
- alg = String.Format("Unknown (0x{0:X4})", _UnsupportedAlgorithmId);
- break;
- }
- return alg;
- }
- }
-
- // workitem 7968
- private string UnsupportedCompressionMethod
- {
- get
- {
- string meth = String.Empty;
- switch ((int)_CompressionMethod)
- {
- case 0:
- meth = "Store";
- break;
- case 1:
- meth = "Shrink";
- break;
- case 8:
- meth = "DEFLATE";
- break;
- case 9:
- meth = "Deflate64";
- break;
- case 12:
- meth = "BZIP2"; // only if BZIP not compiled in
- break;
- case 14:
- meth = "LZMA";
- break;
- case 19:
- meth = "LZ77";
- break;
- case 98:
- meth = "PPMd";
- break;
- default:
- meth = String.Format("Unknown (0x{0:X4})", _CompressionMethod);
- break;
- }
- return meth;
- }
- }
-
-
- internal void ValidateEncryption()
- {
- if (Encryption != EncryptionAlgorithm.PkzipWeak &&
-#if AESCRYPTO
- Encryption != EncryptionAlgorithm.WinZipAes128 &&
- Encryption != EncryptionAlgorithm.WinZipAes256 &&
-#endif
- Encryption != EncryptionAlgorithm.None)
- {
- // workitem 7968
- if (_UnsupportedAlgorithmId != 0)
- throw new ZipException(String.Format("Cannot extract: Entry {0} is encrypted with an algorithm not supported by DotNetZip: {1}",
- FileName, UnsupportedAlgorithm));
- else
- throw new ZipException(String.Format("Cannot extract: Entry {0} uses an unsupported encryption algorithm ({1:X2})",
- FileName, (int)Encryption));
- }
- }
-
-
- private void ValidateCompression()
- {
- if ((_CompressionMethod_FromZipFile != (short)CompressionMethod.None) &&
- (_CompressionMethod_FromZipFile != (short)CompressionMethod.Deflate)
-#if BZIP
- && (_CompressionMethod_FromZipFile != (short)CompressionMethod.BZip2)
-#endif
- )
- throw new ZipException(String.Format("Entry {0} uses an unsupported compression method (0x{1:X2}, {2})",
- FileName, _CompressionMethod_FromZipFile, UnsupportedCompressionMethod));
- }
-
-
- private void SetupCryptoForExtract(string password)
- {
- //if (password == null) return;
- if (_Encryption_FromZipFile == EncryptionAlgorithm.None) return;
-
- if (_Encryption_FromZipFile == EncryptionAlgorithm.PkzipWeak)
- {
- if (password == null)
- throw new ZipException("Missing password.");
-
- this.ArchiveStream.Seek(this.FileDataPosition - 12, SeekOrigin.Begin);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream);
- _zipCrypto_forExtract = ZipCrypto.ForRead(password, this);
- }
-
-#if AESCRYPTO
- else if (_Encryption_FromZipFile == EncryptionAlgorithm.WinZipAes128 ||
- _Encryption_FromZipFile == EncryptionAlgorithm.WinZipAes256)
- {
- if (password == null)
- throw new ZipException("Missing password.");
-
- // If we already have a WinZipAesCrypto object in place, use it.
- // It can be set up in the ReadDirEntry(), or during a previous Extract.
- if (_aesCrypto_forExtract != null)
- {
- _aesCrypto_forExtract.Password = password;
- }
- else
- {
- int sizeOfSaltAndPv = GetLengthOfCryptoHeaderBytes(_Encryption_FromZipFile);
- this.ArchiveStream.Seek(this.FileDataPosition - sizeOfSaltAndPv, SeekOrigin.Begin);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream);
- int keystrength = GetKeyStrengthInBits(_Encryption_FromZipFile);
- _aesCrypto_forExtract = WinZipAesCrypto.ReadFromStream(password, keystrength, this.ArchiveStream);
- }
- }
-#endif
- }
-
-
-
- /// <summary>
- /// Validates that the args are consistent.
- /// </summary>
- /// <remarks>
- /// Only one of {baseDir, outStream} can be non-null.
- /// If baseDir is non-null, then the outputFile is created.
- /// </remarks>
- private bool ValidateOutput(string basedir, Stream outstream, out string outFileName)
- {
- if (basedir != null)
- {
- // Sometimes the name on the entry starts with a slash.
- // Rather than unpack to the root of the volume, we're going to
- // drop the slash and unpack to the specified base directory.
- string f = this.FileName.Replace("\\","/");
-
- // workitem 11772: remove drive letter with separator
- if (f.IndexOf(':') == 1)
- f= f.Substring(2);
-
- if (f.StartsWith("/"))
- f= f.Substring(1);
-
- // String.Contains is not available on .NET CF 2.0
-
- if (_container.ZipFile.FlattenFoldersOnExtract)
- outFileName = Path.Combine(basedir,
- (f.IndexOf('/') != -1) ? Path.GetFileName(f) : f);
- else
- outFileName = Path.Combine(basedir, f);
-
- // workitem 10639
- outFileName = outFileName.Replace("/","\\");
-
- // check if it is a directory
- if ((IsDirectory) || (FileName.EndsWith("/")))
- {
- if (!Directory.Exists(outFileName))
- {
- Directory.CreateDirectory(outFileName);
- _SetTimes(outFileName, false);
- }
- else
- {
- // the dir exists, maybe we want to overwrite times.
- if (ExtractExistingFile == ExtractExistingFileAction.OverwriteSilently)
- _SetTimes(outFileName, false);
- }
- return true; // true == all done, caller will return
- }
- return false; // false == work to do by caller.
- }
-
- if (outstream != null)
- {
- outFileName = null;
- if ((IsDirectory) || (FileName.EndsWith("/")))
- {
- // extract a directory to streamwriter? nothing to do!
- return true; // true == all done! caller can return
- }
- return false;
- }
-
- throw new ArgumentNullException("outstream");
- }
-
-
- #endregion
-
- }
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipEntry.Read.cs b/EPPlus/Packaging/DotNetZip/ZipEntry.Read.cs
deleted file mode 100644
index 46a69eb..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipEntry.Read.cs
+++ /dev/null
@@ -1,798 +0,0 @@
-// ZipEntry.Read.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009-2011 Dino Chiesa
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-July-09 21:31:28>
-//
-// ------------------------------------------------------------------
-//
-// This module defines logic for Reading the ZipEntry from a
-// zip file.
-//
-// ------------------------------------------------------------------
-
-
-using System;
-using System.IO;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- internal partial class ZipEntry
- {
- private int _readExtraDepth;
- private void ReadExtraField()
- {
- _readExtraDepth++;
- // workitem 8098: ok (restore)
- long posn = this.ArchiveStream.Position;
- this.ArchiveStream.Seek(this._RelativeOffsetOfLocalHeader, SeekOrigin.Begin);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream);
-
- byte[] block = new byte[30];
- this.ArchiveStream.Read(block, 0, block.Length);
- int i = 26;
- Int16 filenameLength = (short)(block[i++] + block[i++] * 256);
- Int16 extraFieldLength = (short)(block[i++] + block[i++] * 256);
-
- // workitem 8098: ok (relative)
- this.ArchiveStream.Seek(filenameLength, SeekOrigin.Current);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream);
-
- ProcessExtraField(this.ArchiveStream, extraFieldLength);
-
- // workitem 8098: ok (restore)
- this.ArchiveStream.Seek(posn, SeekOrigin.Begin);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream);
- _readExtraDepth--;
- }
-
-
- private static bool ReadHeader(ZipEntry ze, System.Text.Encoding defaultEncoding)
- {
- int bytesRead = 0;
-
- // change for workitem 8098
- ze._RelativeOffsetOfLocalHeader = ze.ArchiveStream.Position;
-
- int signature = Ionic.Zip.SharedUtilities.ReadEntrySignature(ze.ArchiveStream);
- bytesRead += 4;
-
- // Return false if this is not a local file header signature.
- if (ZipEntry.IsNotValidSig(signature))
- {
- // Getting "not a ZipEntry signature" is not always wrong or an error.
- // This will happen after the last entry in a zipfile. In that case, we
- // expect to read :
- // a ZipDirEntry signature (if a non-empty zip file) or
- // a ZipConstants.EndOfCentralDirectorySignature.
- //
- // Anything else is a surprise.
-
- ze.ArchiveStream.Seek(-4, SeekOrigin.Current); // unread the signature
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(ze.ArchiveStream);
- if (ZipEntry.IsNotValidZipDirEntrySig(signature) && (signature != ZipConstants.EndOfCentralDirectorySignature))
- {
- throw new BadReadException(String.Format(" Bad signature (0x{0:X8}) at position 0x{1:X8}", signature, ze.ArchiveStream.Position));
- }
- return false;
- }
-
- byte[] block = new byte[26];
- int n = ze.ArchiveStream.Read(block, 0, block.Length);
- if (n != block.Length) return false;
- bytesRead += n;
-
- int i = 0;
- ze._VersionNeeded = (Int16)(block[i++] + block[i++] * 256);
- ze._BitField = (Int16)(block[i++] + block[i++] * 256);
- ze._CompressionMethod_FromZipFile = ze._CompressionMethod = (Int16)(block[i++] + block[i++] * 256);
- ze._TimeBlob = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
- // transform the time data into something usable (a DateTime)
- ze._LastModified = Ionic.Zip.SharedUtilities.PackedToDateTime(ze._TimeBlob);
- ze._timestamp |= ZipEntryTimestamp.DOS;
-
- if ((ze._BitField & 0x01) == 0x01)
- {
- ze._Encryption_FromZipFile = ze._Encryption = EncryptionAlgorithm.PkzipWeak; // this *may* change after processing the Extra field
- ze._sourceIsEncrypted = true;
- }
-
- // NB: if ((ze._BitField & 0x0008) != 0x0008), then the Compressed, uncompressed and
- // CRC values are not true values; the true values will follow the entry data.
- // But, regardless of the status of bit 3 in the bitfield, the slots for
- // the three amigos may contain marker values for ZIP64. So we must read them.
- {
- ze._Crc32 = (Int32)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
- ze._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
- ze._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
-
- if ((uint)ze._CompressedSize == 0xFFFFFFFF ||
- (uint)ze._UncompressedSize == 0xFFFFFFFF)
-
- ze._InputUsesZip64 = true;
- }
-
- Int16 filenameLength = (short)(block[i++] + block[i++] * 256);
- Int16 extraFieldLength = (short)(block[i++] + block[i++] * 256);
-
- block = new byte[filenameLength];
- n = ze.ArchiveStream.Read(block, 0, block.Length);
- bytesRead += n;
-
- // if the UTF8 bit is set for this entry, override the
- // encoding the application requested.
-
- if ((ze._BitField & 0x0800) == 0x0800)
- {
- // workitem 12744
- ze.AlternateEncoding = System.Text.Encoding.UTF8;
- ze.AlternateEncodingUsage = ZipOption.Always;
- }
-
- // need to use this form of GetString() for .NET CF
- ze._FileNameInArchive = ze.AlternateEncoding.GetString(block, 0, block.Length);
-
- // workitem 6898
- if (ze._FileNameInArchive.EndsWith("/")) ze.MarkAsDirectory();
-
- bytesRead += ze.ProcessExtraField(ze.ArchiveStream, extraFieldLength);
-
- ze._LengthOfTrailer = 0;
-
- // workitem 6607 - don't read for directories
- // actually get the compressed size and CRC if necessary
- if (!ze._FileNameInArchive.EndsWith("/") && (ze._BitField & 0x0008) == 0x0008)
- {
- // This descriptor exists only if bit 3 of the general
- // purpose bit flag is set (see below). It is byte aligned
- // and immediately follows the last byte of compressed data,
- // as well as any encryption trailer, as with AES.
- // This descriptor is used only when it was not possible to
- // seek in the output .ZIP file, e.g., when the output .ZIP file
- // was standard output or a non-seekable device. For ZIP64(tm) format
- // archives, the compressed and uncompressed sizes are 8 bytes each.
-
- // workitem 8098: ok (restore)
- long posn = ze.ArchiveStream.Position;
-
- // Here, we're going to loop until we find a ZipEntryDataDescriptorSignature and
- // a consistent data record after that. To be consistent, the data record must
- // indicate the length of the entry data.
- bool wantMore = true;
- long SizeOfDataRead = 0;
- int tries = 0;
- while (wantMore)
- {
- tries++;
- // We call the FindSignature shared routine to find the specified signature
- // in the already-opened zip archive, starting from the current cursor
- // position in that filestream. If we cannot find the signature, then the
- // routine returns -1, and the ReadHeader() method returns false,
- // indicating we cannot read a legal entry header. If we have found it,
- // then the FindSignature() method returns the number of bytes in the
- // stream we had to seek forward, to find the sig. We need this to
- // determine if the zip entry is valid, later.
-
- if (ze._container.ZipFile != null)
- ze._container.ZipFile.OnReadBytes(ze);
-
- long d = Ionic.Zip.SharedUtilities.FindSignature(ze.ArchiveStream, ZipConstants.ZipEntryDataDescriptorSignature);
- if (d == -1) return false;
-
- // total size of data read (through all loops of this).
- SizeOfDataRead += d;
-
- if (ze._InputUsesZip64)
- {
- // read 1x 4-byte (CRC) and 2x 8-bytes (Compressed Size, Uncompressed Size)
- block = new byte[20];
- n = ze.ArchiveStream.Read(block, 0, block.Length);
- if (n != 20) return false;
-
- // do not increment bytesRead - it is for entry header only.
- // the data we have just read is a footer (falls after the file data)
- //bytesRead += n;
-
- i = 0;
- ze._Crc32 = (Int32)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
- ze._CompressedSize = BitConverter.ToInt64(block, i);
- i += 8;
- ze._UncompressedSize = BitConverter.ToInt64(block, i);
- i += 8;
-
- ze._LengthOfTrailer = 24; // bytes including sig, CRC, Comp and Uncomp sizes
- }
- else
- {
- // read 3x 4-byte fields (CRC, Compressed Size, Uncompressed Size)
- block = new byte[12];
- n = ze.ArchiveStream.Read(block, 0, block.Length);
- if (n != 12) return false;
-
- // do not increment bytesRead - it is for entry header only.
- // the data we have just read is a footer (falls after the file data)
- //bytesRead += n;
-
- i = 0;
- ze._Crc32 = (Int32)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
- ze._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
- ze._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
-
- ze._LengthOfTrailer = 16; // bytes including sig, CRC, Comp and Uncomp sizes
-
- }
-
- wantMore = (SizeOfDataRead != ze._CompressedSize);
-
- if (wantMore)
- {
- // Seek back to un-read the last 12 bytes - maybe THEY contain
- // the ZipEntryDataDescriptorSignature.
- // (12 bytes for the CRC, Comp and Uncomp size.)
- ze.ArchiveStream.Seek(-12, SeekOrigin.Current);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(ze.ArchiveStream);
-
- // Adjust the size to account for the false signature read in
- // FindSignature().
- SizeOfDataRead += 4;
- }
- }
-
- // seek back to previous position, to prepare to read file data
- // workitem 8098: ok (restore)
- ze.ArchiveStream.Seek(posn, SeekOrigin.Begin);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(ze.ArchiveStream);
- }
-
- ze._CompressedFileDataSize = ze._CompressedSize;
-
-
- // bit 0 set indicates that some kind of encryption is in use
- if ((ze._BitField & 0x01) == 0x01)
- {
-#if AESCRYPTO
- if (ze.Encryption == EncryptionAlgorithm.WinZipAes128 ||
- ze.Encryption == EncryptionAlgorithm.WinZipAes256)
- {
- int bits = ZipEntry.GetKeyStrengthInBits(ze._Encryption_FromZipFile);
- // read in the WinZip AES metadata: salt + PV. 18 bytes for AES256. 10 bytes for AES128.
- ze._aesCrypto_forExtract = WinZipAesCrypto.ReadFromStream(null, bits, ze.ArchiveStream);
- bytesRead += ze._aesCrypto_forExtract.SizeOfEncryptionMetadata - 10; // MAC (follows crypto bytes)
- // according to WinZip, the CompressedSize includes the AES Crypto framing data.
- ze._CompressedFileDataSize -= ze._aesCrypto_forExtract.SizeOfEncryptionMetadata;
- ze._LengthOfTrailer += 10; // MAC
- }
- else
-#endif
- {
- // read in the header data for "weak" encryption
- ze._WeakEncryptionHeader = new byte[12];
- bytesRead += ZipEntry.ReadWeakEncryptionHeader(ze._archiveStream, ze._WeakEncryptionHeader);
- // decrease the filedata size by 12 bytes
- ze._CompressedFileDataSize -= 12;
- }
- }
-
- // Remember the size of the blob for this entry.
- // We also have the starting position in the stream for this entry.
- ze._LengthOfHeader = bytesRead;
- ze._TotalEntrySize = ze._LengthOfHeader + ze._CompressedFileDataSize + ze._LengthOfTrailer;
-
-
- // We've read in the regular entry header, the extra field, and any
- // encryption header. The pointer in the file is now at the start of the
- // filedata, which is potentially compressed and encrypted. Just ahead in
- // the file, there are _CompressedFileDataSize bytes of data, followed by
- // potentially a non-zero length trailer, consisting of optionally, some
- // encryption stuff (10 byte MAC for AES), and the bit-3 trailer (16 or 24
- // bytes).
-
- return true;
- }
-
-
-
- internal static int ReadWeakEncryptionHeader(Stream s, byte[] buffer)
- {
- // PKZIP encrypts the compressed data stream. Encrypted files must
- // be decrypted before they can be extracted.
-
- // Each PKZIP-encrypted file has an extra 12 bytes stored at the start of the data
- // area defining the encryption header for that file. The encryption header is
- // originally set to random values, and then itself encrypted, using three, 32-bit
- // keys. The key values are initialized using the supplied encryption password.
- // After each byte is encrypted, the keys are then updated using pseudo-random
- // number generation techniques in combination with the same CRC-32 algorithm used
- // in PKZIP and implemented in the CRC32.cs module in this project.
-
- // read the 12-byte encryption header
- int additionalBytesRead = s.Read(buffer, 0, 12);
- if (additionalBytesRead != 12)
- throw new ZipException(String.Format("Unexpected end of data at position 0x{0:X8}", s.Position));
-
- return additionalBytesRead;
- }
-
-
-
- private static bool IsNotValidSig(int signature)
- {
- return (signature != ZipConstants.ZipEntrySignature);
- }
-
-
- /// <summary>
- /// Reads one <c>ZipEntry</c> from the given stream. The content for
- /// the entry does not get decompressed or decrypted. This method
- /// basically reads metadata, and seeks.
- /// </summary>
- /// <param name="zc">the ZipContainer this entry belongs to.</param>
- /// <param name="first">
- /// true of this is the first entry being read from the stream.
- /// </param>
- /// <returns>the <c>ZipEntry</c> read from the stream.</returns>
- internal static ZipEntry ReadEntry(ZipContainer zc, bool first)
- {
- ZipFile zf = zc.ZipFile;
- Stream s = zc.ReadStream;
- System.Text.Encoding defaultEncoding = zc.AlternateEncoding;
- ZipEntry entry = new ZipEntry();
- entry._Source = ZipEntrySource.ZipFile;
- entry._container = zc;
- entry._archiveStream = s;
- if (zf != null)
- zf.OnReadEntry(true, null);
-
- if (first) HandlePK00Prefix(s);
-
- // Read entry header, including any encryption header
- if (!ReadHeader(entry, defaultEncoding)) return null;
-
- // Store the position in the stream for this entry
- // change for workitem 8098
- entry.__FileDataPosition = entry.ArchiveStream.Position;
-
- // seek past the data without reading it. We will read on Extract()
- s.Seek(entry._CompressedFileDataSize + entry._LengthOfTrailer, SeekOrigin.Current);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(s);
-
- // ReadHeader moves the file pointer to the end of the entry header,
- // as well as any encryption header.
-
- // CompressedFileDataSize includes:
- // the maybe compressed, maybe encrypted file data
- // the encryption trailer, if any
- // the bit 3 descriptor, if any
-
- // workitem 5306
- // http://www.codeplex.com/DotNetZip/WorkItem/View.aspx?WorkItemId=5306
- HandleUnexpectedDataDescriptor(entry);
-
- if (zf != null)
- {
- zf.OnReadBytes(entry);
- zf.OnReadEntry(false, entry);
- }
-
- return entry;
- }
-
-
- internal static void HandlePK00Prefix(Stream s)
- {
- // in some cases, the zip file begins with "PK00". This is a throwback and is rare,
- // but we handle it anyway. We do not change behavior based on it.
- uint datum = (uint)Ionic.Zip.SharedUtilities.ReadInt(s);
- if (datum != ZipConstants.PackedToRemovableMedia)
- {
- s.Seek(-4, SeekOrigin.Current); // unread the block
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(s);
- }
- }
-
-
-
- private static void HandleUnexpectedDataDescriptor(ZipEntry entry)
- {
- Stream s = entry.ArchiveStream;
-
- // In some cases, the "data descriptor" is present, without a signature, even when
- // bit 3 of the BitField is NOT SET. This is the CRC, followed
- // by the compressed length and the uncompressed length (4 bytes for each
- // of those three elements). Need to check that here.
- //
- uint datum = (uint)Ionic.Zip.SharedUtilities.ReadInt(s);
- if (datum == entry._Crc32)
- {
- int sz = Ionic.Zip.SharedUtilities.ReadInt(s);
- if (sz == entry._CompressedSize)
- {
- sz = Ionic.Zip.SharedUtilities.ReadInt(s);
- if (sz == entry._UncompressedSize)
- {
- // ignore everything and discard it.
- }
- else
- {
- s.Seek(-12, SeekOrigin.Current); // unread the three blocks
-
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(s);
- }
- }
- else
- {
- s.Seek(-8, SeekOrigin.Current); // unread the two blocks
-
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(s);
- }
- }
- else
- {
- s.Seek(-4, SeekOrigin.Current); // unread the block
-
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(s);
- }
- }
-
-
- /// <summary>
- /// Finds a particular segment in the given extra field.
- /// This is used when modifying a previously-generated
- /// extra field, in particular when removing the AES crypto
- /// segment in the extra field.
- /// </summary>
- static internal int FindExtraFieldSegment(byte[] extra, int offx, UInt16 targetHeaderId)
- {
- int j = offx;
- while (j + 3 < extra.Length)
- {
- UInt16 headerId = (UInt16)(extra[j++] + extra[j++] * 256);
- if (headerId == targetHeaderId) return j-2;
-
- // else advance to next segment
- Int16 dataSize = (short)(extra[j++] + extra[j++] * 256);
- j+= dataSize;
- }
-
- return -1;
- }
-
-
- /// <summary>
- /// At current cursor position in the stream, read the extra
- /// field, and set the properties on the ZipEntry instance
- /// appropriately. This can be called when processing the
- /// Extra field in the Central Directory, or in the local
- /// header.
- /// </summary>
- internal int ProcessExtraField(Stream s, Int16 extraFieldLength)
- {
- int additionalBytesRead = 0;
- if (extraFieldLength > 0)
- {
- byte[] buffer = this._Extra = new byte[extraFieldLength];
- additionalBytesRead = s.Read(buffer, 0, buffer.Length);
- long posn = s.Position - additionalBytesRead;
- int j = 0;
- while (j + 3 < buffer.Length)
- {
- int start = j;
- UInt16 headerId = (UInt16)(buffer[j++] + buffer[j++] * 256);
- Int16 dataSize = (short)(buffer[j++] + buffer[j++] * 256);
-
- switch (headerId)
- {
- case 0x000a: // NTFS ctime, atime, mtime
- j = ProcessExtraFieldWindowsTimes(buffer, j, dataSize, posn);
- break;
-
- case 0x5455: // Unix ctime, atime, mtime
- j = ProcessExtraFieldUnixTimes(buffer, j, dataSize, posn);
- break;
-
- case 0x5855: // Info-zip Extra field (outdated)
- // This is outdated, so the field is supported on
- // read only.
- j = ProcessExtraFieldInfoZipTimes(buffer, j, dataSize, posn);
- break;
-
- case 0x7855: // Unix uid/gid
- // ignored. DotNetZip does not handle this field.
- break;
-
- case 0x7875: // ??
- // ignored. I could not find documentation on this field,
- // though it appears in some zip files.
- break;
-
- case 0x0001: // ZIP64
- j = ProcessExtraFieldZip64(buffer, j, dataSize, posn);
- break;
-
-#if AESCRYPTO
- case 0x9901: // WinZip AES encryption is in use. (workitem 6834)
- // we will handle this extra field only if compressionmethod is 0x63
- j = ProcessExtraFieldWinZipAes(buffer, j, dataSize, posn);
- break;
-#endif
- case 0x0017: // workitem 7968: handle PKWare Strong encryption header
- j = ProcessExtraFieldPkwareStrongEncryption(buffer, j);
- break;
- }
-
- // move to the next Header in the extra field
- j = start + dataSize + 4;
- }
- }
- return additionalBytesRead;
- }
-
- private int ProcessExtraFieldPkwareStrongEncryption(byte[] Buffer, int j)
- {
- // Value Size Description
- // ----- ---- -----------
- // 0x0017 2 bytes Tag for this "extra" block type
- // TSize 2 bytes Size of data that follows
- // Format 2 bytes Format definition for this record
- // AlgID 2 bytes Encryption algorithm identifier
- // Bitlen 2 bytes Bit length of encryption key
- // Flags 2 bytes Processing flags
- // CertData TSize-8 Certificate decryption extra field data
- // (refer to the explanation for CertData
- // in the section describing the
- // Certificate Processing Method under
- // the Strong Encryption Specification)
-
- j += 2;
- _UnsupportedAlgorithmId = (UInt16)(Buffer[j++] + Buffer[j++] * 256);
- _Encryption_FromZipFile = _Encryption = EncryptionAlgorithm.Unsupported;
-
- // DotNetZip doesn't support this algorithm, but we don't need to throw
- // here. we might just be reading the archive, which is fine. We'll
- // need to throw if Extract() is called.
-
- return j;
- }
-
-
-#if AESCRYPTO
- private int ProcessExtraFieldWinZipAes(byte[] buffer, int j, Int16 dataSize, long posn)
- {
- if (this._CompressionMethod == 0x0063)
- {
- if ((this._BitField & 0x01) != 0x01)
- throw new BadReadException(String.Format(" Inconsistent metadata at position 0x{0:X16}", posn));
-
- this._sourceIsEncrypted = true;
-
- //this._aesCrypto = new WinZipAesCrypto(this);
- // see spec at http://www.winzip.com/aes_info.htm
- if (dataSize != 7)
- throw new BadReadException(String.Format(" Inconsistent size (0x{0:X4}) in WinZip AES field at position 0x{1:X16}", dataSize, posn));
-
- this._WinZipAesMethod = BitConverter.ToInt16(buffer, j);
- j += 2;
- if (this._WinZipAesMethod != 0x01 && this._WinZipAesMethod != 0x02)
- throw new BadReadException(String.Format(" Unexpected vendor version number (0x{0:X4}) for WinZip AES metadata at position 0x{1:X16}",
- this._WinZipAesMethod, posn));
-
- Int16 vendorId = BitConverter.ToInt16(buffer, j);
- j += 2;
- if (vendorId != 0x4541)
- throw new BadReadException(String.Format(" Unexpected vendor ID (0x{0:X4}) for WinZip AES metadata at position 0x{1:X16}", vendorId, posn));
-
- int keystrength = (buffer[j] == 1) ? 128 : (buffer[j] == 3) ? 256 : -1;
- if (keystrength < 0)
- throw new BadReadException(String.Format("Invalid key strength ({0})", keystrength));
-
- _Encryption_FromZipFile = this._Encryption = (keystrength == 128)
- ? EncryptionAlgorithm.WinZipAes128
- : EncryptionAlgorithm.WinZipAes256;
-
- j++;
-
- // set the actual compression method
- this._CompressionMethod_FromZipFile =
- this._CompressionMethod = BitConverter.ToInt16(buffer, j);
- j += 2; // for the next segment of the extra field
- }
- return j;
- }
-
-#endif
-
- private delegate T Func<T>();
-
- private int ProcessExtraFieldZip64(byte[] buffer, int j, Int16 dataSize, long posn)
- {
- // The PKWare spec says that any of {UncompressedSize, CompressedSize,
- // RelativeOffset} exceeding 0xFFFFFFFF can lead to the ZIP64 header,
- // and the ZIP64 header may contain one or more of those. If the
- // values are present, they will be found in the prescribed order.
- // There may also be a 4-byte "disk start number."
- // This means that the DataSize must be 28 bytes or less.
-
- this._InputUsesZip64 = true;
-
- // workitem 7941: check datasize before reading.
- if (dataSize > 28)
- throw new BadReadException(String.Format(" Inconsistent size (0x{0:X4}) for ZIP64 extra field at position 0x{1:X16}",
- dataSize, posn));
- int remainingData = dataSize;
-
- var slurp = new Func<Int64>( () => {
- if (remainingData < 8)
- throw new BadReadException(String.Format(" Missing data for ZIP64 extra field, position 0x{0:X16}", posn));
- var x = BitConverter.ToInt64(buffer, j);
- j+= 8;
- remainingData -= 8;
- return x;
- });
-
- if (this._UncompressedSize == 0xFFFFFFFF)
- this._UncompressedSize = slurp();
-
- if (this._CompressedSize == 0xFFFFFFFF)
- this._CompressedSize = slurp();
-
- if (this._RelativeOffsetOfLocalHeader == 0xFFFFFFFF)
- this._RelativeOffsetOfLocalHeader = slurp();
-
- // Ignore anything else. Potentially there are 4 more bytes for the
- // disk start number. DotNetZip currently doesn't handle multi-disk
- // archives.
- return j;
- }
-
-
- private int ProcessExtraFieldInfoZipTimes(byte[] buffer, int j, Int16 dataSize, long posn)
- {
- if (dataSize != 12 && dataSize != 8)
- throw new BadReadException(String.Format(" Unexpected size (0x{0:X4}) for InfoZip v1 extra field at position 0x{1:X16}", dataSize, posn));
-
- Int32 timet = BitConverter.ToInt32(buffer, j);
- this._Mtime = _unixEpoch.AddSeconds(timet);
- j += 4;
-
- timet = BitConverter.ToInt32(buffer, j);
- this._Atime = _unixEpoch.AddSeconds(timet);
- j += 4;
-
- this._Ctime = DateTime.UtcNow;
-
- _ntfsTimesAreSet = true;
- _timestamp |= ZipEntryTimestamp.InfoZip1; return j;
- }
-
-
-
- private int ProcessExtraFieldUnixTimes(byte[] buffer, int j, Int16 dataSize, long posn)
- {
- // The Unix filetimes are 32-bit unsigned integers,
- // storing seconds since Unix epoch.
-
- if (dataSize != 13 && dataSize != 9 && dataSize != 5)
- throw new BadReadException(String.Format(" Unexpected size (0x{0:X4}) for Extended Timestamp extra field at position 0x{1:X16}", dataSize, posn));
-
- int remainingData = dataSize;
-
- var slurp = new Func<DateTime>( () => {
- Int32 timet = BitConverter.ToInt32(buffer, j);
- j += 4;
- remainingData -= 4;
- return _unixEpoch.AddSeconds(timet);
- });
-
- if (dataSize == 13 || _readExtraDepth > 0)
- {
- byte flag = buffer[j++];
- remainingData--;
-
- if ((flag & 0x0001) != 0 && remainingData >= 4)
- this._Mtime = slurp();
-
- this._Atime = ((flag & 0x0002) != 0 && remainingData >= 4)
- ? slurp()
- : DateTime.UtcNow;
-
- this._Ctime = ((flag & 0x0004) != 0 && remainingData >= 4)
- ? slurp()
- :DateTime.UtcNow;
-
- _timestamp |= ZipEntryTimestamp.Unix;
- _ntfsTimesAreSet = true;
- _emitUnixTimes = true;
- }
- else
- ReadExtraField(); // will recurse
-
- return j;
- }
-
-
- private int ProcessExtraFieldWindowsTimes(byte[] buffer, int j, Int16 dataSize, long posn)
- {
- // The NTFS filetimes are 64-bit unsigned integers, stored in Intel
- // (least significant byte first) byte order. They are expressed as the
- // number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",
- // which is "01-Jan-1601 00:00:00 UTC".
- //
- // HeaderId 2 bytes 0x000a == NTFS stuff
- // Datasize 2 bytes ?? (usually 32)
- // reserved 4 bytes ??
- // timetag 2 bytes 0x0001 == time
- // size 2 bytes 24 == 8 bytes each for ctime, mtime, atime
- // mtime 8 bytes win32 ticks since win32epoch
- // atime 8 bytes win32 ticks since win32epoch
- // ctime 8 bytes win32 ticks since win32epoch
-
- if (dataSize != 32)
- throw new BadReadException(String.Format(" Unexpected size (0x{0:X4}) for NTFS times extra field at position 0x{1:X16}", dataSize, posn));
-
- j += 4; // reserved
- Int16 timetag = (Int16)(buffer[j] + buffer[j + 1] * 256);
- Int16 addlsize = (Int16)(buffer[j + 2] + buffer[j + 3] * 256);
- j += 4; // tag and size
-
- if (timetag == 0x0001 && addlsize == 24)
- {
- Int64 z = BitConverter.ToInt64(buffer, j);
- this._Mtime = DateTime.FromFileTimeUtc(z);
- j += 8;
-
- // At this point the library *could* set the LastModified value
- // to coincide with the Mtime value. In theory, they refer to
- // the same property of the file, and should be the same anyway,
- // allowing for differences in precision. But they are
- // independent quantities in the zip archive, and this library
- // will keep them separate in the object model. There is no ill
- // effect from this, because as files are extracted, the
- // higher-precision value (Mtime) is used if it is present.
- // Apps may wish to compare the Mtime versus LastModified
- // values, but any difference when both are present is not
- // germaine to the correctness of the library. but note: when
- // explicitly setting either value, both are set. See the setter
- // for LastModified or the SetNtfsTimes() method.
-
- z = BitConverter.ToInt64(buffer, j);
- this._Atime = DateTime.FromFileTimeUtc(z);
- j += 8;
-
- z = BitConverter.ToInt64(buffer, j);
- this._Ctime = DateTime.FromFileTimeUtc(z);
- j += 8;
-
- _ntfsTimesAreSet = true;
- _timestamp |= ZipEntryTimestamp.Windows;
- _emitNtfsTimes = true;
- }
- return j;
- }
-
-
- }
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipEntry.Write.cs b/EPPlus/Packaging/DotNetZip/ZipEntry.Write.cs
deleted file mode 100644
index dc95211..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipEntry.Write.cs
+++ /dev/null
@@ -1,2583 +0,0 @@
-//#define Trace
-
-// ZipEntry.Write.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009-2011 Dino Chiesa
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// Last Saved: <2011-July-30 14:55:47>
-//
-// ------------------------------------------------------------------
-//
-// This module defines logic for writing (saving) the ZipEntry into a
-// zip file.
-//
-// ------------------------------------------------------------------
-
-
-using OfficeOpenXml.Packaging.Ionic.Zlib;
-using System;
-using System.IO;
-using RE = System.Text.RegularExpressions;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- internal partial class ZipEntry
- {
- internal void WriteCentralDirectoryEntry(Stream s)
- {
- byte[] bytes = new byte[4096];
- int i = 0;
- // signature
- bytes[i++] = (byte)(ZipConstants.ZipDirEntrySignature & 0x000000FF);
- bytes[i++] = (byte)((ZipConstants.ZipDirEntrySignature & 0x0000FF00) >> 8);
- bytes[i++] = (byte)((ZipConstants.ZipDirEntrySignature & 0x00FF0000) >> 16);
- bytes[i++] = (byte)((ZipConstants.ZipDirEntrySignature & 0xFF000000) >> 24);
-
- // Version Made By
- // workitem 7071
- // We must not overwrite the VersionMadeBy field when writing out a zip
- // archive. The VersionMadeBy tells the zip reader the meaning of the
- // File attributes. Overwriting the VersionMadeBy will result in
- // inconsistent metadata. Consider the scenario where the application
- // opens and reads a zip file that had been created on Linux. Then the
- // app adds one file to the Zip archive, and saves it. The file
- // attributes for all the entries added on Linux will be significant for
- // Linux. Therefore the VersionMadeBy for those entries must not be
- // changed. Only the entries that are actually created on Windows NTFS
- // should get the VersionMadeBy indicating Windows/NTFS.
- bytes[i++] = (byte)(_VersionMadeBy & 0x00FF);
- bytes[i++] = (byte)((_VersionMadeBy & 0xFF00) >> 8);
-
- // Apparently we want to duplicate the extra field here; we cannot
- // simply zero it out and assume tools and apps will use the right one.
-
- ////Int16 extraFieldLengthSave = (short)(_EntryHeader[28] + _EntryHeader[29] * 256);
- ////_EntryHeader[28] = 0;
- ////_EntryHeader[29] = 0;
-
- // Version Needed, Bitfield, compression method, lastmod,
- // crc, compressed and uncompressed sizes, filename length and extra field length.
- // These are all present in the local file header, but they may be zero values there.
- // So we cannot just copy them.
-
- // workitem 11969: Version Needed To Extract in central directory must be
- // the same as the local entry or MS .NET System.IO.Zip fails read.
- Int16 vNeeded = (Int16)(VersionNeeded != 0 ? VersionNeeded : 20);
- // workitem 12964
- if (_OutputUsesZip64==null)
- {
- // a zipentry in a zipoutputstream, with zero bytes written
- _OutputUsesZip64 = new Nullable<bool>(_container.Zip64 == Zip64Option.Always);
- }
-
- Int16 versionNeededToExtract = (Int16)(_OutputUsesZip64.Value ? 45 : vNeeded);
-#if BZIP
- if (this.CompressionMethod == Ionic.Zip.CompressionMethod.BZip2)
- versionNeededToExtract = 46;
-#endif
-
- bytes[i++] = (byte)(versionNeededToExtract & 0x00FF);
- bytes[i++] = (byte)((versionNeededToExtract & 0xFF00) >> 8);
-
- bytes[i++] = (byte)(_BitField & 0x00FF);
- bytes[i++] = (byte)((_BitField & 0xFF00) >> 8);
-
- bytes[i++] = (byte)(_CompressionMethod & 0x00FF);
- bytes[i++] = (byte)((_CompressionMethod & 0xFF00) >> 8);
-
-#if AESCRYPTO
- if (Encryption == EncryptionAlgorithm.WinZipAes128 ||
- Encryption == EncryptionAlgorithm.WinZipAes256)
- {
- i -= 2;
- bytes[i++] = 0x63;
- bytes[i++] = 0;
- }
-#endif
-
- bytes[i++] = (byte)(_TimeBlob & 0x000000FF);
- bytes[i++] = (byte)((_TimeBlob & 0x0000FF00) >> 8);
- bytes[i++] = (byte)((_TimeBlob & 0x00FF0000) >> 16);
- bytes[i++] = (byte)((_TimeBlob & 0xFF000000) >> 24);
- bytes[i++] = (byte)(_Crc32 & 0x000000FF);
- bytes[i++] = (byte)((_Crc32 & 0x0000FF00) >> 8);
- bytes[i++] = (byte)((_Crc32 & 0x00FF0000) >> 16);
- bytes[i++] = (byte)((_Crc32 & 0xFF000000) >> 24);
-
- int j = 0;
- if (_OutputUsesZip64.Value)
- {
- // CompressedSize (Int32) and UncompressedSize - all 0xFF
- for (j = 0; j < 8; j++)
- bytes[i++] = 0xFF;
- }
- else
- {
- bytes[i++] = (byte)(_CompressedSize & 0x000000FF);
- bytes[i++] = (byte)((_CompressedSize & 0x0000FF00) >> 8);
- bytes[i++] = (byte)((_CompressedSize & 0x00FF0000) >> 16);
- bytes[i++] = (byte)((_CompressedSize & 0xFF000000) >> 24);
-
- bytes[i++] = (byte)(_UncompressedSize & 0x000000FF);
- bytes[i++] = (byte)((_UncompressedSize & 0x0000FF00) >> 8);
- bytes[i++] = (byte)((_UncompressedSize & 0x00FF0000) >> 16);
- bytes[i++] = (byte)((_UncompressedSize & 0xFF000000) >> 24);
- }
-
- byte[] fileNameBytes = GetEncodedFileNameBytes();
- Int16 filenameLength = (Int16)fileNameBytes.Length;
- bytes[i++] = (byte)(filenameLength & 0x00FF);
- bytes[i++] = (byte)((filenameLength & 0xFF00) >> 8);
-
- // do this again because now we have real data
- _presumeZip64 = _OutputUsesZip64.Value;
-
- // workitem 11131
- //
- // cannot generate the extra field again, here's why: In the case of a
- // zero-byte entry, which uses encryption, DotNetZip will "remove" the
- // encryption from the entry. It does this in PostProcessOutput; it
- // modifies the entry header, and rewrites it, resetting the Bitfield
- // (one bit indicates encryption), and potentially resetting the
- // compression method - for AES the Compression method is 0x63, and it
- // would get reset to zero (no compression). It then calls SetLength()
- // to truncate the stream to remove the encryption header (12 bytes for
- // AES256). But, it leaves the previously-generated "Extra Field"
- // metadata (11 bytes) for AES in the entry header. This extra field
- // data is now "orphaned" - it refers to AES encryption when in fact no
- // AES encryption is used. But no problem, the PKWARE spec says that
- // unrecognized extra fields can just be ignored. ok. After "removal"
- // of AES encryption, the length of the Extra Field can remains the
- // same; it's just that there will be 11 bytes in there that previously
- // pertained to AES which are now unused. Even the field code is still
- // there, but it will be unused by readers, as the encryption bit is not
- // set.
- //
- // Re-calculating the Extra field now would produce a block that is 11
- // bytes shorter, and that mismatch - between the extra field in the
- // local header and the extra field in the Central Directory - would
- // cause problems. (where? why? what problems?) So we can't do
- // that. It's all good though, because though the content may have
- // changed, the length definitely has not. Also, the _EntryHeader
- // contains the "updated" extra field (after PostProcessOutput) at
- // offset (30 + filenameLength).
-
- _Extra = ConstructExtraField(true);
-
- Int16 extraFieldLength = (Int16)((_Extra == null) ? 0 : _Extra.Length);
- bytes[i++] = (byte)(extraFieldLength & 0x00FF);
- bytes[i++] = (byte)((extraFieldLength & 0xFF00) >> 8);
-
- // File (entry) Comment Length
- // the _CommentBytes private field was set during WriteHeader()
- int commentLength = (_CommentBytes == null) ? 0 : _CommentBytes.Length;
-
- // the size of our buffer defines the max length of the comment we can write
- if (commentLength + i > bytes.Length) commentLength = bytes.Length - i;
- bytes[i++] = (byte)(commentLength & 0x00FF);
- bytes[i++] = (byte)((commentLength & 0xFF00) >> 8);
-
- // Disk number start
- bool segmented = (this._container.ZipFile != null) &&
- (this._container.ZipFile.MaxOutputSegmentSize != 0);
- if (segmented) // workitem 13915
- {
- // Emit nonzero disknumber only if saving segmented archive.
- bytes[i++] = (byte)(_diskNumber & 0x00FF);
- bytes[i++] = (byte)((_diskNumber & 0xFF00) >> 8);
- }
- else
- {
- // If reading a segmneted archive and saving to a regular archive,
- // ZipEntry._diskNumber will be non-zero but it should be saved as
- // zero.
- bytes[i++] = 0;
- bytes[i++] = 0;
- }
-
- // internal file attrs
- // workitem 7801
- bytes[i++] = (byte)((_IsText) ? 1 : 0); // lo bit: filetype hint. 0=bin, 1=txt.
- bytes[i++] = 0;
-
- // external file attrs
- // workitem 7071
- bytes[i++] = (byte)(_ExternalFileAttrs & 0x000000FF);
- bytes[i++] = (byte)((_ExternalFileAttrs & 0x0000FF00) >> 8);
- bytes[i++] = (byte)((_ExternalFileAttrs & 0x00FF0000) >> 16);
- bytes[i++] = (byte)((_ExternalFileAttrs & 0xFF000000) >> 24);
-
- // workitem 11131
- // relative offset of local header.
- //
- // If necessary to go to 64-bit value, then emit 0xFFFFFFFF,
- // else write out the value.
- //
- // Even if zip64 is required for other reasons - number of the entry
- // > 65534, or uncompressed size of the entry > MAX_INT32, the ROLH
- // need not be stored in a 64-bit field .
- if (_RelativeOffsetOfLocalHeader > 0xFFFFFFFFL) // _OutputUsesZip64.Value
- {
- bytes[i++] = 0xFF;
- bytes[i++] = 0xFF;
- bytes[i++] = 0xFF;
- bytes[i++] = 0xFF;
- }
- else
- {
- bytes[i++] = (byte)(_RelativeOffsetOfLocalHeader & 0x000000FF);
- bytes[i++] = (byte)((_RelativeOffsetOfLocalHeader & 0x0000FF00) >> 8);
- bytes[i++] = (byte)((_RelativeOffsetOfLocalHeader & 0x00FF0000) >> 16);
- bytes[i++] = (byte)((_RelativeOffsetOfLocalHeader & 0xFF000000) >> 24);
- }
-
- // actual filename
- Buffer.BlockCopy(fileNameBytes, 0, bytes, i, filenameLength);
- i += filenameLength;
-
- // "Extra field"
- if (_Extra != null)
- {
- // workitem 11131
- //
- // copy from EntryHeader if available - it may have been updated.
- // if not, copy from Extra. This would be unnecessary if I just
- // updated the Extra field when updating EntryHeader, in
- // PostProcessOutput.
-
- //?? I don't understand why I wouldn't want to just use
- // the recalculated Extra field. ??
-
- // byte[] h = _EntryHeader ?? _Extra;
- // int offx = (h == _EntryHeader) ? 30 + filenameLength : 0;
- // Buffer.BlockCopy(h, offx, bytes, i, extraFieldLength);
- // i += extraFieldLength;
-
- byte[] h = _Extra;
- int offx = 0;
- Buffer.BlockCopy(h, offx, bytes, i, extraFieldLength);
- i += extraFieldLength;
- }
-
- // file (entry) comment
- if (commentLength != 0)
- {
- // now actually write the comment itself into the byte buffer
- Buffer.BlockCopy(_CommentBytes, 0, bytes, i, commentLength);
- // for (j = 0; (j < commentLength) && (i + j < bytes.Length); j++)
- // bytes[i + j] = _CommentBytes[j];
- i += commentLength;
- }
-
- s.Write(bytes, 0, i);
- }
-
-
-#if INFOZIP_UTF8
- static private bool FileNameIsUtf8(char[] FileNameChars)
- {
- bool isUTF8 = false;
- bool isUnicode = false;
- for (int j = 0; j < FileNameChars.Length; j++)
- {
- byte[] b = System.BitConverter.GetBytes(FileNameChars[j]);
- isUnicode |= (b.Length != 2);
- isUnicode |= (b[1] != 0);
- isUTF8 |= ((b[0] & 0x80) != 0);
- }
-
- return isUTF8;
- }
-#endif
-
-
- private byte[] ConstructExtraField(bool forCentralDirectory)
- {
- var listOfBlocks = new System.Collections.Generic.List<byte[]>();
- byte[] block;
-
- // Conditionally emit an extra field with Zip64 information. If the
- // Zip64 option is Always, we emit the field, before knowing that it's
- // necessary. Later, if it turns out this entry does not need zip64,
- // we'll set the header ID to rubbish and the data will be ignored.
- // This results in additional overhead metadata in the zip file, but
- // it will be small in comparison to the entry data.
- //
- // On the other hand if the Zip64 option is AsNecessary and it's NOT
- // for the central directory, then we do the same thing. Or, if the
- // Zip64 option is AsNecessary and it IS for the central directory,
- // and the entry requires zip64, then emit the header.
- if (_container.Zip64 == Zip64Option.Always ||
- (_container.Zip64 == Zip64Option.AsNecessary &&
- (!forCentralDirectory || _entryRequiresZip64.Value)))
- {
- // add extra field for zip64 here
- // workitem 7924
- int sz = 4 + (forCentralDirectory ? 28 : 16);
- block = new byte[sz];
- int i = 0;
-
- if (_presumeZip64 || forCentralDirectory)
- {
- // HeaderId = always use zip64 extensions.
- block[i++] = 0x01;
- block[i++] = 0x00;
- }
- else
- {
- // HeaderId = dummy data now, maybe set to 0x0001 (ZIP64) later.
- block[i++] = 0x99;
- block[i++] = 0x99;
- }
-
- // DataSize
- block[i++] = (byte)(sz - 4); // decimal 28 or 16 (workitem 7924)
- block[i++] = 0x00;
-
- // The actual metadata - we may or may not have real values yet...
-
- // uncompressed size
- Array.Copy(BitConverter.GetBytes(_UncompressedSize), 0, block, i, 8);
- i += 8;
- // compressed size
- Array.Copy(BitConverter.GetBytes(_CompressedSize), 0, block, i, 8);
- i += 8;
-
- // workitem 7924 - only include this if the "extra" field is for
- // use in the central directory. It is unnecessary and not useful
- // for local header; makes WinZip choke.
- if (forCentralDirectory)
- {
- // relative offset
- Array.Copy(BitConverter.GetBytes(_RelativeOffsetOfLocalHeader), 0, block, i, 8);
- i += 8;
-
- // starting disk number
- Array.Copy(BitConverter.GetBytes(0), 0, block, i, 4);
- }
- listOfBlocks.Add(block);
- }
-
-
-#if AESCRYPTO
- if (Encryption == EncryptionAlgorithm.WinZipAes128 ||
- Encryption == EncryptionAlgorithm.WinZipAes256)
- {
- block = new byte[4 + 7];
- int i = 0;
- // extra field for WinZip AES
- // header id
- block[i++] = 0x01;
- block[i++] = 0x99;
-
- // data size
- block[i++] = 0x07;
- block[i++] = 0x00;
-
- // vendor number
- block[i++] = 0x01; // AE-1 - means "Verify CRC"
- block[i++] = 0x00;
-
- // vendor id "AE"
- block[i++] = 0x41;
- block[i++] = 0x45;
-
- // key strength
- int keystrength = GetKeyStrengthInBits(Encryption);
- if (keystrength == 128)
- block[i] = 1;
- else if (keystrength == 256)
- block[i] = 3;
- else
- block[i] = 0xFF;
- i++;
-
- // actual compression method
- block[i++] = (byte)(_CompressionMethod & 0x00FF);
- block[i++] = (byte)(_CompressionMethod & 0xFF00);
-
- listOfBlocks.Add(block);
- }
-#endif
-
- if (_ntfsTimesAreSet && _emitNtfsTimes)
- {
- block = new byte[32 + 4];
- // HeaderId 2 bytes 0x000a == NTFS times
- // Datasize 2 bytes 32
- // reserved 4 bytes ?? don't care
- // timetag 2 bytes 0x0001 == NTFS time
- // size 2 bytes 24 == 8 bytes each for ctime, mtime, atime
- // mtime 8 bytes win32 ticks since win32epoch
- // atime 8 bytes win32 ticks since win32epoch
- // ctime 8 bytes win32 ticks since win32epoch
- int i = 0;
- // extra field for NTFS times
- // header id
- block[i++] = 0x0a;
- block[i++] = 0x00;
-
- // data size
- block[i++] = 32;
- block[i++] = 0;
-
- i += 4; // reserved
-
- // time tag
- block[i++] = 0x01;
- block[i++] = 0x00;
-
- // data size (again)
- block[i++] = 24;
- block[i++] = 0;
-
- Int64 z = _Mtime.ToFileTime();
- Array.Copy(BitConverter.GetBytes(z), 0, block, i, 8);
- i += 8;
- z = _Atime.ToFileTime();
- Array.Copy(BitConverter.GetBytes(z), 0, block, i, 8);
- i += 8;
- z = _Ctime.ToFileTime();
- Array.Copy(BitConverter.GetBytes(z), 0, block, i, 8);
- i += 8;
-
- listOfBlocks.Add(block);
- }
-
- if (_ntfsTimesAreSet && _emitUnixTimes)
- {
- int len = 5 + 4;
- if (!forCentralDirectory) len += 8;
-
- block = new byte[len];
- // local form:
- // --------------
- // HeaderId 2 bytes 0x5455 == unix timestamp
- // Datasize 2 bytes 13
- // flags 1 byte 7 (low three bits all set)
- // mtime 4 bytes seconds since unix epoch
- // atime 4 bytes seconds since unix epoch
- // ctime 4 bytes seconds since unix epoch
- //
- // central directory form:
- //---------------------------------
- // HeaderId 2 bytes 0x5455 == unix timestamp
- // Datasize 2 bytes 5
- // flags 1 byte 7 (low three bits all set)
- // mtime 4 bytes seconds since unix epoch
- //
- int i = 0;
- // extra field for "unix" times
- // header id
- block[i++] = 0x55;
- block[i++] = 0x54;
-
- // data size
- block[i++] = unchecked((byte)(len - 4));
- block[i++] = 0;
-
- // flags
- block[i++] = 0x07;
-
- Int32 z = unchecked((int)((_Mtime - _unixEpoch).TotalSeconds));
- Array.Copy(BitConverter.GetBytes(z), 0, block, i, 4);
- i += 4;
- if (!forCentralDirectory)
- {
- z = unchecked((int)((_Atime - _unixEpoch).TotalSeconds));
- Array.Copy(BitConverter.GetBytes(z), 0, block, i, 4);
- i += 4;
- z = unchecked((int)((_Ctime - _unixEpoch).TotalSeconds));
- Array.Copy(BitConverter.GetBytes(z), 0, block, i, 4);
- i += 4;
- }
- listOfBlocks.Add(block);
- }
-
-
- // inject other blocks here...
-
-
- // concatenate any blocks we've got:
- byte[] aggregateBlock = null;
- if (listOfBlocks.Count > 0)
- {
- int totalLength = 0;
- int i, current = 0;
- for (i = 0; i < listOfBlocks.Count; i++)
- totalLength += listOfBlocks[i].Length;
- aggregateBlock = new byte[totalLength];
- for (i = 0; i < listOfBlocks.Count; i++)
- {
- System.Array.Copy(listOfBlocks[i], 0, aggregateBlock, current, listOfBlocks[i].Length);
- current += listOfBlocks[i].Length;
- }
- }
-
- return aggregateBlock;
- }
-
-
-
- // private System.Text.Encoding GenerateCommentBytes()
- // {
- // var getEncoding = new Func<System.Text.Encoding>({
- // switch (AlternateEncodingUsage)
- // {
- // case ZipOption.Always:
- // return AlternateEncoding;
- // case ZipOption.Never:
- // return ibm437;
- // }
- // var cb = ibm437.GetBytes(_Comment);
- // // need to use this form of GetString() for .NET CF
- // string s1 = ibm437.GetString(cb, 0, cb.Length);
- // if (s1 == _Comment)
- // return ibm437;
- // return AlternateEncoding;
- // });
- //
- // var encoding = getEncoding();
- // _CommentBytes = encoding.GetBytes(_Comment);
- // return encoding;
- // }
-
-
- private string NormalizeFileName()
- {
- // here, we need to flip the backslashes to forward-slashes,
- // also, we need to trim the \\server\share syntax from any UNC path.
- // and finally, we need to remove any leading .\
-
- string SlashFixed = FileName.Replace("\\", "/");
- string s1 = null;
- if ((_TrimVolumeFromFullyQualifiedPaths) && (FileName.Length >= 3)
- && (FileName[1] == ':') && (SlashFixed[2] == '/'))
- {
- // trim off volume letter, colon, and slash
- s1 = SlashFixed.Substring(3);
- }
- else if ((FileName.Length >= 4)
- && ((SlashFixed[0] == '/') && (SlashFixed[1] == '/')))
- {
- int n = SlashFixed.IndexOf('/', 2);
- if (n == -1)
- throw new ArgumentException("The path for that entry appears to be badly formatted");
- s1 = SlashFixed.Substring(n + 1);
- }
- else if ((FileName.Length >= 3)
- && ((SlashFixed[0] == '.') && (SlashFixed[1] == '/')))
- {
- // trim off dot and slash
- s1 = SlashFixed.Substring(2);
- }
- else
- {
- s1 = SlashFixed;
- }
- return s1;
- }
-
-
- /// <summary>
- /// generate and return a byte array that encodes the filename
- /// for the entry.
- /// </summary>
- /// <remarks>
- /// <para>
- /// side effects: generate and store into _CommentBytes the
- /// byte array for any comment attached to the entry. Also
- /// sets _actualEncoding to indicate the actual encoding
- /// used. The same encoding is used for both filename and
- /// comment.
- /// </para>
- /// </remarks>
- private byte[] GetEncodedFileNameBytes()
- {
- // workitem 6513
- var s1 = NormalizeFileName();
-
- switch(AlternateEncodingUsage)
- {
- case ZipOption.Always:
- if (!(_Comment == null || _Comment.Length == 0))
- _CommentBytes = AlternateEncoding.GetBytes(_Comment);
- _actualEncoding = AlternateEncoding;
- return AlternateEncoding.GetBytes(s1);
-
- case ZipOption.Never:
- if (!(_Comment == null || _Comment.Length == 0))
- _CommentBytes = ibm437.GetBytes(_Comment);
- _actualEncoding = ibm437;
- return ibm437.GetBytes(s1);
- }
-
- // arriving here means AlternateEncodingUsage is "AsNecessary"
-
- // case ZipOption.AsNecessary:
- // workitem 6513: when writing, use the alternative encoding
- // only when _actualEncoding is not yet set (it can be set
- // during Read), and when ibm437 will not do.
-
- byte[] result = ibm437.GetBytes(s1);
- // need to use this form of GetString() for .NET CF
- string s2 = ibm437.GetString(result, 0, result.Length);
- _CommentBytes = null;
- if (s2 != s1)
- {
- // Encoding the filename with ibm437 does not allow round-trips.
- // Therefore, use the alternate encoding. Assume it will work,
- // no checking of round trips here.
- result = AlternateEncoding.GetBytes(s1);
- if (_Comment != null && _Comment.Length != 0)
- _CommentBytes = AlternateEncoding.GetBytes(_Comment);
- _actualEncoding = AlternateEncoding;
- return result;
- }
-
- _actualEncoding = ibm437;
-
- // Using ibm437, FileName can be encoded without information
- // loss; now try the Comment.
-
- // if there is no comment, use ibm437.
- if (_Comment == null || _Comment.Length == 0)
- return result;
-
- // there is a comment. Get the encoded form.
- byte[] cbytes = ibm437.GetBytes(_Comment);
- string c2 = ibm437.GetString(cbytes,0,cbytes.Length);
-
- // Check for round-trip.
- if (c2 != Comment)
- {
- // Comment cannot correctly be encoded with ibm437. Use
- // the alternate encoding.
-
- result = AlternateEncoding.GetBytes(s1);
- _CommentBytes = AlternateEncoding.GetBytes(_Comment);
- _actualEncoding = AlternateEncoding;
- return result;
- }
-
- // use IBM437
- _CommentBytes = cbytes;
- return result;
- }
-
-
-
- private bool WantReadAgain()
- {
- if (_UncompressedSize < 0x10) return false;
- if (_CompressionMethod == 0x00) return false;
- if (CompressionLevel == OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel.None) return false;
- if (_CompressedSize < _UncompressedSize) return false;
-
- if (this._Source == ZipEntrySource.Stream && !this._sourceStream.CanSeek) return false;
-
-#if AESCRYPTO
- if (_aesCrypto_forWrite != null && (CompressedSize - _aesCrypto_forWrite.SizeOfEncryptionMetadata) <= UncompressedSize + 0x10) return false;
-#endif
-
- if (_zipCrypto_forWrite != null && (CompressedSize - 12) <= UncompressedSize) return false;
-
- return true;
- }
-
-
-
- private void MaybeUnsetCompressionMethodForWriting(int cycle)
- {
- // if we've already tried with compression... turn it off this time
- if (cycle > 1)
- {
- _CompressionMethod = 0x0;
- return;
- }
- // compression for directories = 0x00 (No Compression)
- if (IsDirectory)
- {
- _CompressionMethod = 0x0;
- return;
- }
-
- if (this._Source == ZipEntrySource.ZipFile)
- {
- return; // do nothing
- }
-
- // If __FileDataPosition is zero, then that means we will get the data
- // from a file or stream.
-
- // It is never possible to compress a zero-length file, so we check for
- // this condition.
-
- if (this._Source == ZipEntrySource.Stream)
- {
- // workitem 7742
- if (_sourceStream != null && _sourceStream.CanSeek)
- {
- // Length prop will throw if CanSeek is false
- long fileLength = _sourceStream.Length;
- if (fileLength == 0)
- {
- _CompressionMethod = 0x00;
- return;
- }
- }
- }
- else if ((this._Source == ZipEntrySource.FileSystem) && (SharedUtilities.GetFileLength(LocalFileName) == 0L))
- {
- _CompressionMethod = 0x00;
- return;
- }
-
- // Ok, we're getting the data to be compressed from a
- // non-zero-length file or stream, or a file or stream of
- // unknown length, and we presume that it is non-zero. In
- // that case we check the callback to see if the app wants
- // to tell us whether to compress or not.
- if (SetCompression != null)
- CompressionLevel = SetCompression(LocalFileName, _FileNameInArchive);
-
- // finally, set CompressionMethod to None if CompressionLevel is None
- if (CompressionLevel == (short)Ionic.Zlib.CompressionLevel.None &&
- CompressionMethod == Ionic.Zip.CompressionMethod.Deflate)
- _CompressionMethod = 0x00;
-
- return;
- }
-
-
-
- // write the header info for an entry
- internal void WriteHeader(Stream s, int cycle)
- {
- // Must remember the offset, within the output stream, of this particular
- // entry header.
- //
- // This is for 2 reasons:
- //
- // 1. so we can determine the RelativeOffsetOfLocalHeader (ROLH) for
- // use in the central directory.
- // 2. so we can seek backward in case there is an error opening or reading
- // the file, and the application decides to skip the file. In this case,
- // we need to seek backward in the output stream to allow the next entry
- // to be added to the zipfile output stream.
- //
- // Normally you would just store the offset before writing to the output
- // stream and be done with it. But the possibility to use split archives
- // makes this approach ineffective. In split archives, each file or segment
- // is bound to a max size limit, and each local file header must not span a
- // segment boundary; it must be written contiguously. If it will fit in the
- // current segment, then the ROLH is just the current Position in the output
- // stream. If it won't fit, then we need a new file (segment) and the ROLH
- // is zero.
- //
- // But we only can know if it is possible to write a header contiguously
- // after we know the size of the local header, a size that varies with
- // things like filename length, comments, and extra fields. We have to
- // compute the header fully before knowing whether it will fit.
- //
- // That takes care of item #1 above. Now, regarding #2. If an error occurs
- // while computing the local header, we want to just seek backward. The
- // exception handling logic (in the caller of WriteHeader) uses ROLH to
- // scroll back.
- //
- // All this means we have to preserve the starting offset before computing
- // the header, and also we have to compute the offset later, to handle the
- // case of split archives.
-
- var counter = s as CountingStream;
-
- // workitem 8098: ok (output)
- // This may change later, for split archives
-
- // Don't set _RelativeOffsetOfLocalHeader. Instead, set a temp variable.
- // This allows for re-streaming, where a zip entry might be read from a
- // zip archive (and maybe decrypted, and maybe decompressed) and then
- // written to another zip archive, with different settings for
- // compression method, compression level, or encryption algorithm.
- _future_ROLH = (counter != null)
- ? counter.ComputedPosition
- : s.Position;
-
- int j = 0, i = 0;
-
- byte[] block = new byte[30];
-
- // signature
- block[i++] = (byte)(ZipConstants.ZipEntrySignature & 0x000000FF);
- block[i++] = (byte)((ZipConstants.ZipEntrySignature & 0x0000FF00) >> 8);
- block[i++] = (byte)((ZipConstants.ZipEntrySignature & 0x00FF0000) >> 16);
- block[i++] = (byte)((ZipConstants.ZipEntrySignature & 0xFF000000) >> 24);
-
- // Design notes for ZIP64:
- //
- // The specification says that the header must include the Compressed
- // and Uncompressed sizes, as well as the CRC32 value. When creating
- // a zip via streamed processing, these quantities are not known until
- // after the compression is done. Thus, a typical way to do it is to
- // insert zeroes for these quantities, then do the compression, then
- // seek back to insert the appropriate values, then seek forward to
- // the end of the file data.
- //
- // There is also the option of using bit 3 in the GP bitfield - to
- // specify that there is a data descriptor after the file data
- // containing these three quantities.
- //
- // This works when the size of the quantities is known, either 32-bits
- // or 64 bits as with the ZIP64 extensions.
- //
- // With Zip64, the 4-byte fields are set to 0xffffffff, and there is a
- // corresponding data block in the "extra field" that contains the
- // actual Compressed, uncompressed sizes. (As well as an additional
- // field, the "Relative Offset of Local Header")
- //
- // The problem is when the app desires to use ZIP64 extensions
- // optionally, only when necessary. Suppose the library assumes no
- // zip64 extensions when writing the header, then after compression
- // finds that the size of the data requires zip64. At this point, the
- // header, already written to the file, won't have the necessary data
- // block in the "extra field". The size of the entry header is fixed,
- // so it is not possible to just "add on" the zip64 data block after
- // compressing the file. On the other hand, always using zip64 will
- // break interoperability with many other systems and apps.
- //
- // The approach we take is to insert a 32-byte dummy data block in the
- // extra field, whenever zip64 is to be used "as necessary". This data
- // block will get the actual zip64 HeaderId and zip64 metadata if
- // necessary. If not necessary, the data block will get a meaningless
- // HeaderId (0x1111), and will be filled with zeroes.
- //
- // When zip64 is actually in use, we also need to set the
- // VersionNeededToExtract field to 45.
- //
- // There is one additional wrinkle: using zip64 as necessary conflicts
- // with output to non-seekable devices. The header is emitted and
- // must indicate whether zip64 is in use, before we know if zip64 is
- // necessary. Because there is no seeking, the header can never be
- // changed. Therefore, on non-seekable devices,
- // Zip64Option.AsNecessary is the same as Zip64Option.Always.
- //
-
-
- // version needed- see AppNote.txt.
- //
- // need v5.1 for PKZIP strong encryption, or v2.0 for no encryption or
- // for PK encryption, 4.5 for zip64. We may reset this later, as
- // necessary or zip64.
-
- _presumeZip64 = (_container.Zip64 == Zip64Option.Always ||
- (_container.Zip64 == Zip64Option.AsNecessary && !s.CanSeek));
- Int16 VersionNeededToExtract = (Int16)(_presumeZip64 ? 45 : 20);
-#if BZIP
- if (this.CompressionMethod == Ionic.Zip.CompressionMethod.BZip2)
- VersionNeededToExtract = 46;
-#endif
-
- // (i==4)
- block[i++] = (byte)(VersionNeededToExtract & 0x00FF);
- block[i++] = (byte)((VersionNeededToExtract & 0xFF00) >> 8);
-
- // Get byte array. Side effect: sets ActualEncoding.
- // Must determine encoding before setting the bitfield.
- // workitem 6513
- byte[] fileNameBytes = GetEncodedFileNameBytes();
- Int16 filenameLength = (Int16)fileNameBytes.Length;
-
- // general purpose bitfield
- // In the current implementation, this library uses only these bits
- // in the GP bitfield:
- // bit 0 = if set, indicates the entry is encrypted
- // bit 3 = if set, indicates the CRC, C and UC sizes follow the file data.
- // bit 6 = strong encryption - for pkware's meaning of strong encryption
- // bit 11 = UTF-8 encoding is used in the comment and filename
-
-
- // Here we set or unset the encryption bit.
- // _BitField may already be set, as with a ZipEntry added into ZipOutputStream, which
- // has bit 3 always set. We only want to set one bit
- if (_Encryption == EncryptionAlgorithm.None)
- _BitField &= ~1; // encryption bit OFF
- else
- _BitField |= 1; // encryption bit ON
-
-
- // workitem 7941: WinZip does not the "strong encryption" bit when using AES.
- // This "Strong Encryption" is a PKWare Strong encryption thing.
- // _BitField |= 0x0020;
-
- // set the UTF8 bit if necessary
-#if SILVERLIGHT
- if (_actualEncoding.WebName == "utf-8")
-#else
- if (_actualEncoding.CodePage == System.Text.Encoding.UTF8.CodePage)
-#endif
- _BitField |= 0x0800;
-
- // The PKZIP spec says that if bit 3 is set (0x0008) in the General
- // Purpose BitField, then the CRC, Compressed size, and uncompressed
- // size are written directly after the file data.
- //
- // These 3 quantities are normally present in the regular zip entry
- // header. But, they are not knowable until after the compression is
- // done. So, in the normal case, we
- //
- // - write the header, using zeros for these quantities
- // - compress the data, and incidentally compute these quantities.
- // - seek back and write the correct values them into the header.
- //
- // This is nice because, while it is more complicated to write the zip
- // file, it is simpler and less error prone to read the zip file, and
- // as a result more applications can read zip files produced this way,
- // with those 3 quantities in the header.
- //
- // But if seeking in the output stream is not possible, then we need
- // to set the appropriate bitfield and emit these quantities after the
- // compressed file data in the output.
- //
- // workitem 7216 - having trouble formatting a zip64 file that is
- // readable by WinZip. not sure why! What I found is that setting
- // bit 3 and following all the implications, the zip64 file is
- // readable by WinZip 12. and Perl's IO::Compress::Zip . Perl takes
- // an interesting approach - it always sets bit 3 if ZIP64 in use.
- // DotNetZip now does the same; this gives better compatibility with
- // WinZip 12.
-
- if (IsDirectory || cycle == 99)
- {
- // (cycle == 99) indicates a zero-length entry written by ZipOutputStream
-
- _BitField &= ~0x0008; // unset bit 3 - no "data descriptor" - ever
- _BitField &= ~0x0001; // unset bit 1 - no encryption - ever
- Encryption = EncryptionAlgorithm.None;
- Password = null;
- }
- else if (!s.CanSeek)
- _BitField |= 0x0008;
-
-#if DONT_GO_THERE
- else if (this.Encryption == EncryptionAlgorithm.PkzipWeak &&
- this._Source != ZipEntrySource.ZipFile)
- {
- // Set bit 3 to avoid the double-read perf issue.
- //
- // When PKZIP encryption is used, byte 11 of the encryption header is
- // used as a consistency check. It is normally set to the MSByte of the
- // CRC. But this means the cRC must be known ebfore compression and
- // encryption, which means the entire stream has to be read twice. To
- // avoid that, the high-byte of the time blob (when in DOS format) can
- // be used for the consistency check (byte 11 in the encryption header).
- // But this means the entry must have bit 3 set.
- //
- // Previously I used a more complex arrangement - using the methods like
- // FigureCrc32(), PrepOutputStream() and others, in order to manage the
- // seek-back in the source stream. Why? Because bit 3 is not always
- // friendly with third-party zip tools, like those on the Mac.
- //
- // This is why this code is still ifdef'd out.
- //
- // Might consider making this yet another programmable option -
- // AlwaysUseBit3ForPkzip. But that's for another day.
- //
- _BitField |= 0x0008;
- }
-#endif
-
- // (i==6)
- block[i++] = (byte)(_BitField & 0x00FF);
- block[i++] = (byte)((_BitField & 0xFF00) >> 8);
-
- // Here, we want to set values for Compressed Size, Uncompressed Size,
- // and CRC. If we have __FileDataPosition as not -1 (zero is a valid
- // FDP), then that means we are reading this zip entry from a zip
- // file, and we have good values for those quantities.
- //
- // If _FileDataPosition is -1, then we are constructing this Entry
- // from nothing. We zero those quantities now, and we will compute
- // actual values for the three quantities later, when we do the
- // compression, and then seek back to write them into the appropriate
- // place in the header.
- if (this.__FileDataPosition == -1)
- {
- //_UncompressedSize = 0; // do not unset - may need this value for restream
- // _Crc32 = 0; // ditto
- _CompressedSize = 0;
- _crcCalculated = false;
- }
-
- // set compression method here
- MaybeUnsetCompressionMethodForWriting(cycle);
-
- // (i==8) compression method
- block[i++] = (byte)(_CompressionMethod & 0x00FF);
- block[i++] = (byte)((_CompressionMethod & 0xFF00) >> 8);
-
- if (cycle == 99)
- {
- // (cycle == 99) indicates a zero-length entry written by ZipOutputStream
- SetZip64Flags();
- }
-
-#if AESCRYPTO
- else if (Encryption == EncryptionAlgorithm.WinZipAes128 || Encryption == EncryptionAlgorithm.WinZipAes256)
- {
- i -= 2;
- block[i++] = 0x63;
- block[i++] = 0;
- }
-#endif
-
- // LastMod
- _TimeBlob = Ionic.Zip.SharedUtilities.DateTimeToPacked(LastModified);
-
- // (i==10) time blob
- block[i++] = (byte)(_TimeBlob & 0x000000FF);
- block[i++] = (byte)((_TimeBlob & 0x0000FF00) >> 8);
- block[i++] = (byte)((_TimeBlob & 0x00FF0000) >> 16);
- block[i++] = (byte)((_TimeBlob & 0xFF000000) >> 24);
-
- // (i==14) CRC - if source==filesystem, this is zero now, actual value
- // will be calculated later. if source==archive, this is a bonafide
- // value.
- block[i++] = (byte)(_Crc32 & 0x000000FF);
- block[i++] = (byte)((_Crc32 & 0x0000FF00) >> 8);
- block[i++] = (byte)((_Crc32 & 0x00FF0000) >> 16);
- block[i++] = (byte)((_Crc32 & 0xFF000000) >> 24);
-
- if (_presumeZip64)
- {
- // (i==18) CompressedSize (Int32) and UncompressedSize - all 0xFF for now
- for (j = 0; j < 8; j++)
- block[i++] = 0xFF;
- }
- else
- {
- // (i==18) CompressedSize (Int32) - this value may or may not be
- // bonafide. if source == filesystem, then it is zero, and we'll
- // learn it after we compress. if source == archive, then it is
- // bonafide data.
- block[i++] = (byte)(_CompressedSize & 0x000000FF);
- block[i++] = (byte)((_CompressedSize & 0x0000FF00) >> 8);
- block[i++] = (byte)((_CompressedSize & 0x00FF0000) >> 16);
- block[i++] = (byte)((_CompressedSize & 0xFF000000) >> 24);
-
- // (i==22) UncompressedSize (Int32) - this value may or may not be
- // bonafide.
- block[i++] = (byte)(_UncompressedSize & 0x000000FF);
- block[i++] = (byte)((_UncompressedSize & 0x0000FF00) >> 8);
- block[i++] = (byte)((_UncompressedSize & 0x00FF0000) >> 16);
- block[i++] = (byte)((_UncompressedSize & 0xFF000000) >> 24);
- }
-
- // (i==26) filename length (Int16)
- block[i++] = (byte)(filenameLength & 0x00FF);
- block[i++] = (byte)((filenameLength & 0xFF00) >> 8);
-
- _Extra = ConstructExtraField(false);
-
- // (i==28) extra field length (short)
- Int16 extraFieldLength = (Int16)((_Extra == null) ? 0 : _Extra.Length);
- block[i++] = (byte)(extraFieldLength & 0x00FF);
- block[i++] = (byte)((extraFieldLength & 0xFF00) >> 8);
-
- // workitem 13542
- byte[] bytes = new byte[i + filenameLength + extraFieldLength];
-
- // get the fixed portion
- Buffer.BlockCopy(block, 0, bytes, 0, i);
- //for (j = 0; j < i; j++) bytes[j] = block[j];
-
- // The filename written to the archive.
- Buffer.BlockCopy(fileNameBytes, 0, bytes, i, fileNameBytes.Length);
- // for (j = 0; j < fileNameBytes.Length; j++)
- // bytes[i + j] = fileNameBytes[j];
-
- i += fileNameBytes.Length;
-
- // "Extra field"
- if (_Extra != null)
- {
- Buffer.BlockCopy(_Extra, 0, bytes, i, _Extra.Length);
- // for (j = 0; j < _Extra.Length; j++)
- // bytes[i + j] = _Extra[j];
- i += _Extra.Length;
- }
-
- _LengthOfHeader = i;
-
- // handle split archives
- var zss = s as ZipSegmentedStream;
- if (zss != null)
- {
- zss.ContiguousWrite = true;
- UInt32 requiredSegment = zss.ComputeSegment(i);
- if (requiredSegment != zss.CurrentSegment)
- _future_ROLH = 0; // rollover!
- else
- _future_ROLH = zss.Position;
-
- _diskNumber = requiredSegment;
- }
-
- // validate the ZIP64 usage
- if (_container.Zip64 == Zip64Option.Never && (uint)_RelativeOffsetOfLocalHeader >= 0xFFFFFFFF)
- throw new ZipException("Offset within the zip archive exceeds 0xFFFFFFFF. Consider setting the UseZip64WhenSaving property on the ZipFile instance.");
-
-
- // finally, write the header to the stream
- s.Write(bytes, 0, i);
-
- // now that the header is written, we can turn off the contiguous write restriction.
- if (zss != null)
- zss.ContiguousWrite = false;
-
- // Preserve this header data, we'll use it again later.
- // ..when seeking backward, to write again, after we have the Crc, compressed
- // and uncompressed sizes.
- // ..and when writing the central directory structure.
- _EntryHeader = bytes;
- }
-
-
-
-
- private Int32 FigureCrc32()
- {
- if (_crcCalculated == false)
- {
- Stream input = null;
- // get the original stream:
- if (this._Source == ZipEntrySource.WriteDelegate)
- {
- var output = new Ionic.Crc.CrcCalculatorStream(Stream.Null);
- // allow the application to write the data
- this._WriteDelegate(this.FileName, output);
- _Crc32 = output.Crc;
- }
- else if (this._Source == ZipEntrySource.ZipFile)
- {
- // nothing to do - the CRC is already set
- }
- else
- {
- if (this._Source == ZipEntrySource.Stream)
- {
- PrepSourceStream();
- input = this._sourceStream;
- }
- else if (this._Source == ZipEntrySource.JitStream)
- {
- // allow the application to open the stream
- if (this._sourceStream == null)
- _sourceStream = this._OpenDelegate(this.FileName);
- PrepSourceStream();
- input = this._sourceStream;
- }
- else if (this._Source == ZipEntrySource.ZipOutputStream)
- {
- }
- else
- {
- //input = File.OpenRead(LocalFileName);
- input = File.Open(LocalFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
- }
-
- var crc32 = new Ionic.Crc.CRC32();
- _Crc32 = crc32.GetCrc32(input);
-
- if (_sourceStream == null)
- {
-#if NETCF
- input.Close();
-#else
- input.Dispose();
-#endif
- }
- }
- _crcCalculated = true;
- }
- return _Crc32;
- }
-
-
- /// <summary>
- /// Stores the position of the entry source stream, or, if the position is
- /// already stored, seeks to that position.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method is called in prep for reading the source stream. If PKZIP
- /// encryption is used, then we need to calc the CRC32 before doing the
- /// encryption, because the CRC is used in the 12th byte of the PKZIP
- /// encryption header. So, we need to be able to seek backward in the source
- /// when saving the ZipEntry. This method is called from the place that
- /// calculates the CRC, and also from the method that does the encryption of
- /// the file data.
- /// </para>
- ///
- /// <para>
- /// The first time through, this method sets the _sourceStreamOriginalPosition
- /// field. Subsequent calls to this method seek to that position.
- /// </para>
- /// </remarks>
- private void PrepSourceStream()
- {
- if (_sourceStream == null)
- throw new ZipException(String.Format("The input stream is null for entry '{0}'.", FileName));
-
- if (this._sourceStreamOriginalPosition != null)
- {
- // this will happen the 2nd cycle through, if the stream is seekable
- this._sourceStream.Position = this._sourceStreamOriginalPosition.Value;
- }
- else if (this._sourceStream.CanSeek)
- {
- // this will happen the first cycle through, if seekable
- this._sourceStreamOriginalPosition = new Nullable<Int64>(this._sourceStream.Position);
- }
- else if (this.Encryption == EncryptionAlgorithm.PkzipWeak)
- {
- // In general, using PKZIP encryption on a a zip entry whose input
- // comes from a non-seekable stream, is tricky. Here's why:
- //
- // Byte 11 of the PKZIP encryption header is used for password
- // validation and consistency checknig.
- //
- // Normally, the highest byte of the CRC is used as the 11th (last) byte
- // in the PKZIP encryption header. This means the CRC must be known
- // before encryption is performed. Normally that means we read the full
- // data stream, compute the CRC, then seek back and read it again for
- // the compression+encryption phase. Obviously this is bad for
- // performance with a large input file.
- //
- // There's a twist in the ZIP spec (actually documented only in infozip
- // code, not in the spec itself) that allows the high-order byte of the
- // last modified time for the entry, when the lastmod time is in packed
- // (DOS) format, to be used for Byte 11 in the encryption header. In
- // this case, the bit 3 "data descriptor" must be used.
- //
- // An intelligent implementation would therefore force the use of the
- // bit 3 data descriptor when PKZIP encryption is in use, regardless.
- // This avoids the double-read of the stream to be encrypted. So far,
- // DotNetZip doesn't do that; it just punts when the input stream is
- // non-seekable, and the output does not use Bit 3.
- //
- // The other option is to use the CRC when it is already available, eg,
- // when the source for the data is a ZipEntry (when the zip file is
- // being updated). In this case we already know the CRC and can just use
- // what we know.
-
- if (this._Source != ZipEntrySource.ZipFile && ((this._BitField & 0x0008) != 0x0008))
- throw new ZipException("It is not possible to use PKZIP encryption on a non-seekable input stream");
- }
- }
-
-
- /// <summary>
- /// Copy metadata that may have been changed by the app. We do this when
- /// resetting the zipFile instance. If the app calls Save() on a ZipFile, then
- /// tries to party on that file some more, we may need to Reset() it , which
- /// means re-reading the entries and then copying the metadata. I think.
- /// </summary>
- internal void CopyMetaData(ZipEntry source)
- {
- this.__FileDataPosition = source.__FileDataPosition;
- this.CompressionMethod = source.CompressionMethod;
- this._CompressionMethod_FromZipFile = source._CompressionMethod_FromZipFile;
- this._CompressedFileDataSize = source._CompressedFileDataSize;
- this._UncompressedSize = source._UncompressedSize;
- this._BitField = source._BitField;
- this._Source = source._Source;
- this._LastModified = source._LastModified;
- this._Mtime = source._Mtime;
- this._Atime = source._Atime;
- this._Ctime = source._Ctime;
- this._ntfsTimesAreSet = source._ntfsTimesAreSet;
- this._emitUnixTimes = source._emitUnixTimes;
- this._emitNtfsTimes = source._emitNtfsTimes;
- }
-
-
- private void OnWriteBlock(Int64 bytesXferred, Int64 totalBytesToXfer)
- {
- if (_container.ZipFile != null)
- _ioOperationCanceled = _container.ZipFile.OnSaveBlock(this, bytesXferred, totalBytesToXfer);
- }
-
-
-
- private void _WriteEntryData(Stream s)
- {
- // Read in the data from the input stream (often a file in the filesystem),
- // and write it to the output stream, calculating a CRC on it as we go.
- // We will also compress and encrypt as necessary.
-
- Stream input = null;
- long fdp = -1L;
- try
- {
- // Want to record the position in the zip file of the zip entry
- // data (as opposed to the metadata). s.Position may fail on some
- // write-only streams, eg stdout or System.Web.HttpResponseStream.
- // We swallow that exception, because we don't care, in that case.
- // But, don't set __FileDataPosition directly. It may be needed
- // to READ the zip entry from the zip file, if this is a
- // "re-stream" situation. In other words if the zip entry has
- // changed compression level, or compression method, or (maybe?)
- // encryption algorithm. In that case if the original entry is
- // encrypted, we need __FileDataPosition to be the value for the
- // input zip file. This s.Position is for the output zipfile. So
- // we copy fdp to __FileDataPosition after this entry has been
- // (maybe) restreamed.
- fdp = s.Position;
- }
- catch (Exception) { }
-
- try
- {
- // Use fileLength for progress updates, and to decide whether we can
- // skip encryption and compression altogether (in case of length==zero)
- long fileLength = SetInputAndFigureFileLength(ref input);
-
- // Wrap a counting stream around the raw output stream:
- // This is the last thing that happens before the bits go to the
- // application-provided stream.
- //
- // Sometimes s is a CountingStream. Doesn't matter. Wrap it with a
- // counter anyway. We need to count at both levels.
-
- CountingStream entryCounter = new CountingStream(s);
-
- Stream encryptor;
- Stream compressor;
-
- if (fileLength != 0L)
- {
- // Maybe wrap an encrypting stream around the counter: This will
- // happen BEFORE output counting, and AFTER compression, if encryption
- // is used.
- encryptor = MaybeApplyEncryption(entryCounter);
-
- // Maybe wrap a compressing Stream around that.
- // This will happen BEFORE encryption (if any) as we write data out.
- compressor = MaybeApplyCompression(encryptor, fileLength);
- }
- else
- {
- encryptor = compressor = entryCounter;
- }
-
- // Wrap a CrcCalculatorStream around that.
- // This will happen BEFORE compression (if any) as we write data out.
- var output = new Ionic.Crc.CrcCalculatorStream(compressor, true);
-
- // output.Write() causes this flow:
- // calc-crc -> compress -> encrypt -> count -> actually write
-
- if (this._Source == ZipEntrySource.WriteDelegate)
- {
- // allow the application to write the data
- this._WriteDelegate(this.FileName, output);
- }
- else
- {
- // synchronously copy the input stream to the output stream-chain
- byte[] buffer = new byte[BufferSize];
- int n;
- while ((n = SharedUtilities.ReadWithRetry(input, buffer, 0, buffer.Length, FileName)) != 0)
- {
- output.Write(buffer, 0, n);
- OnWriteBlock(output.TotalBytesSlurped, fileLength);
- if (_ioOperationCanceled)
- break;
- }
- }
-
- FinishOutputStream(s, entryCounter, encryptor, compressor, output);
- }
- finally
- {
- if (this._Source == ZipEntrySource.JitStream)
- {
- // allow the application to close the stream
- if (this._CloseDelegate != null)
- this._CloseDelegate(this.FileName, input);
- }
- else if ((input as FileStream) != null)
- {
-#if NETCF
- input.Close();
-#else
- input.Dispose();
-#endif
- }
- }
-
- if (_ioOperationCanceled)
- return;
-
- // set FDP now, to allow for re-streaming
- this.__FileDataPosition = fdp;
- PostProcessOutput(s);
- }
-
-
- /// <summary>
- /// Set the input stream and get its length, if possible. The length is
- /// used for progress updates, AND, to allow an optimization in case of
- /// a stream/file of zero length. In that case we skip the Encrypt and
- /// compression Stream. (like DeflateStream or BZip2OutputStream)
- /// </summary>
- private long SetInputAndFigureFileLength(ref Stream input)
- {
- long fileLength = -1L;
- // get the original stream:
- if (this._Source == ZipEntrySource.Stream)
- {
- PrepSourceStream();
- input = this._sourceStream;
-
- // Try to get the length, no big deal if not available.
- try { fileLength = this._sourceStream.Length; }
- catch (NotSupportedException) { }
- }
- else if (this._Source == ZipEntrySource.ZipFile)
- {
- // we are "re-streaming" the zip entry.
- string pwd = (_Encryption_FromZipFile == EncryptionAlgorithm.None) ? null : (this._Password ?? this._container.Password);
- this._sourceStream = InternalOpenReader(pwd);
- PrepSourceStream();
- input = this._sourceStream;
- fileLength = this._sourceStream.Length;
- }
- else if (this._Source == ZipEntrySource.JitStream)
- {
- // allow the application to open the stream
- if (this._sourceStream == null) _sourceStream = this._OpenDelegate(this.FileName);
- PrepSourceStream();
- input = this._sourceStream;
- try { fileLength = this._sourceStream.Length; }
- catch (NotSupportedException) { }
- }
- else if (this._Source == ZipEntrySource.FileSystem)
- {
- // workitem 7145
- FileShare fs = FileShare.ReadWrite;
-#if !NETCF
- // FileShare.Delete is not defined for the Compact Framework
- fs |= FileShare.Delete;
-#endif
- // workitem 8423
- input = File.Open(LocalFileName, FileMode.Open, FileAccess.Read, fs);
- fileLength = input.Length;
- }
-
- return fileLength;
- }
-
-
-
- internal void FinishOutputStream(Stream s,
- CountingStream entryCounter,
- Stream encryptor,
- Stream compressor,
- Ionic.Crc.CrcCalculatorStream output)
- {
- if (output == null) return;
-
- output.Close();
-
- // by calling Close() on the deflate stream, we write the footer bytes, as necessary.
- if ((compressor as Ionic.Zlib.DeflateStream) != null)
- compressor.Close();
-#if BZIP
- else if ((compressor as Ionic.BZip2.BZip2OutputStream) != null)
- compressor.Close();
-#if !NETCF
- else if ((compressor as Ionic.BZip2.ParallelBZip2OutputStream) != null)
- compressor.Close();
-#endif
-#endif
-
-#if !NETCF
- else if ((compressor as Ionic.Zlib.ParallelDeflateOutputStream) != null)
- compressor.Close();
-#endif
-
- encryptor.Flush();
- encryptor.Close();
-
- _LengthOfTrailer = 0;
-
- _UncompressedSize = output.TotalBytesSlurped;
-
-#if AESCRYPTO
- WinZipAesCipherStream wzacs = encryptor as WinZipAesCipherStream;
- if (wzacs != null && _UncompressedSize > 0)
- {
- s.Write(wzacs.FinalAuthentication, 0, 10);
- _LengthOfTrailer += 10;
- }
-#endif
- _CompressedFileDataSize = entryCounter.BytesWritten;
- _CompressedSize = _CompressedFileDataSize; // may be adjusted
- _Crc32 = output.Crc;
-
- // Set _RelativeOffsetOfLocalHeader now, to allow for re-streaming
- StoreRelativeOffset();
- }
-
-
-
-
- internal void PostProcessOutput(Stream s)
- {
- var s1 = s as CountingStream;
-
- // workitem 8931 - for WriteDelegate.
- // The WriteDelegate changes things because there can be a zero-byte stream
- // written. In all other cases DotNetZip knows the length of the stream
- // before compressing and encrypting. In this case we have to circle back,
- // and omit all the crypto stuff - the GP bitfield, and the crypto header.
- if (_UncompressedSize == 0 && _CompressedSize == 0)
- {
- if (this._Source == ZipEntrySource.ZipOutputStream) return; // nothing to do...
-
- if (_Password != null)
- {
- int headerBytesToRetract = 0;
- if (Encryption == EncryptionAlgorithm.PkzipWeak)
- headerBytesToRetract = 12;
-#if AESCRYPTO
- else if (Encryption == EncryptionAlgorithm.WinZipAes128 ||
- Encryption == EncryptionAlgorithm.WinZipAes256)
- {
- headerBytesToRetract = _aesCrypto_forWrite._Salt.Length + _aesCrypto_forWrite.GeneratedPV.Length;
- }
-#endif
- if (this._Source == ZipEntrySource.ZipOutputStream && !s.CanSeek)
- throw new ZipException("Zero bytes written, encryption in use, and non-seekable output.");
-
- if (Encryption != EncryptionAlgorithm.None)
- {
- // seek back in the stream to un-output the security metadata
- s.Seek(-1 * headerBytesToRetract, SeekOrigin.Current);
- s.SetLength(s.Position);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(s);
-
- // workitem 11131
- // adjust the count on the CountingStream as necessary
- if (s1 != null) s1.Adjust(headerBytesToRetract);
-
- // subtract the size of the security header from the _LengthOfHeader
- _LengthOfHeader -= headerBytesToRetract;
- __FileDataPosition -= headerBytesToRetract;
- }
- _Password = null;
-
- // turn off the encryption bit
- _BitField &= ~(0x0001);
-
- // copy the updated bitfield value into the header
- int j = 6;
- _EntryHeader[j++] = (byte)(_BitField & 0x00FF);
- _EntryHeader[j++] = (byte)((_BitField & 0xFF00) >> 8);
-
-#if AESCRYPTO
- if (Encryption == EncryptionAlgorithm.WinZipAes128 ||
- Encryption == EncryptionAlgorithm.WinZipAes256)
- {
- // Fix the extra field - overwrite the 0x9901 headerId
- // with dummy data. (arbitrarily, 0x9999)
- Int16 fnLength = (short)(_EntryHeader[26] + _EntryHeader[27] * 256);
- int offx = 30 + fnLength;
- int aesIndex = FindExtraFieldSegment(_EntryHeader, offx, 0x9901);
- if (aesIndex >= 0)
- {
- _EntryHeader[aesIndex++] = 0x99;
- _EntryHeader[aesIndex++] = 0x99;
- }
- }
-#endif
- }
-
- CompressionMethod = 0;
- Encryption = EncryptionAlgorithm.None;
- }
- else if (_zipCrypto_forWrite != null
-#if AESCRYPTO
- || _aesCrypto_forWrite != null
-#endif
- )
-
- {
- if (Encryption == EncryptionAlgorithm.PkzipWeak)
- {
- _CompressedSize += 12; // 12 extra bytes for the encryption header
- }
-#if AESCRYPTO
- else if (Encryption == EncryptionAlgorithm.WinZipAes128 ||
- Encryption == EncryptionAlgorithm.WinZipAes256)
- {
- // adjust the compressed size to include the variable (salt+pv)
- // security header and 10-byte trailer. According to the winzip AES
- // spec, that metadata is included in the "Compressed Size" figure
- // when encoding the zip archive.
- _CompressedSize += _aesCrypto_forWrite.SizeOfEncryptionMetadata;
- }
-#endif
- }
-
- int i = 8;
- _EntryHeader[i++] = (byte)(_CompressionMethod & 0x00FF);
- _EntryHeader[i++] = (byte)((_CompressionMethod & 0xFF00) >> 8);
-
- i = 14;
- // CRC - the correct value now
- _EntryHeader[i++] = (byte)(_Crc32 & 0x000000FF);
- _EntryHeader[i++] = (byte)((_Crc32 & 0x0000FF00) >> 8);
- _EntryHeader[i++] = (byte)((_Crc32 & 0x00FF0000) >> 16);
- _EntryHeader[i++] = (byte)((_Crc32 & 0xFF000000) >> 24);
-
- SetZip64Flags();
-
- // (i==26) filename length (Int16)
- Int16 filenameLength = (short)(_EntryHeader[26] + _EntryHeader[27] * 256);
- Int16 extraFieldLength = (short)(_EntryHeader[28] + _EntryHeader[29] * 256);
-
- if (_OutputUsesZip64.Value)
- {
- // VersionNeededToExtract - set to 45 to indicate zip64
- _EntryHeader[4] = (byte)(45 & 0x00FF);
- _EntryHeader[5] = 0x00;
-
- // workitem 7924 - don't need bit 3
- // // workitem 7917
- // // set bit 3 for ZIP64 compatibility with WinZip12
- // _BitField |= 0x0008;
- // _EntryHeader[6] = (byte)(_BitField & 0x00FF);
-
- // CompressedSize and UncompressedSize - 0xFF
- for (int j = 0; j < 8; j++)
- _EntryHeader[i++] = 0xff;
-
- // At this point we need to find the "Extra field" that follows the
- // filename. We had already emitted it, but the data (uncomp, comp,
- // ROLH) was not available at the time we did so. Here, we emit it
- // again, with final values.
-
- i = 30 + filenameLength;
- _EntryHeader[i++] = 0x01; // zip64
- _EntryHeader[i++] = 0x00;
-
- i += 2; // skip over data size, which is 16+4
-
- Array.Copy(BitConverter.GetBytes(_UncompressedSize), 0, _EntryHeader, i, 8);
- i += 8;
- Array.Copy(BitConverter.GetBytes(_CompressedSize), 0, _EntryHeader, i, 8);
- }
- else
- {
- // VersionNeededToExtract - reset to 20 since no zip64
- _EntryHeader[4] = (byte)(20 & 0x00FF);
- _EntryHeader[5] = 0x00;
-
- // CompressedSize - the correct value now
- i = 18;
- _EntryHeader[i++] = (byte)(_CompressedSize & 0x000000FF);
- _EntryHeader[i++] = (byte)((_CompressedSize & 0x0000FF00) >> 8);
- _EntryHeader[i++] = (byte)((_CompressedSize & 0x00FF0000) >> 16);
- _EntryHeader[i++] = (byte)((_CompressedSize & 0xFF000000) >> 24);
-
- // UncompressedSize - the correct value now
- _EntryHeader[i++] = (byte)(_UncompressedSize & 0x000000FF);
- _EntryHeader[i++] = (byte)((_UncompressedSize & 0x0000FF00) >> 8);
- _EntryHeader[i++] = (byte)((_UncompressedSize & 0x00FF0000) >> 16);
- _EntryHeader[i++] = (byte)((_UncompressedSize & 0xFF000000) >> 24);
-
- // The HeaderId in the extra field header, is already dummied out.
- if (extraFieldLength != 0)
- {
- i = 30 + filenameLength;
- // For zip archives written by this library, if the zip64
- // header exists, it is the first header. Because of the logic
- // used when first writing the _EntryHeader bytes, the
- // HeaderId is not guaranteed to be any particular value. So
- // we determine if the first header is a putative zip64 header
- // by examining the datasize. UInt16 HeaderId =
- // (UInt16)(_EntryHeader[i] + _EntryHeader[i + 1] * 256);
- Int16 DataSize = (short)(_EntryHeader[i + 2] + _EntryHeader[i + 3] * 256);
- if (DataSize == 16)
- {
- // reset to Header Id to dummy value, effectively dummy-ing out the zip64 metadata
- _EntryHeader[i++] = 0x99;
- _EntryHeader[i++] = 0x99;
- }
- }
- }
-
-
-#if AESCRYPTO
-
- if (Encryption == EncryptionAlgorithm.WinZipAes128 ||
- Encryption == EncryptionAlgorithm.WinZipAes256)
- {
- // Must set compressionmethod to 0x0063 (decimal 99)
- //
- // and then set the compression method bytes inside the extra
- // field to the actual compression method value.
-
- i = 8;
- _EntryHeader[i++] = 0x63;
- _EntryHeader[i++] = 0;
-
- i = 30 + filenameLength;
- do
- {
- UInt16 HeaderId = (UInt16)(_EntryHeader[i] + _EntryHeader[i + 1] * 256);
- Int16 DataSize = (short)(_EntryHeader[i + 2] + _EntryHeader[i + 3] * 256);
- if (HeaderId != 0x9901)
- {
- // skip this header
- i += DataSize + 4;
- }
- else
- {
- i += 9;
- // actual compression method
- _EntryHeader[i++] = (byte)(_CompressionMethod & 0x00FF);
- _EntryHeader[i++] = (byte)(_CompressionMethod & 0xFF00);
- }
- } while (i < (extraFieldLength - 30 - filenameLength));
- }
-#endif
-
- // finally, write the data.
-
- // workitem 7216 - sometimes we don't seek even if we CAN. ASP.NET
- // Response.OutputStream, or stdout are non-seekable. But we may also want
- // to NOT seek in other cases, eg zip64. For all cases, we just check bit 3
- // to see if we want to seek. There's one exception - if using a
- // ZipOutputStream, and PKZip encryption is in use, then we set bit 3 even
- // if the out is seekable. This is so the check on the last byte of the
- // PKZip Encryption Header can be done on the current time, as opposed to
- // the CRC, to prevent streaming the file twice. So, test for
- // ZipOutputStream and seekable, and if so, seek back, even if bit 3 is set.
-
- if ((_BitField & 0x0008) != 0x0008 ||
- (this._Source == ZipEntrySource.ZipOutputStream && s.CanSeek))
- {
- // seek back and rewrite the entry header
- var zss = s as ZipSegmentedStream;
- if (zss != null && _diskNumber != zss.CurrentSegment)
- {
- // In this case the entry header is in a different file,
- // which has already been closed. Need to re-open it.
- using (Stream hseg = ZipSegmentedStream.ForUpdate(this._container.ZipFile.Name, _diskNumber))
- {
- hseg.Seek(this._RelativeOffsetOfLocalHeader, SeekOrigin.Begin);
- hseg.Write(_EntryHeader, 0, _EntryHeader.Length);
- }
- }
- else
- {
- // seek in the raw output stream, to the beginning of the header for
- // this entry.
- // workitem 8098: ok (output)
- s.Seek(this._RelativeOffsetOfLocalHeader, SeekOrigin.Begin);
-
- // write the updated header to the output stream
- s.Write(_EntryHeader, 0, _EntryHeader.Length);
-
- // adjust the count on the CountingStream as necessary
- if (s1 != null) s1.Adjust(_EntryHeader.Length);
-
- // seek in the raw output stream, to the end of the file data
- // for this entry
- s.Seek(_CompressedSize, SeekOrigin.Current);
- }
- }
-
- // emit the descriptor - only if not a directory.
- if (((_BitField & 0x0008) == 0x0008) && !IsDirectory)
- {
- byte[] Descriptor = new byte[16 + (_OutputUsesZip64.Value ? 8 : 0)];
- i = 0;
-
- // signature
- Array.Copy(BitConverter.GetBytes(ZipConstants.ZipEntryDataDescriptorSignature), 0, Descriptor, i, 4);
- i += 4;
-
- // CRC - the correct value now
- Array.Copy(BitConverter.GetBytes(_Crc32), 0, Descriptor, i, 4);
- i += 4;
-
- // workitem 7917
- if (_OutputUsesZip64.Value)
- {
- // CompressedSize - the correct value now
- Array.Copy(BitConverter.GetBytes(_CompressedSize), 0, Descriptor, i, 8);
- i += 8;
-
- // UncompressedSize - the correct value now
- Array.Copy(BitConverter.GetBytes(_UncompressedSize), 0, Descriptor, i, 8);
- i += 8;
- }
- else
- {
- // CompressedSize - (lower 32 bits) the correct value now
- Descriptor[i++] = (byte)(_CompressedSize & 0x000000FF);
- Descriptor[i++] = (byte)((_CompressedSize & 0x0000FF00) >> 8);
- Descriptor[i++] = (byte)((_CompressedSize & 0x00FF0000) >> 16);
- Descriptor[i++] = (byte)((_CompressedSize & 0xFF000000) >> 24);
-
- // UncompressedSize - (lower 32 bits) the correct value now
- Descriptor[i++] = (byte)(_UncompressedSize & 0x000000FF);
- Descriptor[i++] = (byte)((_UncompressedSize & 0x0000FF00) >> 8);
- Descriptor[i++] = (byte)((_UncompressedSize & 0x00FF0000) >> 16);
- Descriptor[i++] = (byte)((_UncompressedSize & 0xFF000000) >> 24);
- }
-
- // finally, write the trailing descriptor to the output stream
- s.Write(Descriptor, 0, Descriptor.Length);
-
- _LengthOfTrailer += Descriptor.Length;
- }
- }
-
-
-
- private void SetZip64Flags()
- {
- // zip64 housekeeping
- _entryRequiresZip64 = new Nullable<bool>
- (_CompressedSize >= 0xFFFFFFFF || _UncompressedSize >= 0xFFFFFFFF || _RelativeOffsetOfLocalHeader >= 0xFFFFFFFF);
-
- // validate the ZIP64 usage
- if (_container.Zip64 == Zip64Option.Never && _entryRequiresZip64.Value)
- throw new ZipException("Compressed or Uncompressed size, or offset exceeds the maximum value. Consider setting the UseZip64WhenSaving property on the ZipFile instance.");
-
- _OutputUsesZip64 = new Nullable<bool>(_container.Zip64 == Zip64Option.Always || _entryRequiresZip64.Value);
- }
-
-
-
- /// <summary>
- /// Prepare the given stream for output - wrap it in a CountingStream, and
- /// then in a CRC stream, and an encryptor and deflator as appropriate.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Previously this was used in ZipEntry.Write(), but in an effort to
- /// introduce some efficiencies in that method I've refactored to put the
- /// code inline. This method still gets called by ZipOutputStream.
- /// </para>
- /// </remarks>
- internal void PrepOutputStream(Stream s,
- long streamLength,
- out CountingStream outputCounter,
- out Stream encryptor,
- out Stream compressor,
- out Ionic.Crc.CrcCalculatorStream output)
- {
- TraceWriteLine("PrepOutputStream: e({0}) comp({1}) crypto({2}) zf({3})",
- FileName,
- CompressionLevel,
- Encryption,
- _container.Name);
-
- // Wrap a counting stream around the raw output stream:
- // This is the last thing that happens before the bits go to the
- // application-provided stream.
- outputCounter = new CountingStream(s);
-
- // Sometimes the incoming "raw" output stream is already a CountingStream.
- // Doesn't matter. Wrap it with a counter anyway. We need to count at both
- // levels.
-
- if (streamLength != 0L)
- {
- // Maybe wrap an encrypting stream around that:
- // This will happen BEFORE output counting, and AFTER deflation, if encryption
- // is used.
- encryptor = MaybeApplyEncryption(outputCounter);
-
- // Maybe wrap a compressing Stream around that.
- // This will happen BEFORE encryption (if any) as we write data out.
- compressor = MaybeApplyCompression(encryptor, streamLength);
- }
- else
- {
- encryptor = compressor = outputCounter;
- }
- // Wrap a CrcCalculatorStream around that.
- // This will happen BEFORE compression (if any) as we write data out.
- output = new Ionic.Crc.CrcCalculatorStream(compressor, true);
- }
-
-
-
- private Stream MaybeApplyCompression(Stream s, long streamLength)
- {
- if (_CompressionMethod == 0x08 && CompressionLevel != Ionic.Zlib.CompressionLevel.None)
- {
-#if !NETCF
- // ParallelDeflateThreshold == 0 means ALWAYS use parallel deflate
- // ParallelDeflateThreshold == -1L means NEVER use parallel deflate
- // Other values specify the actual threshold.
- if (_container.ParallelDeflateThreshold == 0L ||
- (streamLength > _container.ParallelDeflateThreshold &&
- _container.ParallelDeflateThreshold > 0L))
- {
- // This is sort of hacky.
- //
- // It's expensive to create a ParallelDeflateOutputStream, because
- // of the large memory buffers. But the class is unlike most Stream
- // classes in that it can be re-used, so the caller can compress
- // multiple files with it, one file at a time. The key is to call
- // Reset() on it, in between uses.
- //
- // The ParallelDeflateOutputStream is attached to the container
- // itself - there is just one for the entire ZipFile or
- // ZipOutputStream. So it gets created once, per save, and then
- // re-used many times.
- //
- // This approach will break when we go to a "parallel save"
- // approach, where multiple entries within the zip file are being
- // compressed and saved at the same time. But for now it's ok.
- //
-
- // instantiate the ParallelDeflateOutputStream
- if (_container.ParallelDeflater == null)
- {
- _container.ParallelDeflater =
- new ParallelDeflateOutputStream(s,
- CompressionLevel,
- _container.Strategy,
- true);
- // can set the codec buffer size only before the first call to Write().
- if (_container.CodecBufferSize > 0)
- _container.ParallelDeflater.BufferSize = _container.CodecBufferSize;
- if (_container.ParallelDeflateMaxBufferPairs > 0)
- _container.ParallelDeflater.MaxBufferPairs =
- _container.ParallelDeflateMaxBufferPairs;
- }
- // reset it with the new stream
- Ionic.Zlib.ParallelDeflateOutputStream o1 = _container.ParallelDeflater;
- o1.Reset(s);
- return o1;
- }
-#endif
- var o = new DeflateStream(s, OfficeOpenXml.Packaging.Ionic.Zlib.CompressionMode.Compress,
- CompressionLevel,
- true);
- if (_container.CodecBufferSize > 0)
- o.BufferSize = _container.CodecBufferSize;
- o.Strategy = _container.Strategy;
- return o;
- }
-
-
-#if BZIP
- if (_CompressionMethod == 0x0c)
- {
-#if !NETCF
- if (_container.ParallelDeflateThreshold == 0L ||
- (streamLength > _container.ParallelDeflateThreshold &&
- _container.ParallelDeflateThreshold > 0L))
- {
-
- var o1 = new Ionic.BZip2.ParallelBZip2OutputStream(s, true);
- return o1;
- }
-#endif
- var o = new Ionic.BZip2.BZip2OutputStream(s, true);
- return o;
- }
-#endif
-
- return s;
- }
-
-
-
- private Stream MaybeApplyEncryption(Stream s)
- {
- if (Encryption == EncryptionAlgorithm.PkzipWeak)
- {
- TraceWriteLine("MaybeApplyEncryption: e({0}) PKZIP", FileName);
-
- return new ZipCipherStream(s, _zipCrypto_forWrite, CryptoMode.Encrypt);
- }
-#if AESCRYPTO
- if (Encryption == EncryptionAlgorithm.WinZipAes128 ||
- Encryption == EncryptionAlgorithm.WinZipAes256)
- {
- TraceWriteLine("MaybeApplyEncryption: e({0}) AES", FileName);
-
- return new WinZipAesCipherStream(s, _aesCrypto_forWrite, CryptoMode.Encrypt);
- }
-#endif
- TraceWriteLine("MaybeApplyEncryption: e({0}) None", FileName);
-
- return s;
- }
-
-
-
- private void OnZipErrorWhileSaving(Exception e)
- {
- if (_container.ZipFile != null)
- _ioOperationCanceled = _container.ZipFile.OnZipErrorSaving(this, e);
- }
-
-
-
- internal void Write(Stream s)
- {
- var cs1 = s as CountingStream;
- var zss1 = s as ZipSegmentedStream;
-
- bool done = false;
- do
- {
- try
- {
- // When the app is updating a zip file, it may be possible to
- // just copy data for a ZipEntry from the source zipfile to the
- // destination, as a block, without decompressing and
- // recompressing, etc. But, in some cases the app modifies the
- // properties on a ZipEntry prior to calling Save(). A change to
- // any of the metadata - the FileName, CompressioLeve and so on,
- // means DotNetZip cannot simply copy through the existing
- // ZipEntry data unchanged.
- //
- // There are two cases:
- //
- // 1. Changes to only metadata, which means the header and
- // central directory must be changed.
- //
- // 2. Changes to the properties that affect the compressed
- // stream, such as CompressionMethod, CompressionLevel, or
- // EncryptionAlgorithm. In this case, DotNetZip must
- // "re-stream" the data: the old entry data must be maybe
- // decrypted, maybe decompressed, then maybe re-compressed
- // and maybe re-encrypted.
- //
- // This test checks if the source for the entry data is a zip file, and
- // if a restream is necessary. If NOT, then it just copies through
- // one entry, potentially changing the metadata.
-
- if (_Source == ZipEntrySource.ZipFile && !_restreamRequiredOnSave)
- {
- CopyThroughOneEntry(s);
- return;
- }
-
- // Is the entry a directory? If so, the write is relatively simple.
- if (IsDirectory)
- {
- WriteHeader(s, 1);
- StoreRelativeOffset();
- _entryRequiresZip64 = new Nullable<bool>(_RelativeOffsetOfLocalHeader >= 0xFFFFFFFF);
- _OutputUsesZip64 = new Nullable<bool>(_container.Zip64 == Zip64Option.Always || _entryRequiresZip64.Value);
- // handle case for split archives
- if (zss1 != null)
- _diskNumber = zss1.CurrentSegment;
-
- return;
- }
-
- // At this point, the source for this entry is not a directory, and
- // not a previously created zip file, or the source for the entry IS
- // a previously created zip but the settings whave changed in
- // important ways and therefore we will need to process the
- // bytestream (compute crc, maybe compress, maybe encrypt) in order
- // to write the content into the new zip.
- //
- // We do this in potentially 2 passes: The first time we do it as
- // requested, maybe with compression and maybe encryption. If that
- // causes the bytestream to inflate in size, and if compression was
- // on, then we turn off compression and do it again.
-
-
- bool readAgain = true;
- int nCycles = 0;
- do
- {
- nCycles++;
-
- WriteHeader(s, nCycles);
-
- // write the encrypted header
- WriteSecurityMetadata(s);
-
- // write the (potentially compressed, potentially encrypted) file data
- _WriteEntryData(s);
-
- // track total entry size (including the trailing descriptor and MAC)
- _TotalEntrySize = _LengthOfHeader + _CompressedFileDataSize + _LengthOfTrailer;
-
- // The file data has now been written to the stream, and
- // the file pointer is positioned directly after file data.
-
- if (nCycles > 1) readAgain = false;
- else if (!s.CanSeek) readAgain = false;
- else readAgain = WantReadAgain();
-
- if (readAgain)
- {
- // Seek back in the raw output stream, to the beginning of the file
- // data for this entry.
-
- // handle case for split archives
- if (zss1 != null)
- {
- // Console.WriteLine("***_diskNumber/first: {0}", _diskNumber);
- // Console.WriteLine("***_diskNumber/current: {0}", zss.CurrentSegment);
- zss1.TruncateBackward(_diskNumber, _RelativeOffsetOfLocalHeader);
- }
- else
- // workitem 8098: ok (output).
- s.Seek(_RelativeOffsetOfLocalHeader, SeekOrigin.Begin);
-
- // If the last entry expands, we read again; but here, we must
- // truncate the stream to prevent garbage data after the
- // end-of-central-directory.
-
- // workitem 8098: ok (output).
- s.SetLength(s.Position);
-
- // Adjust the count on the CountingStream as necessary.
- if (cs1 != null) cs1.Adjust(_TotalEntrySize);
- }
- }
- while (readAgain);
- _skippedDuringSave = false;
- done = true;
- }
- catch (System.Exception exc1)
- {
- ZipErrorAction orig = this.ZipErrorAction;
- int loop = 0;
- do
- {
- if (ZipErrorAction == ZipErrorAction.Throw)
- throw;
-
- if (ZipErrorAction == ZipErrorAction.Skip ||
- ZipErrorAction == ZipErrorAction.Retry)
- {
- // must reset file pointer here.
- // workitem 13903 - seek back only when necessary
- long p1 = (cs1 != null)
- ? cs1.ComputedPosition
- : s.Position;
- long delta = p1 - _future_ROLH;
- if (delta > 0)
- {
- s.Seek(delta, SeekOrigin.Current); // may throw
- long p2 = s.Position;
- s.SetLength(s.Position); // to prevent garbage if this is the last entry
- if (cs1 != null) cs1.Adjust(p1 - p2);
- }
- if (ZipErrorAction == ZipErrorAction.Skip)
- {
- WriteStatus("Skipping file {0} (exception: {1})", LocalFileName, exc1.ToString());
-
- _skippedDuringSave = true;
- done = true;
- }
- else
- this.ZipErrorAction = orig;
- break;
- }
-
- if (loop > 0) throw;
-
- if (ZipErrorAction == ZipErrorAction.InvokeErrorEvent)
- {
- OnZipErrorWhileSaving(exc1);
- if (_ioOperationCanceled)
- {
- done = true;
- break;
- }
- }
- loop++;
- }
- while (true);
- }
- }
- while (!done);
- }
-
-
- internal void StoreRelativeOffset()
- {
- _RelativeOffsetOfLocalHeader = _future_ROLH;
- }
-
-
-
- internal void NotifySaveComplete()
- {
- // When updating a zip file, there are two contexts for properties
- // like Encryption or CompressionMethod - the values read from the
- // original zip file, and the values used in the updated zip file.
- // The _FromZipFile versions are the originals. At the end of a save,
- // these values are the same. So we need to update them. This takes
- // care of the boundary case where a single zipfile instance can be
- // saved multiple times, with distinct changes to the properties on
- // the entries, in between each Save().
- _Encryption_FromZipFile = _Encryption;
- _CompressionMethod_FromZipFile = _CompressionMethod;
- _restreamRequiredOnSave = false;
- _metadataChanged = false;
- //_Source = ZipEntrySource.None;
- _Source = ZipEntrySource.ZipFile; // workitem 10694
- }
-
-
- internal void WriteSecurityMetadata(Stream outstream)
- {
- if (Encryption == EncryptionAlgorithm.None)
- return;
-
- string pwd = this._Password;
-
- // special handling for source == ZipFile.
- // Want to support the case where we re-stream an encrypted entry. This will involve,
- // at runtime, reading, decrypting, and decompressing from the original zip file, then
- // compressing, encrypting, and writing to the output zip file.
-
- // If that's what we're doing, and the password hasn't been set on the entry,
- // we use the container (ZipFile/ZipOutputStream) password to decrypt.
- // This test here says to use the container password to re-encrypt, as well,
- // with that password, if the entry password is null.
-
- if (this._Source == ZipEntrySource.ZipFile && pwd == null)
- pwd = this._container.Password;
-
- if (pwd == null)
- {
- _zipCrypto_forWrite = null;
-#if AESCRYPTO
- _aesCrypto_forWrite = null;
-#endif
- return;
- }
-
- TraceWriteLine("WriteSecurityMetadata: e({0}) crypto({1}) pw({2})",
- FileName, Encryption.ToString(), pwd);
-
- if (Encryption == EncryptionAlgorithm.PkzipWeak)
- {
- // If PKZip (weak) encryption is in use, then the encrypted entry data
- // is preceded by 12-byte "encryption header" for the entry.
-
- _zipCrypto_forWrite = ZipCrypto.ForWrite(pwd);
-
- // generate the random 12-byte header:
- var rnd = new System.Random();
- byte[] encryptionHeader = new byte[12];
- rnd.NextBytes(encryptionHeader);
-
- // workitem 8271
- if ((this._BitField & 0x0008) == 0x0008)
- {
- // In the case that bit 3 of the general purpose bit flag is set to
- // indicate the presence of a 'data descriptor' (signature
- // 0x08074b50), the last byte of the decrypted header is sometimes
- // compared with the high-order byte of the lastmodified time,
- // rather than the high-order byte of the CRC, to verify the
- // password.
- //
- // This is not documented in the PKWare Appnote.txt.
- // This was discovered this by analysis of the Crypt.c source file in the
- // InfoZip library
- // http://www.info-zip.org/pub/infozip/
-
- // Also, winzip insists on this!
- _TimeBlob = Ionic.Zip.SharedUtilities.DateTimeToPacked(LastModified);
- encryptionHeader[11] = (byte)((this._TimeBlob >> 8) & 0xff);
- }
- else
- {
- // When bit 3 is not set, the CRC value is required before
- // encryption of the file data begins. In this case there is no way
- // around it: must read the stream in its entirety to compute the
- // actual CRC before proceeding.
- FigureCrc32();
- encryptionHeader[11] = (byte)((this._Crc32 >> 24) & 0xff);
- }
-
- // Encrypt the random header, INCLUDING the final byte which is either
- // the high-order byte of the CRC32, or the high-order byte of the
- // _TimeBlob. Must do this BEFORE encrypting the file data. This
- // step changes the state of the cipher, or in the words of the PKZIP
- // spec, it "further initializes" the cipher keys.
-
- byte[] cipherText = _zipCrypto_forWrite.EncryptMessage(encryptionHeader, encryptionHeader.Length);
-
- // Write the ciphered bonafide encryption header.
- outstream.Write(cipherText, 0, cipherText.Length);
- _LengthOfHeader += cipherText.Length; // 12 bytes
- }
-
-#if AESCRYPTO
- else if (Encryption == EncryptionAlgorithm.WinZipAes128 ||
- Encryption == EncryptionAlgorithm.WinZipAes256)
- {
- // If WinZip AES encryption is in use, then the encrypted entry data is
- // preceded by a variable-sized Salt and a 2-byte "password
- // verification" value for the entry.
-
- int keystrength = GetKeyStrengthInBits(Encryption);
- _aesCrypto_forWrite = WinZipAesCrypto.Generate(pwd, keystrength);
- outstream.Write(_aesCrypto_forWrite.Salt, 0, _aesCrypto_forWrite._Salt.Length);
- outstream.Write(_aesCrypto_forWrite.GeneratedPV, 0, _aesCrypto_forWrite.GeneratedPV.Length);
- _LengthOfHeader += _aesCrypto_forWrite._Salt.Length + _aesCrypto_forWrite.GeneratedPV.Length;
-
- TraceWriteLine("WriteSecurityMetadata: AES e({0}) keybits({1}) _LOH({2})",
- FileName, keystrength, _LengthOfHeader);
-
- }
-#endif
-
- }
-
-
-
- private void CopyThroughOneEntry(Stream outStream)
- {
- // Just read the entry from the existing input zipfile and write to the output.
- // But, if metadata has changed (like file times or attributes), or if the ZIP64
- // option has changed, we can re-stream the entry data but must recompute the
- // metadata.
- if (this.LengthOfHeader == 0)
- throw new BadStateException("Bad header length.");
-
- // is it necessary to re-constitute new metadata for this entry?
- bool needRecompute = _metadataChanged ||
- (this.ArchiveStream is ZipSegmentedStream) ||
- (outStream is ZipSegmentedStream) ||
- (_InputUsesZip64 && _container.UseZip64WhenSaving == Zip64Option.Never) ||
- (!_InputUsesZip64 && _container.UseZip64WhenSaving == Zip64Option.Always);
-
- if (needRecompute)
- CopyThroughWithRecompute(outStream);
- else
- CopyThroughWithNoChange(outStream);
-
- // zip64 housekeeping
- _entryRequiresZip64 = new Nullable<bool>
- (_CompressedSize >= 0xFFFFFFFF || _UncompressedSize >= 0xFFFFFFFF ||
- _RelativeOffsetOfLocalHeader >= 0xFFFFFFFF
- );
-
- _OutputUsesZip64 = new Nullable<bool>(_container.Zip64 == Zip64Option.Always || _entryRequiresZip64.Value);
- }
-
-
-
- private void CopyThroughWithRecompute(Stream outstream)
- {
- int n;
- byte[] bytes = new byte[BufferSize];
- var input = new CountingStream(this.ArchiveStream);
-
- long origRelativeOffsetOfHeader = _RelativeOffsetOfLocalHeader;
-
- // The header length may change due to rename of file, add a comment, etc.
- // We need to retain the original.
- int origLengthOfHeader = LengthOfHeader; // including crypto bytes!
-
- // WriteHeader() has the side effect of changing _RelativeOffsetOfLocalHeader
- // and setting _LengthOfHeader. While ReadHeader() reads the crypto header if
- // present, WriteHeader() does not write the crypto header.
- WriteHeader(outstream, 0);
- StoreRelativeOffset();
-
- if (!this.FileName.EndsWith("/"))
- {
- // Not a directory; there is file data.
- // Seek to the beginning of the entry data in the input stream.
-
- long pos = origRelativeOffsetOfHeader + origLengthOfHeader;
- int len = GetLengthOfCryptoHeaderBytes(_Encryption_FromZipFile);
- pos -= len; // want to keep the crypto header
- _LengthOfHeader += len;
-
- input.Seek(pos, SeekOrigin.Begin);
-
- // copy through everything after the header to the output stream
- long remaining = this._CompressedSize;
-
- while (remaining > 0)
- {
- len = (remaining > bytes.Length) ? bytes.Length : (int)remaining;
-
- // read
- n = input.Read(bytes, 0, len);
- //_CheckRead(n);
-
- // write
- outstream.Write(bytes, 0, n);
- remaining -= n;
- OnWriteBlock(input.BytesRead, this._CompressedSize);
- if (_ioOperationCanceled)
- break;
- }
-
- // bit 3 descriptor
- if ((this._BitField & 0x0008) == 0x0008)
- {
- int size = 16;
- if (_InputUsesZip64) size += 8;
- byte[] Descriptor = new byte[size];
- input.Read(Descriptor, 0, size);
-
- if (_InputUsesZip64 && _container.UseZip64WhenSaving == Zip64Option.Never)
- {
- // original descriptor was 24 bytes, now we need 16.
- // Must check for underflow here.
- // signature + CRC.
- outstream.Write(Descriptor, 0, 8);
-
- // Compressed
- if (_CompressedSize > 0xFFFFFFFF)
- throw new InvalidOperationException("ZIP64 is required");
- outstream.Write(Descriptor, 8, 4);
-
- // UnCompressed
- if (_UncompressedSize > 0xFFFFFFFF)
- throw new InvalidOperationException("ZIP64 is required");
- outstream.Write(Descriptor, 16, 4);
- _LengthOfTrailer -= 8;
- }
- else if (!_InputUsesZip64 && _container.UseZip64WhenSaving == Zip64Option.Always)
- {
- // original descriptor was 16 bytes, now we need 24
- // signature + CRC
- byte[] pad = new byte[4];
- outstream.Write(Descriptor, 0, 8);
- // Compressed
- outstream.Write(Descriptor, 8, 4);
- outstream.Write(pad, 0, 4);
- // UnCompressed
- outstream.Write(Descriptor, 12, 4);
- outstream.Write(pad, 0, 4);
- _LengthOfTrailer += 8;
- }
- else
- {
- // same descriptor on input and output. Copy it through.
- outstream.Write(Descriptor, 0, size);
- //_LengthOfTrailer += size;
- }
- }
- }
-
- _TotalEntrySize = _LengthOfHeader + _CompressedFileDataSize + _LengthOfTrailer;
- }
-
-
- private void CopyThroughWithNoChange(Stream outstream)
- {
- int n;
- byte[] bytes = new byte[BufferSize];
- var input = new CountingStream(this.ArchiveStream);
-
- // seek to the beginning of the entry data in the input stream
- input.Seek(this._RelativeOffsetOfLocalHeader, SeekOrigin.Begin);
-
- if (this._TotalEntrySize == 0)
- {
- // We've never set the length of the entry.
- // Set it here.
- this._TotalEntrySize = this._LengthOfHeader + this._CompressedFileDataSize + _LengthOfTrailer;
-
- // The CompressedSize includes all the leading metadata associated
- // to encryption, if any, as well as the compressed data, or
- // compressed-then-encrypted data, and the trailer in case of AES.
-
- // The CompressedFileData size is the same, less the encryption
- // framing data (12 bytes header for PKZip; 10/18 bytes header and
- // 10 byte trailer for AES).
-
- // The _LengthOfHeader includes all the zip entry header plus the
- // crypto header, if any. The _LengthOfTrailer includes the
- // 10-byte MAC for AES, where appropriate, and the bit-3
- // Descriptor, where applicable.
- }
-
-
- // workitem 5616
- // remember the offset, within the output stream, of this particular entry header.
- // This may have changed if any of the other entries changed (eg, if a different
- // entry was removed or added.)
- var counter = outstream as CountingStream;
- _RelativeOffsetOfLocalHeader = (counter != null)
- ? counter.ComputedPosition
- : outstream.Position; // BytesWritten
-
- // copy through the header, filedata, trailer, everything...
- long remaining = this._TotalEntrySize;
- while (remaining > 0)
- {
- int len = (remaining > bytes.Length) ? bytes.Length : (int)remaining;
-
- // read
- n = input.Read(bytes, 0, len);
- //_CheckRead(n);
-
- // write
- outstream.Write(bytes, 0, n);
- remaining -= n;
- OnWriteBlock(input.BytesRead, this._TotalEntrySize);
- if (_ioOperationCanceled)
- break;
- }
- }
-
-
-
-
- [System.Diagnostics.ConditionalAttribute("Trace")]
- private void TraceWriteLine(string format, params object[] varParams)
- {
- lock (_outputLock)
- {
- int tid = System.Threading.Thread.CurrentThread.GetHashCode();
-#if ! (NETCF || SILVERLIGHT)
- Console.ForegroundColor = (ConsoleColor)(tid % 8 + 8);
-#endif
- Console.Write("{0:000} ZipEntry.Write ", tid);
- Console.WriteLine(format, varParams);
-#if ! (NETCF || SILVERLIGHT)
- Console.ResetColor();
-#endif
- }
- }
-
- private object _outputLock = new Object();
- }
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipEntry.cs b/EPPlus/Packaging/DotNetZip/ZipEntry.cs
deleted file mode 100644
index 7d727d0..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipEntry.cs
+++ /dev/null
@@ -1,2968 +0,0 @@
-// ZipEntry.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2006-2010 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-August-06 17:25:53>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the ZipEntry class, which models the entries within a zip file.
-//
-// Created: Tue, 27 Mar 2007 15:30
-//
-// ------------------------------------------------------------------
-
-
-using System;
-using System.IO;
-using Interop = System.Runtime.InteropServices;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- /// <summary>
- /// Represents a single entry in a ZipFile. Typically, applications get a ZipEntry
- /// by enumerating the entries within a ZipFile, or by adding an entry to a ZipFile.
- /// </summary>
-
- [Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00004")]
- [Interop.ComVisible(true)]
-#if !NETCF
- [Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)] // AutoDual
-#endif
- internal partial class ZipEntry
- {
- /// <summary>
- /// Default constructor.
- /// </summary>
- /// <remarks>
- /// Applications should never need to call this directly. It is exposed to
- /// support COM Automation environments.
- /// </remarks>
- public ZipEntry()
- {
- _CompressionMethod = (Int16)CompressionMethod.Deflate;
- _CompressionLevel = Ionic.Zlib.CompressionLevel.Default;
- _Encryption = EncryptionAlgorithm.None;
- _Source = ZipEntrySource.None;
- AlternateEncoding = System.Text.Encoding.ASCII;
- AlternateEncodingUsage = ZipOption.Never;
- }
-
- /// <summary>
- /// The time and date at which the file indicated by the <c>ZipEntry</c> was
- /// last modified.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The DotNetZip library sets the LastModified value for an entry, equal to
- /// the Last Modified time of the file in the filesystem. If an entry is
- /// added from a stream, the library uses <c>System.DateTime.Now</c> for this
- /// value, for the given entry.
- /// </para>
- ///
- /// <para>
- /// This property allows the application to retrieve and possibly set the
- /// LastModified value on an entry, to an arbitrary value. <see
- /// cref="System.DateTime"/> values with a <see cref="System.DateTimeKind" />
- /// setting of <c>DateTimeKind.Unspecified</c> are taken to be expressed as
- /// <c>DateTimeKind.Local</c>.
- /// </para>
- ///
- /// <para>
- /// Be aware that because of the way <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWare's
- /// Zip specification</see> describes how times are stored in the zip file,
- /// the full precision of the <c>System.DateTime</c> datatype is not stored
- /// for the last modified time when saving zip files. For more information on
- /// how times are formatted, see the PKZip specification.
- /// </para>
- ///
- /// <para>
- /// The actual last modified time of a file can be stored in multiple ways in
- /// the zip file, and they are not mutually exclusive:
- /// </para>
- ///
- /// <list type="bullet">
- /// <item>
- /// In the so-called "DOS" format, which has a 2-second precision. Values
- /// are rounded to the nearest even second. For example, if the time on the
- /// file is 12:34:43, then it will be stored as 12:34:44. This first value
- /// is accessible via the <c>LastModified</c> property. This value is always
- /// present in the metadata for each zip entry. In some cases the value is
- /// invalid, or zero.
- /// </item>
- ///
- /// <item>
- /// In the so-called "Windows" or "NTFS" format, as an 8-byte integer
- /// quantity expressed as the number of 1/10 milliseconds (in other words
- /// the number of 100 nanosecond units) since January 1, 1601 (UTC). This
- /// format is how Windows represents file times. This time is accessible
- /// via the <c>ModifiedTime</c> property.
- /// </item>
- ///
- /// <item>
- /// In the "Unix" format, a 4-byte quantity specifying the number of seconds since
- /// January 1, 1970 UTC.
- /// </item>
- ///
- /// <item>
- /// In an older format, now deprecated but still used by some current
- /// tools. This format is also a 4-byte quantity specifying the number of
- /// seconds since January 1, 1970 UTC.
- /// </item>
- ///
- /// </list>
- ///
- /// <para>
- /// Zip tools and libraries will always at least handle (read or write) the
- /// DOS time, and may also handle the other time formats. Keep in mind that
- /// while the names refer to particular operating systems, there is nothing in
- /// the time formats themselves that prevents their use on other operating
- /// systems.
- /// </para>
- ///
- /// <para>
- /// When reading ZIP files, the DotNetZip library reads the Windows-formatted
- /// time, if it is stored in the entry, and sets both <c>LastModified</c> and
- /// <c>ModifiedTime</c> to that value. When writing ZIP files, the DotNetZip
- /// library by default will write both time quantities. It can also emit the
- /// Unix-formatted time if desired (See <see
- /// cref="EmitTimesInUnixFormatWhenSaving"/>.)
- /// </para>
- ///
- /// <para>
- /// The last modified time of the file created upon a call to
- /// <c>ZipEntry.Extract()</c> may be adjusted during extraction to compensate
- /// for differences in how the .NET Base Class Library deals with daylight
- /// saving time (DST) versus how the Windows filesystem deals with daylight
- /// saving time. Raymond Chen <see
- /// href="http://blogs.msdn.com/oldnewthing/archive/2003/10/24/55413.aspx">provides
- /// some good context</see>.
- /// </para>
- ///
- /// <para>
- /// In a nutshell: Daylight savings time rules change regularly. In 2007, for
- /// example, the inception week of DST changed. In 1977, DST was in place all
- /// year round. In 1945, likewise. And so on. Win32 does not attempt to
- /// guess which time zone rules were in effect at the time in question. It
- /// will render a time as "standard time" and allow the app to change to DST
- /// as necessary. .NET makes a different choice.
- /// </para>
- ///
- /// <para>
- /// Compare the output of FileInfo.LastWriteTime.ToString("f") with what you
- /// see in the Windows Explorer property sheet for a file that was last
- /// written to on the other side of the DST transition. For example, suppose
- /// the file was last modified on October 17, 2003, during DST but DST is not
- /// currently in effect. Explorer's file properties reports Thursday, October
- /// 17, 2003, 8:45:38 AM, but .NETs FileInfo reports Thursday, October 17,
- /// 2003, 9:45 AM.
- /// </para>
- ///
- /// <para>
- /// Win32 says, "Thursday, October 17, 2002 8:45:38 AM PST". Note: Pacific
- /// STANDARD Time. Even though October 17 of that year occurred during Pacific
- /// Daylight Time, Win32 displays the time as standard time because that's
- /// what time it is NOW.
- /// </para>
- ///
- /// <para>
- /// .NET BCL assumes that the current DST rules were in place at the time in
- /// question. So, .NET says, "Well, if the rules in effect now were also in
- /// effect on October 17, 2003, then that would be daylight time" so it
- /// displays "Thursday, October 17, 2003, 9:45 AM PDT" - daylight time.
- /// </para>
- ///
- /// <para>
- /// So .NET gives a value which is more intuitively correct, but is also
- /// potentially incorrect, and which is not invertible. Win32 gives a value
- /// which is intuitively incorrect, but is strictly correct.
- /// </para>
- ///
- /// <para>
- /// Because of this funkiness, this library adds one hour to the LastModified
- /// time on the extracted file, if necessary. That is to say, if the time in
- /// question had occurred in what the .NET Base Class Library assumed to be
- /// DST. This assumption may be wrong given the constantly changing DST rules,
- /// but it is the best we can do.
- /// </para>
- ///
- /// </remarks>
- ///
- public DateTime LastModified
- {
- get { return _LastModified.ToLocalTime(); }
- set
- {
- _LastModified = (value.Kind == DateTimeKind.Unspecified)
- ? DateTime.SpecifyKind(value, DateTimeKind.Local)
- : value.ToLocalTime();
- _Mtime = Ionic.Zip.SharedUtilities.AdjustTime_Reverse(_LastModified).ToUniversalTime();
- _metadataChanged = true;
- }
- }
-
-
- private int BufferSize
- {
- get
- {
- return this._container.BufferSize;
- }
- }
-
- /// <summary>
- /// Last Modified time for the file represented by the entry.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This value corresponds to the "last modified" time in the NTFS file times
- /// as described in <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">the Zip
- /// specification</see>. When getting this property, the value may be
- /// different from <see cref="LastModified" />. When setting the property,
- /// the <see cref="LastModified"/> property also gets set, but with a lower
- /// precision.
- /// </para>
- ///
- /// <para>
- /// Let me explain. It's going to take a while, so get
- /// comfortable. Originally, waaaaay back in 1989 when the ZIP specification
- /// was originally described by the esteemed Mr. Phil Katz, the dominant
- /// operating system of the time was MS-DOS. MSDOS stored file times with a
- /// 2-second precision, because, c'mon, <em>who is ever going to need better
- /// resolution than THAT?</em> And so ZIP files, regardless of the platform on
- /// which the zip file was created, store file times in exactly <see
- /// href="http://www.vsft.com/hal/dostime.htm">the same format that DOS used
- /// in 1989</see>.
- /// </para>
- ///
- /// <para>
- /// Since then, the ZIP spec has evolved, but the internal format for file
- /// timestamps remains the same. Despite the fact that the way times are
- /// stored in a zip file is rooted in DOS heritage, any program on any
- /// operating system can format a time in this way, and most zip tools and
- /// libraries DO - they round file times to the nearest even second and store
- /// it just like DOS did 25+ years ago.
- /// </para>
- ///
- /// <para>
- /// PKWare extended the ZIP specification to allow a zip file to store what
- /// are called "NTFS Times" and "Unix(tm) times" for a file. These are the
- /// <em>last write</em>, <em>last access</em>, and <em>file creation</em>
- /// times of a particular file. These metadata are not actually specific
- /// to NTFS or Unix. They are tracked for each file by NTFS and by various
- /// Unix filesystems, but they are also tracked by other filesystems, too.
- /// The key point is that the times are <em>formatted in the zip file</em>
- /// in the same way that NTFS formats the time (ticks since win32 epoch),
- /// or in the same way that Unix formats the time (seconds since Unix
- /// epoch). As with the DOS time, any tool or library running on any
- /// operating system is capable of formatting a time in one of these ways
- /// and embedding it into the zip file.
- /// </para>
- ///
- /// <para>
- /// These extended times are higher precision quantities than the DOS time.
- /// As described above, the (DOS) LastModified has a precision of 2 seconds.
- /// The Unix time is stored with a precision of 1 second. The NTFS time is
- /// stored with a precision of 0.0000001 seconds. The quantities are easily
- /// convertible, except for the loss of precision you may incur.
- /// </para>
- ///
- /// <para>
- /// A zip archive can store the {C,A,M} times in NTFS format, in Unix format,
- /// or not at all. Often a tool running on Unix or Mac will embed the times
- /// in Unix format (1 second precision), while WinZip running on Windows might
- /// embed the times in NTFS format (precision of of 0.0000001 seconds). When
- /// reading a zip file with these "extended" times, in either format,
- /// DotNetZip represents the values with the
- /// <c>ModifiedTime</c>, <c>AccessedTime</c> and <c>CreationTime</c>
- /// properties on the <c>ZipEntry</c>.
- /// </para>
- ///
- /// <para>
- /// While any zip application or library, regardless of the platform it
- /// runs on, could use any of the time formats allowed by the ZIP
- /// specification, not all zip tools or libraries do support all these
- /// formats. Storing the higher-precision times for each entry is
- /// optional for zip files, and many tools and libraries don't use the
- /// higher precision quantities at all. The old DOS time, represented by
- /// <see cref="LastModified"/>, is guaranteed to be present, though it
- /// sometimes unset.
- /// </para>
- ///
- /// <para>
- /// Ok, getting back to the question about how the <c>LastModified</c>
- /// property relates to this <c>ModifiedTime</c>
- /// property... <c>LastModified</c> is always set, while
- /// <c>ModifiedTime</c> is not. (The other times stored in the <em>NTFS
- /// times extension</em>, <c>CreationTime</c> and <c>AccessedTime</c> also
- /// may not be set on an entry that is read from an existing zip file.)
- /// When reading a zip file, then <c>LastModified</c> takes the DOS time
- /// that is stored with the file. If the DOS time has been stored as zero
- /// in the zipfile, then this library will use <c>DateTime.Now</c> for the
- /// <c>LastModified</c> value. If the ZIP file was created by an evolved
- /// tool, then there will also be higher precision NTFS or Unix times in
- /// the zip file. In that case, this library will read those times, and
- /// set <c>LastModified</c> and <c>ModifiedTime</c> to the same value, the
- /// one corresponding to the last write time of the file. If there are no
- /// higher precision times stored for the entry, then <c>ModifiedTime</c>
- /// remains unset (likewise <c>AccessedTime</c> and <c>CreationTime</c>),
- /// and <c>LastModified</c> keeps its DOS time.
- /// </para>
- ///
- /// <para>
- /// When creating zip files with this library, by default the extended time
- /// properties (<c>ModifiedTime</c>, <c>AccessedTime</c>, and
- /// <c>CreationTime</c>) are set on the ZipEntry instance, and these data are
- /// stored in the zip archive for each entry, in NTFS format. If you add an
- /// entry from an actual filesystem file, then the entry gets the actual file
- /// times for that file, to NTFS-level precision. If you add an entry from a
- /// stream, or a string, then the times get the value <c>DateTime.Now</c>. In
- /// this case <c>LastModified</c> and <c>ModifiedTime</c> will be identical,
- /// to 2 seconds of precision. You can explicitly set the
- /// <c>CreationTime</c>, <c>AccessedTime</c>, and <c>ModifiedTime</c> of an
- /// entry using the property setters. If you want to set all of those
- /// quantities, it's more efficient to use the <see
- /// cref="SetEntryTimes(DateTime, DateTime, DateTime)"/> method. Those
- /// changes are not made permanent in the zip file until you call <see
- /// cref="ZipFile.Save()"/> or one of its cousins.
- /// </para>
- ///
- /// <para>
- /// When creating a zip file, you can override the default behavior of
- /// this library for formatting times in the zip file, disabling the
- /// embedding of file times in NTFS format or enabling the storage of file
- /// times in Unix format, or both. You may want to do this, for example,
- /// when creating a zip file on Windows, that will be consumed on a Mac,
- /// by an application that is not hip to the "NTFS times" format. To do
- /// this, use the <see cref="EmitTimesInWindowsFormatWhenSaving"/> and
- /// <see cref="EmitTimesInUnixFormatWhenSaving"/> properties. A valid zip
- /// file may store the file times in both formats. But, there are no
- /// guarantees that a program running on Mac or Linux will gracefully
- /// handle the NTFS-formatted times when Unix times are present, or that a
- /// non-DotNetZip-powered application running on Windows will be able to
- /// handle file times in Unix format. DotNetZip will always do something
- /// reasonable; other libraries or tools may not. When in doubt, test.
- /// </para>
- ///
- /// <para>
- /// I'll bet you didn't think one person could type so much about time, eh?
- /// And reading it was so enjoyable, too! Well, in appreciation, <see
- /// href="http://cheeso.members.winisp.net/DotNetZipDonate.aspx">maybe you
- /// should donate</see>?
- /// </para>
- /// </remarks>
- ///
- /// <seealso cref="AccessedTime"/>
- /// <seealso cref="CreationTime"/>
- /// <seealso cref="Ionic.Zip.ZipEntry.LastModified"/>
- /// <seealso cref="SetEntryTimes"/>
- public DateTime ModifiedTime
- {
- get { return _Mtime; }
- set
- {
- SetEntryTimes(_Ctime, _Atime, value);
- }
- }
-
- /// <summary>
- /// Last Access time for the file represented by the entry.
- /// </summary>
- /// <remarks>
- /// This value may or may not be meaningful. If the <c>ZipEntry</c> was read from an existing
- /// Zip archive, this information may not be available. For an explanation of why, see
- /// <see cref="ModifiedTime"/>.
- /// </remarks>
- /// <seealso cref="ModifiedTime"/>
- /// <seealso cref="CreationTime"/>
- /// <seealso cref="SetEntryTimes"/>
- public DateTime AccessedTime
- {
- get { return _Atime; }
- set
- {
- SetEntryTimes(_Ctime, value, _Mtime);
- }
- }
-
- /// <summary>
- /// The file creation time for the file represented by the entry.
- /// </summary>
- ///
- /// <remarks>
- /// This value may or may not be meaningful. If the <c>ZipEntry</c> was read
- /// from an existing zip archive, and the creation time was not set on the entry
- /// when the zip file was created, then this property may be meaningless. For an
- /// explanation of why, see <see cref="ModifiedTime"/>.
- /// </remarks>
- /// <seealso cref="ModifiedTime"/>
- /// <seealso cref="AccessedTime"/>
- /// <seealso cref="SetEntryTimes"/>
- public DateTime CreationTime
- {
- get { return _Ctime; }
- set
- {
- SetEntryTimes(value, _Atime, _Mtime);
- }
- }
-
- /// <summary>
- /// Sets the NTFS Creation, Access, and Modified times for the given entry.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// When adding an entry from a file or directory, the Creation, Access, and
- /// Modified times for the given entry are automatically set from the
- /// filesystem values. When adding an entry from a stream or string, the
- /// values are implicitly set to DateTime.Now. The application may wish to
- /// set these values to some arbitrary value, before saving the archive, and
- /// can do so using the various setters. If you want to set all of the times,
- /// this method is more efficient.
- /// </para>
- ///
- /// <para>
- /// The values you set here will be retrievable with the <see
- /// cref="ModifiedTime"/>, <see cref="CreationTime"/> and <see
- /// cref="AccessedTime"/> properties.
- /// </para>
- ///
- /// <para>
- /// When this method is called, if both <see
- /// cref="EmitTimesInWindowsFormatWhenSaving"/> and <see
- /// cref="EmitTimesInUnixFormatWhenSaving"/> are false, then the
- /// <c>EmitTimesInWindowsFormatWhenSaving</c> flag is automatically set.
- /// </para>
- ///
- /// <para>
- /// DateTime values provided here without a DateTimeKind are assumed to be Local Time.
- /// </para>
- ///
- /// </remarks>
- /// <param name="created">the creation time of the entry.</param>
- /// <param name="accessed">the last access time of the entry.</param>
- /// <param name="modified">the last modified time of the entry.</param>
- ///
- /// <seealso cref="EmitTimesInWindowsFormatWhenSaving" />
- /// <seealso cref="EmitTimesInUnixFormatWhenSaving" />
- /// <seealso cref="AccessedTime"/>
- /// <seealso cref="CreationTime"/>
- /// <seealso cref="ModifiedTime"/>
- public void SetEntryTimes(DateTime created, DateTime accessed, DateTime modified)
- {
- _ntfsTimesAreSet = true;
- if (created == _zeroHour && created.Kind == _zeroHour.Kind) created = _win32Epoch;
- if (accessed == _zeroHour && accessed.Kind == _zeroHour.Kind) accessed = _win32Epoch;
- if (modified == _zeroHour && modified.Kind == _zeroHour.Kind) modified = _win32Epoch;
- _Ctime = created.ToUniversalTime();
- _Atime = accessed.ToUniversalTime();
- _Mtime = modified.ToUniversalTime();
- _LastModified = _Mtime;
- if (!_emitUnixTimes && !_emitNtfsTimes)
- _emitNtfsTimes = true;
- _metadataChanged = true;
- }
-
-
-
- /// <summary>
- /// Specifies whether the Creation, Access, and Modified times for the given
- /// entry will be emitted in "Windows format" when the zip archive is saved.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// An application creating a zip archive can use this flag to explicitly
- /// specify that the file times for the entry should or should not be stored
- /// in the zip archive in the format used by Windows. The default value of
- /// this property is <c>true</c>.
- /// </para>
- ///
- /// <para>
- /// When adding an entry from a file or directory, the Creation (<see
- /// cref="CreationTime"/>), Access (<see cref="AccessedTime"/>), and Modified
- /// (<see cref="ModifiedTime"/>) times for the given entry are automatically
- /// set from the filesystem values. When adding an entry from a stream or
- /// string, all three values are implicitly set to DateTime.Now. Applications
- /// can also explicitly set those times by calling <see
- /// cref="SetEntryTimes(DateTime, DateTime, DateTime)" />.
- /// </para>
- ///
- /// <para>
- /// <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's
- /// zip specification</see> describes multiple ways to format these times in a
- /// zip file. One is the format Windows applications normally use: 100ns ticks
- /// since Jan 1, 1601 UTC. The other is a format Unix applications typically
- /// use: seconds since January 1, 1970 UTC. Each format can be stored in an
- /// "extra field" in the zip entry when saving the zip archive. The former
- /// uses an extra field with a Header Id of 0x000A, while the latter uses a
- /// header ID of 0x5455.
- /// </para>
- ///
- /// <para>
- /// Not all zip tools and libraries can interpret these fields. Windows
- /// compressed folders is one that can read the Windows Format timestamps,
- /// while I believe the <see href="http://www.info-zip.org/">Infozip</see>
- /// tools can read the Unix format timestamps. Although the time values are
- /// easily convertible, subject to a loss of precision, some tools and
- /// libraries may be able to read only one or the other. DotNetZip can read or
- /// write times in either or both formats.
- /// </para>
- ///
- /// <para>
- /// The times stored are taken from <see cref="ModifiedTime"/>, <see
- /// cref="AccessedTime"/>, and <see cref="CreationTime"/>.
- /// </para>
- ///
- /// <para>
- /// This property is not mutually exclusive from the <see
- /// cref="ZipEntry.EmitTimesInUnixFormatWhenSaving"/> property. It is
- /// possible that a zip entry can embed the timestamps in both forms, one
- /// form, or neither. But, there are no guarantees that a program running on
- /// Mac or Linux will gracefully handle NTFS Formatted times, or that a
- /// non-DotNetZip-powered application running on Windows will be able to
- /// handle file times in Unix format. When in doubt, test.
- /// </para>
- ///
- /// <para>
- /// Normally you will use the <see
- /// cref="ZipFile.EmitTimesInWindowsFormatWhenSaving">ZipFile.EmitTimesInWindowsFormatWhenSaving</see>
- /// property, to specify the behavior for all entries in a zip, rather than
- /// the property on each individual entry.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <seealso cref="SetEntryTimes(DateTime, DateTime, DateTime)"/>
- /// <seealso cref="EmitTimesInUnixFormatWhenSaving"/>
- /// <seealso cref="CreationTime"/>
- /// <seealso cref="AccessedTime"/>
- /// <seealso cref="ModifiedTime"/>
- public bool EmitTimesInWindowsFormatWhenSaving
- {
- get
- {
- return _emitNtfsTimes;
- }
- set
- {
- _emitNtfsTimes = value;
- _metadataChanged = true;
- }
- }
-
- /// <summary>
- /// Specifies whether the Creation, Access, and Modified times for the given
- /// entry will be emitted in "Unix(tm) format" when the zip archive is saved.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// An application creating a zip archive can use this flag to explicitly
- /// specify that the file times for the entry should or should not be stored
- /// in the zip archive in the format used by Unix. By default this flag is
- /// <c>false</c>, meaning the Unix-format times are not stored in the zip
- /// archive.
- /// </para>
- ///
- /// <para>
- /// When adding an entry from a file or directory, the Creation (<see
- /// cref="CreationTime"/>), Access (<see cref="AccessedTime"/>), and Modified
- /// (<see cref="ModifiedTime"/>) times for the given entry are automatically
- /// set from the filesystem values. When adding an entry from a stream or
- /// string, all three values are implicitly set to DateTime.Now. Applications
- /// can also explicitly set those times by calling <see
- /// cref="SetEntryTimes(DateTime, DateTime, DateTime)"/>.
- /// </para>
- ///
- /// <para>
- /// <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's
- /// zip specification</see> describes multiple ways to format these times in a
- /// zip file. One is the format Windows applications normally use: 100ns ticks
- /// since Jan 1, 1601 UTC. The other is a format Unix applications typically
- /// use: seconds since Jan 1, 1970 UTC. Each format can be stored in an
- /// "extra field" in the zip entry when saving the zip archive. The former
- /// uses an extra field with a Header Id of 0x000A, while the latter uses a
- /// header ID of 0x5455.
- /// </para>
- ///
- /// <para>
- /// Not all tools and libraries can interpret these fields. Windows
- /// compressed folders is one that can read the Windows Format timestamps,
- /// while I believe the <see href="http://www.info-zip.org/">Infozip</see>
- /// tools can read the Unix format timestamps. Although the time values are
- /// easily convertible, subject to a loss of precision, some tools and
- /// libraries may be able to read only one or the other. DotNetZip can read or
- /// write times in either or both formats.
- /// </para>
- ///
- /// <para>
- /// The times stored are taken from <see cref="ModifiedTime"/>, <see
- /// cref="AccessedTime"/>, and <see cref="CreationTime"/>.
- /// </para>
- ///
- /// <para>
- /// This property is not mutually exclusive from the <see
- /// cref="ZipEntry.EmitTimesInWindowsFormatWhenSaving"/> property. It is
- /// possible that a zip entry can embed the timestamps in both forms, one
- /// form, or neither. But, there are no guarantees that a program running on
- /// Mac or Linux will gracefully handle NTFS Formatted times, or that a
- /// non-DotNetZip-powered application running on Windows will be able to
- /// handle file times in Unix format. When in doubt, test.
- /// </para>
- ///
- /// <para>
- /// Normally you will use the <see
- /// cref="ZipFile.EmitTimesInUnixFormatWhenSaving">ZipFile.EmitTimesInUnixFormatWhenSaving</see>
- /// property, to specify the behavior for all entries, rather than the
- /// property on each individual entry.
- /// </para>
- /// </remarks>
- ///
- /// <seealso cref="SetEntryTimes(DateTime, DateTime, DateTime)"/>
- /// <seealso cref="EmitTimesInWindowsFormatWhenSaving"/>
- /// <seealso cref="ZipFile.EmitTimesInUnixFormatWhenSaving"/>
- /// <seealso cref="CreationTime"/>
- /// <seealso cref="AccessedTime"/>
- /// <seealso cref="ModifiedTime"/>
- public bool EmitTimesInUnixFormatWhenSaving
- {
- get
- {
- return _emitUnixTimes;
- }
- set
- {
- _emitUnixTimes = value;
- _metadataChanged = true;
- }
- }
-
-
- /// <summary>
- /// The type of timestamp attached to the ZipEntry.
- /// </summary>
- ///
- /// <remarks>
- /// This property is valid only for a ZipEntry that was read from a zip archive.
- /// It indicates the type of timestamp attached to the entry.
- /// </remarks>
- ///
- /// <seealso cref="EmitTimesInWindowsFormatWhenSaving"/>
- /// <seealso cref="EmitTimesInUnixFormatWhenSaving"/>
- internal ZipEntryTimestamp Timestamp
- {
- get
- {
- return _timestamp;
- }
- }
-
- /// <summary>
- /// The file attributes for the entry.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// The <see cref="System.IO.FileAttributes">attributes</see> in NTFS include
- /// ReadOnly, Archive, Hidden, System, and Indexed. When adding a
- /// <c>ZipEntry</c> to a ZipFile, these attributes are set implicitly when
- /// adding an entry from the filesystem. When adding an entry from a stream
- /// or string, the Attributes are not set implicitly. Regardless of the way
- /// an entry was added to a <c>ZipFile</c>, you can set the attributes
- /// explicitly if you like.
- /// </para>
- ///
- /// <para>
- /// When reading a <c>ZipEntry</c> from a <c>ZipFile</c>, the attributes are
- /// set according to the data stored in the <c>ZipFile</c>. If you extract the
- /// entry from the archive to a filesystem file, DotNetZip will set the
- /// attributes on the resulting file accordingly.
- /// </para>
- ///
- /// <para>
- /// The attributes can be set explicitly by the application. For example the
- /// application may wish to set the <c>FileAttributes.ReadOnly</c> bit for all
- /// entries added to an archive, so that on unpack, this attribute will be set
- /// on the extracted file. Any changes you make to this property are made
- /// permanent only when you call a <c>Save()</c> method on the <c>ZipFile</c>
- /// instance that contains the ZipEntry.
- /// </para>
- ///
- /// <para>
- /// For example, an application may wish to zip up a directory and set the
- /// ReadOnly bit on every file in the archive, so that upon later extraction,
- /// the resulting files will be marked as ReadOnly. Not every extraction tool
- /// respects these attributes, but if you unpack with DotNetZip, as for
- /// example in a self-extracting archive, then the attributes will be set as
- /// they are stored in the <c>ZipFile</c>.
- /// </para>
- ///
- /// <para>
- /// These attributes may not be interesting or useful if the resulting archive
- /// is extracted on a non-Windows platform. How these attributes get used
- /// upon extraction depends on the platform and tool used.
- /// </para>
- ///
- /// <para>
- /// This property is only partially supported in the Silverlight version
- /// of the library: applications can read attributes on entries within
- /// ZipFiles. But extracting entries within Silverlight will not set the
- /// attributes on the extracted files.
- /// </para>
- ///
- /// </remarks>
- public System.IO.FileAttributes Attributes
- {
- // workitem 7071
- get { return (System.IO.FileAttributes)_ExternalFileAttrs; }
- set
- {
- _ExternalFileAttrs = (int)value;
- // Since the application is explicitly setting the attributes, overwriting
- // whatever was there, we will explicitly set the Version made by field.
- // workitem 7926 - "version made by" OS should be zero for compat with WinZip
- _VersionMadeBy = (0 << 8) + 45; // v4.5 of the spec
- _metadataChanged = true;
- }
- }
-
-
- /// <summary>
- /// The name of the filesystem file, referred to by the ZipEntry.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This property specifies the thing-to-be-zipped on disk, and is set only
- /// when the <c>ZipEntry</c> is being created from a filesystem file. If the
- /// <c>ZipFile</c> is instantiated by reading an existing .zip archive, then
- /// the LocalFileName will be <c>null</c> (<c>Nothing</c> in VB).
- /// </para>
- ///
- /// <para>
- /// When it is set, the value of this property may be different than <see
- /// cref="FileName"/>, which is the path used in the archive itself. If you
- /// call <c>Zip.AddFile("foop.txt", AlternativeDirectory)</c>, then the path
- /// used for the <c>ZipEntry</c> within the zip archive will be different
- /// than this path.
- /// </para>
- ///
- /// <para>
- /// If the entry is being added from a stream, then this is null (Nothing in VB).
- /// </para>
- ///
- /// </remarks>
- /// <seealso cref="FileName"/>
- internal string LocalFileName
- {
- get { return _LocalFileName; }
- }
-
- /// <summary>
- /// The name of the file contained in the ZipEntry.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This is the name of the entry in the <c>ZipFile</c> itself. When creating
- /// a zip archive, if the <c>ZipEntry</c> has been created from a filesystem
- /// file, via a call to <see cref="ZipFile.AddFile(String,String)"/> or <see
- /// cref="ZipFile.AddItem(String,String)"/>, or a related overload, the value
- /// of this property is derived from the name of that file. The
- /// <c>FileName</c> property does not include drive letters, and may include a
- /// different directory path, depending on the value of the
- /// <c>directoryPathInArchive</c> parameter used when adding the entry into
- /// the <c>ZipFile</c>.
- /// </para>
- ///
- /// <para>
- /// In some cases there is no related filesystem file - for example when a
- /// <c>ZipEntry</c> is created using <see cref="ZipFile.AddEntry(string,
- /// string)"/> or one of the similar overloads. In this case, the value of
- /// this property is derived from the fileName and the directory path passed
- /// to that method.
- /// </para>
- ///
- /// <para>
- /// When reading a zip file, this property takes the value of the entry name
- /// as stored in the zip file. If you extract such an entry, the extracted
- /// file will take the name given by this property.
- /// </para>
- ///
- /// <para>
- /// Applications can set this property when creating new zip archives or when
- /// reading existing archives. When setting this property, the actual value
- /// that is set will replace backslashes with forward slashes, in accordance
- /// with <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">the Zip
- /// specification</see>, for compatibility with Unix(tm) and ... get
- /// this.... Amiga!
- /// </para>
- ///
- /// <para>
- /// If an application reads a <c>ZipFile</c> via <see
- /// cref="ZipFile.Read(String)"/> or a related overload, and then explicitly
- /// sets the FileName on an entry contained within the <c>ZipFile</c>, and
- /// then calls <see cref="ZipFile.Save()"/>, the application will effectively
- /// rename the entry within the zip archive.
- /// </para>
- ///
- /// <para>
- /// If an application sets the value of <c>FileName</c>, then calls
- /// <c>Extract()</c> on the entry, the entry is extracted to a file using the
- /// newly set value as the filename. The <c>FileName</c> value is made
- /// permanent in the zip archive only <em>after</em> a call to one of the
- /// <c>ZipFile.Save()</c> methods on the <c>ZipFile</c> that contains the
- /// ZipEntry.
- /// </para>
- ///
- /// <para>
- /// If an application attempts to set the <c>FileName</c> to a value that
- /// would result in a duplicate entry in the <c>ZipFile</c>, an exception is
- /// thrown.
- /// </para>
- ///
- /// <para>
- /// When a <c>ZipEntry</c> is contained within a <c>ZipFile</c>, applications
- /// cannot rename the entry within the context of a <c>foreach</c> (<c>For
- /// Each</c> in VB) loop, because of the way the <c>ZipFile</c> stores
- /// entries. If you need to enumerate through all the entries and rename one
- /// or more of them, use <see
- /// cref="ZipFile.EntriesSorted">ZipFile.EntriesSorted</see> as the
- /// collection. See also, <see
- /// cref="ZipFile.GetEnumerator()">ZipFile.GetEnumerator()</see>.
- /// </para>
- ///
- /// </remarks>
- public string FileName
- {
- get { return _FileNameInArchive; }
- set
- {
- if (_container.ZipFile == null)
- throw new ZipException("Cannot rename; this is not supported in ZipOutputStream/ZipInputStream.");
-
- // rename the entry!
- if (String.IsNullOrEmpty(value)) throw new ZipException("The FileName must be non empty and non-null.");
-
- var filename = ZipEntry.NameInArchive(value, null);
- // workitem 8180
- if (_FileNameInArchive == filename) return; // nothing to do
-
- // workitem 8047 - when renaming, must remove old and then add a new entry
- this._container.ZipFile.RemoveEntry(this);
- this._container.ZipFile.InternalAddEntry(filename, this);
-
- _FileNameInArchive = filename;
- _container.ZipFile.NotifyEntryChanged();
- _metadataChanged = true;
- }
- }
-
-
- /// <summary>
- /// The stream that provides content for the ZipEntry.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// The application can use this property to set the input stream for an
- /// entry on a just-in-time basis. Imagine a scenario where the application
- /// creates a <c>ZipFile</c> comprised of content obtained from hundreds of
- /// files, via calls to <c>AddFile()</c>. The DotNetZip library opens streams
- /// on these files on a just-in-time basis, only when writing the entry out to
- /// an external store within the scope of a <c>ZipFile.Save()</c> call. Only
- /// one input stream is opened at a time, as each entry is being written out.
- /// </para>
- ///
- /// <para>
- /// Now imagine a different application that creates a <c>ZipFile</c>
- /// with content obtained from hundreds of streams, added through <see
- /// cref="ZipFile.AddEntry(string, System.IO.Stream)"/>. Normally the
- /// application would supply an open stream to that call. But when large
- /// numbers of streams are being added, this can mean many open streams at one
- /// time, unnecessarily.
- /// </para>
- ///
- /// <para>
- /// To avoid this, call <see cref="ZipFile.AddEntry(String, OpenDelegate,
- /// CloseDelegate)"/> and specify delegates that open and close the stream at
- /// the time of Save.
- /// </para>
- ///
- ///
- /// <para>
- /// Setting the value of this property when the entry was not added from a
- /// stream (for example, when the <c>ZipEntry</c> was added with <see
- /// cref="ZipFile.AddFile(String)"/> or <see
- /// cref="ZipFile.AddDirectory(String)"/>, or when the entry was added by
- /// reading an existing zip archive) will throw an exception.
- /// </para>
- ///
- /// </remarks>
- ///
- public Stream InputStream
- {
- get { return _sourceStream; }
-
- set
- {
- if (this._Source != ZipEntrySource.Stream)
- throw new ZipException("You must not set the input stream for this entry.");
-
- _sourceWasJitProvided = true;
- _sourceStream = value;
- }
- }
-
-
- /// <summary>
- /// A flag indicating whether the InputStream was provided Just-in-time.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// When creating a zip archive, an application can obtain content for one or
- /// more of the <c>ZipEntry</c> instances from streams, using the <see
- /// cref="ZipFile.AddEntry(string, System.IO.Stream)"/> method. At the time
- /// of calling that method, the application can supply null as the value of
- /// the stream parameter. By doing so, the application indicates to the
- /// library that it will provide a stream for the entry on a just-in-time
- /// basis, at the time one of the <c>ZipFile.Save()</c> methods is called and
- /// the data for the various entries are being compressed and written out.
- /// </para>
- ///
- /// <para>
- /// In this case, the application can set the <see cref="InputStream"/>
- /// property, typically within the SaveProgress event (event type: <see
- /// cref="ZipProgressEventType.Saving_BeforeWriteEntry"/>) for that entry.
- /// </para>
- ///
- /// <para>
- /// The application will later want to call Close() and Dispose() on that
- /// stream. In the SaveProgress event, when the event type is <see
- /// cref="ZipProgressEventType.Saving_AfterWriteEntry"/>, the application can
- /// do so. This flag indicates that the stream has been provided by the
- /// application on a just-in-time basis and that it is the application's
- /// responsibility to call Close/Dispose on that stream.
- /// </para>
- ///
- /// </remarks>
- /// <seealso cref="InputStream"/>
- public bool InputStreamWasJitProvided
- {
- get { return _sourceWasJitProvided; }
- }
-
-
-
- /// <summary>
- /// An enum indicating the source of the ZipEntry.
- /// </summary>
- internal ZipEntrySource Source
- {
- get { return _Source; }
- }
-
-
- /// <summary>
- /// The version of the zip engine needed to read the ZipEntry.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This is a readonly property, indicating the version of <a
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">the Zip
- /// specification</a> that the extracting tool or library must support to
- /// extract the given entry. Generally higher versions indicate newer
- /// features. Older zip engines obviously won't know about new features, and
- /// won't be able to extract entries that depend on those newer features.
- /// </para>
- ///
- /// <list type="table">
- /// <listheader>
- /// <term>value</term>
- /// <description>Features</description>
- /// </listheader>
- ///
- /// <item>
- /// <term>20</term>
- /// <description>a basic Zip Entry, potentially using PKZIP encryption.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>45</term>
- /// <description>The ZIP64 extension is used on the entry.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>46</term>
- /// <description> File is compressed using BZIP2 compression*</description>
- /// </item>
- ///
- /// <item>
- /// <term>50</term>
- /// <description> File is encrypted using PkWare's DES, 3DES, (broken) RC2 or RC4</description>
- /// </item>
- ///
- /// <item>
- /// <term>51</term>
- /// <description> File is encrypted using PKWare's AES encryption or corrected RC2 encryption.</description>
- /// </item>
- ///
- /// <item>
- /// <term>52</term>
- /// <description> File is encrypted using corrected RC2-64 encryption**</description>
- /// </item>
- ///
- /// <item>
- /// <term>61</term>
- /// <description> File is encrypted using non-OAEP key wrapping***</description>
- /// </item>
- ///
- /// <item>
- /// <term>63</term>
- /// <description> File is compressed using LZMA, PPMd+, Blowfish, or Twofish</description>
- /// </item>
- ///
- /// </list>
- ///
- /// <para>
- /// There are other values possible, not listed here. DotNetZip supports
- /// regular PKZip encryption, and ZIP64 extensions. DotNetZip cannot extract
- /// entries that require a zip engine higher than 45.
- /// </para>
- ///
- /// <para>
- /// This value is set upon reading an existing zip file, or after saving a zip
- /// archive.
- /// </para>
- /// </remarks>
- public Int16 VersionNeeded
- {
- get { return _VersionNeeded; }
- }
-
- /// <summary>
- /// The comment attached to the ZipEntry.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Each entry in a zip file can optionally have a comment associated to
- /// it. The comment might be displayed by a zip tool during extraction, for
- /// example.
- /// </para>
- ///
- /// <para>
- /// By default, the <c>Comment</c> is encoded in IBM437 code page. You can
- /// specify an alternative with <see cref="AlternateEncoding"/> and
- /// <see cref="AlternateEncodingUsage"/>.
- /// </para>
- /// </remarks>
- /// <seealso cref="AlternateEncoding"/>
- /// <seealso cref="AlternateEncodingUsage"/>
- public string Comment
- {
- get { return _Comment; }
- set
- {
- _Comment = value;
- _metadataChanged = true;
- }
- }
-
-
- /// <summary>
- /// Indicates whether the entry requires ZIP64 extensions.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This property is null (Nothing in VB) until a <c>Save()</c> method on the
- /// containing <see cref="ZipFile"/> instance has been called. The property is
- /// non-null (<c>HasValue</c> is true) only after a <c>Save()</c> method has
- /// been called.
- /// </para>
- ///
- /// <para>
- /// After the containing <c>ZipFile</c> has been saved, the Value of this
- /// property is true if any of the following three conditions holds: the
- /// uncompressed size of the entry is larger than 0xFFFFFFFF; the compressed
- /// size of the entry is larger than 0xFFFFFFFF; the relative offset of the
- /// entry within the zip archive is larger than 0xFFFFFFFF. These quantities
- /// are not known until a <c>Save()</c> is attempted on the zip archive and
- /// the compression is applied.
- /// </para>
- ///
- /// <para>
- /// If none of the three conditions holds, then the <c>Value</c> is false.
- /// </para>
- ///
- /// <para>
- /// A <c>Value</c> of false does not indicate that the entry, as saved in the
- /// zip archive, does not use ZIP64. It merely indicates that ZIP64 is
- /// <em>not required</em>. An entry may use ZIP64 even when not required if
- /// the <see cref="ZipFile.UseZip64WhenSaving"/> property on the containing
- /// <c>ZipFile</c> instance is set to <see cref="Zip64Option.Always"/>, or if
- /// the <see cref="ZipFile.UseZip64WhenSaving"/> property on the containing
- /// <c>ZipFile</c> instance is set to <see cref="Zip64Option.AsNecessary"/>
- /// and the output stream was not seekable.
- /// </para>
- ///
- /// </remarks>
- /// <seealso cref="OutputUsedZip64"/>
- public Nullable<bool> RequiresZip64
- {
- get
- {
- return _entryRequiresZip64;
- }
- }
-
- /// <summary>
- /// Indicates whether the entry actually used ZIP64 extensions, as it was most
- /// recently written to the output file or stream.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This Nullable property is null (Nothing in VB) until a <c>Save()</c>
- /// method on the containing <see cref="ZipFile"/> instance has been
- /// called. <c>HasValue</c> is true only after a <c>Save()</c> method has been
- /// called.
- /// </para>
- ///
- /// <para>
- /// The value of this property for a particular <c>ZipEntry</c> may change
- /// over successive calls to <c>Save()</c> methods on the containing ZipFile,
- /// even if the file that corresponds to the <c>ZipEntry</c> does not. This
- /// may happen if other entries contained in the <c>ZipFile</c> expand,
- /// causing the offset for this particular entry to exceed 0xFFFFFFFF.
- /// </para>
- /// </remarks>
- /// <seealso cref="RequiresZip64"/>
- public Nullable<bool> OutputUsedZip64
- {
- get { return _OutputUsesZip64; }
- }
-
-
- /// <summary>
- /// The bitfield for the entry as defined in the zip spec. You probably
- /// never need to look at this.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// You probably do not need to concern yourself with the contents of this
- /// property, but in case you do:
- /// </para>
- ///
- /// <list type="table">
- /// <listheader>
- /// <term>bit</term>
- /// <description>meaning</description>
- /// </listheader>
- ///
- /// <item>
- /// <term>0</term>
- /// <description>set if encryption is used.</description>
- /// </item>
- ///
- /// <item>
- /// <term>1-2</term>
- /// <description>
- /// set to determine whether normal, max, fast deflation. DotNetZip library
- /// always leaves these bits unset when writing (indicating "normal"
- /// deflation"), but can read an entry with any value here.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>3</term>
- /// <description>
- /// Indicates that the Crc32, Compressed and Uncompressed sizes are zero in the
- /// local header. This bit gets set on an entry during writing a zip file, when
- /// it is saved to a non-seekable output stream.
- /// </description>
- /// </item>
- ///
- ///
- /// <item>
- /// <term>4</term>
- /// <description>reserved for "enhanced deflating". This library doesn't do enhanced deflating.</description>
- /// </item>
- ///
- /// <item>
- /// <term>5</term>
- /// <description>set to indicate the zip is compressed patched data. This library doesn't do that.</description>
- /// </item>
- ///
- /// <item>
- /// <term>6</term>
- /// <description>
- /// set if PKWare's strong encryption is used (must also set bit 1 if bit 6 is
- /// set). This bit is not set if WinZip's AES encryption is set.</description>
- /// </item>
- ///
- /// <item>
- /// <term>7</term>
- /// <description>not used</description>
- /// </item>
- ///
- /// <item>
- /// <term>8</term>
- /// <description>not used</description>
- /// </item>
- ///
- /// <item>
- /// <term>9</term>
- /// <description>not used</description>
- /// </item>
- ///
- /// <item>
- /// <term>10</term>
- /// <description>not used</description>
- /// </item>
- ///
- /// <item>
- /// <term>11</term>
- /// <description>
- /// Language encoding flag (EFS). If this bit is set, the filename and comment
- /// fields for this file must be encoded using UTF-8. This library currently
- /// does not support UTF-8.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>12</term>
- /// <description>Reserved by PKWARE for enhanced compression.</description>
- /// </item>
- ///
- /// <item>
- /// <term>13</term>
- /// <description>
- /// Used when encrypting the Central Directory to indicate selected data
- /// values in the Local Header are masked to hide their actual values. See
- /// the section in <a
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">the Zip
- /// specification</a> describing the Strong Encryption Specification for
- /// details.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>14</term>
- /// <description>Reserved by PKWARE.</description>
- /// </item>
- ///
- /// <item>
- /// <term>15</term>
- /// <description>Reserved by PKWARE.</description>
- /// </item>
- ///
- /// </list>
- ///
- /// </remarks>
- public Int16 BitField
- {
- get { return _BitField; }
- }
-
- /// <summary>
- /// The compression method employed for this ZipEntry.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">The
- /// Zip specification</see> allows a variety of compression methods. This
- /// library supports just two: 0x08 = Deflate. 0x00 = Store (no compression),
- /// for reading or writing.
- /// </para>
- ///
- /// <para>
- /// When reading an entry from an existing zipfile, the value you retrieve
- /// here indicates the compression method used on the entry by the original
- /// creator of the zip. When writing a zipfile, you can specify either 0x08
- /// (Deflate) or 0x00 (None). If you try setting something else, you will get
- /// an exception.
- /// </para>
- ///
- /// <para>
- /// You may wish to set <c>CompressionMethod</c> to <c>CompressionMethod.None</c> (0)
- /// when zipping already-compressed data like a jpg, png, or mp3 file.
- /// This can save time and cpu cycles.
- /// </para>
- ///
- /// <para>
- /// When setting this property on a <c>ZipEntry</c> that is read from an
- /// existing zip file, calling <c>ZipFile.Save()</c> will cause the new
- /// CompressionMethod to be used on the entry in the newly saved zip file.
- /// </para>
- ///
- /// <para>
- /// Setting this property may have the side effect of modifying the
- /// <c>CompressionLevel</c> property. If you set the <c>CompressionMethod</c> to a
- /// value other than <c>None</c>, and <c>CompressionLevel</c> is previously
- /// set to <c>None</c>, then <c>CompressionLevel</c> will be set to
- /// <c>Default</c>.
- /// </para>
- /// </remarks>
- ///
- /// <seealso cref="CompressionMethod"/>
- ///
- /// <example>
- /// In this example, the first entry added to the zip archive uses the default
- /// behavior - compression is used where it makes sense. The second entry,
- /// the MP3 file, is added to the archive without being compressed.
- /// <code>
- /// using (ZipFile zip = new ZipFile(ZipFileToCreate))
- /// {
- /// ZipEntry e1= zip.AddFile(@"notes\Readme.txt");
- /// ZipEntry e2= zip.AddFile(@"music\StopThisTrain.mp3");
- /// e2.CompressionMethod = CompressionMethod.None;
- /// zip.Save();
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As New ZipFile(ZipFileToCreate)
- /// zip.AddFile("notes\Readme.txt")
- /// Dim e2 as ZipEntry = zip.AddFile("music\StopThisTrain.mp3")
- /// e2.CompressionMethod = CompressionMethod.None
- /// zip.Save
- /// End Using
- /// </code>
- /// </example>
- internal CompressionMethod CompressionMethod
- {
- get { return (CompressionMethod)_CompressionMethod; }
- set
- {
- if (value == (CompressionMethod)_CompressionMethod) return; // nothing to do.
-
- if (value != CompressionMethod.None && value != CompressionMethod.Deflate
-#if BZIP
- && value != CompressionMethod.BZip2
-#endif
- )
- throw new InvalidOperationException("Unsupported compression method.");
-
- // If the source is a zip archive and there was encryption on the
- // entry, changing the compression method is not supported.
- // if (this._Source == ZipEntrySource.ZipFile && _sourceIsEncrypted)
- // throw new InvalidOperationException("Cannot change compression method on encrypted entries read from archives.");
-
- _CompressionMethod = (Int16)value;
-
- if (_CompressionMethod == (Int16)Ionic.Zip.CompressionMethod.None)
- _CompressionLevel = Ionic.Zlib.CompressionLevel.None;
- else if (CompressionLevel == Ionic.Zlib.CompressionLevel.None)
- _CompressionLevel = Ionic.Zlib.CompressionLevel.Default;
-
- if (_container.ZipFile != null) _container.ZipFile.NotifyEntryChanged();
- _restreamRequiredOnSave = true;
- }
- }
-
-
- /// <summary>
- /// Sets the compression level to be used for the entry when saving the zip
- /// archive. This applies only for CompressionMethod = DEFLATE.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// When using the DEFLATE compression method, Varying the compression
- /// level used on entries can affect the size-vs-speed tradeoff when
- /// compression and decompressing data streams or files.
- /// </para>
- ///
- /// <para>
- /// If you do not set this property, the default compression level is used,
- /// which normally gives a good balance of compression efficiency and
- /// compression speed. In some tests, using <c>BestCompression</c> can
- /// double the time it takes to compress, while delivering just a small
- /// increase in compression efficiency. This behavior will vary with the
- /// type of data you compress. If you are in doubt, just leave this setting
- /// alone, and accept the default.
- /// </para>
- ///
- /// <para>
- /// When setting this property on a <c>ZipEntry</c> that is read from an
- /// existing zip file, calling <c>ZipFile.Save()</c> will cause the new
- /// <c>CompressionLevel</c> to be used on the entry in the newly saved zip file.
- /// </para>
- ///
- /// <para>
- /// Setting this property may have the side effect of modifying the
- /// <c>CompressionMethod</c> property. If you set the <c>CompressionLevel</c>
- /// to a value other than <c>None</c>, <c>CompressionMethod</c> will be set
- /// to <c>Deflate</c>, if it was previously <c>None</c>.
- /// </para>
- ///
- /// <para>
- /// Setting this property has no effect if the <c>CompressionMethod</c> is something
- /// other than <c>Deflate</c> or <c>None</c>.
- /// </para>
- /// </remarks>
- ///
- /// <seealso cref="CompressionMethod"/>
- public OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel CompressionLevel
- {
- get
- {
- return _CompressionLevel;
- }
- set
- {
- if (_CompressionMethod != (short)CompressionMethod.Deflate &&
- _CompressionMethod != (short)CompressionMethod.None)
- return ; // no effect
-
- if (value == OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel.Default &&
- _CompressionMethod == (short)CompressionMethod.Deflate) return; // nothing to do
- _CompressionLevel = value;
-
- if (value == OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel.None &&
- _CompressionMethod == (short)CompressionMethod.None)
- return; // nothing more to do
-
- if (_CompressionLevel == OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel.None)
- _CompressionMethod = (short)OfficeOpenXml.Packaging.Ionic.Zip.CompressionMethod.None;
- else
- _CompressionMethod = (short)OfficeOpenXml.Packaging.Ionic.Zip.CompressionMethod.Deflate;
-
- if (_container.ZipFile != null) _container.ZipFile.NotifyEntryChanged();
- _restreamRequiredOnSave = true;
- }
- }
-
-
-
- /// <summary>
- /// The compressed size of the file, in bytes, within the zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// When reading a <c>ZipFile</c>, this value is read in from the existing
- /// zip file. When creating or updating a <c>ZipFile</c>, the compressed
- /// size is computed during compression. Therefore the value on a
- /// <c>ZipEntry</c> is valid after a call to <c>Save()</c> (or one of its
- /// overloads) in that case.
- /// </remarks>
- ///
- /// <seealso cref="ZipEntry.UncompressedSize"/>
- public Int64 CompressedSize
- {
- get { return _CompressedSize; }
- }
-
- /// <summary>
- /// The size of the file, in bytes, before compression, or after extraction.
- /// </summary>
- ///
- /// <remarks>
- /// When reading a <c>ZipFile</c>, this value is read in from the existing
- /// zip file. When creating or updating a <c>ZipFile</c>, the uncompressed
- /// size is computed during compression. Therefore the value on a
- /// <c>ZipEntry</c> is valid after a call to <c>Save()</c> (or one of its
- /// overloads) in that case.
- /// </remarks>
- ///
- /// <seealso cref="Ionic.Zip.ZipEntry.CompressedSize"/>
- public Int64 UncompressedSize
- {
- get { return _UncompressedSize; }
- }
-
- /// <summary>
- /// The ratio of compressed size to uncompressed size of the ZipEntry.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This is a ratio of the compressed size to the uncompressed size of the
- /// entry, expressed as a double in the range of 0 to 100+. A value of 100
- /// indicates no compression at all. It could be higher than 100 when the
- /// compression algorithm actually inflates the data, as may occur for small
- /// files, or uncompressible data that is encrypted.
- /// </para>
- ///
- /// <para>
- /// You could format it for presentation to a user via a format string of
- /// "{3,5:F0}%" to see it as a percentage.
- /// </para>
- ///
- /// <para>
- /// If the size of the original uncompressed file is 0, implying a
- /// denominator of 0, the return value will be zero.
- /// </para>
- ///
- /// <para>
- /// This property is valid after reading in an existing zip file, or after
- /// saving the <c>ZipFile</c> that contains the ZipEntry. You cannot know the
- /// effect of a compression transform until you try it.
- /// </para>
- ///
- /// </remarks>
- public Double CompressionRatio
- {
- get
- {
- if (UncompressedSize == 0) return 0;
- return 100 * (1.0 - (1.0 * CompressedSize) / (1.0 * UncompressedSize));
- }
- }
-
- /// <summary>
- /// The 32-bit CRC (Cyclic Redundancy Check) on the contents of the ZipEntry.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para> You probably don't need to concern yourself with this. It is used
- /// internally by DotNetZip to verify files or streams upon extraction. </para>
- ///
- /// <para> The value is a <see href="http://en.wikipedia.org/wiki/CRC32">32-bit
- /// CRC</see> using 0xEDB88320 for the polynomial. This is the same CRC-32 used in
- /// PNG, MPEG-2, and other protocols and formats. It is a read-only property; when
- /// creating a Zip archive, the CRC for each entry is set only after a call to
- /// <c>Save()</c> on the containing ZipFile. When reading an existing zip file, the value
- /// of this property reflects the stored CRC for the entry. </para>
- ///
- /// </remarks>
- public Int32 Crc
- {
- get { return _Crc32; }
- }
-
- /// <summary>
- /// True if the entry is a directory (not a file).
- /// This is a readonly property on the entry.
- /// </summary>
- public bool IsDirectory
- {
- get { return _IsDirectory; }
- }
-
- /// <summary>
- /// A derived property that is <c>true</c> if the entry uses encryption.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This is a readonly property on the entry. When reading a zip file,
- /// the value for the <c>ZipEntry</c> is determined by the data read
- /// from the zip file. After saving a ZipFile, the value of this
- /// property for each <c>ZipEntry</c> indicates whether encryption was
- /// actually used (which will have been true if the <see
- /// cref="Password"/> was set and the <see cref="Encryption"/> property
- /// was something other than <see cref="EncryptionAlgorithm.None"/>.
- /// </para>
- /// </remarks>
- public bool UsesEncryption
- {
- get { return (_Encryption_FromZipFile != EncryptionAlgorithm.None); }
- }
-
-
- /// <summary>
- /// Set this to specify which encryption algorithm to use for the entry when
- /// saving it to a zip archive.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// Set this property in order to encrypt the entry when the <c>ZipFile</c> is
- /// saved. When setting this property, you must also set a <see
- /// cref="Password"/> on the entry. If you set a value other than <see
- /// cref="EncryptionAlgorithm.None"/> on this property and do not set a
- /// <c>Password</c> then the entry will not be encrypted. The <c>ZipEntry</c>
- /// data is encrypted as the <c>ZipFile</c> is saved, when you call <see
- /// cref="ZipFile.Save()"/> or one of its cousins on the containing
- /// <c>ZipFile</c> instance. You do not need to specify the <c>Encryption</c>
- /// when extracting entries from an archive.
- /// </para>
- ///
- /// <para>
- /// The Zip specification from PKWare defines a set of encryption algorithms,
- /// and the data formats for the zip archive that support them, and PKWare
- /// supports those algorithms in the tools it produces. Other vendors of tools
- /// and libraries, such as WinZip or Xceed, typically support <em>a
- /// subset</em> of the algorithms specified by PKWare. These tools can
- /// sometimes support additional different encryption algorithms and data
- /// formats, not specified by PKWare. The AES Encryption specified and
- /// supported by WinZip is the most popular example. This library supports a
- /// subset of the complete set of algorithms specified by PKWare and other
- /// vendors.
- /// </para>
- ///
- /// <para>
- /// There is no common, ubiquitous multi-vendor standard for strong encryption
- /// within zip files. There is broad support for so-called "traditional" Zip
- /// encryption, sometimes called Zip 2.0 encryption, as <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">specified
- /// by PKWare</see>, but this encryption is considered weak and
- /// breakable. This library currently supports the Zip 2.0 "weak" encryption,
- /// and also a stronger WinZip-compatible AES encryption, using either 128-bit
- /// or 256-bit key strength. If you want DotNetZip to support an algorithm
- /// that is not currently supported, call the author of this library and maybe
- /// we can talk business.
- /// </para>
- ///
- /// <para>
- /// The <see cref="ZipFile"/> class also has a <see
- /// cref="ZipFile.Encryption"/> property. In most cases you will use
- /// <em>that</em> property when setting encryption. This property takes
- /// precedence over any <c>Encryption</c> set on the <c>ZipFile</c> itself.
- /// Typically, you would use the per-entry Encryption when most entries in the
- /// zip archive use one encryption algorithm, and a few entries use a
- /// different one. If all entries in the zip file use the same Encryption,
- /// then it is simpler to just set this property on the ZipFile itself, when
- /// creating a zip archive.
- /// </para>
- ///
- /// <para>
- /// Some comments on updating archives: If you read a <c>ZipFile</c>, you can
- /// modify the Encryption on an encrypted entry: you can remove encryption
- /// from an entry that was encrypted; you can encrypt an entry that was not
- /// encrypted previously; or, you can change the encryption algorithm. The
- /// changes in encryption are not made permanent until you call Save() on the
- /// <c>ZipFile</c>. To effect changes in encryption, the entry content is
- /// streamed through several transformations, depending on the modification
- /// the application has requested. For example if the entry is not encrypted
- /// and the application sets <c>Encryption</c> to <c>PkzipWeak</c>, then at
- /// the time of <c>Save()</c>, the original entry is read and decompressed,
- /// then re-compressed and encrypted. Conversely, if the original entry is
- /// encrypted with <c>PkzipWeak</c> encryption, and the application sets the
- /// <c>Encryption</c> property to <c>WinZipAes128</c>, then at the time of
- /// <c>Save()</c>, the original entry is decrypted via PKZIP encryption and
- /// decompressed, then re-compressed and re-encrypted with AES. This all
- /// happens automatically within the library, but it can be time-consuming for
- /// large entries.
- /// </para>
- ///
- /// <para>
- /// Additionally, when updating archives, it is not possible to change the
- /// password when changing the encryption algorithm. To change both the
- /// algorithm and the password, you need to Save() the zipfile twice. First
- /// set the <c>Encryption</c> to None, then call <c>Save()</c>. Then set the
- /// <c>Encryption</c> to the new value (not "None"), then call <c>Save()</c>
- /// once again.
- /// </para>
- ///
- /// <para>
- /// The WinZip AES encryption algorithms are not supported on the .NET Compact
- /// Framework.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// <para>
- /// This example creates a zip archive that uses encryption, and then extracts
- /// entries from the archive. When creating the zip archive, the ReadMe.txt
- /// file is zipped without using a password or encryption. The other file
- /// uses encryption.
- /// </para>
- /// <code>
- /// // Create a zip archive with AES Encryption.
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// zip.AddFile("ReadMe.txt")
- /// ZipEntry e1= zip.AddFile("2008-Regional-Sales-Report.pdf");
- /// e1.Encryption= EncryptionAlgorithm.WinZipAes256;
- /// e1.Password= "Top.Secret.No.Peeking!";
- /// zip.Save("EncryptedArchive.zip");
- /// }
- ///
- /// // Extract a zip archive that uses AES Encryption.
- /// // You do not need to specify the algorithm during extraction.
- /// using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip"))
- /// {
- /// // Specify the password that is used during extraction, for
- /// // all entries that require a password:
- /// zip.Password= "Top.Secret.No.Peeking!";
- /// zip.ExtractAll("extractDirectory");
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// ' Create a zip that uses Encryption.
- /// Using zip As New ZipFile()
- /// zip.AddFile("ReadMe.txt")
- /// Dim e1 as ZipEntry
- /// e1= zip.AddFile("2008-Regional-Sales-Report.pdf")
- /// e1.Encryption= EncryptionAlgorithm.WinZipAes256
- /// e1.Password= "Top.Secret.No.Peeking!"
- /// zip.Save("EncryptedArchive.zip")
- /// End Using
- ///
- /// ' Extract a zip archive that uses AES Encryption.
- /// ' You do not need to specify the algorithm during extraction.
- /// Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip"))
- /// ' Specify the password that is used during extraction, for
- /// ' all entries that require a password:
- /// zip.Password= "Top.Secret.No.Peeking!"
- /// zip.ExtractAll("extractDirectory")
- /// End Using
- /// </code>
- ///
- /// </example>
- ///
- /// <exception cref="System.InvalidOperationException">
- /// Thrown in the setter if EncryptionAlgorithm.Unsupported is specified.
- /// </exception>
- ///
- /// <seealso cref="Ionic.Zip.ZipEntry.Password">ZipEntry.Password</seealso>
- /// <seealso cref="Ionic.Zip.ZipFile.Encryption">ZipFile.Encryption</seealso>
- internal EncryptionAlgorithm Encryption
- {
- get
- {
- return _Encryption;
- }
- set
- {
- if (value == _Encryption) return; // no change
-
- if (value == EncryptionAlgorithm.Unsupported)
- throw new InvalidOperationException("You may not set Encryption to that value.");
-
- // If the source is a zip archive and there was encryption
- // on the entry, this will not work. <XXX>
- //if (this._Source == ZipEntrySource.ZipFile && _sourceIsEncrypted)
- // throw new InvalidOperationException("You cannot change the encryption method on encrypted entries read from archives.");
-
- _Encryption = value;
- _restreamRequiredOnSave = true;
- if (_container.ZipFile!=null)
- _container.ZipFile.NotifyEntryChanged();
- }
- }
-
-
- /// <summary>
- /// The Password to be used when encrypting a <c>ZipEntry</c> upon
- /// <c>ZipFile.Save()</c>, or when decrypting an entry upon Extract().
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This is a write-only property on the entry. Set this to request that the
- /// entry be encrypted when writing the zip archive, or set it to specify the
- /// password to be used when extracting an existing entry that is encrypted.
- /// </para>
- ///
- /// <para>
- /// The password set here is implicitly used to encrypt the entry during the
- /// <see cref="ZipFile.Save()"/> operation, or to decrypt during the <see
- /// cref="Extract()"/> or <see cref="OpenReader()"/> operation. If you set
- /// the Password on a <c>ZipEntry</c> after calling <c>Save()</c>, there is no
- /// effect.
- /// </para>
- ///
- /// <para>
- /// Consider setting the <see cref="Encryption"/> property when using a
- /// password. Answering concerns that the standard password protection
- /// supported by all zip tools is weak, WinZip has extended the ZIP
- /// specification with a way to use AES Encryption to protect entries in the
- /// Zip file. Unlike the "PKZIP 2.0" encryption specified in the PKZIP
- /// specification, <see href=
- /// "http://en.wikipedia.org/wiki/Advanced_Encryption_Standard">AES
- /// Encryption</see> uses a standard, strong, tested, encryption
- /// algorithm. DotNetZip can create zip archives that use WinZip-compatible
- /// AES encryption, if you set the <see cref="Encryption"/> property. But,
- /// archives created that use AES encryption may not be readable by all other
- /// tools and libraries. For example, Windows Explorer cannot read a
- /// "compressed folder" (a zip file) that uses AES encryption, though it can
- /// read a zip file that uses "PKZIP encryption."
- /// </para>
- ///
- /// <para>
- /// The <see cref="ZipFile"/> class also has a <see cref="ZipFile.Password"/>
- /// property. This property takes precedence over any password set on the
- /// ZipFile itself. Typically, you would use the per-entry Password when most
- /// entries in the zip archive use one password, and a few entries use a
- /// different password. If all entries in the zip file use the same password,
- /// then it is simpler to just set this property on the ZipFile itself,
- /// whether creating a zip archive or extracting a zip archive.
- /// </para>
- ///
- /// <para>
- /// Some comments on updating archives: If you read a <c>ZipFile</c>, you
- /// cannot modify the password on any encrypted entry, except by extracting
- /// the entry with the original password (if any), removing the original entry
- /// via <see cref="ZipFile.RemoveEntry(ZipEntry)"/>, and then adding a new
- /// entry with a new Password.
- /// </para>
- ///
- /// <para>
- /// For example, suppose you read a <c>ZipFile</c>, and there is an encrypted
- /// entry. Setting the Password property on that <c>ZipEntry</c> and then
- /// calling <c>Save()</c> on the <c>ZipFile</c> does not update the password
- /// on that entry in the archive. Neither is an exception thrown. Instead,
- /// what happens during the <c>Save()</c> is the existing entry is copied
- /// through to the new zip archive, in its original encrypted form. Upon
- /// re-reading that archive, the entry can be decrypted with its original
- /// password.
- /// </para>
- ///
- /// <para>
- /// If you read a ZipFile, and there is an un-encrypted entry, you can set the
- /// <c>Password</c> on the entry and then call Save() on the ZipFile, and get
- /// encryption on that entry.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// <para>
- /// This example creates a zip file with two entries, and then extracts the
- /// entries from the zip file. When creating the zip file, the two files are
- /// added to the zip file using password protection. Each entry uses a
- /// different password. During extraction, each file is extracted with the
- /// appropriate password.
- /// </para>
- /// <code>
- /// // create a file with encryption
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// ZipEntry entry;
- /// entry= zip.AddFile("Declaration.txt");
- /// entry.Password= "123456!";
- /// entry = zip.AddFile("Report.xls");
- /// entry.Password= "1Secret!";
- /// zip.Save("EncryptedArchive.zip");
- /// }
- ///
- /// // extract entries that use encryption
- /// using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip"))
- /// {
- /// ZipEntry entry;
- /// entry = zip["Declaration.txt"];
- /// entry.Password = "123456!";
- /// entry.Extract("extractDir");
- /// entry = zip["Report.xls"];
- /// entry.Password = "1Secret!";
- /// entry.Extract("extractDir");
- /// }
- ///
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As New ZipFile
- /// Dim entry as ZipEntry
- /// entry= zip.AddFile("Declaration.txt")
- /// entry.Password= "123456!"
- /// entry = zip.AddFile("Report.xls")
- /// entry.Password= "1Secret!"
- /// zip.Save("EncryptedArchive.zip")
- /// End Using
- ///
- ///
- /// ' extract entries that use encryption
- /// Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip"))
- /// Dim entry as ZipEntry
- /// entry = zip("Declaration.txt")
- /// entry.Password = "123456!"
- /// entry.Extract("extractDir")
- /// entry = zip("Report.xls")
- /// entry.Password = "1Secret!"
- /// entry.Extract("extractDir")
- /// End Using
- ///
- /// </code>
- ///
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipEntry.Encryption"/>
- /// <seealso cref="Ionic.Zip.ZipFile.Password">ZipFile.Password</seealso>
- public string Password
- {
- set
- {
- _Password = value;
- if (_Password == null)
- {
- _Encryption = EncryptionAlgorithm.None;
- }
- else
- {
- // We're setting a non-null password.
-
- // For entries obtained from a zip file that are encrypted, we cannot
- // simply restream (recompress, re-encrypt) the file data, because we
- // need the old password in order to decrypt the data, and then we
- // need the new password to encrypt. So, setting the password is
- // never going to work on an entry that is stored encrypted in a zipfile.
-
- // But it is not en error to set the password, obviously: callers will
- // set the password in order to Extract encrypted archives.
-
- // If the source is a zip archive and there was previously no encryption
- // on the entry, then we must re-stream the entry in order to encrypt it.
- if (this._Source == ZipEntrySource.ZipFile && !_sourceIsEncrypted)
- _restreamRequiredOnSave = true;
-
- if (Encryption == EncryptionAlgorithm.None)
- {
- _Encryption = EncryptionAlgorithm.PkzipWeak;
- }
- }
- }
- private get { return _Password; }
- }
-
-
-
- internal bool IsChanged
- {
- get
- {
- return _restreamRequiredOnSave | _metadataChanged;
- }
- }
-
-
- /// <summary>
- /// The action the library should take when extracting a file that already exists.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This property affects the behavior of the Extract methods (one of the
- /// <c>Extract()</c> or <c>ExtractWithPassword()</c> overloads), when
- /// extraction would would overwrite an existing filesystem file. If you do
- /// not set this property, the library throws an exception when extracting
- /// an entry would overwrite an existing file.
- /// </para>
- ///
- /// <para>
- /// This property has no effect when extracting to a stream, or when the file to be
- /// extracted does not already exist.
- /// </para>
- ///
- /// </remarks>
- /// <seealso cref="Ionic.Zip.ZipFile.ExtractExistingFile"/>
- ///
- /// <example>
- /// This example shows how to set the <c>ExtractExistingFile</c> property in
- /// an <c>ExtractProgress</c> event, in response to user input. The
- /// <c>ExtractProgress</c> event is invoked if and only if the
- /// <c>ExtractExistingFile</c> property was previously set to
- /// <c>ExtractExistingFileAction.InvokeExtractProgressEvent</c>.
- /// <code lang="C#">
- /// public static void ExtractProgress(object sender, ExtractProgressEventArgs e)
- /// {
- /// if (e.EventType == ZipProgressEventType.Extracting_BeforeExtractEntry)
- /// Console.WriteLine("extract {0} ", e.CurrentEntry.FileName);
- ///
- /// else if (e.EventType == ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite)
- /// {
- /// ZipEntry entry = e.CurrentEntry;
- /// string response = null;
- /// // Ask the user if he wants overwrite the file
- /// do
- /// {
- /// Console.Write("Overwrite {0} in {1} ? (y/n/C) ", entry.FileName, e.ExtractLocation);
- /// response = Console.ReadLine();
- /// Console.WriteLine();
- ///
- /// } while (response != null && response[0]!='Y' &&
- /// response[0]!='N' && response[0]!='C');
- ///
- /// if (response[0]=='C')
- /// e.Cancel = true;
- /// else if (response[0]=='Y')
- /// entry.ExtractExistingFile = ExtractExistingFileAction.OverwriteSilently;
- /// else
- /// entry.ExtractExistingFile= ExtractExistingFileAction.DoNotOverwrite;
- /// }
- /// }
- /// </code>
- /// </example>
- internal ExtractExistingFileAction ExtractExistingFile
- {
- get;
- set;
- }
-
-
- /// <summary>
- /// The action to take when an error is encountered while
- /// opening or reading files as they are saved into a zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Errors can occur within a call to <see
- /// cref="ZipFile.Save()">ZipFile.Save</see>, as the various files contained
- /// in a ZipFile are being saved into the zip archive. During the
- /// <c>Save</c>, DotNetZip will perform a <c>File.Open</c> on the file
- /// associated to the ZipEntry, and then will read the entire contents of
- /// the file as it is zipped. Either the open or the Read may fail, because
- /// of lock conflicts or other reasons. Using this property, you can
- /// specify the action to take when such errors occur.
- /// </para>
- ///
- /// <para>
- /// Typically you will NOT set this property on individual ZipEntry
- /// instances. Instead, you will set the <see
- /// cref="ZipFile.ZipErrorAction">ZipFile.ZipErrorAction</see> property on
- /// the ZipFile instance, before adding any entries to the
- /// <c>ZipFile</c>. If you do this, errors encountered on behalf of any of
- /// the entries in the ZipFile will be handled the same way.
- /// </para>
- ///
- /// <para>
- /// But, if you use a <see cref="ZipFile.ZipError"/> handler, you will want
- /// to set this property on the <c>ZipEntry</c> within the handler, to
- /// communicate back to DotNetZip what you would like to do with the
- /// particular error.
- /// </para>
- ///
- /// </remarks>
- /// <seealso cref="Ionic.Zip.ZipFile.ZipErrorAction"/>
- /// <seealso cref="Ionic.Zip.ZipFile.ZipError"/>
- internal ZipErrorAction ZipErrorAction
- {
- get;
- set;
- }
-
-
- /// <summary>
- /// Indicates whether the entry was included in the most recent save.
- /// </summary>
- /// <remarks>
- /// An entry can be excluded or skipped from a save if there is an error
- /// opening or reading the entry.
- /// </remarks>
- /// <seealso cref="ZipErrorAction"/>
- internal bool IncludedInMostRecentSave
- {
- get
- {
- return !_skippedDuringSave;
- }
- }
-
-
- /// <summary>
- /// A callback that allows the application to specify the compression to use
- /// for a given entry that is about to be added to the zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// See <see cref="ZipFile.SetCompression" />
- /// </para>
- /// </remarks>
- public SetCompressionCallback SetCompression
- {
- get;
- set;
- }
-
-
-
- /// <summary>
- /// Set to indicate whether to use UTF-8 encoding for filenames and comments.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// If this flag is set, the comment and filename for the entry will be
- /// encoded with UTF-8, as described in <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">the Zip
- /// specification</see>, if necessary. "Necessary" means, the filename or
- /// entry comment (if any) cannot be reflexively encoded and decoded using the
- /// default code page, IBM437.
- /// </para>
- ///
- /// <para>
- /// Setting this flag to true is equivalent to setting <see
- /// cref="ProvisionalAlternateEncoding"/> to <c>System.Text.Encoding.UTF8</c>.
- /// </para>
- ///
- /// <para>
- /// This flag has no effect or relation to the text encoding used within the
- /// file itself.
- /// </para>
- ///
- /// </remarks>
- [Obsolete("Beginning with v1.9.1.6 of DotNetZip, this property is obsolete. It will be removed in a future version of the library. Your applications should use AlternateEncoding and AlternateEncodingUsage instead.")]
- public bool UseUnicodeAsNecessary
- {
- get
- {
- return (AlternateEncoding == System.Text.Encoding.GetEncoding("UTF-8")) &&
- (AlternateEncodingUsage == ZipOption.AsNecessary);
- }
- set
- {
- if (value)
- {
- AlternateEncoding = System.Text.Encoding.GetEncoding("UTF-8");
- AlternateEncodingUsage = ZipOption.AsNecessary;
-
- }
- else
- {
- AlternateEncoding = Ionic.Zip.ZipFile.DefaultEncoding;
- AlternateEncodingUsage = ZipOption.Never;
- }
- }
- }
-
- /// <summary>
- /// The text encoding to use for the FileName and Comment on this ZipEntry,
- /// when the default encoding is insufficient.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// Don't use this property. See <see cref='AlternateEncoding'/>.
- /// </para>
- ///
- /// </remarks>
- [Obsolete("This property is obsolete since v1.9.1.6. Use AlternateEncoding and AlternateEncodingUsage instead.", true)]
- public System.Text.Encoding ProvisionalAlternateEncoding
- {
- get; set;
- }
-
- /// <summary>
- /// Specifies the alternate text encoding used by this ZipEntry
- /// </summary>
- /// <remarks>
- /// <para>
- /// The default text encoding used in Zip files for encoding filenames and
- /// comments is IBM437, which is something like a superset of ASCII. In
- /// cases where this is insufficient, applications can specify an
- /// alternate encoding.
- /// </para>
- /// <para>
- /// When creating a zip file, the usage of the alternate encoding is
- /// governed by the <see cref="AlternateEncodingUsage"/> property.
- /// Typically you would set both properties to tell DotNetZip to employ an
- /// encoding that is not IBM437 in the zipfile you are creating.
- /// </para>
- /// <para>
- /// Keep in mind that because the ZIP specification states that the only
- /// valid encodings to use are IBM437 and UTF-8, if you use something
- /// other than that, then zip tools and libraries may not be able to
- /// successfully read the zip archive you generate.
- /// </para>
- /// <para>
- /// The zip specification states that applications should presume that
- /// IBM437 is in use, except when a special bit is set, which indicates
- /// UTF-8. There is no way to specify an arbitrary code page, within the
- /// zip file itself. When you create a zip file encoded with gb2312 or
- /// ibm861 or anything other than IBM437 or UTF-8, then the application
- /// that reads the zip file needs to "know" which code page to use. In
- /// some cases, the code page used when reading is chosen implicitly. For
- /// example, WinRar uses the ambient code page for the host desktop
- /// operating system. The pitfall here is that if you create a zip in
- /// Copenhagen and send it to Tokyo, the reader of the zipfile may not be
- /// able to decode successfully.
- /// </para>
- /// </remarks>
- /// <example>
- /// This example shows how to create a zipfile encoded with a
- /// language-specific encoding:
- /// <code>
- /// using (var zip = new ZipFile())
- /// {
- /// zip.AlternateEnoding = System.Text.Encoding.GetEncoding("ibm861");
- /// zip.AlternateEnodingUsage = ZipOption.Always;
- /// zip.AddFileS(arrayOfFiles);
- /// zip.Save("Myarchive-Encoded-in-IBM861.zip");
- /// }
- /// </code>
- /// </example>
- /// <seealso cref="ZipFile.AlternateEncodingUsage" />
- public System.Text.Encoding AlternateEncoding
- {
- get; set;
- }
-
-
- /// <summary>
- /// Describes if and when this instance should apply
- /// AlternateEncoding to encode the FileName and Comment, when
- /// saving.
- /// </summary>
- /// <seealso cref="ZipFile.AlternateEncoding" />
- internal ZipOption AlternateEncodingUsage
- {
- get; set;
- }
-
-
- // /// <summary>
- // /// The text encoding actually used for this ZipEntry.
- // /// </summary>
- // ///
- // /// <remarks>
- // ///
- // /// <para>
- // /// This read-only property describes the encoding used by the
- // /// <c>ZipEntry</c>. If the entry has been read in from an existing ZipFile,
- // /// then it may take the value UTF-8, if the entry is coded to specify UTF-8.
- // /// If the entry does not specify UTF-8, the typical case, then the encoding
- // /// used is whatever the application specified in the call to
- // /// <c>ZipFile.Read()</c>. If the application has used one of the overloads of
- // /// <c>ZipFile.Read()</c> that does not accept an encoding parameter, then the
- // /// encoding used is IBM437, which is the default encoding described in the
- // /// ZIP specification. </para>
- // ///
- // /// <para>
- // /// If the entry is being created, then the value of ActualEncoding is taken
- // /// according to the logic described in the documentation for <see
- // /// cref="ZipFile.ProvisionalAlternateEncoding" />. </para>
- // ///
- // /// <para>
- // /// An application might be interested in retrieving this property to see if
- // /// an entry read in from a file has used Unicode (UTF-8). </para>
- // ///
- // /// </remarks>
- // ///
- // /// <seealso cref="ZipFile.ProvisionalAlternateEncoding" />
- // public System.Text.Encoding ActualEncoding
- // {
- // get
- // {
- // return _actualEncoding;
- // }
- // }
-
-
-
-
- internal static string NameInArchive(String filename, string directoryPathInArchive)
- {
- string result = null;
- if (directoryPathInArchive == null)
- result = filename;
-
- else
- {
- if (String.IsNullOrEmpty(directoryPathInArchive))
- {
- result = Path.GetFileName(filename);
- }
- else
- {
- // explicitly specify a pathname for this file
- result = Path.Combine(directoryPathInArchive, Path.GetFileName(filename));
- }
- }
-
- //result = Path.GetFullPath(result);
- result = SharedUtilities.NormalizePathForUseInZipFile(result);
-
- return result;
- }
-
- // workitem 9073
- internal static ZipEntry CreateFromNothing(String nameInArchive)
- {
- return Create(nameInArchive, ZipEntrySource.None, null, null);
- }
-
- internal static ZipEntry CreateFromFile(String filename, string nameInArchive)
- {
- return Create(nameInArchive, ZipEntrySource.FileSystem, filename, null);
- }
-
- internal static ZipEntry CreateForStream(String entryName, Stream s)
- {
- return Create(entryName, ZipEntrySource.Stream, s, null);
- }
-
- internal static ZipEntry CreateForWriter(String entryName, WriteDelegate d)
- {
- return Create(entryName, ZipEntrySource.WriteDelegate, d, null);
- }
-
- internal static ZipEntry CreateForJitStreamProvider(string nameInArchive, OpenDelegate opener, CloseDelegate closer)
- {
- return Create(nameInArchive, ZipEntrySource.JitStream, opener, closer);
- }
-
- internal static ZipEntry CreateForZipOutputStream(string nameInArchive)
- {
- return Create(nameInArchive, ZipEntrySource.ZipOutputStream, null, null);
- }
-
-
- private static ZipEntry Create(string nameInArchive, ZipEntrySource source, Object arg1, Object arg2)
- {
- if (String.IsNullOrEmpty(nameInArchive))
- throw new Ionic.Zip.ZipException("The entry name must be non-null and non-empty.");
-
- ZipEntry entry = new ZipEntry();
-
- // workitem 7071
- // workitem 7926 - "version made by" OS should be zero for compat with WinZip
- entry._VersionMadeBy = (0 << 8) + 45; // indicates the attributes are FAT Attributes, and v4.5 of the spec
- entry._Source = source;
- entry._Mtime = entry._Atime = entry._Ctime = DateTime.UtcNow;
-
- if (source == ZipEntrySource.Stream)
- {
- entry._sourceStream = (arg1 as Stream); // may or may not be null
- }
- else if (source == ZipEntrySource.WriteDelegate)
- {
- entry._WriteDelegate = (arg1 as WriteDelegate); // may or may not be null
- }
- else if (source == ZipEntrySource.JitStream)
- {
- entry._OpenDelegate = (arg1 as OpenDelegate); // may or may not be null
- entry._CloseDelegate = (arg2 as CloseDelegate); // may or may not be null
- }
- else if (source == ZipEntrySource.ZipOutputStream)
- {
- }
- // workitem 9073
- else if (source == ZipEntrySource.None)
- {
- // make this a valid value, for later.
- entry._Source = ZipEntrySource.FileSystem;
- }
- else
- {
- String filename = (arg1 as String); // must not be null
-
- if (String.IsNullOrEmpty(filename))
- throw new Ionic.Zip.ZipException("The filename must be non-null and non-empty.");
-
- try
- {
- // The named file may or may not exist at this time. For
- // example, when adding a directory by name. We test existence
- // when necessary: when saving the ZipFile, or when getting the
- // attributes, and so on.
-
-#if NETCF
- // workitem 6878
- // Ionic.Zip.SharedUtilities.AdjustTime_Win32ToDotNet
- entry._Mtime = File.GetLastWriteTime(filename).ToUniversalTime();
- entry._Ctime = File.GetCreationTime(filename).ToUniversalTime();
- entry._Atime = File.GetLastAccessTime(filename).ToUniversalTime();
-
- // workitem 7071
- // can only get attributes of files that exist.
- if (File.Exists(filename) || Directory.Exists(filename))
- entry._ExternalFileAttrs = (int)NetCfFile.GetAttributes(filename);
-
-#elif SILVERLIGHT
- entry._Mtime =
- entry._Ctime =
- entry._Atime = System.DateTime.UtcNow;
- entry._ExternalFileAttrs = (int)0;
-#else
- // workitem 6878??
- entry._Mtime = File.GetLastWriteTime(filename).ToUniversalTime();
- entry._Ctime = File.GetCreationTime(filename).ToUniversalTime();
- entry._Atime = File.GetLastAccessTime(filename).ToUniversalTime();
-
- // workitem 7071
- // can only get attributes on files that exist.
- if (File.Exists(filename) || Directory.Exists(filename))
- entry._ExternalFileAttrs = (int)File.GetAttributes(filename);
-
-#endif
- entry._ntfsTimesAreSet = true;
-
- entry._LocalFileName = Path.GetFullPath(filename); // workitem 8813
-
- }
- catch (System.IO.PathTooLongException ptle)
- {
- // workitem 14035
- var msg = String.Format("The path is too long, filename={0}",
- filename);
- throw new ZipException(msg, ptle);
- }
-
- }
-
- entry._LastModified = entry._Mtime;
- entry._FileNameInArchive = SharedUtilities.NormalizePathForUseInZipFile(nameInArchive);
- // We don't actually slurp in the file data until the caller invokes Write on this entry.
-
- return entry;
- }
-
-
-
-
- internal void MarkAsDirectory()
- {
- _IsDirectory = true;
- // workitem 6279
- if (!_FileNameInArchive.EndsWith("/"))
- _FileNameInArchive += "/";
- }
-
-
-
- /// <summary>
- /// Indicates whether an entry is marked as a text file. Be careful when
- /// using on this property. Unless you have a good reason, you should
- /// probably ignore this property.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The ZIP format includes a provision for specifying whether an entry in
- /// the zip archive is a text or binary file. This property exposes that
- /// metadata item. Be careful when using this property: It's not clear
- /// that this property as a firm meaning, across tools and libraries.
- /// </para>
- ///
- /// <para>
- /// To be clear, when reading a zip file, the property value may or may
- /// not be set, and its value may or may not be valid. Not all entries
- /// that you may think of as "text" entries will be so marked, and entries
- /// marked as "text" are not guaranteed in any way to be text entries.
- /// Whether the value is set and set correctly depends entirely on the
- /// application that produced the zip file.
- /// </para>
- ///
- /// <para>
- /// There are many zip tools available, and when creating zip files, some
- /// of them "respect" the IsText metadata field, and some of them do not.
- /// Unfortunately, even when an application tries to do "the right thing",
- /// it's not always clear what "the right thing" is.
- /// </para>
- ///
- /// <para>
- /// There's no firm definition of just what it means to be "a text file",
- /// and the zip specification does not help in this regard. Twenty years
- /// ago, text was ASCII, each byte was less than 127. IsText meant, all
- /// bytes in the file were less than 127. These days, it is not the case
- /// that all text files have all bytes less than 127. Any unicode file
- /// may have bytes that are above 0x7f. The zip specification has nothing
- /// to say on this topic. Therefore, it's not clear what IsText really
- /// means.
- /// </para>
- ///
- /// <para>
- /// This property merely tells a reading application what is stored in the
- /// metadata for an entry, without guaranteeing its validity or its
- /// meaning.
- /// </para>
- ///
- /// <para>
- /// When DotNetZip is used to create a zipfile, it attempts to set this
- /// field "correctly." For example, if a file ends in ".txt", this field
- /// will be set. Your application may override that default setting. When
- /// writing a zip file, you must set the property before calling
- /// <c>Save()</c> on the ZipFile.
- /// </para>
- ///
- /// <para>
- /// When reading a zip file, a more general way to decide just what kind
- /// of file is contained in a particular entry is to use the file type
- /// database stored in the operating system. The operating system stores
- /// a table that says, a file with .jpg extension is a JPG image file, a
- /// file with a .xml extension is an XML document, a file with a .txt is a
- /// pure ASCII text document, and so on. To get this information on
- /// Windows, <see
- /// href="http://www.codeproject.com/KB/cs/GetFileTypeAndIcon.aspx"> you
- /// need to read and parse the registry.</see> </para>
- /// </remarks>
- ///
- /// <example>
- /// <code>
- /// using (var zip = new ZipFile())
- /// {
- /// var e = zip.UpdateFile("Descriptions.mme", "");
- /// e.IsText = true;
- /// zip.Save(zipPath);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As New ZipFile
- /// Dim e2 as ZipEntry = zip.AddFile("Descriptions.mme", "")
- /// e.IsText= True
- /// zip.Save(zipPath)
- /// End Using
- /// </code>
- /// </example>
- public bool IsText
- {
- // workitem 7801
- get { return _IsText; }
- set { _IsText = value; }
- }
-
-
-
- /// <summary>Provides a string representation of the instance.</summary>
- /// <returns>a string representation of the instance.</returns>
- public override String ToString()
- {
- return String.Format("ZipEntry::{0}", FileName);
- }
-
-
- internal Stream ArchiveStream
- {
- get
- {
- if (_archiveStream == null)
- {
- if (_container.ZipFile != null)
- {
- var zf = _container.ZipFile;
- zf.Reset(false);
- _archiveStream = zf.StreamForDiskNumber(_diskNumber);
- }
- else
- {
- _archiveStream = _container.ZipOutputStream.OutputStream;
- }
- }
- return _archiveStream;
- }
- }
-
-
- private void SetFdpLoh()
- {
- // The value for FileDataPosition has not yet been set.
- // Therefore, seek to the local header, and figure the start of file data.
- // workitem 8098: ok (restore)
- long origPosition = this.ArchiveStream.Position;
- try
- {
- this.ArchiveStream.Seek(this._RelativeOffsetOfLocalHeader, SeekOrigin.Begin);
-
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream);
- }
- catch (System.IO.IOException exc1)
- {
- string description = String.Format("Exception seeking entry({0}) offset(0x{1:X8}) len(0x{2:X8})",
- this.FileName, this._RelativeOffsetOfLocalHeader,
- this.ArchiveStream.Length);
- throw new BadStateException(description, exc1);
- }
-
- byte[] block = new byte[30];
- this.ArchiveStream.Read(block, 0, block.Length);
-
- // At this point we could verify the contents read from the local header
- // with the contents read from the central header. We could, but don't need to.
- // So we won't.
-
- Int16 filenameLength = (short)(block[26] + block[27] * 256);
- Int16 extraFieldLength = (short)(block[28] + block[29] * 256);
-
- // Console.WriteLine(" pos 0x{0:X8} ({0})", this.ArchiveStream.Position);
- // Console.WriteLine(" seek 0x{0:X8} ({0})", filenameLength + extraFieldLength);
-
- this.ArchiveStream.Seek(filenameLength + extraFieldLength, SeekOrigin.Current);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream);
-
- this._LengthOfHeader = 30 + extraFieldLength + filenameLength +
- GetLengthOfCryptoHeaderBytes(_Encryption_FromZipFile);
-
- // Console.WriteLine(" ROLH 0x{0:X8} ({0})", _RelativeOffsetOfLocalHeader);
- // Console.WriteLine(" LOH 0x{0:X8} ({0})", _LengthOfHeader);
- // workitem 8098: ok (arithmetic)
- this.__FileDataPosition = _RelativeOffsetOfLocalHeader + _LengthOfHeader;
- // Console.WriteLine(" FDP 0x{0:X8} ({0})", __FileDataPosition);
-
- // restore file position:
- // workitem 8098: ok (restore)
- this.ArchiveStream.Seek(origPosition, SeekOrigin.Begin);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream);
- }
-
-
-
-#if AESCRYPTO
- private static int GetKeyStrengthInBits(EncryptionAlgorithm a)
- {
- if (a == EncryptionAlgorithm.WinZipAes256) return 256;
- else if (a == EncryptionAlgorithm.WinZipAes128) return 128;
- return -1;
- }
-#endif
-
- internal static int GetLengthOfCryptoHeaderBytes(EncryptionAlgorithm a)
- {
- //if ((_BitField & 0x01) != 0x01) return 0;
- if (a == EncryptionAlgorithm.None) return 0;
-
-#if AESCRYPTO
- if (a == EncryptionAlgorithm.WinZipAes128 ||
- a == EncryptionAlgorithm.WinZipAes256)
- {
- int KeyStrengthInBits = GetKeyStrengthInBits(a);
- int sizeOfSaltAndPv = ((KeyStrengthInBits / 8 / 2) + 2);
- return sizeOfSaltAndPv;
- }
-#endif
- if (a == EncryptionAlgorithm.PkzipWeak)
- return 12;
- throw new ZipException("internal error");
- }
-
-
- internal long FileDataPosition
- {
- get
- {
- if (__FileDataPosition == -1)
- SetFdpLoh();
-
- return __FileDataPosition;
- }
- }
-
- private int LengthOfHeader
- {
- get
- {
- if (_LengthOfHeader == 0)
- SetFdpLoh();
-
- return _LengthOfHeader;
- }
- }
-
-
-
- private ZipCrypto _zipCrypto_forExtract;
- private ZipCrypto _zipCrypto_forWrite;
-#if AESCRYPTO
- private WinZipAesCrypto _aesCrypto_forExtract;
- private WinZipAesCrypto _aesCrypto_forWrite;
- private Int16 _WinZipAesMethod;
-#endif
-
- internal DateTime _LastModified;
- private DateTime _Mtime, _Atime, _Ctime; // workitem 6878: NTFS quantities
- private bool _ntfsTimesAreSet;
- private bool _emitNtfsTimes = true;
- private bool _emitUnixTimes; // by default, false
- private bool _TrimVolumeFromFullyQualifiedPaths = true; // by default, trim them.
- internal string _LocalFileName;
- private string _FileNameInArchive;
- internal Int16 _VersionNeeded;
- internal Int16 _BitField;
- internal Int16 _CompressionMethod;
- private Int16 _CompressionMethod_FromZipFile;
- private Ionic.Zlib.CompressionLevel _CompressionLevel;
- internal string _Comment;
- private bool _IsDirectory;
- private byte[] _CommentBytes;
- internal Int64 _CompressedSize;
- internal Int64 _CompressedFileDataSize; // CompressedSize less 12 bytes for the encryption header, if any
- internal Int64 _UncompressedSize;
- internal Int32 _TimeBlob;
- private bool _crcCalculated;
- internal Int32 _Crc32;
- internal byte[] _Extra;
- private bool _metadataChanged;
- private bool _restreamRequiredOnSave;
- private bool _sourceIsEncrypted;
- private bool _skippedDuringSave;
- private UInt32 _diskNumber;
-
- private static System.Text.Encoding ibm437 = System.Text.Encoding.ASCII;
- //private System.Text.Encoding _provisionalAlternateEncoding = System.Text.Encoding.ASCII;
- private System.Text.Encoding _actualEncoding;
-
- internal ZipContainer _container;
-
- private long __FileDataPosition = -1;
- private byte[] _EntryHeader;
- internal Int64 _RelativeOffsetOfLocalHeader;
- private Int64 _future_ROLH;
- private Int64 _TotalEntrySize;
- private int _LengthOfHeader;
- private int _LengthOfTrailer;
- internal bool _InputUsesZip64;
- private UInt32 _UnsupportedAlgorithmId;
-
- internal string _Password;
- internal ZipEntrySource _Source;
- internal EncryptionAlgorithm _Encryption;
- internal EncryptionAlgorithm _Encryption_FromZipFile;
- internal byte[] _WeakEncryptionHeader;
- internal Stream _archiveStream;
- private Stream _sourceStream;
- private Nullable<Int64> _sourceStreamOriginalPosition;
- private bool _sourceWasJitProvided;
- private bool _ioOperationCanceled;
- private bool _presumeZip64;
- private Nullable<bool> _entryRequiresZip64;
- private Nullable<bool> _OutputUsesZip64;
- private bool _IsText; // workitem 7801
- private ZipEntryTimestamp _timestamp;
-
- private static System.DateTime _unixEpoch = new System.DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
- private static System.DateTime _win32Epoch = System.DateTime.FromFileTimeUtc(0L);
- private static System.DateTime _zeroHour = new System.DateTime(1, 1, 1, 0, 0, 0, DateTimeKind.Utc);
-
- private WriteDelegate _WriteDelegate;
- private OpenDelegate _OpenDelegate;
- private CloseDelegate _CloseDelegate;
-
-
- // summary
- // The default size of the IO buffer for ZipEntry instances. Currently it is 8192 bytes.
- // summary
- //public const int IO_BUFFER_SIZE_DEFAULT = 8192; // 0x8000; // 0x4400
-
- }
-
-
-
- /// <summary>
- /// An enum that specifies the type of timestamp available on the ZipEntry.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// The last modified time of a file can be stored in multiple ways in
- /// a zip file, and they are not mutually exclusive:
- /// </para>
- ///
- /// <list type="bullet">
- /// <item>
- /// In the so-called "DOS" format, which has a 2-second precision. Values
- /// are rounded to the nearest even second. For example, if the time on the
- /// file is 12:34:43, then it will be stored as 12:34:44. This first value
- /// is accessible via the <c>LastModified</c> property. This value is always
- /// present in the metadata for each zip entry. In some cases the value is
- /// invalid, or zero.
- /// </item>
- ///
- /// <item>
- /// In the so-called "Windows" or "NTFS" format, as an 8-byte integer
- /// quantity expressed as the number of 1/10 milliseconds (in other words
- /// the number of 100 nanosecond units) since January 1, 1601 (UTC). This
- /// format is how Windows represents file times. This time is accessible
- /// via the <c>ModifiedTime</c> property.
- /// </item>
- ///
- /// <item>
- /// In the "Unix" format, a 4-byte quantity specifying the number of seconds since
- /// January 1, 1970 UTC.
- /// </item>
- ///
- /// <item>
- /// In an older format, now deprecated but still used by some current
- /// tools. This format is also a 4-byte quantity specifying the number of
- /// seconds since January 1, 1970 UTC.
- /// </item>
- ///
- /// </list>
- ///
- /// <para>
- /// This bit field describes which of the formats were found in a <c>ZipEntry</c> that was read.
- /// </para>
- ///
- /// </remarks>
- [Flags]
- internal enum ZipEntryTimestamp
- {
- /// <summary>
- /// Default value.
- /// </summary>
- None = 0,
-
- /// <summary>
- /// A DOS timestamp with 2-second precision.
- /// </summary>
- DOS = 1,
-
- /// <summary>
- /// A Windows timestamp with 100-ns precision.
- /// </summary>
- Windows = 2,
-
- /// <summary>
- /// A Unix timestamp with 1-second precision.
- /// </summary>
- Unix = 4,
-
- /// <summary>
- /// A Unix timestamp with 1-second precision, stored in InfoZip v1 format. This
- /// format is outdated and is supported for reading archives only.
- /// </summary>
- InfoZip1 = 8,
- }
-
-
-
- /// <summary>
- /// The method of compression to use for a particular ZipEntry.
- /// </summary>
- ///
- /// <remarks>
- /// <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWare's
- /// ZIP Specification</see> describes a number of distinct
- /// cmopression methods that can be used within a zip
- /// file. DotNetZip supports a subset of them.
- /// </remarks>
- internal enum CompressionMethod
- {
- /// <summary>
- /// No compression at all. For COM environments, the value is 0 (zero).
- /// </summary>
- None = 0,
-
- /// <summary>
- /// DEFLATE compression, as described in <see
- /// href="http://www.ietf.org/rfc/rfc1951.txt">IETF RFC
- /// 1951</see>. This is the "normal" compression used in zip
- /// files. For COM environments, the value is 8.
- /// </summary>
- Deflate = 8,
-
-#if BZIP
- /// <summary>
- /// BZip2 compression, a compression algorithm developed by Julian Seward.
- /// For COM environments, the value is 12.
- /// </summary>
- BZip2 = 12,
-#endif
- }
-
-
-#if NETCF
- internal class NetCfFile
- {
- public static int SetTimes(string filename, DateTime ctime, DateTime atime, DateTime mtime)
- {
- IntPtr hFile = (IntPtr) CreateFileCE(filename,
- (uint)0x40000000L, // (uint)FileAccess.Write,
- (uint)0x00000002L, // (uint)FileShare.Write,
- 0,
- (uint) 3, // == open existing
- (uint)0, // flagsAndAttributes
- 0);
-
- if((int)hFile == -1)
- {
- // workitem 7944: don't throw on failure to set file times
- // throw new ZipException("CreateFileCE Failed");
- return Interop.Marshal.GetLastWin32Error();
- }
-
- SetFileTime(hFile,
- BitConverter.GetBytes(ctime.ToFileTime()),
- BitConverter.GetBytes(atime.ToFileTime()),
- BitConverter.GetBytes(mtime.ToFileTime()));
-
- CloseHandle(hFile);
- return 0;
- }
-
-
- public static int SetLastWriteTime(string filename, DateTime mtime)
- {
- IntPtr hFile = (IntPtr) CreateFileCE(filename,
- (uint)0x40000000L, // (uint)FileAccess.Write,
- (uint)0x00000002L, // (uint)FileShare.Write,
- 0,
- (uint) 3, // == open existing
- (uint)0, // flagsAndAttributes
- 0);
-
- if((int)hFile == -1)
- {
- // workitem 7944: don't throw on failure to set file time
- // throw new ZipException(String.Format("CreateFileCE Failed ({0})",
- // Interop.Marshal.GetLastWin32Error()));
- return Interop.Marshal.GetLastWin32Error();
- }
-
- SetFileTime(hFile, null, null,
- BitConverter.GetBytes(mtime.ToFileTime()));
-
- CloseHandle(hFile);
- return 0;
- }
-
-
- [Interop.DllImport("coredll.dll", EntryPoint="CreateFile", SetLastError=true)]
- internal static extern int CreateFileCE(string lpFileName,
- uint dwDesiredAccess,
- uint dwShareMode,
- int lpSecurityAttributes,
- uint dwCreationDisposition,
- uint dwFlagsAndAttributes,
- int hTemplateFile);
-
-
- [Interop.DllImport("coredll", EntryPoint="GetFileAttributes", SetLastError=true)]
- internal static extern uint GetAttributes(string lpFileName);
-
- [Interop.DllImport("coredll", EntryPoint="SetFileAttributes", SetLastError=true)]
- internal static extern bool SetAttributes(string lpFileName, uint dwFileAttributes);
-
- [Interop.DllImport("coredll", EntryPoint="SetFileTime", SetLastError=true)]
- internal static extern bool SetFileTime(IntPtr hFile, byte[] lpCreationTime, byte[] lpLastAccessTime, byte[] lpLastWriteTime);
-
- [Interop.DllImport("coredll.dll", SetLastError=true)]
- internal static extern bool CloseHandle(IntPtr hObject);
-
- }
-#endif
-
-
-
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipEntrySource.cs b/EPPlus/Packaging/DotNetZip/ZipEntrySource.cs
deleted file mode 100644
index eb90a18..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipEntrySource.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-// ZipEntrySource.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2009-November-19 11:18:42>
-//
-// ------------------------------------------------------------------
-//
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- /// <summary>
- /// An enum that specifies the source of the ZipEntry.
- /// </summary>
- internal enum ZipEntrySource
- {
- /// <summary>
- /// Default value. Invalid on a bonafide ZipEntry.
- /// </summary>
- None = 0,
-
- /// <summary>
- /// The entry was instantiated by calling AddFile() or another method that
- /// added an entry from the filesystem.
- /// </summary>
- FileSystem,
-
- /// <summary>
- /// The entry was instantiated via <see cref="Ionic.Zip.ZipFile.AddEntry(string,string)"/> or
- /// <see cref="Ionic.Zip.ZipFile.AddEntry(string,System.IO.Stream)"/> .
- /// </summary>
- Stream,
-
- /// <summary>
- /// The ZipEntry was instantiated by reading a zipfile.
- /// </summary>
- ZipFile,
-
- /// <summary>
- /// The content for the ZipEntry will be or was provided by the WriteDelegate.
- /// </summary>
- WriteDelegate,
-
- /// <summary>
- /// The content for the ZipEntry will be obtained from the stream dispensed by the <c>OpenDelegate</c>.
- /// The entry was instantiated via <see cref="Ionic.Zip.ZipFile.AddEntry(string,OpenDelegate,CloseDelegate)"/>.
- /// </summary>
- JitStream,
-
- /// <summary>
- /// The content for the ZipEntry will be or was obtained from a <c>ZipOutputStream</c>.
- /// </summary>
- ZipOutputStream,
- }
-
-}
\ No newline at end of file
diff --git a/EPPlus/Packaging/DotNetZip/ZipErrorAction.cs b/EPPlus/Packaging/DotNetZip/ZipErrorAction.cs
deleted file mode 100644
index f8894dd..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipErrorAction.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-// ZipErrorAction.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2009-September-01 18:43:20>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the ZipErrorAction enum, which provides
-// an action to take when errors occur when opening or reading
-// files to be added to a zip file.
-//
-// ------------------------------------------------------------------
-
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- /// <summary>
- /// An enum providing the options when an error occurs during opening or reading
- /// of a file or directory that is being saved to a zip file.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This enum describes the actions that the library can take when an error occurs
- /// opening or reading a file, as it is being saved into a Zip archive.
- /// </para>
- ///
- /// <para>
- /// In some cases an error will occur when DotNetZip tries to open a file to be
- /// added to the zip archive. In other cases, an error might occur after the
- /// file has been successfully opened, while DotNetZip is reading the file.
- /// </para>
- ///
- /// <para>
- /// The first problem might occur when calling AddDirectory() on a directory
- /// that contains a Clipper .dbf file; the file is locked by Clipper and
- /// cannot be opened by another process. An example of the second problem is
- /// the ERROR_LOCK_VIOLATION that results when a file is opened by another
- /// process, but not locked, and a range lock has been taken on the file.
- /// Microsoft Outlook takes range locks on .PST files.
- /// </para>
- /// </remarks>
- internal enum ZipErrorAction
- {
- /// <summary>
- /// Throw an exception when an error occurs while zipping. This is the default
- /// behavior. (For COM clients, this is a 0 (zero).)
- /// </summary>
- Throw,
-
- /// <summary>
- /// When an error occurs during zipping, for example a file cannot be opened,
- /// skip the file causing the error, and continue zipping. (For COM clients,
- /// this is a 1.)
- /// </summary>
- Skip,
-
- /// <summary>
- /// When an error occurs during zipping, for example a file cannot be opened,
- /// retry the operation that caused the error. Be careful with this option. If
- /// the error is not temporary, the library will retry forever. (For COM
- /// clients, this is a 2.)
- /// </summary>
- Retry,
-
- /// <summary>
- /// When an error occurs, invoke the zipError event. The event type used is
- /// <see cref="ZipProgressEventType.Error_Saving"/>. A typical use of this option:
- /// a GUI application may wish to pop up a dialog to allow the user to view the
- /// error that occurred, and choose an appropriate action. After your
- /// processing in the error event, if you want to skip the file, set <see
- /// cref="ZipEntry.ZipErrorAction"/> on the
- /// <c>ZipProgressEventArgs.CurrentEntry</c> to <c>Skip</c>. If you want the
- /// exception to be thrown, set <c>ZipErrorAction</c> on the <c>CurrentEntry</c>
- /// to <c>Throw</c>. If you want to cancel the zip, set
- /// <c>ZipProgressEventArgs.Cancel</c> to true. Cancelling differs from using
- /// Skip in that a cancel will not save any further entries, if there are any.
- /// (For COM clients, the value of this enum is a 3.)
- /// </summary>
- InvokeErrorEvent,
- }
-
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipFile.AddUpdate.cs b/EPPlus/Packaging/DotNetZip/ZipFile.AddUpdate.cs
deleted file mode 100644
index 46e9588..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipFile.AddUpdate.cs
+++ /dev/null
@@ -1,2182 +0,0 @@
-// ZipFile.AddUpdate.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009-2011 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-November-01 13:56:58>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the methods for Adding and Updating entries in
-// the ZipFile.
-//
-// ------------------------------------------------------------------
-//
-
-
-using System;
-using System.IO;
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- internal partial class ZipFile
- {
- /// <summary>
- /// Adds an item, either a file or a directory, to a zip file archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method is handy if you are adding things to zip archive and don't
- /// want to bother distinguishing between directories or files. Any files are
- /// added as single entries. A directory added through this method is added
- /// recursively: all files and subdirectories contained within the directory
- /// are added to the <c>ZipFile</c>.
- /// </para>
- ///
- /// <para>
- /// The name of the item may be a relative path or a fully-qualified
- /// path. Remember, the items contained in <c>ZipFile</c> instance get written
- /// to the disk only when you call <see cref="ZipFile.Save()"/> or a similar
- /// save method.
- /// </para>
- ///
- /// <para>
- /// The directory name used for the file within the archive is the same
- /// as the directory name (potentially a relative path) specified in the
- /// <paramref name="fileOrDirectoryName"/>.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to the
- /// <c>ZipEntry</c> added.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddFile(string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.AddDirectory(string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateItem(string)"/>
- ///
- /// <overloads>This method has two overloads.</overloads>
- /// <param name="fileOrDirectoryName">
- /// the name of the file or directory to add.</param>
- ///
- /// <returns>The <c>ZipEntry</c> added.</returns>
- public ZipEntry AddItem(string fileOrDirectoryName)
- {
- return AddItem(fileOrDirectoryName, null);
- }
-
-
- /// <summary>
- /// Adds an item, either a file or a directory, to a zip file archive,
- /// explicitly specifying the directory path to be used in the archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// If adding a directory, the add is recursive on all files and
- /// subdirectories contained within it.
- /// </para>
- /// <para>
- /// The name of the item may be a relative path or a fully-qualified path.
- /// The item added by this call to the <c>ZipFile</c> is not read from the
- /// disk nor written to the zip file archive until the application calls
- /// Save() on the <c>ZipFile</c>.
- /// </para>
- ///
- /// <para>
- /// This version of the method allows the caller to explicitly specify the
- /// directory path to be used in the archive, which would override the
- /// "natural" path of the filesystem file.
- /// </para>
- ///
- /// <para>
- /// Encryption will be used on the file data if the <c>Password</c> has
- /// been set on the <c>ZipFile</c> object, prior to calling this method.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to the
- /// <c>ZipEntry</c> added.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <exception cref="System.IO.FileNotFoundException">
- /// Thrown if the file or directory passed in does not exist.
- /// </exception>
- ///
- /// <param name="fileOrDirectoryName">the name of the file or directory to add.
- /// </param>
- ///
- /// <param name="directoryPathInArchive">
- /// The name of the directory path to use within the zip archive. This path
- /// need not refer to an extant directory in the current filesystem. If the
- /// files within the zip are later extracted, this is the path used for the
- /// extracted file. Passing <c>null</c> (<c>Nothing</c> in VB) will use the
- /// path on the fileOrDirectoryName. Passing the empty string ("") will
- /// insert the item at the root path within the archive.
- /// </param>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddFile(string, string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.AddDirectory(string, string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateItem(string, string)"/>
- ///
- /// <example>
- /// This example shows how to zip up a set of files into a flat hierarchy,
- /// regardless of where in the filesystem the files originated. The resulting
- /// zip archive will contain a toplevel directory named "flat", which itself
- /// will contain files Readme.txt, MyProposal.docx, and Image1.jpg. A
- /// subdirectory under "flat" called SupportFiles will contain all the files
- /// in the "c:\SupportFiles" directory on disk.
- ///
- /// <code>
- /// String[] itemnames= {
- /// "c:\\fixedContent\\Readme.txt",
- /// "MyProposal.docx",
- /// "c:\\SupportFiles", // a directory
- /// "images\\Image1.jpg"
- /// };
- ///
- /// try
- /// {
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// for (int i = 1; i < itemnames.Length; i++)
- /// {
- /// // will add Files or Dirs, recurses and flattens subdirectories
- /// zip.AddItem(itemnames[i],"flat");
- /// }
- /// zip.Save(ZipToCreate);
- /// }
- /// }
- /// catch (System.Exception ex1)
- /// {
- /// System.Console.Error.WriteLine("exception: {0}", ex1);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Dim itemnames As String() = _
- /// New String() { "c:\fixedContent\Readme.txt", _
- /// "MyProposal.docx", _
- /// "SupportFiles", _
- /// "images\Image1.jpg" }
- /// Try
- /// Using zip As New ZipFile
- /// Dim i As Integer
- /// For i = 1 To itemnames.Length - 1
- /// ' will add Files or Dirs, recursing and flattening subdirectories.
- /// zip.AddItem(itemnames(i), "flat")
- /// Next i
- /// zip.Save(ZipToCreate)
- /// End Using
- /// Catch ex1 As Exception
- /// Console.Error.WriteLine("exception: {0}", ex1.ToString())
- /// End Try
- /// </code>
- /// </example>
- /// <returns>The <c>ZipEntry</c> added.</returns>
- public ZipEntry AddItem(String fileOrDirectoryName, String directoryPathInArchive)
- {
- if (File.Exists(fileOrDirectoryName))
- return AddFile(fileOrDirectoryName, directoryPathInArchive);
-
- if (Directory.Exists(fileOrDirectoryName))
- return AddDirectory(fileOrDirectoryName, directoryPathInArchive);
-
- throw new FileNotFoundException(String.Format("That file or directory ({0}) does not exist!",
- fileOrDirectoryName));
- }
-
- /// <summary>
- /// Adds a File to a Zip file archive.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// This call collects metadata for the named file in the filesystem,
- /// including the file attributes and the timestamp, and inserts that metadata
- /// into the resulting ZipEntry. Only when the application calls Save() on
- /// the <c>ZipFile</c>, does DotNetZip read the file from the filesystem and
- /// then write the content to the zip file archive.
- /// </para>
- ///
- /// <para>
- /// This method will throw an exception if an entry with the same name already
- /// exists in the <c>ZipFile</c>.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to the
- /// <c>ZipEntry</c> added.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// <para>
- /// In this example, three files are added to a Zip archive. The ReadMe.txt
- /// file will be placed in the root of the archive. The .png file will be
- /// placed in a folder within the zip called photos\personal. The pdf file
- /// will be included into a folder within the zip called Desktop.
- /// </para>
- /// <code>
- /// try
- /// {
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// zip.AddFile("c:\\photos\\personal\\7440-N49th.png");
- /// zip.AddFile("c:\\Desktop\\2008-Regional-Sales-Report.pdf");
- /// zip.AddFile("ReadMe.txt");
- ///
- /// zip.Save("Package.zip");
- /// }
- /// }
- /// catch (System.Exception ex1)
- /// {
- /// System.Console.Error.WriteLine("exception: " + ex1);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Try
- /// Using zip As ZipFile = New ZipFile
- /// zip.AddFile("c:\photos\personal\7440-N49th.png")
- /// zip.AddFile("c:\Desktop\2008-Regional-Sales-Report.pdf")
- /// zip.AddFile("ReadMe.txt")
- /// zip.Save("Package.zip")
- /// End Using
- /// Catch ex1 As Exception
- /// Console.Error.WriteLine("exception: {0}", ex1.ToString)
- /// End Try
- /// </code>
- /// </example>
- ///
- /// <overloads>This method has two overloads.</overloads>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddItem(string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.AddDirectory(string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateFile(string)"/>
- ///
- /// <param name="fileName">
- /// The name of the file to add. It should refer to a file in the filesystem.
- /// The name of the file may be a relative path or a fully-qualified path.
- /// </param>
- /// <returns>The <c>ZipEntry</c> corresponding to the File added.</returns>
- public ZipEntry AddFile(string fileName)
- {
- return AddFile(fileName, null);
- }
-
-
-
-
-
- /// <summary>
- /// Adds a File to a Zip file archive, potentially overriding the path to be
- /// used within the zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The file added by this call to the <c>ZipFile</c> is not written to the
- /// zip file archive until the application calls Save() on the <c>ZipFile</c>.
- /// </para>
- ///
- /// <para>
- /// This method will throw an exception if an entry with the same name already
- /// exists in the <c>ZipFile</c>.
- /// </para>
- ///
- /// <para>
- /// This version of the method allows the caller to explicitly specify the
- /// directory path to be used in the archive.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to the
- /// <c>ZipEntry</c> added.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// <para>
- /// In this example, three files are added to a Zip archive. The ReadMe.txt
- /// file will be placed in the root of the archive. The .png file will be
- /// placed in a folder within the zip called images. The pdf file will be
- /// included into a folder within the zip called files\docs, and will be
- /// encrypted with the given password.
- /// </para>
- /// <code>
- /// try
- /// {
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// // the following entry will be inserted at the root in the archive.
- /// zip.AddFile("c:\\datafiles\\ReadMe.txt", "");
- /// // this image file will be inserted into the "images" directory in the archive.
- /// zip.AddFile("c:\\photos\\personal\\7440-N49th.png", "images");
- /// // the following will result in a password-protected file called
- /// // files\\docs\\2008-Regional-Sales-Report.pdf in the archive.
- /// zip.Password = "EncryptMe!";
- /// zip.AddFile("c:\\Desktop\\2008-Regional-Sales-Report.pdf", "files\\docs");
- /// zip.Save("Archive.zip");
- /// }
- /// }
- /// catch (System.Exception ex1)
- /// {
- /// System.Console.Error.WriteLine("exception: {0}", ex1);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Try
- /// Using zip As ZipFile = New ZipFile
- /// ' the following entry will be inserted at the root in the archive.
- /// zip.AddFile("c:\datafiles\ReadMe.txt", "")
- /// ' this image file will be inserted into the "images" directory in the archive.
- /// zip.AddFile("c:\photos\personal\7440-N49th.png", "images")
- /// ' the following will result in a password-protected file called
- /// ' files\\docs\\2008-Regional-Sales-Report.pdf in the archive.
- /// zip.Password = "EncryptMe!"
- /// zip.AddFile("c:\Desktop\2008-Regional-Sales-Report.pdf", "files\documents")
- /// zip.Save("Archive.zip")
- /// End Using
- /// Catch ex1 As Exception
- /// Console.Error.WriteLine("exception: {0}", ex1)
- /// End Try
- /// </code>
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddItem(string,string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.AddDirectory(string, string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateFile(string,string)"/>
- ///
- /// <param name="fileName">
- /// The name of the file to add. The name of the file may be a relative path
- /// or a fully-qualified path.
- /// </param>
- ///
- /// <param name="directoryPathInArchive">
- /// Specifies a directory path to use to override any path in the fileName.
- /// This path may, or may not, correspond to a real directory in the current
- /// filesystem. If the files within the zip are later extracted, this is the
- /// path used for the extracted file. Passing <c>null</c> (<c>Nothing</c> in
- /// VB) will use the path on the fileName, if any. Passing the empty string
- /// ("") will insert the item at the root path within the archive.
- /// </param>
- ///
- /// <returns>The <c>ZipEntry</c> corresponding to the file added.</returns>
- public ZipEntry AddFile(string fileName, String directoryPathInArchive)
- {
- string nameInArchive = ZipEntry.NameInArchive(fileName, directoryPathInArchive);
- ZipEntry ze = ZipEntry.CreateFromFile(fileName, nameInArchive);
- if (Verbose) StatusMessageTextWriter.WriteLine("adding {0}...", fileName);
- return _InternalAddEntry(ze);
- }
-
-
- /// <summary>
- /// This method removes a collection of entries from the <c>ZipFile</c>.
- /// </summary>
- ///
- /// <param name="entriesToRemove">
- /// A collection of ZipEntry instances from this zip file to be removed. For
- /// example, you can pass in an array of ZipEntry instances; or you can call
- /// SelectEntries(), and then add or remove entries from that
- /// ICollection<ZipEntry> (ICollection(Of ZipEntry) in VB), and pass
- /// that ICollection to this method.
- /// </param>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.SelectEntries(String)" />
- /// <seealso cref="Ionic.Zip.ZipFile.RemoveSelectedEntries(String)" />
- public void RemoveEntries(System.Collections.Generic.ICollection<ZipEntry> entriesToRemove)
- {
- if (entriesToRemove == null)
- throw new ArgumentNullException("entriesToRemove");
-
- foreach (ZipEntry e in entriesToRemove)
- {
- this.RemoveEntry(e);
- }
- }
-
-
- /// <summary>
- /// This method removes a collection of entries from the <c>ZipFile</c>, by name.
- /// </summary>
- ///
- /// <param name="entriesToRemove">
- /// A collection of strings that refer to names of entries to be removed
- /// from the <c>ZipFile</c>. For example, you can pass in an array or a
- /// List of Strings that provide the names of entries to be removed.
- /// </param>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.SelectEntries(String)" />
- /// <seealso cref="Ionic.Zip.ZipFile.RemoveSelectedEntries(String)" />
- public void RemoveEntries(System.Collections.Generic.ICollection<String> entriesToRemove)
- {
- if (entriesToRemove == null)
- throw new ArgumentNullException("entriesToRemove");
-
- foreach (String e in entriesToRemove)
- {
- this.RemoveEntry(e);
- }
- }
-
-
- /// <summary>
- /// This method adds a set of files to the <c>ZipFile</c>.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Use this method to add a set of files to the zip archive, in one call.
- /// For example, a list of files received from
- /// <c>System.IO.Directory.GetFiles()</c> can be added to a zip archive in one
- /// call.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to each
- /// ZipEntry added.
- /// </para>
- /// </remarks>
- ///
- /// <param name="fileNames">
- /// The collection of names of the files to add. Each string should refer to a
- /// file in the filesystem. The name of the file may be a relative path or a
- /// fully-qualified path.
- /// </param>
- ///
- /// <example>
- /// This example shows how to create a zip file, and add a few files into it.
- /// <code>
- /// String ZipFileToCreate = "archive1.zip";
- /// String DirectoryToZip = "c:\\reports";
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// // Store all files found in the top level directory, into the zip archive.
- /// String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip);
- /// zip.AddFiles(filenames);
- /// zip.Save(ZipFileToCreate);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Dim ZipFileToCreate As String = "archive1.zip"
- /// Dim DirectoryToZip As String = "c:\reports"
- /// Using zip As ZipFile = New ZipFile
- /// ' Store all files found in the top level directory, into the zip archive.
- /// Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip)
- /// zip.AddFiles(filenames)
- /// zip.Save(ZipFileToCreate)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddSelectedFiles(String, String)" />
- public void AddFiles(System.Collections.Generic.IEnumerable<String> fileNames)
- {
- this.AddFiles(fileNames, null);
- }
-
-
- /// <summary>
- /// Adds or updates a set of files in the <c>ZipFile</c>.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Any files that already exist in the archive are updated. Any files that
- /// don't yet exist in the archive are added.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to each
- /// ZipEntry added.
- /// </para>
- /// </remarks>
- ///
- /// <param name="fileNames">
- /// The collection of names of the files to update. Each string should refer to a file in
- /// the filesystem. The name of the file may be a relative path or a fully-qualified path.
- /// </param>
- ///
- public void UpdateFiles(System.Collections.Generic.IEnumerable<String> fileNames)
- {
- this.UpdateFiles(fileNames, null);
- }
-
-
- /// <summary>
- /// Adds a set of files to the <c>ZipFile</c>, using the
- /// specified directory path in the archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Any directory structure that may be present in the
- /// filenames contained in the list is "flattened" in the
- /// archive. Each file in the list is added to the archive in
- /// the specified top-level directory.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see
- /// cref="Encryption"/>, <see cref="Password"/>, <see
- /// cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see
- /// cref="ExtractExistingFile"/>, <see
- /// cref="ZipErrorAction"/>, and <see
- /// cref="CompressionLevel"/>, their respective values at the
- /// time of this call will be applied to each ZipEntry added.
- /// </para>
- /// </remarks>
- ///
- /// <param name="fileNames">
- /// The names of the files to add. Each string should refer to
- /// a file in the filesystem. The name of the file may be a
- /// relative path or a fully-qualified path.
- /// </param>
- ///
- /// <param name="directoryPathInArchive">
- /// Specifies a directory path to use to override any path in the file name.
- /// Th is path may, or may not, correspond to a real directory in the current
- /// filesystem. If the files within the zip are later extracted, this is the
- /// path used for the extracted file. Passing <c>null</c> (<c>Nothing</c> in
- /// VB) will use the path on each of the <c>fileNames</c>, if any. Passing
- /// the empty string ("") will insert the item at the root path within the
- /// archive.
- /// </param>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddSelectedFiles(String, String)" />
- public void AddFiles(System.Collections.Generic.IEnumerable<String> fileNames, String directoryPathInArchive)
- {
- AddFiles(fileNames, false, directoryPathInArchive);
- }
-
-
-
- /// <summary>
- /// Adds a set of files to the <c>ZipFile</c>, using the specified directory
- /// path in the archive, and preserving the full directory structure in the
- /// filenames.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// Think of the <paramref name="directoryPathInArchive"/> as a "root" or
- /// base directory used in the archive for the files that get added. when
- /// <paramref name="preserveDirHierarchy"/> is true, the hierarchy of files
- /// found in the filesystem will be placed, with the hierarchy intact,
- /// starting at that root in the archive. When <c>preserveDirHierarchy</c>
- /// is false, the path hierarchy of files is flattned, and the flattened
- /// set of files gets placed in the root within the archive as specified in
- /// <c>directoryPathInArchive</c>.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to each
- /// ZipEntry added.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="fileNames">
- /// The names of the files to add. Each string should refer to a file in the
- /// filesystem. The name of the file may be a relative path or a
- /// fully-qualified path.
- /// </param>
- ///
- /// <param name="directoryPathInArchive">
- /// Specifies a directory path to use as a prefix for each entry name.
- /// This path may, or may not, correspond to a real directory in the current
- /// filesystem. If the files within the zip are later extracted, this is the
- /// path used for the extracted file. Passing <c>null</c> (<c>Nothing</c> in
- /// VB) will use the path on each of the <c>fileNames</c>, if any. Passing
- /// the empty string ("") will insert the item at the root path within the
- /// archive.
- /// </param>
- ///
- /// <param name="preserveDirHierarchy">
- /// whether the entries in the zip archive will reflect the directory
- /// hierarchy that is present in the various filenames. For example, if
- /// <paramref name="fileNames"/> includes two paths,
- /// \Animalia\Chordata\Mammalia\Info.txt and
- /// \Plantae\Magnoliophyta\Dicotyledon\Info.txt, then calling this method
- /// with <paramref name="preserveDirHierarchy"/> = <c>false</c> will
- /// result in an exception because of a duplicate entry name, while
- /// calling this method with <paramref name="preserveDirHierarchy"/> =
- /// <c>true</c> will result in the full direcory paths being included in
- /// the entries added to the ZipFile.
- /// </param>
- /// <seealso cref="Ionic.Zip.ZipFile.AddSelectedFiles(String, String)" />
- public void AddFiles(System.Collections.Generic.IEnumerable<String> fileNames,
- bool preserveDirHierarchy,
- String directoryPathInArchive)
- {
- if (fileNames == null)
- throw new ArgumentNullException("fileNames");
-
- _addOperationCanceled = false;
- OnAddStarted();
- if (preserveDirHierarchy)
- {
- foreach (var f in fileNames)
- {
- if (_addOperationCanceled) break;
- if (directoryPathInArchive != null)
- {
- //string s = SharedUtilities.NormalizePath(Path.Combine(directoryPathInArchive, Path.GetDirectoryName(f)));
- string s = Path.GetFullPath(Path.Combine(directoryPathInArchive, Path.GetDirectoryName(f)));
- this.AddFile(f, s);
- }
- else
- this.AddFile(f, null);
- }
- }
- else
- {
- foreach (var f in fileNames)
- {
- if (_addOperationCanceled) break;
- this.AddFile(f, directoryPathInArchive);
- }
- }
- if (!_addOperationCanceled)
- OnAddCompleted();
- }
-
-
- /// <summary>
- /// Adds or updates a set of files to the <c>ZipFile</c>, using the specified
- /// directory path in the archive.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// Any files that already exist in the archive are updated. Any files that
- /// don't yet exist in the archive are added.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to each
- /// ZipEntry added.
- /// </para>
- /// </remarks>
- ///
- /// <param name="fileNames">
- /// The names of the files to add or update. Each string should refer to a
- /// file in the filesystem. The name of the file may be a relative path or a
- /// fully-qualified path.
- /// </param>
- ///
- /// <param name="directoryPathInArchive">
- /// Specifies a directory path to use to override any path in the file name.
- /// This path may, or may not, correspond to a real directory in the current
- /// filesystem. If the files within the zip are later extracted, this is the
- /// path used for the extracted file. Passing <c>null</c> (<c>Nothing</c> in
- /// VB) will use the path on each of the <c>fileNames</c>, if any. Passing
- /// the empty string ("") will insert the item at the root path within the
- /// archive.
- /// </param>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddSelectedFiles(String, String)" />
- public void UpdateFiles(System.Collections.Generic.IEnumerable<String> fileNames, String directoryPathInArchive)
- {
- if (fileNames == null)
- throw new ArgumentNullException("fileNames");
-
- OnAddStarted();
- foreach (var f in fileNames)
- this.UpdateFile(f, directoryPathInArchive);
- OnAddCompleted();
- }
-
-
-
-
- /// <summary>
- /// Adds or Updates a File in a Zip file archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method adds a file to a zip archive, or, if the file already exists
- /// in the zip archive, this method Updates the content of that given filename
- /// in the zip archive. The <c>UpdateFile</c> method might more accurately be
- /// called "AddOrUpdateFile".
- /// </para>
- ///
- /// <para>
- /// Upon success, there is no way for the application to learn whether the file
- /// was added versus updated.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to the
- /// <c>ZipEntry</c> added.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example shows how to Update an existing entry in a zipfile. The first
- /// call to UpdateFile adds the file to the newly-created zip archive. The
- /// second call to UpdateFile updates the content for that file in the zip
- /// archive.
- ///
- /// <code>
- /// using (ZipFile zip1 = new ZipFile())
- /// {
- /// // UpdateFile might more accurately be called "AddOrUpdateFile"
- /// zip1.UpdateFile("MyDocuments\\Readme.txt");
- /// zip1.UpdateFile("CustomerList.csv");
- /// zip1.Comment = "This zip archive has been created.";
- /// zip1.Save("Content.zip");
- /// }
- ///
- /// using (ZipFile zip2 = ZipFile.Read("Content.zip"))
- /// {
- /// zip2.UpdateFile("Updates\\Readme.txt");
- /// zip2.Comment = "This zip archive has been updated: The Readme.txt file has been changed.";
- /// zip2.Save();
- /// }
- ///
- /// </code>
- /// <code lang="VB">
- /// Using zip1 As New ZipFile
- /// ' UpdateFile might more accurately be called "AddOrUpdateFile"
- /// zip1.UpdateFile("MyDocuments\Readme.txt")
- /// zip1.UpdateFile("CustomerList.csv")
- /// zip1.Comment = "This zip archive has been created."
- /// zip1.Save("Content.zip")
- /// End Using
- ///
- /// Using zip2 As ZipFile = ZipFile.Read("Content.zip")
- /// zip2.UpdateFile("Updates\Readme.txt")
- /// zip2.Comment = "This zip archive has been updated: The Readme.txt file has been changed."
- /// zip2.Save
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddFile(string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateDirectory(string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateItem(string)"/>
- ///
- /// <param name="fileName">
- /// The name of the file to add or update. It should refer to a file in the
- /// filesystem. The name of the file may be a relative path or a
- /// fully-qualified path.
- /// </param>
- ///
- /// <returns>
- /// The <c>ZipEntry</c> corresponding to the File that was added or updated.
- /// </returns>
- public ZipEntry UpdateFile(string fileName)
- {
- return UpdateFile(fileName, null);
- }
-
-
-
- /// <summary>
- /// Adds or Updates a File in a Zip file archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method adds a file to a zip archive, or, if the file already exists
- /// in the zip archive, this method Updates the content of that given filename
- /// in the zip archive.
- /// </para>
- ///
- /// <para>
- /// This version of the method allows the caller to explicitly specify the
- /// directory path to be used in the archive. The entry to be added or
- /// updated is found by using the specified directory path, combined with the
- /// basename of the specified filename.
- /// </para>
- ///
- /// <para>
- /// Upon success, there is no way for the application to learn if the file was
- /// added versus updated.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to the
- /// <c>ZipEntry</c> added.
- /// </para>
- /// </remarks>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddFile(string,string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateDirectory(string,string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateItem(string,string)"/>
- ///
- /// <param name="fileName">
- /// The name of the file to add or update. It should refer to a file in the
- /// filesystem. The name of the file may be a relative path or a
- /// fully-qualified path.
- /// </param>
- ///
- /// <param name="directoryPathInArchive">
- /// Specifies a directory path to use to override any path in the
- /// <c>fileName</c>. This path may, or may not, correspond to a real
- /// directory in the current filesystem. If the files within the zip are
- /// later extracted, this is the path used for the extracted file. Passing
- /// <c>null</c> (<c>Nothing</c> in VB) will use the path on the
- /// <c>fileName</c>, if any. Passing the empty string ("") will insert the
- /// item at the root path within the archive.
- /// </param>
- ///
- /// <returns>
- /// The <c>ZipEntry</c> corresponding to the File that was added or updated.
- /// </returns>
- public ZipEntry UpdateFile(string fileName, String directoryPathInArchive)
- {
- // ideally this would all be transactional!
- var key = ZipEntry.NameInArchive(fileName, directoryPathInArchive);
- if (this[key] != null)
- this.RemoveEntry(key);
- return this.AddFile(fileName, directoryPathInArchive);
- }
-
-
-
-
-
- /// <summary>
- /// Add or update a directory in a zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// If the specified directory does not exist in the archive, then this method
- /// is equivalent to calling <c>AddDirectory()</c>. If the specified
- /// directory already exists in the archive, then this method updates any
- /// existing entries, and adds any new entries. Any entries that are in the
- /// zip archive but not in the specified directory, are left alone. In other
- /// words, the contents of the zip file will be a union of the previous
- /// contents and the new files.
- /// </remarks>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateFile(string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.AddDirectory(string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateItem(string)"/>
- ///
- /// <param name="directoryName">
- /// The path to the directory to be added to the zip archive, or updated in
- /// the zip archive.
- /// </param>
- ///
- /// <returns>
- /// The <c>ZipEntry</c> corresponding to the Directory that was added or updated.
- /// </returns>
- public ZipEntry UpdateDirectory(string directoryName)
- {
- return UpdateDirectory(directoryName, null);
- }
-
-
- /// <summary>
- /// Add or update a directory in the zip archive at the specified root
- /// directory in the archive.
- /// </summary>
- ///
- /// <remarks>
- /// If the specified directory does not exist in the archive, then this method
- /// is equivalent to calling <c>AddDirectory()</c>. If the specified
- /// directory already exists in the archive, then this method updates any
- /// existing entries, and adds any new entries. Any entries that are in the
- /// zip archive but not in the specified directory, are left alone. In other
- /// words, the contents of the zip file will be a union of the previous
- /// contents and the new files.
- /// </remarks>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateFile(string,string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.AddDirectory(string,string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateItem(string,string)"/>
- ///
- /// <param name="directoryName">
- /// The path to the directory to be added to the zip archive, or updated
- /// in the zip archive.
- /// </param>
- ///
- /// <param name="directoryPathInArchive">
- /// Specifies a directory path to use to override any path in the
- /// <c>directoryName</c>. This path may, or may not, correspond to a real
- /// directory in the current filesystem. If the files within the zip are
- /// later extracted, this is the path used for the extracted file. Passing
- /// <c>null</c> (<c>Nothing</c> in VB) will use the path on the
- /// <c>directoryName</c>, if any. Passing the empty string ("") will insert
- /// the item at the root path within the archive.
- /// </param>
- ///
- /// <returns>
- /// The <c>ZipEntry</c> corresponding to the Directory that was added or updated.
- /// </returns>
- public ZipEntry UpdateDirectory(string directoryName, String directoryPathInArchive)
- {
- return this.AddOrUpdateDirectoryImpl(directoryName, directoryPathInArchive, AddOrUpdateAction.AddOrUpdate);
- }
-
-
-
-
-
- /// <summary>
- /// Add or update a file or directory in the zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This is useful when the application is not sure or does not care if the
- /// item to be added is a file or directory, and does not know or does not
- /// care if the item already exists in the <c>ZipFile</c>. Calling this method
- /// is equivalent to calling <c>RemoveEntry()</c> if an entry by the same name
- /// already exists, followed calling by <c>AddItem()</c>.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to the
- /// <c>ZipEntry</c> added.
- /// </para>
- /// </remarks>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddItem(string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateFile(string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateDirectory(string)"/>
- ///
- /// <param name="itemName">
- /// the path to the file or directory to be added or updated.
- /// </param>
- public void UpdateItem(string itemName)
- {
- UpdateItem(itemName, null);
- }
-
-
- /// <summary>
- /// Add or update a file or directory.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method is useful when the application is not sure or does not care if
- /// the item to be added is a file or directory, and does not know or does not
- /// care if the item already exists in the <c>ZipFile</c>. Calling this method
- /// is equivalent to calling <c>RemoveEntry()</c>, if an entry by that name
- /// exists, and then calling <c>AddItem()</c>.
- /// </para>
- ///
- /// <para>
- /// This version of the method allows the caller to explicitly specify the
- /// directory path to be used for the item being added to the archive. The
- /// entry or entries that are added or updated will use the specified
- /// <c>DirectoryPathInArchive</c>. Extracting the entry from the archive will
- /// result in a file stored in that directory path.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to the
- /// <c>ZipEntry</c> added.
- /// </para>
- /// </remarks>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddItem(string, string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateFile(string, string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateDirectory(string, string)"/>
- ///
- /// <param name="itemName">
- /// The path for the File or Directory to be added or updated.
- /// </param>
- /// <param name="directoryPathInArchive">
- /// Specifies a directory path to use to override any path in the
- /// <c>itemName</c>. This path may, or may not, correspond to a real
- /// directory in the current filesystem. If the files within the zip are
- /// later extracted, this is the path used for the extracted file. Passing
- /// <c>null</c> (<c>Nothing</c> in VB) will use the path on the
- /// <c>itemName</c>, if any. Passing the empty string ("") will insert the
- /// item at the root path within the archive.
- /// </param>
- public void UpdateItem(string itemName, string directoryPathInArchive)
- {
- if (File.Exists(itemName))
- UpdateFile(itemName, directoryPathInArchive);
-
- else if (Directory.Exists(itemName))
- UpdateDirectory(itemName, directoryPathInArchive);
-
- else
- throw new FileNotFoundException(String.Format("That file or directory ({0}) does not exist!", itemName));
- }
-
-
-
-
- /// <summary>
- /// Adds a named entry into the zip archive, taking content for the entry
- /// from a string.
- /// </summary>
- ///
- /// <remarks>
- /// Calling this method creates an entry using the given fileName and
- /// directory path within the archive. There is no need for a file by the
- /// given name to exist in the filesystem; the name is used within the zip
- /// archive only. The content for the entry is encoded using the default text
- /// encoding for the machine, or on Silverlight, using UTF-8.
- /// </remarks>
- ///
- /// <param name="content">
- /// The content of the file, should it be extracted from the zip.
- /// </param>
- ///
- /// <param name="entryName">
- /// The name, including any path, to use for the entry within the archive.
- /// </param>
- ///
- /// <returns>The <c>ZipEntry</c> added.</returns>
- ///
- /// <example>
- ///
- /// This example shows how to add an entry to the zipfile, using a string as
- /// content for that entry.
- ///
- /// <code lang="C#">
- /// string Content = "This string will be the content of the Readme.txt file in the zip archive.";
- /// using (ZipFile zip1 = new ZipFile())
- /// {
- /// zip1.AddFile("MyDocuments\\Resume.doc", "files");
- /// zip1.AddEntry("Readme.txt", Content);
- /// zip1.Comment = "This zip file was created at " + System.DateTime.Now.ToString("G");
- /// zip1.Save("Content.zip");
- /// }
- ///
- /// </code>
- /// <code lang="VB">
- /// Public Sub Run()
- /// Dim Content As String = "This string will be the content of the Readme.txt file in the zip archive."
- /// Using zip1 As ZipFile = New ZipFile
- /// zip1.AddEntry("Readme.txt", Content)
- /// zip1.AddFile("MyDocuments\Resume.doc", "files")
- /// zip1.Comment = ("This zip file was created at " & DateTime.Now.ToString("G"))
- /// zip1.Save("Content.zip")
- /// End Using
- /// End Sub
- /// </code>
- /// </example>
- public ZipEntry AddEntry(string entryName, string content)
- {
-#if SILVERLIGHT
- return AddEntry(entryName, content, System.Text.Encoding.UTF8);
-#else
- return AddEntry(entryName, content, System.Text.Encoding.Default);
-#endif
- }
-
-
-
- /// <summary>
- /// Adds a named entry into the zip archive, taking content for the entry
- /// from a string, and using the specified text encoding.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// Calling this method creates an entry using the given fileName and
- /// directory path within the archive. There is no need for a file by the
- /// given name to exist in the filesystem; the name is used within the zip
- /// archive only.
- /// </para>
- ///
- /// <para>
- /// The content for the entry, a string value, is encoded using the given
- /// text encoding. A BOM (byte-order-mark) is emitted into the file, if the
- /// Encoding parameter is set for that.
- /// </para>
- ///
- /// <para>
- /// Most Encoding classes support a constructor that accepts a boolean,
- /// indicating whether to emit a BOM or not. For example see <see
- /// cref="System.Text.UTF8Encoding(bool)"/>.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="entryName">
- /// The name, including any path, to use within the archive for the entry.
- /// </param>
- ///
- /// <param name="content">
- /// The content of the file, should it be extracted from the zip.
- /// </param>
- ///
- /// <param name="encoding">
- /// The text encoding to use when encoding the string. Be aware: This is
- /// distinct from the text encoding used to encode the fileName, as specified
- /// in <see cref="ProvisionalAlternateEncoding" />.
- /// </param>
- ///
- /// <returns>The <c>ZipEntry</c> added.</returns>
- ///
- public ZipEntry AddEntry(string entryName, string content, System.Text.Encoding encoding)
- {
- // cannot employ a using clause here. We need the stream to
- // persist after exit from this method.
- var ms = new MemoryStream();
-
- // cannot use a using clause here; StreamWriter takes
- // ownership of the stream and Disposes it before we are ready.
- var sw = new StreamWriter(ms, encoding);
- sw.Write(content);
- sw.Flush();
-
- // reset to allow reading later
- ms.Seek(0, SeekOrigin.Begin);
-
- return AddEntry(entryName, ms);
-
- // must not dispose the MemoryStream - it will be used later.
- }
-
-
- /// <summary>
- /// Create an entry in the <c>ZipFile</c> using the given <c>Stream</c>
- /// as input. The entry will have the given filename.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// The application should provide an open, readable stream; in this case it
- /// will be read during the call to <see cref="ZipFile.Save()"/> or one of
- /// its overloads.
- /// </para>
- ///
- /// <para>
- /// The passed stream will be read from its current position. If
- /// necessary, callers should set the position in the stream before
- /// calling AddEntry(). This might be appropriate when using this method
- /// with a MemoryStream, for example.
- /// </para>
- ///
- /// <para>
- /// In cases where a large number of streams will be added to the
- /// <c>ZipFile</c>, the application may wish to avoid maintaining all of the
- /// streams open simultaneously. To handle this situation, the application
- /// should use the <see cref="AddEntry(string, OpenDelegate, CloseDelegate)"/>
- /// overload.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to the
- /// <c>ZipEntry</c> added.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// <para>
- /// This example adds a single entry to a <c>ZipFile</c> via a <c>Stream</c>.
- /// </para>
- ///
- /// <code lang="C#">
- /// String zipToCreate = "Content.zip";
- /// String fileNameInArchive = "Content-From-Stream.bin";
- /// using (System.IO.Stream streamToRead = MyStreamOpener())
- /// {
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// ZipEntry entry= zip.AddEntry(fileNameInArchive, streamToRead);
- /// zip.AddFile("Readme.txt");
- /// zip.Save(zipToCreate); // the stream is read implicitly here
- /// }
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Dim zipToCreate As String = "Content.zip"
- /// Dim fileNameInArchive As String = "Content-From-Stream.bin"
- /// Using streamToRead as System.IO.Stream = MyStreamOpener()
- /// Using zip As ZipFile = New ZipFile()
- /// Dim entry as ZipEntry = zip.AddEntry(fileNameInArchive, streamToRead)
- /// zip.AddFile("Readme.txt")
- /// zip.Save(zipToCreate) '' the stream is read implicitly, here
- /// End Using
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateEntry(string, System.IO.Stream)"/>
- ///
- /// <param name="entryName">
- /// The name, including any path, which is shown in the zip file for the added
- /// entry.
- /// </param>
- /// <param name="stream">
- /// The input stream from which to grab content for the file
- /// </param>
- /// <returns>The <c>ZipEntry</c> added.</returns>
- public ZipEntry AddEntry(string entryName, Stream stream)
- {
- ZipEntry ze = ZipEntry.CreateForStream(entryName, stream);
- ze.SetEntryTimes(DateTime.Now,DateTime.Now,DateTime.Now);
- if (Verbose) StatusMessageTextWriter.WriteLine("adding {0}...", entryName);
- return _InternalAddEntry(ze);
- }
-
-
-
- /// <summary>
- /// Add a ZipEntry for which content is written directly by the application.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// When the application needs to write the zip entry data, use this
- /// method to add the ZipEntry. For example, in the case that the
- /// application wishes to write the XML representation of a DataSet into
- /// a ZipEntry, the application can use this method to do so.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to the
- /// <c>ZipEntry</c> added.
- /// </para>
- ///
- /// <para>
- /// About progress events: When using the WriteDelegate, DotNetZip does
- /// not issue any SaveProgress events with <c>EventType</c> = <see
- /// cref="ZipProgressEventType.Saving_EntryBytesRead">
- /// Saving_EntryBytesRead</see>. (This is because it is the
- /// application's code that runs in WriteDelegate - there's no way for
- /// DotNetZip to know when to issue a EntryBytesRead event.)
- /// Applications that want to update a progress bar or similar status
- /// indicator should do so from within the WriteDelegate
- /// itself. DotNetZip will issue the other SaveProgress events,
- /// including <see cref="ZipProgressEventType.Saving_Started">
- /// Saving_Started</see>,
- /// <see cref="ZipProgressEventType.Saving_BeforeWriteEntry">
- /// Saving_BeforeWriteEntry</see>, and <see
- /// cref="ZipProgressEventType.Saving_AfterWriteEntry">
- /// Saving_AfterWriteEntry</see>.
- /// </para>
- ///
- /// <para>
- /// Note: When you use PKZip encryption, it's normally necessary to
- /// compute the CRC of the content to be encrypted, before compressing or
- /// encrypting it. Therefore, when using PKZip encryption with a
- /// WriteDelegate, the WriteDelegate CAN BE called twice: once to compute
- /// the CRC, and the second time to potentially compress and
- /// encrypt. Surprising, but true. This is because PKWARE specified that
- /// the encryption initialization data depends on the CRC.
- /// If this happens, for each call of the delegate, your
- /// application must stream the same entry data in its entirety. If your
- /// application writes different data during the second call, it will
- /// result in a corrupt zip file.
- /// </para>
- ///
- /// <para>
- /// The double-read behavior happens with all types of entries, not only
- /// those that use WriteDelegate. It happens if you add an entry from a
- /// filesystem file, or using a string, or a stream, or an opener/closer
- /// pair. But in those cases, DotNetZip takes care of reading twice; in
- /// the case of the WriteDelegate, the application code gets invoked
- /// twice. Be aware.
- /// </para>
- ///
- /// <para>
- /// As you can imagine, this can cause performance problems for large
- /// streams, and it can lead to correctness problems when you use a
- /// <c>WriteDelegate</c>. This is a pretty big pitfall. There are two
- /// ways to avoid it. First, and most preferred: don't use PKZIP
- /// encryption. If you use the WinZip AES encryption, this problem
- /// doesn't occur, because the encryption protocol doesn't require the CRC
- /// up front. Second: if you do choose to use PKZIP encryption, write out
- /// to a non-seekable stream (like standard output, or the
- /// Response.OutputStream in an ASP.NET application). In this case,
- /// DotNetZip will use an alternative encryption protocol that does not
- /// rely on the CRC of the content. This also implies setting bit 3 in
- /// the zip entry, which still presents problems for some zip tools.
- /// </para>
- ///
- /// <para>
- /// In the future I may modify DotNetZip to *always* use bit 3 when PKZIP
- /// encryption is in use. This seems like a win overall, but there will
- /// be some work involved. If you feel strongly about it, visit the
- /// DotNetZip forums and vote up <see
- /// href="http://dotnetzip.codeplex.com/workitem/13686">the Workitem
- /// tracking this issue</see>.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="entryName">the name of the entry to add</param>
- /// <param name="writer">the delegate which will write the entry content</param>
- /// <returns>the ZipEntry added</returns>
- ///
- /// <example>
- ///
- /// This example shows an application filling a DataSet, then saving the
- /// contents of that DataSet as XML, into a ZipEntry in a ZipFile, using an
- /// anonymous delegate in C#. The DataSet XML is never saved to a disk file.
- ///
- /// <code lang="C#">
- /// var c1= new System.Data.SqlClient.SqlConnection(connstring1);
- /// var da = new System.Data.SqlClient.SqlDataAdapter()
- /// {
- /// SelectCommand= new System.Data.SqlClient.SqlCommand(strSelect, c1)
- /// };
- ///
- /// DataSet ds1 = new DataSet();
- /// da.Fill(ds1, "Invoices");
- ///
- /// using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
- /// {
- /// zip.AddEntry(zipEntryName, (name,stream) => ds1.WriteXml(stream) );
- /// zip.Save(zipFileName);
- /// }
- /// </code>
- /// </example>
- ///
- /// <example>
- ///
- /// This example uses an anonymous method in C# as the WriteDelegate to provide
- /// the data for the ZipEntry. The example is a bit contrived - the
- /// <c>AddFile()</c> method is a simpler way to insert the contents of a file
- /// into an entry in a zip file. On the other hand, if there is some sort of
- /// processing or transformation of the file contents required before writing,
- /// the application could use the <c>WriteDelegate</c> to do it, in this way.
- ///
- /// <code lang="C#">
- /// using (var input = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ))
- /// {
- /// using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
- /// {
- /// zip.AddEntry(zipEntryName, (name,output) =>
- /// {
- /// byte[] buffer = new byte[BufferSize];
- /// int n;
- /// while ((n = input.Read(buffer, 0, buffer.Length)) != 0)
- /// {
- /// // could transform the data here...
- /// output.Write(buffer, 0, n);
- /// // could update a progress bar here
- /// }
- /// });
- ///
- /// zip.Save(zipFileName);
- /// }
- /// }
- /// </code>
- /// </example>
- ///
- /// <example>
- ///
- /// This example uses a named delegate in VB to write data for the given
- /// ZipEntry (VB9 does not have anonymous delegates). The example here is a bit
- /// contrived - a simpler way to add the contents of a file to a ZipEntry is to
- /// simply use the appropriate <c>AddFile()</c> method. The key scenario for
- /// which the <c>WriteDelegate</c> makes sense is saving a DataSet, in XML
- /// format, to the zip file. The DataSet can write XML to a stream, and the
- /// WriteDelegate is the perfect place to write into the zip file. There may be
- /// other data structures that can write to a stream, but cannot be read as a
- /// stream. The <c>WriteDelegate</c> would be appropriate for those cases as
- /// well.
- ///
- /// <code lang="VB">
- /// Private Sub WriteEntry (ByVal name As String, ByVal output As Stream)
- /// Using input As FileStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
- /// Dim n As Integer = -1
- /// Dim buffer As Byte() = New Byte(BufferSize){}
- /// Do While n <> 0
- /// n = input.Read(buffer, 0, buffer.Length)
- /// output.Write(buffer, 0, n)
- /// Loop
- /// End Using
- /// End Sub
- ///
- /// Public Sub Run()
- /// Using zip = New ZipFile
- /// zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry))
- /// zip.Save(zipFileName)
- /// End Using
- /// End Sub
- /// </code>
- /// </example>
- public ZipEntry AddEntry(string entryName, WriteDelegate writer)
- {
- ZipEntry ze = ZipEntry.CreateForWriter(entryName, writer);
- if (Verbose) StatusMessageTextWriter.WriteLine("adding {0}...", entryName);
- return _InternalAddEntry(ze);
- }
-
-
- /// <summary>
- /// Add an entry, for which the application will provide a stream
- /// containing the entry data, on a just-in-time basis.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// In cases where the application wishes to open the stream that
- /// holds the content for the ZipEntry, on a just-in-time basis, the
- /// application can use this method. The application provides an
- /// opener delegate that will be called by the DotNetZip library to
- /// obtain a readable stream that can be read to get the bytes for
- /// the given entry. Typically, this delegate opens a stream.
- /// Optionally, the application can provide a closer delegate as
- /// well, which will be called by DotNetZip when all bytes have been
- /// read from the entry.
- /// </para>
- ///
- /// <para>
- /// These delegates are called from within the scope of the call to
- /// ZipFile.Save().
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to the
- /// <c>ZipEntry</c> added.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example uses anonymous methods in C# to open and close the
- /// source stream for the content for a zip entry.
- ///
- /// <code lang="C#">
- /// using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
- /// {
- /// zip.AddEntry(zipEntryName,
- /// (name) => File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ),
- /// (name, stream) => stream.Close()
- /// );
- ///
- /// zip.Save(zipFileName);
- /// }
- /// </code>
- ///
- /// </example>
- ///
- /// <example>
- ///
- /// This example uses delegates in VB.NET to open and close the
- /// the source stream for the content for a zip entry. VB 9.0 lacks
- /// support for "Sub" lambda expressions, and so the CloseDelegate must
- /// be an actual, named Sub.
- ///
- /// <code lang="VB">
- ///
- /// Function MyStreamOpener(ByVal entryName As String) As Stream
- /// '' This simply opens a file. You probably want to do somethinig
- /// '' more involved here: open a stream to read from a database,
- /// '' open a stream on an HTTP connection, and so on.
- /// Return File.OpenRead(entryName)
- /// End Function
- ///
- /// Sub MyStreamCloser(entryName As String, stream As Stream)
- /// stream.Close()
- /// End Sub
- ///
- /// Public Sub Run()
- /// Dim dirToZip As String = "fodder"
- /// Dim zipFileToCreate As String = "Archive.zip"
- /// Dim opener As OpenDelegate = AddressOf MyStreamOpener
- /// Dim closer As CloseDelegate = AddressOf MyStreamCloser
- /// Dim numFilestoAdd As Int32 = 4
- /// Using zip As ZipFile = New ZipFile
- /// Dim i As Integer
- /// For i = 0 To numFilesToAdd - 1
- /// zip.AddEntry(String.Format("content-{0:000}.txt"), opener, closer)
- /// Next i
- /// zip.Save(zipFileToCreate)
- /// End Using
- /// End Sub
- ///
- /// </code>
- /// </example>
- ///
- /// <param name="entryName">the name of the entry to add</param>
- /// <param name="opener">
- /// the delegate that will be invoked by ZipFile.Save() to get the
- /// readable stream for the given entry. ZipFile.Save() will call
- /// read on this stream to obtain the data for the entry. This data
- /// will then be compressed and written to the newly created zip
- /// file.
- /// </param>
- /// <param name="closer">
- /// the delegate that will be invoked to close the stream. This may
- /// be null (Nothing in VB), in which case no call is makde to close
- /// the stream.
- /// </param>
- /// <returns>the ZipEntry added</returns>
- ///
- public ZipEntry AddEntry(string entryName, OpenDelegate opener, CloseDelegate closer)
- {
- ZipEntry ze = ZipEntry.CreateForJitStreamProvider(entryName, opener, closer);
- ze.SetEntryTimes(DateTime.Now,DateTime.Now,DateTime.Now);
- if (Verbose) StatusMessageTextWriter.WriteLine("adding {0}...", entryName);
- return _InternalAddEntry(ze);
- }
-
-
-
- private ZipEntry _InternalAddEntry(ZipEntry ze)
- {
- // stamp all the props onto the entry
- ze._container = new ZipContainer(this);
- ze.CompressionMethod = this.CompressionMethod;
- ze.CompressionLevel = this.CompressionLevel;
- ze.ExtractExistingFile = this.ExtractExistingFile;
- ze.ZipErrorAction = this.ZipErrorAction;
- ze.SetCompression = this.SetCompression;
- ze.AlternateEncoding = this.AlternateEncoding;
- ze.AlternateEncodingUsage = this.AlternateEncodingUsage;
- ze.Password = this._Password;
- ze.Encryption = this.Encryption;
- ze.EmitTimesInWindowsFormatWhenSaving = this._emitNtfsTimes;
- ze.EmitTimesInUnixFormatWhenSaving = this._emitUnixTimes;
- //string key = DictionaryKeyForEntry(ze);
- InternalAddEntry(ze.FileName,ze);
- AfterAddEntry(ze);
- return ze;
- }
-
-
-
-
- /// <summary>
- /// Updates the given entry in the <c>ZipFile</c>, using the given
- /// string as content for the <c>ZipEntry</c>.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// Calling this method is equivalent to removing the <c>ZipEntry</c> for
- /// the given file name and directory path, if it exists, and then calling
- /// <see cref="AddEntry(String,String)" />. See the documentation for
- /// that method for further explanation. The string content is encoded
- /// using the default encoding for the machine, or on Silverlight, using
- /// UTF-8. This encoding is distinct from the encoding used for the
- /// filename itself. See <see cref="AlternateEncoding"/>.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="entryName">
- /// The name, including any path, to use within the archive for the entry.
- /// </param>
- ///
- /// <param name="content">
- /// The content of the file, should it be extracted from the zip.
- /// </param>
- ///
- /// <returns>The <c>ZipEntry</c> added.</returns>
- ///
- public ZipEntry UpdateEntry(string entryName, string content)
- {
-#if SILVERLIGHT
- return UpdateEntry(entryName, content, System.Text.Encoding.UTF8);
-#else
- return UpdateEntry(entryName, content, System.Text.Encoding.Default);
-#endif
- }
-
-
- /// <summary>
- /// Updates the given entry in the <c>ZipFile</c>, using the given string as
- /// content for the <c>ZipEntry</c>.
- /// </summary>
- ///
- /// <remarks>
- /// Calling this method is equivalent to removing the <c>ZipEntry</c> for the
- /// given file name and directory path, if it exists, and then calling <see
- /// cref="AddEntry(String,String, System.Text.Encoding)" />. See the
- /// documentation for that method for further explanation.
- /// </remarks>
- ///
- /// <param name="entryName">
- /// The name, including any path, to use within the archive for the entry.
- /// </param>
- ///
- /// <param name="content">
- /// The content of the file, should it be extracted from the zip.
- /// </param>
- ///
- /// <param name="encoding">
- /// The text encoding to use when encoding the string. Be aware: This is
- /// distinct from the text encoding used to encode the filename. See <see
- /// cref="AlternateEncoding" />.
- /// </param>
- ///
- /// <returns>The <c>ZipEntry</c> added.</returns>
- ///
- public ZipEntry UpdateEntry(string entryName, string content, System.Text.Encoding encoding)
- {
- RemoveEntryForUpdate(entryName);
- return AddEntry(entryName, content, encoding);
- }
-
-
-
- /// <summary>
- /// Updates the given entry in the <c>ZipFile</c>, using the given delegate
- /// as the source for content for the <c>ZipEntry</c>.
- /// </summary>
- ///
- /// <remarks>
- /// Calling this method is equivalent to removing the <c>ZipEntry</c> for the
- /// given file name and directory path, if it exists, and then calling <see
- /// cref="AddEntry(String,WriteDelegate)" />. See the
- /// documentation for that method for further explanation.
- /// </remarks>
- ///
- /// <param name="entryName">
- /// The name, including any path, to use within the archive for the entry.
- /// </param>
- ///
- /// <param name="writer">the delegate which will write the entry content.</param>
- ///
- /// <returns>The <c>ZipEntry</c> added.</returns>
- ///
- public ZipEntry UpdateEntry(string entryName, WriteDelegate writer)
- {
- RemoveEntryForUpdate(entryName);
- return AddEntry(entryName, writer);
- }
-
-
-
- /// <summary>
- /// Updates the given entry in the <c>ZipFile</c>, using the given delegates
- /// to open and close the stream that provides the content for the <c>ZipEntry</c>.
- /// </summary>
- ///
- /// <remarks>
- /// Calling this method is equivalent to removing the <c>ZipEntry</c> for the
- /// given file name and directory path, if it exists, and then calling <see
- /// cref="AddEntry(String,OpenDelegate, CloseDelegate)" />. See the
- /// documentation for that method for further explanation.
- /// </remarks>
- ///
- /// <param name="entryName">
- /// The name, including any path, to use within the archive for the entry.
- /// </param>
- ///
- /// <param name="opener">
- /// the delegate that will be invoked to open the stream
- /// </param>
- /// <param name="closer">
- /// the delegate that will be invoked to close the stream
- /// </param>
- ///
- /// <returns>The <c>ZipEntry</c> added or updated.</returns>
- ///
- public ZipEntry UpdateEntry(string entryName, OpenDelegate opener, CloseDelegate closer)
- {
- RemoveEntryForUpdate(entryName);
- return AddEntry(entryName, opener, closer);
- }
-
-
- /// <summary>
- /// Updates the given entry in the <c>ZipFile</c>, using the given stream as
- /// input, and the given filename and given directory Path.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Calling the method is equivalent to calling <c>RemoveEntry()</c> if an
- /// entry by the same name already exists, and then calling <c>AddEntry()</c>
- /// with the given <c>fileName</c> and stream.
- /// </para>
- ///
- /// <para>
- /// The stream must be open and readable during the call to
- /// <c>ZipFile.Save</c>. You can dispense the stream on a just-in-time basis
- /// using the <see cref="ZipEntry.InputStream"/> property. Check the
- /// documentation of that property for more information.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to the
- /// <c>ZipEntry</c> added.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddEntry(string, System.IO.Stream)"/>
- /// <seealso cref="ZipEntry.InputStream"/>
- ///
- /// <param name="entryName">
- /// The name, including any path, to use within the archive for the entry.
- /// </param>
- ///
- /// <param name="stream">The input stream from which to read file data.</param>
- /// <returns>The <c>ZipEntry</c> added.</returns>
- public ZipEntry UpdateEntry(string entryName, Stream stream)
- {
- RemoveEntryForUpdate(entryName);
- return AddEntry(entryName, stream);
- }
-
-
- private void RemoveEntryForUpdate(string entryName)
- {
- if (String.IsNullOrEmpty(entryName))
- throw new ArgumentNullException("entryName");
-
- string directoryPathInArchive = null;
- if (entryName.IndexOf('\\') != -1)
- {
- directoryPathInArchive = Path.GetDirectoryName(entryName);
- entryName = Path.GetFileName(entryName);
- }
- var key = ZipEntry.NameInArchive(entryName, directoryPathInArchive);
- if (this[key] != null)
- this.RemoveEntry(key);
- }
-
-
-
-
- /// <summary>
- /// Add an entry into the zip archive using the given filename and
- /// directory path within the archive, and the given content for the
- /// file. No file is created in the filesystem.
- /// </summary>
- ///
- /// <param name="byteContent">The data to use for the entry.</param>
- ///
- /// <param name="entryName">
- /// The name, including any path, to use within the archive for the entry.
- /// </param>
- ///
- /// <returns>The <c>ZipEntry</c> added.</returns>
- public ZipEntry AddEntry(string entryName, byte[] byteContent)
- {
- if (byteContent == null) throw new ArgumentException("bad argument", "byteContent");
- var ms = new MemoryStream(byteContent);
- return AddEntry(entryName, ms);
- }
-
-
- /// <summary>
- /// Updates the given entry in the <c>ZipFile</c>, using the given byte
- /// array as content for the entry.
- /// </summary>
- ///
- /// <remarks>
- /// Calling this method is equivalent to removing the <c>ZipEntry</c>
- /// for the given filename and directory path, if it exists, and then
- /// calling <see cref="AddEntry(String,byte[])" />. See the
- /// documentation for that method for further explanation.
- /// </remarks>
- ///
- /// <param name="entryName">
- /// The name, including any path, to use within the archive for the entry.
- /// </param>
- ///
- /// <param name="byteContent">The content to use for the <c>ZipEntry</c>.</param>
- ///
- /// <returns>The <c>ZipEntry</c> added.</returns>
- ///
- public ZipEntry UpdateEntry(string entryName, byte[] byteContent)
- {
- RemoveEntryForUpdate(entryName);
- return AddEntry(entryName, byteContent);
- }
-
-
-// private string DictionaryKeyForEntry(ZipEntry ze1)
-// {
-// var filename = SharedUtilities.NormalizePathForUseInZipFile(ze1.FileName);
-// return filename;
-// }
-
-
- /// <summary>
- /// Adds the contents of a filesystem directory to a Zip file archive.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// The name of the directory may be a relative path or a fully-qualified
- /// path. Any files within the named directory are added to the archive. Any
- /// subdirectories within the named directory are also added to the archive,
- /// recursively.
- /// </para>
- ///
- /// <para>
- /// Top-level entries in the named directory will appear as top-level entries
- /// in the zip archive. Entries in subdirectories in the named directory will
- /// result in entries in subdirectories in the zip archive.
- /// </para>
- ///
- /// <para>
- /// If you want the entries to appear in a containing directory in the zip
- /// archive itself, then you should call the AddDirectory() overload that
- /// allows you to explicitly specify a directory path for use in the archive.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to each
- /// ZipEntry added.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddItem(string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.AddFile(string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateDirectory(string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.AddDirectory(string, string)"/>
- ///
- /// <overloads>This method has 2 overloads.</overloads>
- ///
- /// <param name="directoryName">The name of the directory to add.</param>
- /// <returns>The <c>ZipEntry</c> added.</returns>
- public ZipEntry AddDirectory(string directoryName)
- {
- return AddDirectory(directoryName, null);
- }
-
-
- /// <summary>
- /// Adds the contents of a filesystem directory to a Zip file archive,
- /// overriding the path to be used for entries in the archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The name of the directory may be a relative path or a fully-qualified
- /// path. The add operation is recursive, so that any files or subdirectories
- /// within the name directory are also added to the archive.
- /// </para>
- ///
- /// <para>
- /// Top-level entries in the named directory will appear as top-level entries
- /// in the zip archive. Entries in subdirectories in the named directory will
- /// result in entries in subdirectories in the zip archive.
- /// </para>
- ///
- /// <para>
- /// For <c>ZipFile</c> properties including <see cref="Encryption"/>, <see
- /// cref="Password"/>, <see cref="SetCompression"/>, <see
- /// cref="ProvisionalAlternateEncoding"/>, <see cref="ExtractExistingFile"/>,
- /// <see cref="ZipErrorAction"/>, and <see cref="CompressionLevel"/>, their
- /// respective values at the time of this call will be applied to each
- /// ZipEntry added.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// <para>
- /// In this code, calling the ZipUp() method with a value of "c:\reports" for
- /// the directory parameter will result in a zip file structure in which all
- /// entries are contained in a toplevel "reports" directory.
- /// </para>
- ///
- /// <code lang="C#">
- /// public void ZipUp(string targetZip, string directory)
- /// {
- /// using (var zip = new ZipFile())
- /// {
- /// zip.AddDirectory(directory, System.IO.Path.GetFileName(directory));
- /// zip.Save(targetZip);
- /// }
- /// }
- /// </code>
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddItem(string, string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.AddFile(string, string)"/>
- /// <seealso cref="Ionic.Zip.ZipFile.UpdateDirectory(string, string)"/>
- ///
- /// <param name="directoryName">The name of the directory to add.</param>
- ///
- /// <param name="directoryPathInArchive">
- /// Specifies a directory path to use to override any path in the
- /// DirectoryName. This path may, or may not, correspond to a real directory
- /// in the current filesystem. If the zip is later extracted, this is the
- /// path used for the extracted file or directory. Passing <c>null</c>
- /// (<c>Nothing</c> in VB) or the empty string ("") will insert the items at
- /// the root path within the archive.
- /// </param>
- ///
- /// <returns>The <c>ZipEntry</c> added.</returns>
- public ZipEntry AddDirectory(string directoryName, string directoryPathInArchive)
- {
- return AddOrUpdateDirectoryImpl(directoryName, directoryPathInArchive, AddOrUpdateAction.AddOnly);
- }
-
-
- /// <summary>
- /// Creates a directory in the zip archive.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// Use this when you want to create a directory in the archive but there is
- /// no corresponding filesystem representation for that directory.
- /// </para>
- ///
- /// <para>
- /// You will probably not need to do this in your code. One of the only times
- /// you will want to do this is if you want an empty directory in the zip
- /// archive. The reason: if you add a file to a zip archive that is stored
- /// within a multi-level directory, all of the directory tree is implicitly
- /// created in the zip archive.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="directoryNameInArchive">
- /// The name of the directory to create in the archive.
- /// </param>
- /// <returns>The <c>ZipEntry</c> added.</returns>
- public ZipEntry AddDirectoryByName(string directoryNameInArchive)
- {
- // workitem 9073
- ZipEntry dir = ZipEntry.CreateFromNothing(directoryNameInArchive);
- dir._container = new ZipContainer(this);
- dir.MarkAsDirectory();
- dir.AlternateEncoding = this.AlternateEncoding; // workitem 8984
- dir.AlternateEncodingUsage = this.AlternateEncodingUsage;
- dir.SetEntryTimes(DateTime.Now,DateTime.Now,DateTime.Now);
- dir.EmitTimesInWindowsFormatWhenSaving = _emitNtfsTimes;
- dir.EmitTimesInUnixFormatWhenSaving = _emitUnixTimes;
- dir._Source = ZipEntrySource.Stream;
- //string key = DictionaryKeyForEntry(dir);
- InternalAddEntry(dir.FileName,dir);
- AfterAddEntry(dir);
- return dir;
- }
-
-
-
- private ZipEntry AddOrUpdateDirectoryImpl(string directoryName,
- string rootDirectoryPathInArchive,
- AddOrUpdateAction action)
- {
- if (rootDirectoryPathInArchive == null)
- {
- rootDirectoryPathInArchive = "";
- }
-
- return AddOrUpdateDirectoryImpl(directoryName, rootDirectoryPathInArchive, action, true, 0);
- }
-
-
- internal void InternalAddEntry(String name, ZipEntry entry)
- {
- _entries.Add(name, entry);
- _zipEntriesAsList = null;
- _contentsChanged = true;
- }
-
-
-
- private ZipEntry AddOrUpdateDirectoryImpl(string directoryName,
- string rootDirectoryPathInArchive,
- AddOrUpdateAction action,
- bool recurse,
- int level)
- {
- if (Verbose)
- StatusMessageTextWriter.WriteLine("{0} {1}...",
- (action == AddOrUpdateAction.AddOnly) ? "adding" : "Adding or updating",
- directoryName);
-
- if (level == 0)
- {
- _addOperationCanceled = false;
- OnAddStarted();
- }
-
- // workitem 13371
- if (_addOperationCanceled)
- return null;
-
- string dirForEntries = rootDirectoryPathInArchive;
- ZipEntry baseDir = null;
-
- if (level > 0)
- {
- int f = directoryName.Length;
- for (int i = level; i > 0; i--)
- f = directoryName.LastIndexOfAny("/\\".ToCharArray(), f - 1, f - 1);
-
- dirForEntries = directoryName.Substring(f + 1);
- dirForEntries = Path.Combine(rootDirectoryPathInArchive, dirForEntries);
- }
-
- // if not top level, or if the root is non-empty, then explicitly add the directory
- if (level > 0 || rootDirectoryPathInArchive != "")
- {
- baseDir = ZipEntry.CreateFromFile(directoryName, dirForEntries);
- baseDir._container = new ZipContainer(this);
- baseDir.AlternateEncoding = this.AlternateEncoding; // workitem 6410
- baseDir.AlternateEncodingUsage = this.AlternateEncodingUsage;
- baseDir.MarkAsDirectory();
- baseDir.EmitTimesInWindowsFormatWhenSaving = _emitNtfsTimes;
- baseDir.EmitTimesInUnixFormatWhenSaving = _emitUnixTimes;
-
- // add the directory only if it does not exist.
- // It's not an error if it already exists.
- if (!_entries.ContainsKey(baseDir.FileName))
- {
- InternalAddEntry(baseDir.FileName,baseDir);
- AfterAddEntry(baseDir);
- }
- dirForEntries = baseDir.FileName;
- }
-
- if (!_addOperationCanceled)
- {
-
- String[] filenames = Directory.GetFiles(directoryName);
-
- if (recurse)
- {
- // add the files:
- foreach (String filename in filenames)
- {
- if (_addOperationCanceled) break;
- if (action == AddOrUpdateAction.AddOnly)
- AddFile(filename, dirForEntries);
- else
- UpdateFile(filename, dirForEntries);
- }
-
- if (!_addOperationCanceled)
- {
- // add the subdirectories:
- String[] dirnames = Directory.GetDirectories(directoryName);
- foreach (String dir in dirnames)
- {
- // workitem 8617: Optionally traverse reparse points
-#if SILVERLIGHT
-#elif NETCF
- FileAttributes fileAttrs = (FileAttributes) NetCfFile.GetAttributes(dir);
-#else
- FileAttributes fileAttrs = System.IO.File.GetAttributes(dir);
-#endif
- if (this.AddDirectoryWillTraverseReparsePoints
-#if !SILVERLIGHT
- || ((fileAttrs & FileAttributes.ReparsePoint) == 0)
-#endif
- )
- AddOrUpdateDirectoryImpl(dir, rootDirectoryPathInArchive, action, recurse, level + 1);
-
- }
-
- }
- }
- }
-
- if (level == 0)
- OnAddCompleted();
-
- return baseDir;
- }
-
- }
-
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipFile.Check.cs b/EPPlus/Packaging/DotNetZip/ZipFile.Check.cs
deleted file mode 100644
index 3870556..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipFile.Check.cs
+++ /dev/null
@@ -1,352 +0,0 @@
-// ZipFile.Check.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009-2011 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-July-31 14:40:50>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the methods for doing Checks on zip files.
-// These are not necessary to include in the Reduced or CF
-// version of the library.
-//
-// ------------------------------------------------------------------
-//
-
-
-using System;
-using System.IO;
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- internal partial class ZipFile
- {
- /// <summary>
- /// Checks a zip file to see if its directory is consistent.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// In cases of data error, the directory within a zip file can get out
- /// of synch with the entries in the zip file. This method checks the
- /// given zip file and returns true if this has occurred.
- /// </para>
- ///
- /// <para> This method may take a long time to run for large zip files. </para>
- ///
- /// <para>
- /// This method is not supported in the Reduced or Compact Framework
- /// versions of DotNetZip.
- /// </para>
- ///
- /// <para>
- /// Developers using COM can use the <see
- /// cref="ComHelper.CheckZip(String)">ComHelper.CheckZip(String)</see>
- /// method.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="zipFileName">The filename to of the zip file to check.</param>
- ///
- /// <returns>true if the named zip file checks OK. Otherwise, false. </returns>
- ///
- /// <seealso cref="FixZipDirectory(string)"/>
- /// <seealso cref="CheckZip(string,bool,System.IO.TextWriter)"/>
- public static bool CheckZip(string zipFileName)
- {
- return CheckZip(zipFileName, false, null);
- }
-
-
- /// <summary>
- /// Checks a zip file to see if its directory is consistent,
- /// and optionally fixes the directory if necessary.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// In cases of data error, the directory within a zip file can get out of
- /// synch with the entries in the zip file. This method checks the given
- /// zip file, and returns true if this has occurred. It also optionally
- /// fixes the zipfile, saving the fixed copy in <em>Name</em>_Fixed.zip.
- /// </para>
- ///
- /// <para>
- /// This method may take a long time to run for large zip files. It
- /// will take even longer if the file actually needs to be fixed, and if
- /// <c>fixIfNecessary</c> is true.
- /// </para>
- ///
- /// <para>
- /// This method is not supported in the Reduced or Compact
- /// Framework versions of DotNetZip.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="zipFileName">The filename to of the zip file to check.</param>
- ///
- /// <param name="fixIfNecessary">If true, the method will fix the zip file if
- /// necessary.</param>
- ///
- /// <param name="writer">
- /// a TextWriter in which messages generated while checking will be written.
- /// </param>
- ///
- /// <returns>true if the named zip is OK; false if the file needs to be fixed.</returns>
- ///
- /// <seealso cref="CheckZip(string)"/>
- /// <seealso cref="FixZipDirectory(string)"/>
- public static bool CheckZip(string zipFileName, bool fixIfNecessary,
- TextWriter writer)
-
- {
- ZipFile zip1 = null, zip2 = null;
- bool isOk = true;
- try
- {
- zip1 = new ZipFile();
- zip1.FullScan = true;
- zip1.Initialize(zipFileName);
-
- zip2 = ZipFile.Read(zipFileName);
-
- foreach (var e1 in zip1)
- {
- foreach (var e2 in zip2)
- {
- if (e1.FileName == e2.FileName)
- {
- if (e1._RelativeOffsetOfLocalHeader != e2._RelativeOffsetOfLocalHeader)
- {
- isOk = false;
- if (writer != null)
- writer.WriteLine("{0}: mismatch in RelativeOffsetOfLocalHeader (0x{1:X16} != 0x{2:X16})",
- e1.FileName, e1._RelativeOffsetOfLocalHeader,
- e2._RelativeOffsetOfLocalHeader);
- }
- if (e1._CompressedSize != e2._CompressedSize)
- {
- isOk = false;
- if (writer != null)
- writer.WriteLine("{0}: mismatch in CompressedSize (0x{1:X16} != 0x{2:X16})",
- e1.FileName, e1._CompressedSize,
- e2._CompressedSize);
- }
- if (e1._UncompressedSize != e2._UncompressedSize)
- {
- isOk = false;
- if (writer != null)
- writer.WriteLine("{0}: mismatch in UncompressedSize (0x{1:X16} != 0x{2:X16})",
- e1.FileName, e1._UncompressedSize,
- e2._UncompressedSize);
- }
- if (e1.CompressionMethod != e2.CompressionMethod)
- {
- isOk = false;
- if (writer != null)
- writer.WriteLine("{0}: mismatch in CompressionMethod (0x{1:X4} != 0x{2:X4})",
- e1.FileName, e1.CompressionMethod,
- e2.CompressionMethod);
- }
- if (e1.Crc != e2.Crc)
- {
- isOk = false;
- if (writer != null)
- writer.WriteLine("{0}: mismatch in Crc32 (0x{1:X4} != 0x{2:X4})",
- e1.FileName, e1.Crc,
- e2.Crc);
- }
-
- // found a match, so stop the inside loop
- break;
- }
- }
- }
-
- zip2.Dispose();
- zip2 = null;
-
- if (!isOk && fixIfNecessary)
- {
- string newFileName = Path.GetFileNameWithoutExtension(zipFileName);
- newFileName = System.String.Format("{0}_fixed.zip", newFileName);
- zip1.Save(newFileName);
- }
- }
- finally
- {
- if (zip1 != null) zip1.Dispose();
- if (zip2 != null) zip2.Dispose();
- }
- return isOk;
- }
-
-
-
- /// <summary>
- /// Rewrite the directory within a zipfile.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// In cases of data error, the directory in a zip file can get out of
- /// synch with the entries in the zip file. This method attempts to fix
- /// the zip file if this has occurred.
- /// </para>
- ///
- /// <para> This can take a long time for large zip files. </para>
- ///
- /// <para> This won't work if the zip file uses a non-standard
- /// code page - neither IBM437 nor UTF-8. </para>
- ///
- /// <para>
- /// This method is not supported in the Reduced or Compact Framework
- /// versions of DotNetZip.
- /// </para>
- ///
- /// <para>
- /// Developers using COM can use the <see
- /// cref="ComHelper.FixZipDirectory(String)">ComHelper.FixZipDirectory(String)</see>
- /// method.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="zipFileName">The filename to of the zip file to fix.</param>
- ///
- /// <seealso cref="CheckZip(string)"/>
- /// <seealso cref="CheckZip(string,bool,System.IO.TextWriter)"/>
- public static void FixZipDirectory(string zipFileName)
- {
- using (var zip = new ZipFile())
- {
- zip.FullScan = true;
- zip.Initialize(zipFileName);
- zip.Save(zipFileName);
- }
- }
-
-
-
- /// <summary>
- /// Verify the password on a zip file.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Keep in mind that passwords in zipfiles are applied to
- /// zip entries, not to the entire zip file. So testing a
- /// zipfile for a particular password doesn't work in the
- /// general case. On the other hand, it's often the case
- /// that a single password will be used on all entries in a
- /// zip file. This method works for that case.
- /// </para>
- /// <para>
- /// There is no way to check a password without doing the
- /// decryption. So this code decrypts and extracts the given
- /// zipfile into <see cref="System.IO.Stream.Null"/>
- /// </para>
- /// </remarks>
- ///
- /// <param name="zipFileName">The filename to of the zip file to fix.</param>
- ///
- /// <param name="password">The password to check.</param>
- ///
- /// <returns>a bool indicating whether the password matches.</returns>
- public static bool CheckZipPassword(string zipFileName, string password)
- {
- // workitem 13664
- bool success = false;
- try
- {
- using (ZipFile zip1 = ZipFile.Read(zipFileName))
- {
- foreach (var e in zip1)
- {
- if (!e.IsDirectory && e.UsesEncryption)
- {
- e.ExtractWithPassword(System.IO.Stream.Null, password);
- }
- }
- }
- success = true;
- }
- catch(Ionic.Zip.BadPasswordException) { }
- return success;
- }
-
-
- /// <summary>
- /// Provides a human-readable string with information about the ZipFile.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The information string contains 10 lines or so, about each ZipEntry,
- /// describing whether encryption is in use, the compressed and uncompressed
- /// length of the entry, the offset of the entry, and so on. As a result the
- /// information string can be very long for zip files that contain many
- /// entries.
- /// </para>
- /// <para>
- /// This information is mostly useful for diagnostic purposes.
- /// </para>
- /// </remarks>
- public string Info
- {
- get
- {
- var builder = new System.Text.StringBuilder();
- builder.Append(string.Format(" ZipFile: {0}\n", this.Name));
- if (!string.IsNullOrEmpty(this._Comment))
- {
- builder.Append(string.Format(" Comment: {0}\n", this._Comment));
- }
- if (this._versionMadeBy != 0)
- {
- builder.Append(string.Format(" version made by: 0x{0:X4}\n", this._versionMadeBy));
- }
- if (this._versionNeededToExtract != 0)
- {
- builder.Append(string.Format("needed to extract: 0x{0:X4}\n", this._versionNeededToExtract));
- }
-
- builder.Append(string.Format(" uses ZIP64: {0}\n", this.InputUsesZip64));
-
- builder.Append(string.Format(" disk with CD: {0}\n", this._diskNumberWithCd));
- if (this._OffsetOfCentralDirectory == 0xFFFFFFFF)
- builder.Append(string.Format(" CD64 offset: 0x{0:X16}\n", this._OffsetOfCentralDirectory64));
- else
- builder.Append(string.Format(" CD offset: 0x{0:X8}\n", this._OffsetOfCentralDirectory));
- builder.Append("\n");
- foreach (ZipEntry entry in this._entries.Values)
- {
- builder.Append(entry.Info);
- }
- return builder.ToString();
- }
- }
-
-
- }
-
-}
\ No newline at end of file
diff --git a/EPPlus/Packaging/DotNetZip/ZipFile.Events.cs b/EPPlus/Packaging/DotNetZip/ZipFile.Events.cs
deleted file mode 100644
index 573e076..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipFile.Events.cs
+++ /dev/null
@@ -1,1219 +0,0 @@
-// ZipFile.Events.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2008, 2009, 2011 Dino Chiesa .
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-July-09 08:42:35>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the methods for issuing events from the ZipFile class.
-//
-// ------------------------------------------------------------------
-//
-
-using System;
-using System.IO;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- internal partial class ZipFile
- {
- private string ArchiveNameForEvent
- {
- get
- {
- return (_name != null) ? _name : "(stream)";
- }
- }
-
- #region Save
-
- /// <summary>
- /// An event handler invoked when a Save() starts, before and after each
- /// entry has been written to the archive, when a Save() completes, and
- /// during other Save events.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Depending on the particular event, different properties on the <see
- /// cref="SaveProgressEventArgs"/> parameter are set. The following
- /// table summarizes the available EventTypes and the conditions under
- /// which this event handler is invoked with a
- /// <c>SaveProgressEventArgs</c> with the given EventType.
- /// </para>
- ///
- /// <list type="table">
- /// <listheader>
- /// <term>value of EntryType</term>
- /// <description>Meaning and conditions</description>
- /// </listheader>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Saving_Started</term>
- /// <description>Fired when ZipFile.Save() begins.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Saving_BeforeSaveEntry</term>
- /// <description>
- /// Fired within ZipFile.Save(), just before writing data for each
- /// particular entry.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Saving_AfterSaveEntry</term>
- /// <description>
- /// Fired within ZipFile.Save(), just after having finished writing data
- /// for each particular entry.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Saving_Completed</term>
- /// <description>Fired when ZipFile.Save() has completed.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Saving_AfterSaveTempArchive</term>
- /// <description>
- /// Fired after the temporary file has been created. This happens only
- /// when saving to a disk file. This event will not be invoked when
- /// saving to a stream.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Saving_BeforeRenameTempArchive</term>
- /// <description>
- /// Fired just before renaming the temporary file to the permanent
- /// location. This happens only when saving to a disk file. This event
- /// will not be invoked when saving to a stream.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Saving_AfterRenameTempArchive</term>
- /// <description>
- /// Fired just after renaming the temporary file to the permanent
- /// location. This happens only when saving to a disk file. This event
- /// will not be invoked when saving to a stream.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Saving_AfterCompileSelfExtractor</term>
- /// <description>
- /// Fired after a self-extracting archive has finished compiling. This
- /// EventType is used only within SaveSelfExtractor().
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Saving_BytesRead</term>
- /// <description>
- /// Set during the save of a particular entry, to update progress of the
- /// Save(). When this EventType is set, the BytesTransferred is the
- /// number of bytes that have been read from the source stream. The
- /// TotalBytesToTransfer is the number of bytes in the uncompressed
- /// file.
- /// </description>
- /// </item>
- ///
- /// </list>
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example uses an anonymous method to handle the
- /// SaveProgress event, by updating a progress bar.
- ///
- /// <code lang="C#">
- /// progressBar1.Value = 0;
- /// progressBar1.Max = listbox1.Items.Count;
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// // listbox1 contains a list of filenames
- /// zip.AddFiles(listbox1.Items);
- ///
- /// // do the progress bar:
- /// zip.SaveProgress += (sender, e) => {
- /// if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry) {
- /// progressBar1.PerformStep();
- /// }
- /// };
- ///
- /// zip.Save(fs);
- /// }
- /// </code>
- /// </example>
- ///
- /// <example>
- /// This example uses a named method as the
- /// <c>SaveProgress</c> event handler, to update the user, in a
- /// console-based application.
- ///
- /// <code lang="C#">
- /// static bool justHadByteUpdate= false;
- /// public static void SaveProgress(object sender, SaveProgressEventArgs e)
- /// {
- /// if (e.EventType == ZipProgressEventType.Saving_Started)
- /// Console.WriteLine("Saving: {0}", e.ArchiveName);
- ///
- /// else if (e.EventType == ZipProgressEventType.Saving_Completed)
- /// {
- /// justHadByteUpdate= false;
- /// Console.WriteLine();
- /// Console.WriteLine("Done: {0}", e.ArchiveName);
- /// }
- ///
- /// else if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry)
- /// {
- /// if (justHadByteUpdate)
- /// Console.WriteLine();
- /// Console.WriteLine(" Writing: {0} ({1}/{2})",
- /// e.CurrentEntry.FileName, e.EntriesSaved, e.EntriesTotal);
- /// justHadByteUpdate= false;
- /// }
- ///
- /// else if (e.EventType == ZipProgressEventType.Saving_EntryBytesRead)
- /// {
- /// if (justHadByteUpdate)
- /// Console.SetCursorPosition(0, Console.CursorTop);
- /// Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer,
- /// e.BytesTransferred / (0.01 * e.TotalBytesToTransfer ));
- /// justHadByteUpdate= true;
- /// }
- /// }
- ///
- /// public static ZipUp(string targetZip, string directory)
- /// {
- /// using (var zip = new ZipFile()) {
- /// zip.SaveProgress += SaveProgress;
- /// zip.AddDirectory(directory);
- /// zip.Save(targetZip);
- /// }
- /// }
- ///
- /// </code>
- ///
- /// <code lang="VB">
- /// Public Sub ZipUp(ByVal targetZip As String, ByVal directory As String)
- /// Using zip As ZipFile = New ZipFile
- /// AddHandler zip.SaveProgress, AddressOf MySaveProgress
- /// zip.AddDirectory(directory)
- /// zip.Save(targetZip)
- /// End Using
- /// End Sub
- ///
- /// Private Shared justHadByteUpdate As Boolean = False
- ///
- /// Public Shared Sub MySaveProgress(ByVal sender As Object, ByVal e As SaveProgressEventArgs)
- /// If (e.EventType Is ZipProgressEventType.Saving_Started) Then
- /// Console.WriteLine("Saving: {0}", e.ArchiveName)
- ///
- /// ElseIf (e.EventType Is ZipProgressEventType.Saving_Completed) Then
- /// justHadByteUpdate = False
- /// Console.WriteLine
- /// Console.WriteLine("Done: {0}", e.ArchiveName)
- ///
- /// ElseIf (e.EventType Is ZipProgressEventType.Saving_BeforeWriteEntry) Then
- /// If justHadByteUpdate Then
- /// Console.WriteLine
- /// End If
- /// Console.WriteLine(" Writing: {0} ({1}/{2})", e.CurrentEntry.FileName, e.EntriesSaved, e.EntriesTotal)
- /// justHadByteUpdate = False
- ///
- /// ElseIf (e.EventType Is ZipProgressEventType.Saving_EntryBytesRead) Then
- /// If justHadByteUpdate Then
- /// Console.SetCursorPosition(0, Console.CursorTop)
- /// End If
- /// Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, _
- /// e.TotalBytesToTransfer, _
- /// (CDbl(e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer)))
- /// justHadByteUpdate = True
- /// End If
- /// End Sub
- /// </code>
- /// </example>
- ///
- /// <example>
- ///
- /// This is a more complete example of using the SaveProgress
- /// events in a Windows Forms application, with a
- /// Thread object.
- ///
- /// <code lang="C#">
- /// delegate void SaveEntryProgress(SaveProgressEventArgs e);
- /// delegate void ButtonClick(object sender, EventArgs e);
- ///
- /// internal class WorkerOptions
- /// {
- /// public string ZipName;
- /// public string Folder;
- /// public string Encoding;
- /// public string Comment;
- /// public int ZipFlavor;
- /// public Zip64Option Zip64;
- /// }
- ///
- /// private int _progress2MaxFactor;
- /// private bool _saveCanceled;
- /// private long _totalBytesBeforeCompress;
- /// private long _totalBytesAfterCompress;
- /// private Thread _workerThread;
- ///
- ///
- /// private void btnZipup_Click(object sender, EventArgs e)
- /// {
- /// KickoffZipup();
- /// }
- ///
- /// private void btnCancel_Click(object sender, EventArgs e)
- /// {
- /// if (this.lblStatus.InvokeRequired)
- /// {
- /// this.lblStatus.Invoke(new ButtonClick(this.btnCancel_Click), new object[] { sender, e });
- /// }
- /// else
- /// {
- /// _saveCanceled = true;
- /// lblStatus.Text = "Canceled...";
- /// ResetState();
- /// }
- /// }
- ///
- /// private void KickoffZipup()
- /// {
- /// _folderName = tbDirName.Text;
- ///
- /// if (_folderName == null || _folderName == "") return;
- /// if (this.tbZipName.Text == null || this.tbZipName.Text == "") return;
- ///
- /// // check for existence of the zip file:
- /// if (System.IO.File.Exists(this.tbZipName.Text))
- /// {
- /// var dlgResult = MessageBox.Show(String.Format("The file you have specified ({0}) already exists." +
- /// " Do you want to overwrite this file?", this.tbZipName.Text),
- /// "Confirmation is Required", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
- /// if (dlgResult != DialogResult.Yes) return;
- /// System.IO.File.Delete(this.tbZipName.Text);
- /// }
- ///
- /// _saveCanceled = false;
- /// _nFilesCompleted = 0;
- /// _totalBytesAfterCompress = 0;
- /// _totalBytesBeforeCompress = 0;
- /// this.btnOk.Enabled = false;
- /// this.btnOk.Text = "Zipping...";
- /// this.btnCancel.Enabled = true;
- /// lblStatus.Text = "Zipping...";
- ///
- /// var options = new WorkerOptions
- /// {
- /// ZipName = this.tbZipName.Text,
- /// Folder = _folderName,
- /// Encoding = "ibm437"
- /// };
- ///
- /// if (this.comboBox1.SelectedIndex != 0)
- /// {
- /// options.Encoding = this.comboBox1.SelectedItem.ToString();
- /// }
- ///
- /// if (this.radioFlavorSfxCmd.Checked)
- /// options.ZipFlavor = 2;
- /// else if (this.radioFlavorSfxGui.Checked)
- /// options.ZipFlavor = 1;
- /// else options.ZipFlavor = 0;
- ///
- /// if (this.radioZip64AsNecessary.Checked)
- /// options.Zip64 = Zip64Option.AsNecessary;
- /// else if (this.radioZip64Always.Checked)
- /// options.Zip64 = Zip64Option.Always;
- /// else options.Zip64 = Zip64Option.Never;
- ///
- /// options.Comment = String.Format("Encoding:{0} || Flavor:{1} || ZIP64:{2}\r\nCreated at {3} || {4}\r\n",
- /// options.Encoding,
- /// FlavorToString(options.ZipFlavor),
- /// options.Zip64.ToString(),
- /// System.DateTime.Now.ToString("yyyy-MMM-dd HH:mm:ss"),
- /// this.Text);
- ///
- /// if (this.tbComment.Text != TB_COMMENT_NOTE)
- /// options.Comment += this.tbComment.Text;
- ///
- /// _workerThread = new Thread(this.DoSave);
- /// _workerThread.Name = "Zip Saver thread";
- /// _workerThread.Start(options);
- /// this.Cursor = Cursors.WaitCursor;
- /// }
- ///
- ///
- /// private void DoSave(Object p)
- /// {
- /// WorkerOptions options = p as WorkerOptions;
- /// try
- /// {
- /// using (var zip1 = new ZipFile())
- /// {
- /// zip1.ProvisionalAlternateEncoding = System.Text.Encoding.GetEncoding(options.Encoding);
- /// zip1.Comment = options.Comment;
- /// zip1.AddDirectory(options.Folder);
- /// _entriesToZip = zip1.EntryFileNames.Count;
- /// SetProgressBars();
- /// zip1.SaveProgress += this.zip1_SaveProgress;
- ///
- /// zip1.UseZip64WhenSaving = options.Zip64;
- ///
- /// if (options.ZipFlavor == 1)
- /// zip1.SaveSelfExtractor(options.ZipName, SelfExtractorFlavor.WinFormsApplication);
- /// else if (options.ZipFlavor == 2)
- /// zip1.SaveSelfExtractor(options.ZipName, SelfExtractorFlavor.ConsoleApplication);
- /// else
- /// zip1.Save(options.ZipName);
- /// }
- /// }
- /// catch (System.Exception exc1)
- /// {
- /// MessageBox.Show(String.Format("Exception while zipping: {0}", exc1.Message));
- /// btnCancel_Click(null, null);
- /// }
- /// }
- ///
- ///
- ///
- /// void zip1_SaveProgress(object sender, SaveProgressEventArgs e)
- /// {
- /// switch (e.EventType)
- /// {
- /// case ZipProgressEventType.Saving_AfterWriteEntry:
- /// StepArchiveProgress(e);
- /// break;
- /// case ZipProgressEventType.Saving_EntryBytesRead:
- /// StepEntryProgress(e);
- /// break;
- /// case ZipProgressEventType.Saving_Completed:
- /// SaveCompleted();
- /// break;
- /// case ZipProgressEventType.Saving_AfterSaveTempArchive:
- /// // this event only occurs when saving an SFX file
- /// TempArchiveSaved();
- /// break;
- /// }
- /// if (_saveCanceled)
- /// e.Cancel = true;
- /// }
- ///
- ///
- ///
- /// private void StepArchiveProgress(SaveProgressEventArgs e)
- /// {
- /// if (this.progressBar1.InvokeRequired)
- /// {
- /// this.progressBar1.Invoke(new SaveEntryProgress(this.StepArchiveProgress), new object[] { e });
- /// }
- /// else
- /// {
- /// if (!_saveCanceled)
- /// {
- /// _nFilesCompleted++;
- /// this.progressBar1.PerformStep();
- /// _totalBytesAfterCompress += e.CurrentEntry.CompressedSize;
- /// _totalBytesBeforeCompress += e.CurrentEntry.UncompressedSize;
- ///
- /// // reset the progress bar for the entry:
- /// this.progressBar2.Value = this.progressBar2.Maximum = 1;
- ///
- /// this.Update();
- /// }
- /// }
- /// }
- ///
- ///
- /// private void StepEntryProgress(SaveProgressEventArgs e)
- /// {
- /// if (this.progressBar2.InvokeRequired)
- /// {
- /// this.progressBar2.Invoke(new SaveEntryProgress(this.StepEntryProgress), new object[] { e });
- /// }
- /// else
- /// {
- /// if (!_saveCanceled)
- /// {
- /// if (this.progressBar2.Maximum == 1)
- /// {
- /// // reset
- /// Int64 max = e.TotalBytesToTransfer;
- /// _progress2MaxFactor = 0;
- /// while (max > System.Int32.MaxValue)
- /// {
- /// max /= 2;
- /// _progress2MaxFactor++;
- /// }
- /// this.progressBar2.Maximum = (int)max;
- /// lblStatus.Text = String.Format("{0} of {1} files...({2})",
- /// _nFilesCompleted + 1, _entriesToZip, e.CurrentEntry.FileName);
- /// }
- ///
- /// int xferred = e.BytesTransferred >> _progress2MaxFactor;
- ///
- /// this.progressBar2.Value = (xferred >= this.progressBar2.Maximum)
- /// ? this.progressBar2.Maximum
- /// : xferred;
- ///
- /// this.Update();
- /// }
- /// }
- /// }
- ///
- /// private void SaveCompleted()
- /// {
- /// if (this.lblStatus.InvokeRequired)
- /// {
- /// this.lblStatus.Invoke(new MethodInvoker(this.SaveCompleted));
- /// }
- /// else
- /// {
- /// lblStatus.Text = String.Format("Done, Compressed {0} files, {1:N0}% of original.",
- /// _nFilesCompleted, (100.00 * _totalBytesAfterCompress) / _totalBytesBeforeCompress);
- /// ResetState();
- /// }
- /// }
- ///
- /// private void ResetState()
- /// {
- /// this.btnCancel.Enabled = false;
- /// this.btnOk.Enabled = true;
- /// this.btnOk.Text = "Zip it!";
- /// this.progressBar1.Value = 0;
- /// this.progressBar2.Value = 0;
- /// this.Cursor = Cursors.Default;
- /// if (!_workerThread.IsAlive)
- /// _workerThread.Join();
- /// }
- /// </code>
- ///
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.ReadProgress"/>
- /// <seealso cref="Ionic.Zip.ZipFile.AddProgress"/>
- /// <seealso cref="Ionic.Zip.ZipFile.ExtractProgress"/>
- internal event EventHandler<SaveProgressEventArgs> SaveProgress;
-
-
- internal bool OnSaveBlock(ZipEntry entry, Int64 bytesXferred, Int64 totalBytesToXfer)
- {
- EventHandler<SaveProgressEventArgs> sp = SaveProgress;
- if (sp != null)
- {
- var e = SaveProgressEventArgs.ByteUpdate(ArchiveNameForEvent, entry,
- bytesXferred, totalBytesToXfer);
- sp(this, e);
- if (e.Cancel)
- _saveOperationCanceled = true;
- }
- return _saveOperationCanceled;
- }
-
- private void OnSaveEntry(int current, ZipEntry entry, bool before)
- {
- EventHandler<SaveProgressEventArgs> sp = SaveProgress;
- if (sp != null)
- {
- var e = new SaveProgressEventArgs(ArchiveNameForEvent, before, _entries.Count, current, entry);
- sp(this, e);
- if (e.Cancel)
- _saveOperationCanceled = true;
- }
- }
-
- private void OnSaveEvent(ZipProgressEventType eventFlavor)
- {
- EventHandler<SaveProgressEventArgs> sp = SaveProgress;
- if (sp != null)
- {
- var e = new SaveProgressEventArgs(ArchiveNameForEvent, eventFlavor);
- sp(this, e);
- if (e.Cancel)
- _saveOperationCanceled = true;
- }
- }
-
- private void OnSaveStarted()
- {
- EventHandler<SaveProgressEventArgs> sp = SaveProgress;
- if (sp != null)
- {
- var e = SaveProgressEventArgs.Started(ArchiveNameForEvent);
- sp(this, e);
- if (e.Cancel)
- _saveOperationCanceled = true;
- }
- }
- private void OnSaveCompleted()
- {
- EventHandler<SaveProgressEventArgs> sp = SaveProgress;
- if (sp != null)
- {
- var e = SaveProgressEventArgs.Completed(ArchiveNameForEvent);
- sp(this, e);
- }
- }
- #endregion
-
-
- #region Read
- /// <summary>
- /// An event handler invoked before, during, and after the reading of a zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Depending on the particular event being signaled, different properties on the
- /// <see cref="ReadProgressEventArgs"/> parameter are set. The following table
- /// summarizes the available EventTypes and the conditions under which this
- /// event handler is invoked with a <c>ReadProgressEventArgs</c> with the given EventType.
- /// </para>
- ///
- /// <list type="table">
- /// <listheader>
- /// <term>value of EntryType</term>
- /// <description>Meaning and conditions</description>
- /// </listheader>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Reading_Started</term>
- /// <description>Fired just as ZipFile.Read() begins. Meaningful properties: ArchiveName.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Reading_Completed</term>
- /// <description>Fired when ZipFile.Read() has completed. Meaningful properties: ArchiveName.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Reading_ArchiveBytesRead</term>
- /// <description>Fired while reading, updates the number of bytes read for the entire archive.
- /// Meaningful properties: ArchiveName, CurrentEntry, BytesTransferred, TotalBytesToTransfer.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Reading_BeforeReadEntry</term>
- /// <description>Indicates an entry is about to be read from the archive.
- /// Meaningful properties: ArchiveName, EntriesTotal.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Reading_AfterReadEntry</term>
- /// <description>Indicates an entry has just been read from the archive.
- /// Meaningful properties: ArchiveName, EntriesTotal, CurrentEntry.
- /// </description>
- /// </item>
- ///
- /// </list>
- /// </remarks>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.SaveProgress"/>
- /// <seealso cref="Ionic.Zip.ZipFile.AddProgress"/>
- /// <seealso cref="Ionic.Zip.ZipFile.ExtractProgress"/>
- internal event EventHandler<ReadProgressEventArgs> ReadProgress;
-
- private void OnReadStarted()
- {
- EventHandler<ReadProgressEventArgs> rp = ReadProgress;
- if (rp != null)
- {
- var e = ReadProgressEventArgs.Started(ArchiveNameForEvent);
- rp(this, e);
- }
- }
-
- private void OnReadCompleted()
- {
- EventHandler<ReadProgressEventArgs> rp = ReadProgress;
- if (rp != null)
- {
- var e = ReadProgressEventArgs.Completed(ArchiveNameForEvent);
- rp(this, e);
- }
- }
-
- internal void OnReadBytes(ZipEntry entry)
- {
- EventHandler<ReadProgressEventArgs> rp = ReadProgress;
- if (rp != null)
- {
- var e = ReadProgressEventArgs.ByteUpdate(ArchiveNameForEvent,
- entry,
- ReadStream.Position,
- LengthOfReadStream);
- rp(this, e);
- }
- }
-
- internal void OnReadEntry(bool before, ZipEntry entry)
- {
- EventHandler<ReadProgressEventArgs> rp = ReadProgress;
- if (rp != null)
- {
- ReadProgressEventArgs e = (before)
- ? ReadProgressEventArgs.Before(ArchiveNameForEvent, _entries.Count)
- : ReadProgressEventArgs.After(ArchiveNameForEvent, entry, _entries.Count);
- rp(this, e);
- }
- }
-
- private Int64 _lengthOfReadStream = -99;
- private Int64 LengthOfReadStream
- {
- get
- {
- if (_lengthOfReadStream == -99)
- {
- _lengthOfReadStream = (_ReadStreamIsOurs)
- ? SharedUtilities.GetFileLength(_name)
- : -1L;
- }
- return _lengthOfReadStream;
- }
- }
- #endregion
-
-
- #region Extract
- /// <summary>
- /// An event handler invoked before, during, and after extraction of
- /// entries in the zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Depending on the particular event, different properties on the <see
- /// cref="ExtractProgressEventArgs"/> parameter are set. The following
- /// table summarizes the available EventTypes and the conditions under
- /// which this event handler is invoked with a
- /// <c>ExtractProgressEventArgs</c> with the given EventType.
- /// </para>
- ///
- /// <list type="table">
- /// <listheader>
- /// <term>value of EntryType</term>
- /// <description>Meaning and conditions</description>
- /// </listheader>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Extracting_BeforeExtractAll</term>
- /// <description>
- /// Set when ExtractAll() begins. The ArchiveName, Overwrite, and
- /// ExtractLocation properties are meaningful.</description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Extracting_AfterExtractAll</term>
- /// <description>
- /// Set when ExtractAll() has completed. The ArchiveName, Overwrite,
- /// and ExtractLocation properties are meaningful.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Extracting_BeforeExtractEntry</term>
- /// <description>
- /// Set when an Extract() on an entry in the ZipFile has begun.
- /// Properties that are meaningful: ArchiveName, EntriesTotal,
- /// CurrentEntry, Overwrite, ExtractLocation, EntriesExtracted.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Extracting_AfterExtractEntry</term>
- /// <description>
- /// Set when an Extract() on an entry in the ZipFile has completed.
- /// Properties that are meaningful: ArchiveName, EntriesTotal,
- /// CurrentEntry, Overwrite, ExtractLocation, EntriesExtracted.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Extracting_EntryBytesWritten</term>
- /// <description>
- /// Set within a call to Extract() on an entry in the ZipFile, as data
- /// is extracted for the entry. Properties that are meaningful:
- /// ArchiveName, CurrentEntry, BytesTransferred, TotalBytesToTransfer.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite</term>
- /// <description>
- /// Set within a call to Extract() on an entry in the ZipFile, when the
- /// extraction would overwrite an existing file. This event type is used
- /// only when <c>ExtractExistingFileAction</c> on the <c>ZipFile</c> or
- /// <c>ZipEntry</c> is set to <c>InvokeExtractProgressEvent</c>.
- /// </description>
- /// </item>
- ///
- /// </list>
- ///
- /// </remarks>
- ///
- /// <example>
- /// <code>
- /// private static bool justHadByteUpdate = false;
- /// public static void ExtractProgress(object sender, ExtractProgressEventArgs e)
- /// {
- /// if(e.EventType == ZipProgressEventType.Extracting_EntryBytesWritten)
- /// {
- /// if (justHadByteUpdate)
- /// Console.SetCursorPosition(0, Console.CursorTop);
- ///
- /// Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer,
- /// e.BytesTransferred / (0.01 * e.TotalBytesToTransfer ));
- /// justHadByteUpdate = true;
- /// }
- /// else if(e.EventType == ZipProgressEventType.Extracting_BeforeExtractEntry)
- /// {
- /// if (justHadByteUpdate)
- /// Console.WriteLine();
- /// Console.WriteLine("Extracting: {0}", e.CurrentEntry.FileName);
- /// justHadByteUpdate= false;
- /// }
- /// }
- ///
- /// public static ExtractZip(string zipToExtract, string directory)
- /// {
- /// string TargetDirectory= "extract";
- /// using (var zip = ZipFile.Read(zipToExtract)) {
- /// zip.ExtractProgress += ExtractProgress;
- /// foreach (var e in zip1)
- /// {
- /// e.Extract(TargetDirectory, true);
- /// }
- /// }
- /// }
- ///
- /// </code>
- /// <code lang="VB">
- /// Public Shared Sub Main(ByVal args As String())
- /// Dim ZipToUnpack As String = "C1P3SML.zip"
- /// Dim TargetDir As String = "ExtractTest_Extract"
- /// Console.WriteLine("Extracting file {0} to {1}", ZipToUnpack, TargetDir)
- /// Using zip1 As ZipFile = ZipFile.Read(ZipToUnpack)
- /// AddHandler zip1.ExtractProgress, AddressOf MyExtractProgress
- /// Dim e As ZipEntry
- /// For Each e In zip1
- /// e.Extract(TargetDir, True)
- /// Next
- /// End Using
- /// End Sub
- ///
- /// Private Shared justHadByteUpdate As Boolean = False
- ///
- /// Public Shared Sub MyExtractProgress(ByVal sender As Object, ByVal e As ExtractProgressEventArgs)
- /// If (e.EventType = ZipProgressEventType.Extracting_EntryBytesWritten) Then
- /// If ExtractTest.justHadByteUpdate Then
- /// Console.SetCursorPosition(0, Console.CursorTop)
- /// End If
- /// Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, (CDbl(e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer)))
- /// ExtractTest.justHadByteUpdate = True
- /// ElseIf (e.EventType = ZipProgressEventType.Extracting_BeforeExtractEntry) Then
- /// If ExtractTest.justHadByteUpdate Then
- /// Console.WriteLine
- /// End If
- /// Console.WriteLine("Extracting: {0}", e.CurrentEntry.FileName)
- /// ExtractTest.justHadByteUpdate = False
- /// End If
- /// End Sub
- /// </code>
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.SaveProgress"/>
- /// <seealso cref="Ionic.Zip.ZipFile.ReadProgress"/>
- /// <seealso cref="Ionic.Zip.ZipFile.AddProgress"/>
- internal event EventHandler<ExtractProgressEventArgs> ExtractProgress;
-
-
-
- private void OnExtractEntry(int current, bool before, ZipEntry currentEntry, string path)
- {
- EventHandler<ExtractProgressEventArgs> ep = ExtractProgress;
- if (ep != null)
- {
- var e = new ExtractProgressEventArgs(ArchiveNameForEvent, before, _entries.Count, current, currentEntry, path);
- ep(this, e);
- if (e.Cancel)
- _extractOperationCanceled = true;
- }
- }
-
-
- // Can be called from within ZipEntry._ExtractOne.
- internal bool OnExtractBlock(ZipEntry entry, Int64 bytesWritten, Int64 totalBytesToWrite)
- {
- EventHandler<ExtractProgressEventArgs> ep = ExtractProgress;
- if (ep != null)
- {
- var e = ExtractProgressEventArgs.ByteUpdate(ArchiveNameForEvent, entry,
- bytesWritten, totalBytesToWrite);
- ep(this, e);
- if (e.Cancel)
- _extractOperationCanceled = true;
- }
- return _extractOperationCanceled;
- }
-
-
- // Can be called from within ZipEntry.InternalExtract.
- internal bool OnSingleEntryExtract(ZipEntry entry, string path, bool before)
- {
- EventHandler<ExtractProgressEventArgs> ep = ExtractProgress;
- if (ep != null)
- {
- var e = (before)
- ? ExtractProgressEventArgs.BeforeExtractEntry(ArchiveNameForEvent, entry, path)
- : ExtractProgressEventArgs.AfterExtractEntry(ArchiveNameForEvent, entry, path);
- ep(this, e);
- if (e.Cancel)
- _extractOperationCanceled = true;
- }
- return _extractOperationCanceled;
- }
-
- internal bool OnExtractExisting(ZipEntry entry, string path)
- {
- EventHandler<ExtractProgressEventArgs> ep = ExtractProgress;
- if (ep != null)
- {
- var e = ExtractProgressEventArgs.ExtractExisting(ArchiveNameForEvent, entry, path);
- ep(this, e);
- if (e.Cancel)
- _extractOperationCanceled = true;
- }
- return _extractOperationCanceled;
- }
-
-
- private void OnExtractAllCompleted(string path)
- {
- EventHandler<ExtractProgressEventArgs> ep = ExtractProgress;
- if (ep != null)
- {
- var e = ExtractProgressEventArgs.ExtractAllCompleted(ArchiveNameForEvent,
- path );
- ep(this, e);
- }
- }
-
-
- private void OnExtractAllStarted(string path)
- {
- EventHandler<ExtractProgressEventArgs> ep = ExtractProgress;
- if (ep != null)
- {
- var e = ExtractProgressEventArgs.ExtractAllStarted(ArchiveNameForEvent,
- path );
- ep(this, e);
- }
- }
-
-
- #endregion
-
-
-
- #region Add
- /// <summary>
- /// An event handler invoked before, during, and after Adding entries to a zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// Adding a large number of entries to a zip file can take a long
- /// time. For example, when calling <see cref="AddDirectory(string)"/> on a
- /// directory that contains 50,000 files, it could take 3 minutes or so.
- /// This event handler allws an application to track the progress of the Add
- /// operation, and to optionally cancel a lengthy Add operation.
- /// </remarks>
- ///
- /// <example>
- /// <code lang="C#">
- ///
- /// int _numEntriesToAdd= 0;
- /// int _numEntriesAdded= 0;
- /// void AddProgressHandler(object sender, AddProgressEventArgs e)
- /// {
- /// switch (e.EventType)
- /// {
- /// case ZipProgressEventType.Adding_Started:
- /// Console.WriteLine("Adding files to the zip...");
- /// break;
- /// case ZipProgressEventType.Adding_AfterAddEntry:
- /// _numEntriesAdded++;
- /// Console.WriteLine(String.Format("Adding file {0}/{1} :: {2}",
- /// _numEntriesAdded, _numEntriesToAdd, e.CurrentEntry.FileName));
- /// break;
- /// case ZipProgressEventType.Adding_Completed:
- /// Console.WriteLine("Added all files");
- /// break;
- /// }
- /// }
- ///
- /// void CreateTheZip()
- /// {
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// zip.AddProgress += AddProgressHandler;
- /// zip.AddDirectory(System.IO.Path.GetFileName(DirToZip));
- /// zip.Save(ZipFileToCreate);
- /// }
- /// }
- ///
- /// </code>
- ///
- /// <code lang="VB">
- ///
- /// Private Sub AddProgressHandler(ByVal sender As Object, ByVal e As AddProgressEventArgs)
- /// Select Case e.EventType
- /// Case ZipProgressEventType.Adding_Started
- /// Console.WriteLine("Adding files to the zip...")
- /// Exit Select
- /// Case ZipProgressEventType.Adding_AfterAddEntry
- /// Console.WriteLine(String.Format("Adding file {0}", e.CurrentEntry.FileName))
- /// Exit Select
- /// Case ZipProgressEventType.Adding_Completed
- /// Console.WriteLine("Added all files")
- /// Exit Select
- /// End Select
- /// End Sub
- ///
- /// Sub CreateTheZip()
- /// Using zip as ZipFile = New ZipFile
- /// AddHandler zip.AddProgress, AddressOf AddProgressHandler
- /// zip.AddDirectory(System.IO.Path.GetFileName(DirToZip))
- /// zip.Save(ZipFileToCreate);
- /// End Using
- /// End Sub
- ///
- /// </code>
- ///
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.SaveProgress"/>
- /// <seealso cref="Ionic.Zip.ZipFile.ReadProgress"/>
- /// <seealso cref="Ionic.Zip.ZipFile.ExtractProgress"/>
- internal event EventHandler<AddProgressEventArgs> AddProgress;
-
- private void OnAddStarted()
- {
- EventHandler<AddProgressEventArgs> ap = AddProgress;
- if (ap != null)
- {
- var e = AddProgressEventArgs.Started(ArchiveNameForEvent);
- ap(this, e);
- if (e.Cancel) // workitem 13371
- _addOperationCanceled = true;
- }
- }
-
- private void OnAddCompleted()
- {
- EventHandler<AddProgressEventArgs> ap = AddProgress;
- if (ap != null)
- {
- var e = AddProgressEventArgs.Completed(ArchiveNameForEvent);
- ap(this, e);
- }
- }
-
- internal void AfterAddEntry(ZipEntry entry)
- {
- EventHandler<AddProgressEventArgs> ap = AddProgress;
- if (ap != null)
- {
- var e = AddProgressEventArgs.AfterEntry(ArchiveNameForEvent, entry, _entries.Count);
- ap(this, e);
- if (e.Cancel) // workitem 13371
- _addOperationCanceled = true;
- }
- }
-
- #endregion
-
-
-
- #region Error
- /// <summary>
- /// An event that is raised when an error occurs during open or read of files
- /// while saving a zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Errors can occur as a file is being saved to the zip archive. For
- /// example, the File.Open may fail, or a File.Read may fail, because of
- /// lock conflicts or other reasons. If you add a handler to this event,
- /// you can handle such errors in your own code. If you don't add a
- /// handler, the library will throw an exception if it encounters an I/O
- /// error during a call to <c>Save()</c>.
- /// </para>
- ///
- /// <para>
- /// Setting a handler implicitly sets <see cref="ZipFile.ZipErrorAction"/> to
- /// <c>ZipErrorAction.InvokeErrorEvent</c>.
- /// </para>
- ///
- /// <para>
- /// The handler you add applies to all <see cref="ZipEntry"/> items that are
- /// subsequently added to the <c>ZipFile</c> instance. If you set this
- /// property after you have added items to the <c>ZipFile</c>, but before you
- /// have called <c>Save()</c>, errors that occur while saving those items
- /// will not cause the error handler to be invoked.
- /// </para>
- ///
- /// <para>
- /// If you want to handle any errors that occur with any entry in the zip
- /// file using the same error handler, then add your error handler once,
- /// before adding any entries to the zip archive.
- /// </para>
- ///
- /// <para>
- /// In the error handler method, you need to set the <see
- /// cref="ZipEntry.ZipErrorAction"/> property on the
- /// <c>ZipErrorEventArgs.CurrentEntry</c>. This communicates back to
- /// DotNetZip what you would like to do with this particular error. Within
- /// an error handler, if you set the <c>ZipEntry.ZipErrorAction</c> property
- /// on the <c>ZipEntry</c> to <c>ZipErrorAction.InvokeErrorEvent</c> or if
- /// you don't set it at all, the library will throw the exception. (It is the
- /// same as if you had set the <c>ZipEntry.ZipErrorAction</c> property on the
- /// <c>ZipEntry</c> to <c>ZipErrorAction.Throw</c>.) If you set the
- /// <c>ZipErrorEventArgs.Cancel</c> to true, the entire <c>Save()</c> will be
- /// canceled.
- /// </para>
- ///
- /// <para>
- /// In the case that you use <c>ZipErrorAction.Skip</c>, implying that
- /// you want to skip the entry for which there's been an error, DotNetZip
- /// tries to seek backwards in the output stream, and truncate all bytes
- /// written on behalf of that particular entry. This works only if the
- /// output stream is seekable. It will not work, for example, when using
- /// ASPNET's Response.OutputStream.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example shows how to use an event handler to handle
- /// errors during save of the zip file.
- /// <code lang="C#">
- ///
- /// public static void MyZipError(object sender, ZipErrorEventArgs e)
- /// {
- /// Console.WriteLine("Error saving {0}...", e.FileName);
- /// Console.WriteLine(" Exception: {0}", e.exception);
- /// ZipEntry entry = e.CurrentEntry;
- /// string response = null;
- /// // Ask the user whether he wants to skip this error or not
- /// do
- /// {
- /// Console.Write("Retry, Skip, Throw, or Cancel ? (R/S/T/C) ");
- /// response = Console.ReadLine();
- /// Console.WriteLine();
- ///
- /// } while (response != null &&
- /// response[0]!='S' && response[0]!='s' &&
- /// response[0]!='R' && response[0]!='r' &&
- /// response[0]!='T' && response[0]!='t' &&
- /// response[0]!='C' && response[0]!='c');
- ///
- /// e.Cancel = (response[0]=='C' || response[0]=='c');
- ///
- /// if (response[0]=='S' || response[0]=='s')
- /// entry.ZipErrorAction = ZipErrorAction.Skip;
- /// else if (response[0]=='R' || response[0]=='r')
- /// entry.ZipErrorAction = ZipErrorAction.Retry;
- /// else if (response[0]=='T' || response[0]=='t')
- /// entry.ZipErrorAction = ZipErrorAction.Throw;
- /// }
- ///
- /// public void SaveTheFile()
- /// {
- /// string directoryToZip = "fodder";
- /// string directoryInArchive = "files";
- /// string zipFileToCreate = "Archive.zip";
- /// using (var zip = new ZipFile())
- /// {
- /// // set the event handler before adding any entries
- /// zip.ZipError += MyZipError;
- /// zip.AddDirectory(directoryToZip, directoryInArchive);
- /// zip.Save(zipFileToCreate);
- /// }
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Private Sub MyZipError(ByVal sender As Object, ByVal e As Ionic.Zip.ZipErrorEventArgs)
- /// ' At this point, the application could prompt the user for an action to take.
- /// ' But in this case, this application will simply automatically skip the file, in case of error.
- /// Console.WriteLine("Zip Error, entry {0}", e.CurrentEntry.FileName)
- /// Console.WriteLine(" Exception: {0}", e.exception)
- /// ' set the desired ZipErrorAction on the CurrentEntry to communicate that to DotNetZip
- /// e.CurrentEntry.ZipErrorAction = Zip.ZipErrorAction.Skip
- /// End Sub
- ///
- /// Public Sub SaveTheFile()
- /// Dim directoryToZip As String = "fodder"
- /// Dim directoryInArchive As String = "files"
- /// Dim zipFileToCreate as String = "Archive.zip"
- /// Using zipArchive As ZipFile = New ZipFile
- /// ' set the event handler before adding any entries
- /// AddHandler zipArchive.ZipError, AddressOf MyZipError
- /// zipArchive.AddDirectory(directoryToZip, directoryInArchive)
- /// zipArchive.Save(zipFileToCreate)
- /// End Using
- /// End Sub
- ///
- /// </code>
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.ZipErrorAction"/>
- internal event EventHandler<ZipErrorEventArgs> ZipError;
-
- internal bool OnZipErrorSaving(ZipEntry entry, Exception exc)
- {
- if (ZipError != null)
- {
- lock (LOCK)
- {
- var e = ZipErrorEventArgs.Saving(this.Name, entry, exc);
- ZipError(this, e);
- if (e.Cancel)
- _saveOperationCanceled = true;
- }
- }
- return _saveOperationCanceled;
- }
- #endregion
-
- }
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipFile.Extract.cs b/EPPlus/Packaging/DotNetZip/ZipFile.Extract.cs
deleted file mode 100644
index 2fd8646..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipFile.Extract.cs
+++ /dev/null
@@ -1,298 +0,0 @@
-// ZipFile.Extract.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-July-31 14:45:18>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the methods for Extract operations on zip files.
-//
-// ------------------------------------------------------------------
-//
-
-
-using System;
-using System.IO;
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
-
- internal partial class ZipFile
- {
-
- /// <summary>
- /// Extracts all of the items in the zip archive, to the specified path in the
- /// filesystem. The path can be relative or fully-qualified.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method will extract all entries in the <c>ZipFile</c> to the
- /// specified path.
- /// </para>
- ///
- /// <para>
- /// If an extraction of a file from the zip archive would overwrite an
- /// existing file in the filesystem, the action taken is dictated by the
- /// ExtractExistingFile property, which overrides any setting you may have
- /// made on individual ZipEntry instances. By default, if you have not
- /// set that property on the <c>ZipFile</c> instance, the entry will not
- /// be extracted, the existing file will not be overwritten and an
- /// exception will be thrown. To change this, set the property, or use the
- /// <see cref="ZipFile.ExtractAll(string,
- /// Ionic.Zip.ExtractExistingFileAction)" /> overload that allows you to
- /// specify an ExtractExistingFileAction parameter.
- /// </para>
- ///
- /// <para>
- /// The action to take when an extract would overwrite an existing file
- /// applies to all entries. If you want to set this on a per-entry basis,
- /// then you must use one of the <see
- /// cref="ZipEntry.Extract()">ZipEntry.Extract</see> methods.
- /// </para>
- ///
- /// <para>
- /// This method will send verbose output messages to the <see
- /// cref="StatusMessageTextWriter"/>, if it is set on the <c>ZipFile</c>
- /// instance.
- /// </para>
- ///
- /// <para>
- /// You may wish to take advantage of the <c>ExtractProgress</c> event.
- /// </para>
- ///
- /// <para>
- /// About timestamps: When extracting a file entry from a zip archive, the
- /// extracted file gets the last modified time of the entry as stored in
- /// the archive. The archive may also store extended file timestamp
- /// information, including last accessed and created times. If these are
- /// present in the <c>ZipEntry</c>, then the extracted file will also get
- /// these times.
- /// </para>
- ///
- /// <para>
- /// A Directory entry is somewhat different. It will get the times as
- /// described for a file entry, but, if there are file entries in the zip
- /// archive that, when extracted, appear in the just-created directory,
- /// then when those file entries are extracted, the last modified and last
- /// accessed times of the directory will change, as a side effect. The
- /// result is that after an extraction of a directory and a number of
- /// files within the directory, the last modified and last accessed
- /// timestamps on the directory will reflect the time that the last file
- /// was extracted into the directory, rather than the time stored in the
- /// zip archive for the directory.
- /// </para>
- ///
- /// <para>
- /// To compensate, when extracting an archive with <c>ExtractAll</c>,
- /// DotNetZip will extract all the file and directory entries as described
- /// above, but it will then make a second pass on the directories, and
- /// reset the times on the directories to reflect what is stored in the
- /// zip archive.
- /// </para>
- ///
- /// <para>
- /// This compensation is performed only within the context of an
- /// <c>ExtractAll</c>. If you call <c>ZipEntry.Extract</c> on a directory
- /// entry, the timestamps on directory in the filesystem will reflect the
- /// times stored in the zip. If you then call <c>ZipEntry.Extract</c> on
- /// a file entry, which is extracted into the directory, the timestamps on
- /// the directory will be updated to the current time.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// This example extracts all the entries in a zip archive file, to the
- /// specified target directory. The extraction will overwrite any
- /// existing files silently.
- ///
- /// <code>
- /// String TargetDirectory= "unpack";
- /// using(ZipFile zip= ZipFile.Read(ZipFileToExtract))
- /// {
- /// zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently;
- /// zip.ExtractAll(TargetDirectory);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Dim TargetDirectory As String = "unpack"
- /// Using zip As ZipFile = ZipFile.Read(ZipFileToExtract)
- /// zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently
- /// zip.ExtractAll(TargetDirectory)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.ExtractProgress"/>
- /// <seealso cref="Ionic.Zip.ZipFile.ExtractExistingFile"/>
- ///
- /// <param name="path">
- /// The path to which the contents of the zipfile will be extracted.
- /// The path can be relative or fully-qualified.
- /// </param>
- ///
- public void ExtractAll(string path)
- {
- _InternalExtractAll(path, true);
- }
-
-
-
- /// <summary>
- /// Extracts all of the items in the zip archive, to the specified path in the
- /// filesystem, using the specified behavior when extraction would overwrite an
- /// existing file.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This method will extract all entries in the <c>ZipFile</c> to the specified
- /// path. For an extraction that would overwrite an existing file, the behavior
- /// is dictated by <paramref name="extractExistingFile"/>, which overrides any
- /// setting you may have made on individual ZipEntry instances.
- /// </para>
- ///
- /// <para>
- /// The action to take when an extract would overwrite an existing file
- /// applies to all entries. If you want to set this on a per-entry basis,
- /// then you must use <see cref="ZipEntry.Extract(String,
- /// ExtractExistingFileAction)" /> or one of the similar methods.
- /// </para>
- ///
- /// <para>
- /// Calling this method is equivalent to setting the <see
- /// cref="ExtractExistingFile"/> property and then calling <see
- /// cref="ExtractAll(String)"/>.
- /// </para>
- ///
- /// <para>
- /// This method will send verbose output messages to the
- /// <see cref="StatusMessageTextWriter"/>, if it is set on the <c>ZipFile</c> instance.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// This example extracts all the entries in a zip archive file, to the
- /// specified target directory. It does not overwrite any existing files.
- /// <code>
- /// String TargetDirectory= "c:\\unpack";
- /// using(ZipFile zip= ZipFile.Read(ZipFileToExtract))
- /// {
- /// zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Dim TargetDirectory As String = "c:\unpack"
- /// Using zip As ZipFile = ZipFile.Read(ZipFileToExtract)
- /// zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="path">
- /// The path to which the contents of the zipfile will be extracted.
- /// The path can be relative or fully-qualified.
- /// </param>
- ///
- /// <param name="extractExistingFile">
- /// The action to take if extraction would overwrite an existing file.
- /// </param>
- /// <seealso cref="ExtractSelectedEntries(String,ExtractExistingFileAction)"/>
- internal void ExtractAll(string path, ExtractExistingFileAction extractExistingFile)
- {
- ExtractExistingFile = extractExistingFile;
- _InternalExtractAll(path, true);
- }
-
-
- private void _InternalExtractAll(string path, bool overrideExtractExistingProperty)
- {
- bool header = Verbose;
- _inExtractAll = true;
- try
- {
- OnExtractAllStarted(path);
-
- int n = 0;
- foreach (ZipEntry e in _entries.Values)
- {
- if (header)
- {
- StatusMessageTextWriter.WriteLine("\n{1,-22} {2,-8} {3,4} {4,-8} {0}",
- "Name", "Modified", "Size", "Ratio", "Packed");
- StatusMessageTextWriter.WriteLine(new System.String('-', 72));
- header = false;
- }
- if (Verbose)
- {
- StatusMessageTextWriter.WriteLine("{1,-22} {2,-8} {3,4:F0}% {4,-8} {0}",
- e.FileName,
- e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"),
- e.UncompressedSize,
- e.CompressionRatio,
- e.CompressedSize);
- if (!String.IsNullOrEmpty(e.Comment))
- StatusMessageTextWriter.WriteLine(" Comment: {0}", e.Comment);
- }
- e.Password = _Password; // this may be null
- OnExtractEntry(n, true, e, path);
- if (overrideExtractExistingProperty)
- e.ExtractExistingFile = this.ExtractExistingFile;
- e.Extract(path);
- n++;
- OnExtractEntry(n, false, e, path);
- if (_extractOperationCanceled)
- break;
- }
-
- if (!_extractOperationCanceled)
- {
- // workitem 8264:
- // now, set times on directory entries, again.
- // The problem is, extracting a file changes the times on the parent
- // directory. So after all files have been extracted, we have to
- // run through the directories again.
- foreach (ZipEntry e in _entries.Values)
- {
- // check if it is a directory
- if ((e.IsDirectory) || (e.FileName.EndsWith("/")))
- {
- string outputFile = (e.FileName.StartsWith("/"))
- ? Path.Combine(path, e.FileName.Substring(1))
- : Path.Combine(path, e.FileName);
-
- e._SetTimes(outputFile, false);
- }
- }
- OnExtractAllCompleted(path);
- }
-
- }
- finally
- {
-
- _inExtractAll = false;
- }
- }
-
-
- }
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipFile.Read.cs b/EPPlus/Packaging/DotNetZip/ZipFile.Read.cs
deleted file mode 100644
index a2ed0b4..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipFile.Read.cs
+++ /dev/null
@@ -1,1110 +0,0 @@
-// ZipFile.Read.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009-2011 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-August-05 11:38:59>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the methods for Reading zip files.
-//
-// ------------------------------------------------------------------
-//
-
-
-using System;
-using System.IO;
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- /// <summary>
- /// A class for collecting the various options that can be used when
- /// Reading zip files for extraction or update.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// When reading a zip file, there are several options an
- /// application can set, to modify how the file is read, or what
- /// the library does while reading. This class collects those
- /// options into one container.
- /// </para>
- ///
- /// <para>
- /// Pass an instance of the <c>ReadOptions</c> class into the
- /// <c>ZipFile.Read()</c> method.
- /// </para>
- ///
- /// <seealso cref="ZipFile.Read(String, ReadOptions)"/>.
- /// <seealso cref="ZipFile.Read(Stream, ReadOptions)"/>.
- /// </remarks>
- internal class ReadOptions
- {
- /// <summary>
- /// An event handler for Read operations. When opening large zip
- /// archives, you may want to display a progress bar or other
- /// indicator of status progress while reading. This parameter
- /// allows you to specify a ReadProgress Event Handler directly.
- /// When you call <c>Read()</c>, the progress event is invoked as
- /// necessary.
- /// </summary>
- public EventHandler<ReadProgressEventArgs> ReadProgress { get; set; }
-
- /// <summary>
- /// The <c>System.IO.TextWriter</c> to use for writing verbose status messages
- /// during operations on the zip archive. A console application may wish to
- /// pass <c>System.Console.Out</c> to get messages on the Console. A graphical
- /// or headless application may wish to capture the messages in a different
- /// <c>TextWriter</c>, such as a <c>System.IO.StringWriter</c>.
- /// </summary>
- public TextWriter StatusMessageWriter { get; set; }
-
- /// <summary>
- /// The <c>System.Text.Encoding</c> to use when reading in the zip archive. Be
- /// careful specifying the encoding. If the value you use here is not the same
- /// as the Encoding used when the zip archive was created (possibly by a
- /// different archiver) you will get unexpected results and possibly exceptions.
- /// </summary>
- ///
- /// <seealso cref="ZipFile.ProvisionalAlternateEncoding"/>
- ///
- public System.Text.Encoding @Encoding { get; set; }
- }
-
-
- internal partial class ZipFile
- {
- /// <summary>
- /// Reads a zip file archive and returns the instance.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The stream is read using the default <c>System.Text.Encoding</c>, which is the
- /// <c>IBM437</c> codepage.
- /// </para>
- /// </remarks>
- ///
- /// <exception cref="System.Exception">
- /// Thrown if the <c>ZipFile</c> cannot be read. The implementation of this method
- /// relies on <c>System.IO.File.OpenRead</c>, which can throw a variety of exceptions,
- /// including specific exceptions if a file is not found, an unauthorized access
- /// exception, exceptions for poorly formatted filenames, and so on.
- /// </exception>
- ///
- /// <param name="fileName">
- /// The name of the zip archive to open. This can be a fully-qualified or relative
- /// pathname.
- /// </param>
- ///
- /// <seealso cref="ZipFile.Read(String, ReadOptions)"/>.
- ///
- /// <returns>The instance read from the zip archive.</returns>
- ///
- public static ZipFile Read(string fileName)
- {
- return ZipFile.Read(fileName, null, null, null);
- }
-
-
- /// <summary>
- /// Reads a zip file archive from the named filesystem file using the
- /// specified options.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This version of the <c>Read()</c> method allows the caller to pass
- /// in a <c>TextWriter</c> an <c>Encoding</c>, via an instance of the
- /// <c>ReadOptions</c> class. The <c>ZipFile</c> is read in using the
- /// specified encoding for entries where UTF-8 encoding is not
- /// explicitly specified.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- ///
- /// <para>
- /// This example shows how to read a zip file using the Big-5 Chinese
- /// code page (950), and extract each entry in the zip file, while
- /// sending status messages out to the Console.
- /// </para>
- ///
- /// <para>
- /// For this code to work as intended, the zipfile must have been
- /// created using the big5 code page (CP950). This is typical, for
- /// example, when using WinRar on a machine with CP950 set as the
- /// default code page. In that case, the names of entries within the
- /// Zip archive will be stored in that code page, and reading the zip
- /// archive must be done using that code page. If the application did
- /// not use the correct code page in ZipFile.Read(), then names of
- /// entries within the zip archive would not be correctly retrieved.
- /// </para>
- ///
- /// <code lang="C#">
- /// string zipToExtract = "MyArchive.zip";
- /// string extractDirectory = "extract";
- /// var options = new ReadOptions
- /// {
- /// StatusMessageWriter = System.Console.Out,
- /// Encoding = System.Text.Encoding.GetEncoding(950)
- /// };
- /// using (ZipFile zip = ZipFile.Read(zipToExtract, options))
- /// {
- /// foreach (ZipEntry e in zip)
- /// {
- /// e.Extract(extractDirectory);
- /// }
- /// }
- /// </code>
- ///
- ///
- /// <code lang="VB">
- /// Dim zipToExtract as String = "MyArchive.zip"
- /// Dim extractDirectory as String = "extract"
- /// Dim options as New ReadOptions
- /// options.Encoding = System.Text.Encoding.GetEncoding(950)
- /// options.StatusMessageWriter = System.Console.Out
- /// Using zip As ZipFile = ZipFile.Read(zipToExtract, options)
- /// Dim e As ZipEntry
- /// For Each e In zip
- /// e.Extract(extractDirectory)
- /// Next
- /// End Using
- /// </code>
- /// </example>
- ///
- ///
- /// <example>
- ///
- /// <para>
- /// This example shows how to read a zip file using the default
- /// code page, to remove entries that have a modified date before a given threshold,
- /// sending status messages out to a <c>StringWriter</c>.
- /// </para>
- ///
- /// <code lang="C#">
- /// var options = new ReadOptions
- /// {
- /// StatusMessageWriter = new System.IO.StringWriter()
- /// };
- /// using (ZipFile zip = ZipFile.Read("PackedDocuments.zip", options))
- /// {
- /// var Threshold = new DateTime(2007,7,4);
- /// // We cannot remove the entry from the list, within the context of
- /// // an enumeration of said list.
- /// // So we add the doomed entry to a list to be removed later.
- /// // pass 1: mark the entries for removal
- /// var MarkedEntries = new System.Collections.Generic.List<ZipEntry>();
- /// foreach (ZipEntry e in zip)
- /// {
- /// if (e.LastModified < Threshold)
- /// MarkedEntries.Add(e);
- /// }
- /// // pass 2: actually remove the entry.
- /// foreach (ZipEntry zombie in MarkedEntries)
- /// zip.RemoveEntry(zombie);
- /// zip.Comment = "This archive has been updated.";
- /// zip.Save();
- /// }
- /// // can now use contents of sw, eg store in an audit log
- /// </code>
- ///
- /// <code lang="VB">
- /// Dim options as New ReadOptions
- /// options.StatusMessageWriter = New System.IO.StringWriter
- /// Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip", options)
- /// Dim Threshold As New DateTime(2007, 7, 4)
- /// ' We cannot remove the entry from the list, within the context of
- /// ' an enumeration of said list.
- /// ' So we add the doomed entry to a list to be removed later.
- /// ' pass 1: mark the entries for removal
- /// Dim MarkedEntries As New System.Collections.Generic.List(Of ZipEntry)
- /// Dim e As ZipEntry
- /// For Each e In zip
- /// If (e.LastModified < Threshold) Then
- /// MarkedEntries.Add(e)
- /// End If
- /// Next
- /// ' pass 2: actually remove the entry.
- /// Dim zombie As ZipEntry
- /// For Each zombie In MarkedEntries
- /// zip.RemoveEntry(zombie)
- /// Next
- /// zip.Comment = "This archive has been updated."
- /// zip.Save
- /// End Using
- /// ' can now use contents of sw, eg store in an audit log
- /// </code>
- /// </example>
- ///
- /// <exception cref="System.Exception">
- /// Thrown if the zipfile cannot be read. The implementation of
- /// this method relies on <c>System.IO.File.OpenRead</c>, which
- /// can throw a variety of exceptions, including specific
- /// exceptions if a file is not found, an unauthorized access
- /// exception, exceptions for poorly formatted filenames, and so
- /// on.
- /// </exception>
- ///
- /// <param name="fileName">
- /// The name of the zip archive to open.
- /// This can be a fully-qualified or relative pathname.
- /// </param>
- ///
- /// <param name="options">
- /// The set of options to use when reading the zip file.
- /// </param>
- ///
- /// <returns>The ZipFile instance read from the zip archive.</returns>
- ///
- /// <seealso cref="ZipFile.Read(Stream, ReadOptions)"/>
- ///
- internal static ZipFile Read(string fileName,
- ReadOptions options)
- {
- if (options == null)
- throw new ArgumentNullException("options");
- return Read(fileName,
- options.StatusMessageWriter,
- options.Encoding,
- options.ReadProgress);
- }
-
- /// <summary>
- /// Reads a zip file archive using the specified text encoding, the specified
- /// TextWriter for status messages, and the specified ReadProgress event handler,
- /// and returns the instance.
- /// </summary>
- ///
- /// <param name="fileName">
- /// The name of the zip archive to open.
- /// This can be a fully-qualified or relative pathname.
- /// </param>
- ///
- /// <param name="readProgress">
- /// An event handler for Read operations.
- /// </param>
- ///
- /// <param name="statusMessageWriter">
- /// The <c>System.IO.TextWriter</c> to use for writing verbose status messages
- /// during operations on the zip archive. A console application may wish to
- /// pass <c>System.Console.Out</c> to get messages on the Console. A graphical
- /// or headless application may wish to capture the messages in a different
- /// <c>TextWriter</c>, such as a <c>System.IO.StringWriter</c>.
- /// </param>
- ///
- /// <param name="encoding">
- /// The <c>System.Text.Encoding</c> to use when reading in the zip archive. Be
- /// careful specifying the encoding. If the value you use here is not the same
- /// as the Encoding used when the zip archive was created (possibly by a
- /// different archiver) you will get unexpected results and possibly exceptions.
- /// </param>
- ///
- /// <returns>The instance read from the zip archive.</returns>
- ///
- private static ZipFile Read(string fileName,
- TextWriter statusMessageWriter,
- System.Text.Encoding encoding,
- EventHandler<ReadProgressEventArgs> readProgress)
- {
- ZipFile zf = new ZipFile();
- zf.AlternateEncoding = encoding ?? DefaultEncoding;
- zf.AlternateEncodingUsage = ZipOption.Always;
- zf._StatusMessageTextWriter = statusMessageWriter;
- zf._name = fileName;
- if (readProgress != null)
- zf.ReadProgress = readProgress;
-
- if (zf.Verbose) zf._StatusMessageTextWriter.WriteLine("reading from {0}...", fileName);
-
- ReadIntoInstance(zf);
- zf._fileAlreadyExists = true;
-
- return zf;
- }
-
- /// <summary>
- /// Reads a zip archive from a stream.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// When reading from a file, it's probably easier to just use
- /// <see cref="ZipFile.Read(String,
- /// ReadOptions)">ZipFile.Read(String, ReadOptions)</see>. This
- /// overload is useful when when the zip archive content is
- /// available from an already-open stream. The stream must be
- /// open and readable and seekable when calling this method. The
- /// stream is left open when the reading is completed.
- /// </para>
- ///
- /// <para>
- /// Using this overload, the stream is read using the default
- /// <c>System.Text.Encoding</c>, which is the <c>IBM437</c>
- /// codepage. If you want to specify the encoding to use when
- /// reading the zipfile content, see
- /// <see cref="ZipFile.Read(Stream,
- /// ReadOptions)">ZipFile.Read(Stream, ReadOptions)</see>. This
- /// </para>
- ///
- /// <para>
- /// Reading of zip content begins at the current position in the
- /// stream. This means if you have a stream that concatenates
- /// regular data and zip data, if you position the open, readable
- /// stream at the start of the zip data, you will be able to read
- /// the zip archive using this constructor, or any of the ZipFile
- /// constructors that accept a <see cref="System.IO.Stream" /> as
- /// input. Some examples of where this might be useful: the zip
- /// content is concatenated at the end of a regular EXE file, as
- /// some self-extracting archives do. (Note: SFX files produced
- /// by DotNetZip do not work this way; they can be read as normal
- /// ZIP files). Another example might be a stream being read from
- /// a database, where the zip content is embedded within an
- /// aggregate stream of data.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// <para>
- /// This example shows how to Read zip content from a stream, and
- /// extract one entry into a different stream. In this example,
- /// the filename "NameOfEntryInArchive.doc", refers only to the
- /// name of the entry within the zip archive. A file by that
- /// name is not created in the filesystem. The I/O is done
- /// strictly with the given streams.
- /// </para>
- ///
- /// <code>
- /// using (ZipFile zip = ZipFile.Read(InputStream))
- /// {
- /// zip.Extract("NameOfEntryInArchive.doc", OutputStream);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip as ZipFile = ZipFile.Read(InputStream)
- /// zip.Extract("NameOfEntryInArchive.doc", OutputStream)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="zipStream">the stream containing the zip data.</param>
- ///
- /// <returns>The ZipFile instance read from the stream</returns>
- ///
- public static ZipFile Read(Stream zipStream)
- {
- return Read(zipStream, null, null, null);
- }
-
- /// <summary>
- /// Reads a zip file archive from the given stream using the
- /// specified options.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// When reading from a file, it's probably easier to just use
- /// <see cref="ZipFile.Read(String,
- /// ReadOptions)">ZipFile.Read(String, ReadOptions)</see>. This
- /// overload is useful when when the zip archive content is
- /// available from an already-open stream. The stream must be
- /// open and readable and seekable when calling this method. The
- /// stream is left open when the reading is completed.
- /// </para>
- ///
- /// <para>
- /// Reading of zip content begins at the current position in the
- /// stream. This means if you have a stream that concatenates
- /// regular data and zip data, if you position the open, readable
- /// stream at the start of the zip data, you will be able to read
- /// the zip archive using this constructor, or any of the ZipFile
- /// constructors that accept a <see cref="System.IO.Stream" /> as
- /// input. Some examples of where this might be useful: the zip
- /// content is concatenated at the end of a regular EXE file, as
- /// some self-extracting archives do. (Note: SFX files produced
- /// by DotNetZip do not work this way; they can be read as normal
- /// ZIP files). Another example might be a stream being read from
- /// a database, where the zip content is embedded within an
- /// aggregate stream of data.
- /// </para>
- /// </remarks>
- ///
- /// <param name="zipStream">the stream containing the zip data.</param>
- ///
- /// <param name="options">
- /// The set of options to use when reading the zip file.
- /// </param>
- ///
- /// <exception cref="System.Exception">
- /// Thrown if the zip archive cannot be read.
- /// </exception>
- ///
- /// <returns>The ZipFile instance read from the stream.</returns>
- ///
- /// <seealso cref="ZipFile.Read(String, ReadOptions)"/>
- ///
- internal static ZipFile Read(Stream zipStream, ReadOptions options)
- {
- if (options == null)
- throw new ArgumentNullException("options");
-
- return Read(zipStream,
- options.StatusMessageWriter,
- options.Encoding,
- options.ReadProgress);
- }
-
-
-
- /// <summary>
- /// Reads a zip archive from a stream, using the specified text Encoding, the
- /// specified TextWriter for status messages,
- /// and the specified ReadProgress event handler.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Reading of zip content begins at the current position in the stream. This
- /// means if you have a stream that concatenates regular data and zip data, if
- /// you position the open, readable stream at the start of the zip data, you
- /// will be able to read the zip archive using this constructor, or any of the
- /// ZipFile constructors that accept a <see cref="System.IO.Stream" /> as
- /// input. Some examples of where this might be useful: the zip content is
- /// concatenated at the end of a regular EXE file, as some self-extracting
- /// archives do. (Note: SFX files produced by DotNetZip do not work this
- /// way). Another example might be a stream being read from a database, where
- /// the zip content is embedded within an aggregate stream of data.
- /// </para>
- /// </remarks>
- ///
- /// <param name="zipStream">the stream containing the zip data.</param>
- ///
- /// <param name="statusMessageWriter">
- /// The <c>System.IO.TextWriter</c> to which verbose status messages are written
- /// during operations on the <c>ZipFile</c>. For example, in a console
- /// application, System.Console.Out works, and will get a message for each entry
- /// added to the ZipFile. If the TextWriter is <c>null</c>, no verbose messages
- /// are written.
- /// </param>
- ///
- /// <param name="encoding">
- /// The text encoding to use when reading entries that do not have the UTF-8
- /// encoding bit set. Be careful specifying the encoding. If the value you use
- /// here is not the same as the Encoding used when the zip archive was created
- /// (possibly by a different archiver) you will get unexpected results and
- /// possibly exceptions. See the <see cref="ProvisionalAlternateEncoding"/>
- /// property for more information.
- /// </param>
- ///
- /// <param name="readProgress">
- /// An event handler for Read operations.
- /// </param>
- ///
- /// <returns>an instance of ZipFile</returns>
- private static ZipFile Read(Stream zipStream,
- TextWriter statusMessageWriter,
- System.Text.Encoding encoding,
- EventHandler<ReadProgressEventArgs> readProgress)
- {
- if (zipStream == null)
- throw new ArgumentNullException("zipStream");
-
- ZipFile zf = new ZipFile();
- zf._StatusMessageTextWriter = statusMessageWriter;
- zf._alternateEncoding = encoding ?? ZipFile.DefaultEncoding;
- zf._alternateEncodingUsage = ZipOption.Always;
- if (readProgress != null)
- zf.ReadProgress += readProgress;
- zf._readstream = (zipStream.Position == 0L)
- ? zipStream
- : new OffsetStream(zipStream);
- zf._ReadStreamIsOurs = false;
- if (zf.Verbose) zf._StatusMessageTextWriter.WriteLine("reading from stream...");
-
- ReadIntoInstance(zf);
- return zf;
- }
-
-
-
- private static void ReadIntoInstance(ZipFile zf)
- {
- Stream s = zf.ReadStream;
- try
- {
- zf._readName = zf._name; // workitem 13915
- if (!s.CanSeek)
- {
- ReadIntoInstance_Orig(zf);
- return;
- }
-
- zf.OnReadStarted();
-
- // change for workitem 8098
- //zf._originPosition = s.Position;
-
- // Try reading the central directory, rather than scanning the file.
-
- uint datum = ReadFirstFourBytes(s);
-
- if (datum == ZipConstants.EndOfCentralDirectorySignature)
- return;
-
-
- // start at the end of the file...
- // seek backwards a bit, then look for the EoCD signature.
- int nTries = 0;
- bool success = false;
-
- // The size of the end-of-central-directory-footer plus 2 bytes is 18.
- // This implies an archive comment length of 0. We'll add a margin of
- // safety and start "in front" of that, when looking for the
- // EndOfCentralDirectorySignature
- long posn = s.Length - 64;
- long maxSeekback = Math.Max(s.Length - 0x4000, 10);
- do
- {
- if (posn < 0) posn = 0; // BOF
- s.Seek(posn, SeekOrigin.Begin);
- long bytesRead = SharedUtilities.FindSignature(s, (int)ZipConstants.EndOfCentralDirectorySignature);
- if (bytesRead != -1)
- success = true;
- else
- {
- if (posn==0) break; // started at the BOF and found nothing
- nTries++;
- // Weird: with NETCF, negative offsets from SeekOrigin.End DO
- // NOT WORK. So rather than seek a negative offset, we seek
- // from SeekOrigin.Begin using a smaller number.
- posn -= (32 * (nTries + 1) * nTries);
- }
- }
- while (!success && posn > maxSeekback);
-
- if (success)
- {
- // workitem 8299
- zf._locEndOfCDS = s.Position - 4;
-
- byte[] block = new byte[16];
- s.Read(block, 0, block.Length);
-
- zf._diskNumberWithCd = BitConverter.ToUInt16(block, 2);
-
- if (zf._diskNumberWithCd == 0xFFFF)
- throw new ZipException("Spanned archives with more than 65534 segments are not supported at this time.");
-
- zf._diskNumberWithCd++; // I think the number in the file differs from reality by 1
-
- int i = 12;
-
- uint offset32 = (uint) BitConverter.ToUInt32(block, i);
- if (offset32 == 0xFFFFFFFF)
- {
- Zip64SeekToCentralDirectory(zf);
- }
- else
- {
- zf._OffsetOfCentralDirectory = offset32;
- // change for workitem 8098
- s.Seek(offset32, SeekOrigin.Begin);
- }
-
- ReadCentralDirectory(zf);
- }
- else
- {
- // Could not find the central directory.
- // Fallback to the old method.
- // workitem 8098: ok
- //s.Seek(zf._originPosition, SeekOrigin.Begin);
- s.Seek(0L, SeekOrigin.Begin);
- ReadIntoInstance_Orig(zf);
- }
- }
- catch (Exception ex1)
- {
- if (zf._ReadStreamIsOurs && zf._readstream != null)
- {
- try
- {
-#if NETCF
- zf._readstream.Close();
-#else
- zf._readstream.Dispose();
-#endif
- zf._readstream = null;
- }
- finally { }
- }
-
- throw new ZipException("Cannot read that as a ZipFile", ex1);
- }
-
- // the instance has been read in
- zf._contentsChanged = false;
- }
-
-
-
- private static void Zip64SeekToCentralDirectory(ZipFile zf)
- {
- Stream s = zf.ReadStream;
- byte[] block = new byte[16];
-
- // seek back to find the ZIP64 EoCD.
- // I think this might not work for .NET CF ?
- s.Seek(-40, SeekOrigin.Current);
- s.Read(block, 0, 16);
-
- Int64 offset64 = BitConverter.ToInt64(block, 8);
- zf._OffsetOfCentralDirectory = 0xFFFFFFFF;
- zf._OffsetOfCentralDirectory64 = offset64;
- // change for workitem 8098
- s.Seek(offset64, SeekOrigin.Begin);
- //zf.SeekFromOrigin(Offset64);
-
- uint datum = (uint)Ionic.Zip.SharedUtilities.ReadInt(s);
- if (datum != ZipConstants.Zip64EndOfCentralDirectoryRecordSignature)
- throw new BadReadException(String.Format(" Bad signature (0x{0:X8}) looking for ZIP64 EoCD Record at position 0x{1:X8}", datum, s.Position));
-
- s.Read(block, 0, 8);
- Int64 Size = BitConverter.ToInt64(block, 0);
-
- block = new byte[Size];
- s.Read(block, 0, block.Length);
-
- offset64 = BitConverter.ToInt64(block, 36);
- // change for workitem 8098
- s.Seek(offset64, SeekOrigin.Begin);
- //zf.SeekFromOrigin(Offset64);
- }
-
-
- private static uint ReadFirstFourBytes(Stream s)
- {
- uint datum = (uint)Ionic.Zip.SharedUtilities.ReadInt(s);
- return datum;
- }
-
-
-
- private static void ReadCentralDirectory(ZipFile zf)
- {
- // We must have the central directory footer record, in order to properly
- // read zip dir entries from the central directory. This because the logic
- // knows when to open a spanned file when the volume number for the central
- // directory differs from the volume number for the zip entry. The
- // _diskNumberWithCd was set when originally finding the offset for the
- // start of the Central Directory.
-
- // workitem 9214
- bool inputUsesZip64 = false;
- ZipEntry de;
- // in lieu of hashset, use a dictionary
- var previouslySeen = new Dictionary<String,object>();
- while ((de = ZipEntry.ReadDirEntry(zf, previouslySeen)) != null)
- {
- de.ResetDirEntry();
- zf.OnReadEntry(true, null);
-
- if (zf.Verbose)
- zf.StatusMessageTextWriter.WriteLine("entry {0}", de.FileName);
-
- zf._entries.Add(de.FileName,de);
-
- // workitem 9214
- if (de._InputUsesZip64) inputUsesZip64 = true;
- previouslySeen.Add(de.FileName, null); // to prevent dupes
- }
-
- // workitem 9214; auto-set the zip64 flag
- if (inputUsesZip64) zf.UseZip64WhenSaving = Zip64Option.Always;
-
- // workitem 8299
- if (zf._locEndOfCDS > 0)
- zf.ReadStream.Seek(zf._locEndOfCDS, SeekOrigin.Begin);
-
- ReadCentralDirectoryFooter(zf);
-
- if (zf.Verbose && !String.IsNullOrEmpty(zf.Comment))
- zf.StatusMessageTextWriter.WriteLine("Zip file Comment: {0}", zf.Comment);
-
- // We keep the read stream open after reading.
-
- if (zf.Verbose)
- zf.StatusMessageTextWriter.WriteLine("read in {0} entries.", zf._entries.Count);
-
- zf.OnReadCompleted();
- }
-
-
-
-
- // build the TOC by reading each entry in the file.
- private static void ReadIntoInstance_Orig(ZipFile zf)
- {
- zf.OnReadStarted();
- //zf._entries = new System.Collections.Generic.List<ZipEntry>();
- zf._entries = new System.Collections.Generic.Dictionary<String,ZipEntry>();
-
- ZipEntry e;
- if (zf.Verbose)
- if (zf.Name == null)
- zf.StatusMessageTextWriter.WriteLine("Reading zip from stream...");
- else
- zf.StatusMessageTextWriter.WriteLine("Reading zip {0}...", zf.Name);
-
- // work item 6647: PK00 (packed to removable disk)
- bool firstEntry = true;
- ZipContainer zc = new ZipContainer(zf);
- while ((e = ZipEntry.ReadEntry(zc, firstEntry)) != null)
- {
- if (zf.Verbose)
- zf.StatusMessageTextWriter.WriteLine(" {0}", e.FileName);
-
- zf._entries.Add(e.FileName,e);
- firstEntry = false;
- }
-
- // read the zipfile's central directory structure here.
- // workitem 9912
- // But, because it may be corrupted, ignore errors.
- try
- {
- ZipEntry de;
- // in lieu of hashset, use a dictionary
- var previouslySeen = new Dictionary<String,Object>();
- while ((de = ZipEntry.ReadDirEntry(zf, previouslySeen)) != null)
- {
- // Housekeeping: Since ZipFile exposes ZipEntry elements in the enumerator,
- // we need to copy the comment that we grab from the ZipDirEntry
- // into the ZipEntry, so the application can access the comment.
- // Also since ZipEntry is used to Write zip files, we need to copy the
- // file attributes to the ZipEntry as appropriate.
- ZipEntry e1 = zf._entries[de.FileName];
- if (e1 != null)
- {
- e1._Comment = de.Comment;
- if (de.IsDirectory) e1.MarkAsDirectory();
- }
- previouslySeen.Add(de.FileName,null); // to prevent dupes
- }
-
- // workitem 8299
- if (zf._locEndOfCDS > 0)
- zf.ReadStream.Seek(zf._locEndOfCDS, SeekOrigin.Begin);
-
- ReadCentralDirectoryFooter(zf);
-
- if (zf.Verbose && !String.IsNullOrEmpty(zf.Comment))
- zf.StatusMessageTextWriter.WriteLine("Zip file Comment: {0}", zf.Comment);
- }
- catch (ZipException) { }
- catch (IOException) { }
-
- zf.OnReadCompleted();
- }
-
-
-
-
- private static void ReadCentralDirectoryFooter(ZipFile zf)
- {
- Stream s = zf.ReadStream;
- int signature = Ionic.Zip.SharedUtilities.ReadSignature(s);
-
- byte[] block = null;
- int j = 0;
- if (signature == ZipConstants.Zip64EndOfCentralDirectoryRecordSignature)
- {
- // We have a ZIP64 EOCD
- // This data block is 4 bytes sig, 8 bytes size, 44 bytes fixed data,
- // followed by a variable-sized extension block. We have read the sig already.
- // 8 - datasize (64 bits)
- // 2 - version made by
- // 2 - version needed to extract
- // 4 - number of this disk
- // 4 - number of the disk with the start of the CD
- // 8 - total number of entries in the CD on this disk
- // 8 - total number of entries in the CD
- // 8 - size of the CD
- // 8 - offset of the CD
- // -----------------------
- // 52 bytes
-
- block = new byte[8 + 44];
- s.Read(block, 0, block.Length);
-
- Int64 DataSize = BitConverter.ToInt64(block, 0); // == 44 + the variable length
-
- if (DataSize < 44)
- throw new ZipException("Bad size in the ZIP64 Central Directory.");
-
- zf._versionMadeBy = BitConverter.ToUInt16(block, j);
- j += 2;
- zf._versionNeededToExtract = BitConverter.ToUInt16(block, j);
- j += 2;
- zf._diskNumberWithCd = BitConverter.ToUInt32(block, j);
- j += 2;
-
- //zf._diskNumberWithCd++; // hack!!
-
- // read the extended block
- block = new byte[DataSize - 44];
- s.Read(block, 0, block.Length);
- // discard the result
-
- signature = Ionic.Zip.SharedUtilities.ReadSignature(s);
- if (signature != ZipConstants.Zip64EndOfCentralDirectoryLocatorSignature)
- throw new ZipException("Inconsistent metadata in the ZIP64 Central Directory.");
-
- block = new byte[16];
- s.Read(block, 0, block.Length);
- // discard the result
-
- signature = Ionic.Zip.SharedUtilities.ReadSignature(s);
- }
-
- // Throw if this is not a signature for "end of central directory record"
- // This is a sanity check.
- if (signature != ZipConstants.EndOfCentralDirectorySignature)
- {
- s.Seek(-4, SeekOrigin.Current);
- throw new BadReadException(String.Format("Bad signature ({0:X8}) at position 0x{1:X8}",
- signature, s.Position));
- }
-
- // read the End-of-Central-Directory-Record
- block = new byte[16];
- zf.ReadStream.Read(block, 0, block.Length);
-
- // off sz data
- // -------------------------------------------------------
- // 0 4 end of central dir signature (0x06054b50)
- // 4 2 number of this disk
- // 6 2 number of the disk with start of the central directory
- // 8 2 total number of entries in the central directory on this disk
- // 10 2 total number of entries in the central directory
- // 12 4 size of the central directory
- // 16 4 offset of start of central directory with respect to the starting disk number
- // 20 2 ZIP file comment length
- // 22 ?? ZIP file comment
-
- if (zf._diskNumberWithCd == 0)
- {
- zf._diskNumberWithCd = BitConverter.ToUInt16(block, 2);
- //zf._diskNumberWithCd++; // hack!!
- }
-
- // read the comment here
- ReadZipFileComment(zf);
- }
-
-
-
- private static void ReadZipFileComment(ZipFile zf)
- {
- // read the comment here
- byte[] block = new byte[2];
- zf.ReadStream.Read(block, 0, block.Length);
-
- Int16 commentLength = (short)(block[0] + block[1] * 256);
- if (commentLength > 0)
- {
- block = new byte[commentLength];
- zf.ReadStream.Read(block, 0, block.Length);
-
- // workitem 10392 - prefer ProvisionalAlternateEncoding,
- // first. The fix for workitem 6513 tried to use UTF8
- // only as necessary, but that is impossible to test
- // for, in this direction. There's no way to know what
- // characters the already-encoded bytes refer
- // to. Therefore, must do what the user tells us.
-
- string s1 = zf.AlternateEncoding.GetString(block, 0, block.Length);
- zf.Comment = s1;
- }
- }
-
-
- // private static bool BlocksAreEqual(byte[] a, byte[] b)
- // {
- // if (a.Length != b.Length) return false;
- // for (int i = 0; i < a.Length; i++)
- // {
- // if (a[i] != b[i]) return false;
- // }
- // return true;
- // }
-
-
-
- /// <summary>
- /// Checks the given file to see if it appears to be a valid zip file.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// Calling this method is equivalent to calling <see cref="IsZipFile(string,
- /// bool)"/> with the testExtract parameter set to false.
- /// </para>
- /// </remarks>
- ///
- /// <param name="fileName">The file to check.</param>
- /// <returns>true if the file appears to be a zip file.</returns>
- public static bool IsZipFile(string fileName)
- {
- return IsZipFile(fileName, false);
- }
-
-
- /// <summary>
- /// Checks a file to see if it is a valid zip file.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method opens the specified zip file, reads in the zip archive,
- /// verifying the ZIP metadata as it reads.
- /// </para>
- ///
- /// <para>
- /// If everything succeeds, then the method returns true. If anything fails -
- /// for example if an incorrect signature or CRC is found, indicating a
- /// corrupt file, the the method returns false. This method also returns
- /// false for a file that does not exist.
- /// </para>
- ///
- /// <para>
- /// If <paramref name="testExtract"/> is true, as part of its check, this
- /// method reads in the content for each entry, expands it, and checks CRCs.
- /// This provides an additional check beyond verifying the zip header and
- /// directory data.
- /// </para>
- ///
- /// <para>
- /// If <paramref name="testExtract"/> is true, and if any of the zip entries
- /// are protected with a password, this method will return false. If you want
- /// to verify a <c>ZipFile</c> that has entries which are protected with a
- /// password, you will need to do that manually.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="fileName">The zip file to check.</param>
- /// <param name="testExtract">true if the caller wants to extract each entry.</param>
- /// <returns>true if the file contains a valid zip file.</returns>
- public static bool IsZipFile(string fileName, bool testExtract)
- {
- bool result = false;
- try
- {
- if (!File.Exists(fileName)) return false;
-
- using (var s = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
- {
- result = IsZipFile(s, testExtract);
- }
- }
- catch (IOException) { }
- catch (ZipException) { }
- return result;
- }
-
-
- /// <summary>
- /// Checks a stream to see if it contains a valid zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method reads the zip archive contained in the specified stream, verifying
- /// the ZIP metadata as it reads. If testExtract is true, this method also extracts
- /// each entry in the archive, dumping all the bits into <see cref="Stream.Null"/>.
- /// </para>
- ///
- /// <para>
- /// If everything succeeds, then the method returns true. If anything fails -
- /// for example if an incorrect signature or CRC is found, indicating a corrupt
- /// file, the the method returns false. This method also returns false for a
- /// file that does not exist.
- /// </para>
- ///
- /// <para>
- /// If <c>testExtract</c> is true, this method reads in the content for each
- /// entry, expands it, and checks CRCs. This provides an additional check
- /// beyond verifying the zip header data.
- /// </para>
- ///
- /// <para>
- /// If <c>testExtract</c> is true, and if any of the zip entries are protected
- /// with a password, this method will return false. If you want to verify a
- /// ZipFile that has entries which are protected with a password, you will need
- /// to do that manually.
- /// </para>
- /// </remarks>
- ///
- /// <seealso cref="IsZipFile(string, bool)"/>
- ///
- /// <param name="stream">The stream to check.</param>
- /// <param name="testExtract">true if the caller wants to extract each entry.</param>
- /// <returns>true if the stream contains a valid zip archive.</returns>
- public static bool IsZipFile(Stream stream, bool testExtract)
- {
- if (stream == null)
- throw new ArgumentNullException("stream");
-
- bool result = false;
- try
- {
- if (!stream.CanRead) return false;
-
- var bitBucket = Stream.Null;
-
- using (ZipFile zip1 = ZipFile.Read(stream, null, null, null))
- {
- if (testExtract)
- {
- foreach (var e in zip1)
- {
- if (!e.IsDirectory)
- {
- e.Extract(bitBucket);
- }
- }
- }
- }
- result = true;
- }
- catch (IOException) { }
- catch (ZipException) { }
- return result;
- }
-
-
-
-
- }
-
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipFile.Save.cs b/EPPlus/Packaging/DotNetZip/ZipFile.Save.cs
deleted file mode 100644
index b66c5c9..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipFile.Save.cs
+++ /dev/null
@@ -1,964 +0,0 @@
-// ZipFile.Save.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-August-05 13:31:23>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the methods for Save operations on zip files.
-//
-// ------------------------------------------------------------------
-//
-
-
-using System;
-using System.IO;
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
-
- internal partial class ZipFile
- {
-
- /// <summary>
- /// Delete file with retry on UnauthorizedAccessException.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// When calling File.Delete() on a file that has been "recently"
- /// created, the call sometimes fails with
- /// UnauthorizedAccessException. This method simply retries the Delete 3
- /// times with a sleep between tries.
- /// </para>
- /// </remarks>
- ///
- /// <param name='filename'>the name of the file to be deleted</param>
- private void DeleteFileWithRetry(string filename)
- {
- bool done = false;
- int nRetries = 3;
- for (int i=0; i < nRetries && !done; i++)
- {
- try
- {
- File.Delete(filename);
- done = true;
- }
- catch (System.UnauthorizedAccessException)
- {
- Console.WriteLine("************************************************** Retry delete.");
- System.Threading.Thread.Sleep(200+i*200);
- }
- }
- }
-
-
- /// <summary>
- /// Saves the Zip archive to a file, specified by the Name property of the
- /// <c>ZipFile</c>.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The <c>ZipFile</c> instance is written to storage, typically a zip file
- /// in a filesystem, only when the caller calls <c>Save</c>. In the typical
- /// case, the Save operation writes the zip content to a temporary file, and
- /// then renames the temporary file to the desired name. If necessary, this
- /// method will delete a pre-existing file before the rename.
- /// </para>
- ///
- /// <para>
- /// The <see cref="ZipFile.Name"/> property is specified either explicitly,
- /// or implicitly using one of the parameterized ZipFile constructors. For
- /// COM Automation clients, the <c>Name</c> property must be set explicitly,
- /// because COM Automation clients cannot call parameterized constructors.
- /// </para>
- ///
- /// <para>
- /// When using a filesystem file for the Zip output, it is possible to call
- /// <c>Save</c> multiple times on the <c>ZipFile</c> instance. With each
- /// call the zip content is re-written to the same output file.
- /// </para>
- ///
- /// <para>
- /// Data for entries that have been added to the <c>ZipFile</c> instance is
- /// written to the output when the <c>Save</c> method is called. This means
- /// that the input streams for those entries must be available at the time
- /// the application calls <c>Save</c>. If, for example, the application
- /// adds entries with <c>AddEntry</c> using a dynamically-allocated
- /// <c>MemoryStream</c>, the memory stream must not have been disposed
- /// before the call to <c>Save</c>. See the <see
- /// cref="ZipEntry.InputStream"/> property for more discussion of the
- /// availability requirements of the input stream for an entry, and an
- /// approach for providing just-in-time stream lifecycle management.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.AddEntry(String, System.IO.Stream)"/>
- ///
- /// <exception cref="Ionic.Zip.BadStateException">
- /// Thrown if you haven't specified a location or stream for saving the zip,
- /// either in the constructor or by setting the Name property, or if you try
- /// to save a regular zip archive to a filename with a .exe extension.
- /// </exception>
- ///
- /// <exception cref="System.OverflowException">
- /// Thrown if <see cref="MaxOutputSegmentSize"/> is non-zero, and the number
- /// of segments that would be generated for the spanned zip file during the
- /// save operation exceeds 99. If this happens, you need to increase the
- /// segment size.
- /// </exception>
- ///
- public void Save()
- {
- try
- {
- bool thisSaveUsedZip64 = false;
- _saveOperationCanceled = false;
- _numberOfSegmentsForMostRecentSave = 0;
- OnSaveStarted();
-
- if (WriteStream == null)
- throw new BadStateException("You haven't specified where to save the zip.");
-
- if (_name != null && _name.EndsWith(".exe") && !_SavingSfx)
- throw new BadStateException("You specified an EXE for a plain zip file.");
-
- // check if modified, before saving.
- if (!_contentsChanged)
- {
- OnSaveCompleted();
- if (Verbose) StatusMessageTextWriter.WriteLine("No save is necessary....");
- return;
- }
-
- Reset(true);
-
- if (Verbose) StatusMessageTextWriter.WriteLine("saving....");
-
- // validate the number of entries
- if (_entries.Count >= 0xFFFF && _zip64 == Zip64Option.Never)
- throw new ZipException("The number of entries is 65535 or greater. Consider setting the UseZip64WhenSaving property on the ZipFile instance.");
-
-
- // write an entry in the zip for each file
- int n = 0;
- // workitem 9831
- ICollection<ZipEntry> c = (SortEntriesBeforeSaving) ? EntriesSorted : Entries;
- foreach (ZipEntry e in c) // _entries.Values
- {
- OnSaveEntry(n, e, true);
- e.Write(WriteStream);
- if (_saveOperationCanceled)
- break;
-
- n++;
- OnSaveEntry(n, e, false);
- if (_saveOperationCanceled)
- break;
-
- // Some entries can be skipped during the save.
- if (e.IncludedInMostRecentSave)
- thisSaveUsedZip64 |= e.OutputUsedZip64.Value;
- }
-
-
-
- if (_saveOperationCanceled)
- return;
-
- var zss = WriteStream as ZipSegmentedStream;
-
- _numberOfSegmentsForMostRecentSave = (zss!=null)
- ? zss.CurrentSegment
- : 1;
-
- bool directoryNeededZip64 =
- ZipOutput.WriteCentralDirectoryStructure
- (WriteStream,
- c,
- _numberOfSegmentsForMostRecentSave,
- _zip64,
- Comment,
- new ZipContainer(this));
-
- OnSaveEvent(ZipProgressEventType.Saving_AfterSaveTempArchive);
-
- _hasBeenSaved = true;
- _contentsChanged = false;
-
- thisSaveUsedZip64 |= directoryNeededZip64;
- _OutputUsesZip64 = new Nullable<bool>(thisSaveUsedZip64);
-
-
- // do the rename as necessary
- if (_name != null &&
- (_temporaryFileName!=null || zss != null))
- {
- // _temporaryFileName may remain null if we are writing to a stream.
- // only close the stream if there is a file behind it.
-#if NETCF
- WriteStream.Close();
-#else
- WriteStream.Dispose();
-#endif
- if (_saveOperationCanceled)
- return;
-
- if (_fileAlreadyExists && this._readstream != null)
- {
- // This means we opened and read a zip file.
- // If we are now saving to the same file, we need to close the
- // orig file, first.
- this._readstream.Close();
- this._readstream = null;
- // the archiveStream for each entry needs to be null
- foreach (var e in c)
- {
- var zss1 = e._archiveStream as ZipSegmentedStream;
- if (zss1 != null)
-#if NETCF
- zss1.Close();
-#else
- zss1.Dispose();
-#endif
- e._archiveStream = null;
- }
- }
-
- string tmpName = null;
- if (File.Exists(_name))
- {
- // the steps:
- //
- // 1. Delete tmpName
- // 2. move existing zip to tmpName
- // 3. rename (File.Move) working file to name of existing zip
- // 4. delete tmpName
- //
- // This series of steps avoids the exception,
- // System.IO.IOException:
- // "Cannot create a file when that file already exists."
- //
- // Cannot just call File.Replace() here because
- // there is a possibility that the TEMP volume is different
- // that the volume for the final file (c:\ vs d:\).
- // So we need to do a Delete+Move pair.
- //
- // But, when doing the delete, Windows allows a process to
- // delete the file, even though it is held open by, say, a
- // virus scanner. It gets internally marked as "delete
- // pending". The file does not actually get removed from the
- // file system, it is still there after the File.Delete
- // call.
- //
- // Therefore, we need to move the existing zip, which may be
- // held open, to some other name. Then rename our working
- // file to the desired name, then delete (possibly delete
- // pending) the "other name".
- //
- // Ideally this would be transactional. It's possible that the
- // delete succeeds and the move fails. Lacking transactions, if
- // this kind of failure happens, we're hosed, and this logic will
- // throw on the next File.Move().
- //
- //File.Delete(_name);
- // workitem 10447
-#if NETCF || SILVERLIGHT
- tmpName = _name + "." + SharedUtilities.GenerateRandomStringImpl(8,0) + ".tmp";
-#else
- tmpName = _name + "." + Path.GetRandomFileName();
-#endif
- if (File.Exists(tmpName))
- DeleteFileWithRetry(tmpName);
- File.Move(_name, tmpName);
- }
-
- OnSaveEvent(ZipProgressEventType.Saving_BeforeRenameTempArchive);
- File.Move((zss != null) ? zss.CurrentTempName : _temporaryFileName,
- _name);
-
- OnSaveEvent(ZipProgressEventType.Saving_AfterRenameTempArchive);
-
- if (tmpName != null)
- {
- try
- {
- // not critical
- if (File.Exists(tmpName))
- File.Delete(tmpName);
- }
- catch
- {
- // don't care about exceptions here.
- }
-
- }
- _fileAlreadyExists = true;
- }
-
- NotifyEntriesSaveComplete(c);
- OnSaveCompleted();
- _JustSaved = true;
- }
-
- // workitem 5043
- finally
- {
- CleanupAfterSaveOperation();
- }
-
- return;
- }
-
-
-
- private static void NotifyEntriesSaveComplete(ICollection<ZipEntry> c)
- {
- foreach (ZipEntry e in c)
- {
- e.NotifySaveComplete();
- }
- }
-
-
- private void RemoveTempFile()
- {
- try
- {
- if (File.Exists(_temporaryFileName))
- {
- File.Delete(_temporaryFileName);
- }
- }
- catch (IOException ex1)
- {
- if (Verbose)
- StatusMessageTextWriter.WriteLine("ZipFile::Save: could not delete temp file: {0}.", ex1.Message);
- }
- }
-
-
- private void CleanupAfterSaveOperation()
- {
- if (_name != null)
- {
- // close the stream if there is a file behind it.
- if (_writestream != null)
- {
- try
- {
- // workitem 7704
-#if NETCF
- _writestream.Close();
-#else
- _writestream.Dispose();
-#endif
- }
- catch (System.IO.IOException) { }
- }
- _writestream = null;
-
- if (_temporaryFileName != null)
- {
- RemoveTempFile();
- _temporaryFileName = null;
- }
- }
- }
-
-
- /// <summary>
- /// Save the file to a new zipfile, with the given name.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method allows the application to explicitly specify the name of the zip
- /// file when saving. Use this when creating a new zip file, or when
- /// updating a zip archive.
- /// </para>
- ///
- /// <para>
- /// An application can also save a zip archive in several places by calling this
- /// method multiple times in succession, with different filenames.
- /// </para>
- ///
- /// <para>
- /// The <c>ZipFile</c> instance is written to storage, typically a zip file in a
- /// filesystem, only when the caller calls <c>Save</c>. The Save operation writes
- /// the zip content to a temporary file, and then renames the temporary file
- /// to the desired name. If necessary, this method will delete a pre-existing file
- /// before the rename.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <exception cref="System.ArgumentException">
- /// Thrown if you specify a directory for the filename.
- /// </exception>
- ///
- /// <param name="fileName">
- /// The name of the zip archive to save to. Existing files will
- /// be overwritten with great prejudice.
- /// </param>
- ///
- /// <example>
- /// This example shows how to create and Save a zip file.
- /// <code>
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// zip.AddDirectory(@"c:\reports\January");
- /// zip.Save("January.zip");
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As New ZipFile()
- /// zip.AddDirectory("c:\reports\January")
- /// zip.Save("January.zip")
- /// End Using
- /// </code>
- ///
- /// </example>
- ///
- /// <example>
- /// This example shows how to update a zip file.
- /// <code>
- /// using (ZipFile zip = ZipFile.Read("ExistingArchive.zip"))
- /// {
- /// zip.AddFile("NewData.csv");
- /// zip.Save("UpdatedArchive.zip");
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As ZipFile = ZipFile.Read("ExistingArchive.zip")
- /// zip.AddFile("NewData.csv")
- /// zip.Save("UpdatedArchive.zip")
- /// End Using
- /// </code>
- ///
- /// </example>
- public void Save(String fileName)
- {
- // Check for the case where we are re-saving a zip archive
- // that was originally instantiated with a stream. In that case,
- // the _name will be null. If so, we set _writestream to null,
- // which insures that we'll cons up a new WriteStream (with a filesystem
- // file backing it) in the Save() method.
- if (_name == null)
- _writestream = null;
-
- else _readName = _name; // workitem 13915
-
- _name = fileName;
- if (Directory.Exists(_name))
- throw new ZipException("Bad Directory", new System.ArgumentException("That name specifies an existing directory. Please specify a filename.", "fileName"));
- _contentsChanged = true;
- _fileAlreadyExists = File.Exists(_name);
- Save();
- }
-
-
- /// <summary>
- /// Save the zip archive to the specified stream.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The <c>ZipFile</c> instance is written to storage - typically a zip file
- /// in a filesystem, but using this overload, the storage can be anything
- /// accessible via a writable stream - only when the caller calls <c>Save</c>.
- /// </para>
- ///
- /// <para>
- /// Use this method to save the zip content to a stream directly. A common
- /// scenario is an ASP.NET application that dynamically generates a zip file
- /// and allows the browser to download it. The application can call
- /// <c>Save(Response.OutputStream)</c> to write a zipfile directly to the
- /// output stream, without creating a zip file on the disk on the ASP.NET
- /// server.
- /// </para>
- ///
- /// <para>
- /// Be careful when saving a file to a non-seekable stream, including
- /// <c>Response.OutputStream</c>. When DotNetZip writes to a non-seekable
- /// stream, the zip archive is formatted in such a way that may not be
- /// compatible with all zip tools on all platforms. It's a perfectly legal
- /// and compliant zip file, but some people have reported problems opening
- /// files produced this way using the Mac OS archive utility.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example saves the zipfile content into a MemoryStream, and
- /// then gets the array of bytes from that MemoryStream.
- ///
- /// <code lang="C#">
- /// using (var zip = new Ionic.Zip.ZipFile())
- /// {
- /// zip.CompressionLevel= Ionic.Zlib.CompressionLevel.BestCompression;
- /// zip.Password = "VerySecret.";
- /// zip.Encryption = EncryptionAlgorithm.WinZipAes128;
- /// zip.AddFile(sourceFileName);
- /// MemoryStream output = new MemoryStream();
- /// zip.Save(output);
- ///
- /// byte[] zipbytes = output.ToArray();
- /// }
- /// </code>
- /// </example>
- ///
- /// <example>
- /// <para>
- /// This example shows a pitfall you should avoid. DO NOT read
- /// from a stream, then try to save to the same stream. DO
- /// NOT DO THIS:
- /// </para>
- ///
- /// <code lang="C#">
- /// using (var fs = new FileSteeam(filename, FileMode.Open))
- /// {
- /// using (var zip = Ionic.Zip.ZipFile.Read(inputStream))
- /// {
- /// zip.AddEntry("Name1.txt", "this is the content");
- /// zip.Save(inputStream); // NO NO NO!!
- /// }
- /// }
- /// </code>
- ///
- /// <para>
- /// Better like this:
- /// </para>
- ///
- /// <code lang="C#">
- /// using (var zip = Ionic.Zip.ZipFile.Read(filename))
- /// {
- /// zip.AddEntry("Name1.txt", "this is the content");
- /// zip.Save(); // YES!
- /// }
- /// </code>
- ///
- /// </example>
- ///
- /// <param name="outputStream">
- /// The <c>System.IO.Stream</c> to write to. It must be
- /// writable. If you created the ZipFile instanct by calling
- /// ZipFile.Read(), this stream must not be the same stream
- /// you passed to ZipFile.Read().
- /// </param>
- public void Save(Stream outputStream)
- {
- if (outputStream == null)
- throw new ArgumentNullException("outputStream");
- if (!outputStream.CanWrite)
- throw new ArgumentException("Must be a writable stream.", "outputStream");
-
- // if we had a filename to save to, we are now obliterating it.
- _name = null;
-
- _writestream = new CountingStream(outputStream);
-
- _contentsChanged = true;
- _fileAlreadyExists = false;
- Save();
- }
-
-
- }
-
-
-
- internal static class ZipOutput
- {
- public static bool WriteCentralDirectoryStructure(Stream s,
- ICollection<ZipEntry> entries,
- uint numSegments,
- Zip64Option zip64,
- String comment,
- ZipContainer container)
- {
- var zss = s as ZipSegmentedStream;
- if (zss != null)
- zss.ContiguousWrite = true;
-
- // write to a memory stream in order to keep the
- // CDR contiguous
- Int64 aLength = 0;
- using (var ms = new MemoryStream())
- {
- foreach (ZipEntry e in entries)
- {
- if (e.IncludedInMostRecentSave)
- {
- // this writes a ZipDirEntry corresponding to the ZipEntry
- e.WriteCentralDirectoryEntry(ms);
- }
- }
- var a = ms.ToArray();
- s.Write(a, 0, a.Length);
- aLength = a.Length;
- }
-
-
- // We need to keep track of the start and
- // Finish of the Central Directory Structure.
-
- // Cannot always use WriteStream.Length or Position; some streams do
- // not support these. (eg, ASP.NET Response.OutputStream) In those
- // cases we have a CountingStream.
-
- // Also, we cannot just set Start as s.Position bfore the write, and Finish
- // as s.Position after the write. In a split zip, the write may actually
- // flip to the next segment. In that case, Start will be zero. But we
- // don't know that til after we know the size of the thing to write. So the
- // answer is to compute the directory, then ask the ZipSegmentedStream which
- // segment that directory would fall in, it it were written. Then, include
- // that data into the directory, and finally, write the directory to the
- // output stream.
-
- var output = s as CountingStream;
- long Finish = (output != null) ? output.ComputedPosition : s.Position; // BytesWritten
- long Start = Finish - aLength;
-
- // need to know which segment the EOCD record starts in
- UInt32 startSegment = (zss != null)
- ? zss.CurrentSegment
- : 0;
-
- Int64 SizeOfCentralDirectory = Finish - Start;
-
- int countOfEntries = CountEntries(entries);
-
- bool needZip64CentralDirectory =
- zip64 == Zip64Option.Always ||
- countOfEntries >= 0xFFFF ||
- SizeOfCentralDirectory > 0xFFFFFFFF ||
- Start > 0xFFFFFFFF;
-
- byte[] a2 = null;
-
- // emit ZIP64 extensions as required
- if (needZip64CentralDirectory)
- {
- if (zip64 == Zip64Option.Never)
- {
-#if NETCF
- throw new ZipException("The archive requires a ZIP64 Central Directory. Consider enabling ZIP64 extensions.");
-#else
- System.Diagnostics.StackFrame sf = new System.Diagnostics.StackFrame(1);
- if (sf.GetMethod().DeclaringType == typeof(ZipFile))
- throw new ZipException("The archive requires a ZIP64 Central Directory. Consider setting the ZipFile.UseZip64WhenSaving property.");
- else
- throw new ZipException("The archive requires a ZIP64 Central Directory. Consider setting the ZipOutputStream.EnableZip64 property.");
-#endif
-
- }
-
- var a = GenZip64EndOfCentralDirectory(Start, Finish, countOfEntries, numSegments);
- a2 = GenCentralDirectoryFooter(Start, Finish, zip64, countOfEntries, comment, container);
- if (startSegment != 0)
- {
- UInt32 thisSegment = zss.ComputeSegment(a.Length + a2.Length);
- int i = 16;
- // number of this disk
- Array.Copy(BitConverter.GetBytes(thisSegment), 0, a, i, 4);
- i += 4;
- // number of the disk with the start of the central directory
- //Array.Copy(BitConverter.GetBytes(startSegment), 0, a, i, 4);
- Array.Copy(BitConverter.GetBytes(thisSegment), 0, a, i, 4);
-
- i = 60;
- // offset 60
- // number of the disk with the start of the zip64 eocd
- Array.Copy(BitConverter.GetBytes(thisSegment), 0, a, i, 4);
- i += 4;
- i += 8;
-
- // offset 72
- // total number of disks
- Array.Copy(BitConverter.GetBytes(thisSegment), 0, a, i, 4);
- }
- s.Write(a, 0, a.Length);
- }
- else
- a2 = GenCentralDirectoryFooter(Start, Finish, zip64, countOfEntries, comment, container);
-
-
- // now, the regular footer
- if (startSegment != 0)
- {
- // The assumption is the central directory is never split across
- // segment boundaries.
-
- UInt16 thisSegment = (UInt16) zss.ComputeSegment(a2.Length);
- int i = 4;
- // number of this disk
- Array.Copy(BitConverter.GetBytes(thisSegment), 0, a2, i, 2);
- i += 2;
- // number of the disk with the start of the central directory
- //Array.Copy(BitConverter.GetBytes((UInt16)startSegment), 0, a2, i, 2);
- Array.Copy(BitConverter.GetBytes(thisSegment), 0, a2, i, 2);
- i += 2;
- }
-
- s.Write(a2, 0, a2.Length);
-
- // reset the contiguous write property if necessary
- if (zss != null)
- zss.ContiguousWrite = false;
-
- return needZip64CentralDirectory;
- }
-
-
- private static System.Text.Encoding GetEncoding(ZipContainer container, string t)
- {
- switch (container.AlternateEncodingUsage)
- {
- case ZipOption.Always:
- return container.AlternateEncoding;
- case ZipOption.Never:
- return container.DefaultEncoding;
- }
-
- // AsNecessary is in force
- var e = container.DefaultEncoding;
- if (t == null) return e;
-
- var bytes = e.GetBytes(t);
- var t2 = e.GetString(bytes,0,bytes.Length);
- if (t2.Equals(t)) return e;
- return container.AlternateEncoding;
- }
-
-
-
- private static byte[] GenCentralDirectoryFooter(long StartOfCentralDirectory,
- long EndOfCentralDirectory,
- Zip64Option zip64,
- int entryCount,
- string comment,
- ZipContainer container)
- {
- System.Text.Encoding encoding = GetEncoding(container, comment);
- int j = 0;
- int bufferLength = 22;
- byte[] block = null;
- Int16 commentLength = 0;
- if ((comment != null) && (comment.Length != 0))
- {
- block = encoding.GetBytes(comment);
- commentLength = (Int16)block.Length;
- }
- bufferLength += commentLength;
- byte[] bytes = new byte[bufferLength];
-
- int i = 0;
- // signature
- byte[] sig = BitConverter.GetBytes(ZipConstants.EndOfCentralDirectorySignature);
- Array.Copy(sig, 0, bytes, i, 4);
- i+=4;
-
- // number of this disk
- // (this number may change later)
- bytes[i++] = 0;
- bytes[i++] = 0;
-
- // number of the disk with the start of the central directory
- // (this number may change later)
- bytes[i++] = 0;
- bytes[i++] = 0;
-
- // handle ZIP64 extensions for the end-of-central-directory
- if (entryCount >= 0xFFFF || zip64 == Zip64Option.Always)
- {
- // the ZIP64 version.
- for (j = 0; j < 4; j++)
- bytes[i++] = 0xFF;
- }
- else
- {
- // the standard version.
- // total number of entries in the central dir on this disk
- bytes[i++] = (byte)(entryCount & 0x00FF);
- bytes[i++] = (byte)((entryCount & 0xFF00) >> 8);
-
- // total number of entries in the central directory
- bytes[i++] = (byte)(entryCount & 0x00FF);
- bytes[i++] = (byte)((entryCount & 0xFF00) >> 8);
- }
-
- // size of the central directory
- Int64 SizeOfCentralDirectory = EndOfCentralDirectory - StartOfCentralDirectory;
-
- if (SizeOfCentralDirectory >= 0xFFFFFFFF || StartOfCentralDirectory >= 0xFFFFFFFF)
- {
- // The actual data is in the ZIP64 central directory structure
- for (j = 0; j < 8; j++)
- bytes[i++] = 0xFF;
- }
- else
- {
- // size of the central directory (we just get the low 4 bytes)
- bytes[i++] = (byte)(SizeOfCentralDirectory & 0x000000FF);
- bytes[i++] = (byte)((SizeOfCentralDirectory & 0x0000FF00) >> 8);
- bytes[i++] = (byte)((SizeOfCentralDirectory & 0x00FF0000) >> 16);
- bytes[i++] = (byte)((SizeOfCentralDirectory & 0xFF000000) >> 24);
-
- // offset of the start of the central directory (we just get the low 4 bytes)
- bytes[i++] = (byte)(StartOfCentralDirectory & 0x000000FF);
- bytes[i++] = (byte)((StartOfCentralDirectory & 0x0000FF00) >> 8);
- bytes[i++] = (byte)((StartOfCentralDirectory & 0x00FF0000) >> 16);
- bytes[i++] = (byte)((StartOfCentralDirectory & 0xFF000000) >> 24);
- }
-
-
- // zip archive comment
- if ((comment == null) || (comment.Length == 0))
- {
- // no comment!
- bytes[i++] = (byte)0;
- bytes[i++] = (byte)0;
- }
- else
- {
- // the size of our buffer defines the max length of the comment we can write
- if (commentLength + i + 2 > bytes.Length) commentLength = (Int16)(bytes.Length - i - 2);
- bytes[i++] = (byte)(commentLength & 0x00FF);
- bytes[i++] = (byte)((commentLength & 0xFF00) >> 8);
-
- if (commentLength != 0)
- {
- // now actually write the comment itself into the byte buffer
- for (j = 0; (j < commentLength) && (i + j < bytes.Length); j++)
- {
- bytes[i + j] = block[j];
- }
- i += j;
- }
- }
-
- // s.Write(bytes, 0, i);
- return bytes;
- }
-
-
-
- private static byte[] GenZip64EndOfCentralDirectory(long StartOfCentralDirectory,
- long EndOfCentralDirectory,
- int entryCount,
- uint numSegments)
- {
- const int bufferLength = 12 + 44 + 20;
-
- byte[] bytes = new byte[bufferLength];
-
- int i = 0;
- // signature
- byte[] sig = BitConverter.GetBytes(ZipConstants.Zip64EndOfCentralDirectoryRecordSignature);
- Array.Copy(sig, 0, bytes, i, 4);
- i+=4;
-
- // There is a possibility to include "Extensible" data in the zip64
- // end-of-central-dir record. I cannot figure out what it might be used to
- // store, so the size of this record is always fixed. Maybe it is used for
- // strong encryption data? That is for another day.
- long DataSize = 44;
- Array.Copy(BitConverter.GetBytes(DataSize), 0, bytes, i, 8);
- i += 8;
-
- // offset 12
- // VersionMadeBy = 45;
- bytes[i++] = 45;
- bytes[i++] = 0x00;
-
- // VersionNeededToExtract = 45;
- bytes[i++] = 45;
- bytes[i++] = 0x00;
-
- // offset 16
- // number of the disk, and the disk with the start of the central dir.
- // (this may change later)
- for (int j = 0; j < 8; j++)
- bytes[i++] = 0x00;
-
- // offset 24
- long numberOfEntries = entryCount;
- Array.Copy(BitConverter.GetBytes(numberOfEntries), 0, bytes, i, 8);
- i += 8;
- Array.Copy(BitConverter.GetBytes(numberOfEntries), 0, bytes, i, 8);
- i += 8;
-
- // offset 40
- Int64 SizeofCentraldirectory = EndOfCentralDirectory - StartOfCentralDirectory;
- Array.Copy(BitConverter.GetBytes(SizeofCentraldirectory), 0, bytes, i, 8);
- i += 8;
- Array.Copy(BitConverter.GetBytes(StartOfCentralDirectory), 0, bytes, i, 8);
- i += 8;
-
- // offset 56
- // now, the locator
- // signature
- sig = BitConverter.GetBytes(ZipConstants.Zip64EndOfCentralDirectoryLocatorSignature);
- Array.Copy(sig, 0, bytes, i, 4);
- i+=4;
-
- // offset 60
- // number of the disk with the start of the zip64 eocd
- // (this will change later) (it will?)
- uint x2 = (numSegments==0)?0:(uint)(numSegments-1);
- Array.Copy(BitConverter.GetBytes(x2), 0, bytes, i, 4);
- i+=4;
-
- // offset 64
- // relative offset of the zip64 eocd
- Array.Copy(BitConverter.GetBytes(EndOfCentralDirectory), 0, bytes, i, 8);
- i += 8;
-
- // offset 72
- // total number of disks
- // (this will change later)
- Array.Copy(BitConverter.GetBytes(numSegments), 0, bytes, i, 4);
- i+=4;
-
- return bytes;
- }
-
-
-
- private static int CountEntries(ICollection<ZipEntry> _entries)
- {
- // Cannot just emit _entries.Count, because some of the entries
- // may have been skipped.
- int count = 0;
- foreach (var entry in _entries)
- if (entry.IncludedInMostRecentSave) count++;
- return count;
- }
-
-
-
-
- }
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipFile.SaveSelfExtractor.cs b/EPPlus/Packaging/DotNetZip/ZipFile.SaveSelfExtractor.cs
deleted file mode 100644
index 800a058..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipFile.SaveSelfExtractor.cs
+++ /dev/null
@@ -1,1101 +0,0 @@
-// ZipFile.saveSelfExtractor.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2008-2011 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-August-10 19:22:46>
-//
-// ------------------------------------------------------------------
-//
-// This is a the source module that implements the stuff for saving to a
-// self-extracting Zip archive.
-//
-// ZipFile is set up as a "partial class" - defined in multiple .cs source modules.
-// This is one of the source modules for the ZipFile class.
-//
-// Here's the design: The self-extracting zip file is just a regular managed EXE
-// file, with embedded resources. The managed code logic instantiates a ZipFile, and
-// then extracts each entry. The embedded resources include the zip archive content,
-// as well as the Zip library itself. The latter is required so that self-extracting
-// can work on any machine, whether or not it has the DotNetZip library installed on
-// it.
-//
-// What we need to do is create the animal I just described, within a method on the
-// ZipFile class. This source module provides that capability. The method is
-// SaveSelfExtractor().
-//
-// The way the method works: it uses the programmatic interface to the csc.exe
-// compiler, Microsoft.CSharp.CSharpCodeProvider, to compile "boilerplate"
-// extraction logic into a new assembly. As part of that compile, we embed within
-// that assembly the zip archive itself, as well as the Zip library.
-//
-// Therefore we need to first save to a temporary zip file, then produce the exe.
-//
-// There are a few twists.
-//
-// The Visual Studio Project structure is a little weird. There are code files
-// that ARE NOT compiled during a normal build of the VS Solution. They are
-// marked as embedded resources. These are the various "boilerplate" modules that
-// are used in the self-extractor. These modules are: WinFormsSelfExtractorStub.cs
-// WinFormsSelfExtractorStub.Designer.cs CommandLineSelfExtractorStub.cs
-// PasswordDialog.cs PasswordDialog.Designer.cs
-//
-// At design time, if you want to modify the way the GUI looks, you have to
-// mark those modules to have a "compile" build action. Then tweak em, test,
-// etc. Then again mark them as "Embedded resource".
-//
-// ------------------------------------------------------------------
-
-using System;
-using System.Reflection;
-using System.IO;
-using System.Collections.Generic;
-
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
-#if !NO_SFX
- /// <summary>
- /// An enum that provides the different self-extractor flavors
- /// </summary>
- internal enum SelfExtractorFlavor
- {
- /// <summary>
- /// A self-extracting zip archive that runs from the console or
- /// command line.
- /// </summary>
- ConsoleApplication = 0,
-
- /// <summary>
- /// A self-extracting zip archive that presents a graphical user
- /// interface when it is executed.
- /// </summary>
- WinFormsApplication,
- }
-
- /// <summary>
- /// The options for generating a self-extracting archive.
- /// </summary>
- internal class SelfExtractorSaveOptions
- {
- /// <summary>
- /// The type of SFX to create.
- /// </summary>
- public SelfExtractorFlavor Flavor
- {
- get;
- set;
- }
-
- /// <summary>
- /// The command to run after extraction.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This is optional. Leave it empty (<c>null</c> in C# or <c>Nothing</c> in
- /// VB) to run no command after extraction.
- /// </para>
- ///
- /// <para>
- /// If it is non-empty, the SFX will execute the command specified in this
- /// string on the user's machine, and using the extract directory as the
- /// working directory for the process, after unpacking the archive. The
- /// program to execute can include a path, if you like. If you want to execute
- /// a program that accepts arguments, specify the program name, followed by a
- /// space, and then the arguments for the program, each separated by a space,
- /// just as you would on a normal command line. Example: <c>program.exe arg1
- /// arg2</c>. The string prior to the first space will be taken as the
- /// program name, and the string following the first space specifies the
- /// arguments to the program.
- /// </para>
- ///
- /// <para>
- /// If you want to execute a program that has a space in the name or path of
- /// the file, surround the program name in double-quotes. The first character
- /// of the command line should be a double-quote character, and there must be
- /// a matching double-quote following the end of the program file name. Any
- /// optional arguments to the program follow that, separated by
- /// spaces. Example: <c>"c:\project files\program name.exe" arg1 arg2</c>.
- /// </para>
- ///
- /// <para>
- /// If the flavor of the SFX is <c>SelfExtractorFlavor.ConsoleApplication</c>,
- /// then the SFX starts a new process, using this string as the post-extract
- /// command line. The SFX waits for the process to exit. The exit code of
- /// the post-extract command line is returned as the exit code of the
- /// command-line self-extractor exe. A non-zero exit code is typically used to
- /// indicated a failure by the program. In the case of an SFX, a non-zero exit
- /// code may indicate a failure during extraction, OR, it may indicate a
- /// failure of the run-after-extract program if specified, OR, it may indicate
- /// the run-after-extract program could not be fuond. There is no way to
- /// distinguish these conditions from the calling shell, aside from parsing
- /// the output of the SFX. If you have Quiet set to <c>true</c>, you may not
- /// see error messages, if a problem occurs.
- /// </para>
- ///
- /// <para>
- /// If the flavor of the SFX is
- /// <c>SelfExtractorFlavor.WinFormsApplication</c>, then the SFX starts a new
- /// process, using this string as the post-extract command line, and using the
- /// extract directory as the working directory for the process. The SFX does
- /// not wait for the command to complete, and does not check the exit code of
- /// the program. If the run-after-extract program cannot be fuond, a message
- /// box is displayed indicating that fact.
- /// </para>
- ///
- /// <para>
- /// You can specify environment variables within this string, with a format like
- /// <c>%NAME%</c>. The value of these variables will be expanded at the time
- /// the SFX is run. Example: <c>%WINDIR%\system32\xcopy.exe</c> may expand at
- /// runtime to <c>c:\Windows\System32\xcopy.exe</c>.
- /// </para>
- ///
- /// <para>
- /// By combining this with the <c>RemoveUnpackedFilesAfterExecute</c>
- /// flag, you can create an SFX that extracts itself, runs a file that
- /// was extracted, then deletes all the files that were extracted. If
- /// you want it to run "invisibly" then set <c>Flavor</c> to
- /// <c>SelfExtractorFlavor.ConsoleApplication</c>, and set <c>Quiet</c>
- /// to true. The user running such an EXE will see a console window
- /// appear, then disappear quickly. You may also want to specify the
- /// default extract location, with <c>DefaultExtractDirectory</c>.
- /// </para>
- ///
- /// <para>
- /// If you set <c>Flavor</c> to
- /// <c>SelfExtractorFlavor.WinFormsApplication</c>, and set <c>Quiet</c> to
- /// true, then a GUI with progressbars is displayed, but it is
- /// "non-interactive" - it accepts no input from the user. Instead the SFX
- /// just automatically unpacks and exits.
- /// </para>
- ///
- /// </remarks>
- public String PostExtractCommandLine
- {
- get;
- set;
- }
-
- /// <summary>
- /// The default extract directory the user will see when
- /// running the self-extracting archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Passing null (or Nothing in VB) here will cause the Self Extractor to use
- /// the the user's personal directory (<see
- /// cref="Environment.SpecialFolder.Personal"/>) for the default extract
- /// location.
- /// </para>
- ///
- /// <para>
- /// This is only a default location. The actual extract location will be
- /// settable on the command line when the SFX is executed.
- /// </para>
- ///
- /// <para>
- /// You can specify environment variables within this string,
- /// with <c>%NAME%</c>. The value of these variables will be
- /// expanded at the time the SFX is run. Example:
- /// <c>%USERPROFILE%\Documents\unpack</c> may expand at runtime to
- /// <c>c:\users\melvin\Documents\unpack</c>.
- /// </para>
- /// </remarks>
- public String DefaultExtractDirectory
- {
- get;
- set;
- }
-
- /// <summary>
- /// The name of an .ico file in the filesystem to use for the application icon
- /// for the generated SFX.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Normally, DotNetZip will embed an "zipped folder" icon into the generated
- /// SFX. If you prefer to use a different icon, you can specify it here. It
- /// should be a .ico file. This file is passed as the <c>/win32icon</c>
- /// option to the csc.exe compiler when constructing the SFX file.
- /// </para>
- /// </remarks>
- ///
- public string IconFile
- {
- get;
- set;
- }
-
- /// <summary>
- /// Whether the ConsoleApplication SFX will be quiet during extraction.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This option affects the way the generated SFX runs. By default it is
- /// false. When you set it to true,...
- /// </para>
- ///
- /// <list type="table">
- /// <listheader>
- /// <term>Flavor</term>
- /// <description>Behavior</description>
- /// </listheader>
- ///
- /// <item>
- /// <term><c>ConsoleApplication</c></term>
- /// <description><para>no messages will be emitted during successful
- /// operation.</para> <para> Double-clicking the SFX in Windows
- /// Explorer or as an attachment in an email will cause a console
- /// window to appear briefly, before it disappears. If you run the
- /// ConsoleApplication SFX from the cmd.exe prompt, it runs as a
- /// normal console app; by default, because it is quiet, it displays
- /// no messages to the console. If you pass the -v+ command line
- /// argument to the Console SFX when you run it, you will get verbose
- /// messages to the console. </para>
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term><c>WinFormsApplication</c></term>
- /// <description>the SFX extracts automatically when the application
- /// is launched, with no additional user input.
- /// </description>
- /// </item>
- ///
- /// </list>
- ///
- /// <para>
- /// When you set it to false,...
- /// </para>
- ///
- /// <list type="table">
- /// <listheader>
- /// <term>Flavor</term>
- /// <description>Behavior</description>
- /// </listheader>
- ///
- /// <item>
- /// <term><c>ConsoleApplication</c></term>
- /// <description><para>the extractor will emit a
- /// message to the console for each entry extracted.</para>
- /// <para>
- /// When double-clicking to launch the SFX, the console window will
- /// remain, and the SFX will emit a message for each file as it
- /// extracts. The messages fly by quickly, they won't be easily
- /// readable, unless the extracted files are fairly large.
- /// </para>
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term><c>WinFormsApplication</c></term>
- /// <description>the SFX presents a forms UI and allows the user to select
- /// options before extracting.
- /// </description>
- /// </item>
- ///
- /// </list>
- ///
- /// </remarks>
- public bool Quiet
- {
- get;
- set;
- }
-
-
- /// <summary>
- /// Specify what the self-extractor will do when extracting an entry
- /// would overwrite an existing file.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The default behavvior is to Throw.
- /// </para>
- /// </remarks>
- public Ionic.Zip.ExtractExistingFileAction ExtractExistingFile
- {
- get;
- set;
- }
-
-
- /// <summary>
- /// Whether to remove the files that have been unpacked, after executing the
- /// PostExtractCommandLine.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// If true, and if there is a <see
- /// cref="SelfExtractorSaveOptions.PostExtractCommandLine">
- /// PostExtractCommandLine</see>, and if the command runs successfully,
- /// then the files that the SFX unpacked will be removed, afterwards. If
- /// the command does not complete successfully (non-zero return code),
- /// that is interpreted as a failure, and the extracted files will not be
- /// removed.
- /// </para>
- ///
- /// <para>
- /// Setting this flag, and setting <c>Flavor</c> to
- /// <c>SelfExtractorFlavor.ConsoleApplication</c>, and setting <c>Quiet</c> to
- /// true, results in an SFX that extracts itself, runs a file that was
- /// extracted, then deletes all the files that were extracted, with no
- /// intervention by the user. You may also want to specify the default
- /// extract location, with <c>DefaultExtractDirectory</c>.
- /// </para>
- ///
- /// </remarks>
- public bool RemoveUnpackedFilesAfterExecute
- {
- get;
- set;
- }
-
-
- /// <summary>
- /// The file version number to embed into the generated EXE. It will show up, for
- /// example, during a mouseover in Windows Explorer.
- /// </summary>
- ///
- public Version FileVersion
- {
- get;
- set;
- }
-
- /// <summary>
- /// The product version to embed into the generated EXE. It will show up, for
- /// example, during a mouseover in Windows Explorer.
- /// </summary>
- ///
- /// <remarks>
- /// You can use any arbitrary string, but a human-readable version number is
- /// recommended. For example "v1.2 alpha" or "v4.2 RC2". If you specify nothing,
- /// then there is no product version embedded into the EXE.
- /// </remarks>
- ///
- public String ProductVersion
- {
- get;
- set;
- }
-
- /// <summary>
- /// The copyright notice, if any, to embed into the generated EXE.
- /// </summary>
- ///
- /// <remarks>
- /// It will show up, for example, while viewing properties of the file in
- /// Windows Explorer. You can use any arbitrary string, but typically you
- /// want something like "Copyright � Dino Chiesa 2011".
- /// </remarks>
- ///
- public String Copyright
- {
- get;
- set;
- }
-
-
- /// <summary>
- /// The description to embed into the generated EXE.
- /// </summary>
- ///
- /// <remarks>
- /// Use any arbitrary string. This text will be displayed during a
- /// mouseover in Windows Explorer. If you specify nothing, then the string
- /// "DotNetZip SFX Archive" is embedded into the EXE as the description.
- /// </remarks>
- ///
- public String Description
- {
- get;
- set;
- }
-
- /// <summary>
- /// The product name to embed into the generated EXE.
- /// </summary>
- ///
- /// <remarks>
- /// Use any arbitrary string. This text will be displayed
- /// while viewing properties of the EXE file in
- /// Windows Explorer.
- /// </remarks>
- ///
- public String ProductName
- {
- get;
- set;
- }
-
- /// <summary>
- /// The title to display in the Window of a GUI SFX, while it extracts.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// By default the title show in the GUI window of a self-extractor
- /// is "DotNetZip Self-extractor (http://DotNetZip.codeplex.com/)".
- /// You can change that by setting this property before saving the SFX.
- /// </para>
- ///
- /// <para>
- /// This property has an effect only when producing a Self-extractor
- /// of flavor <c>SelfExtractorFlavor.WinFormsApplication</c>.
- /// </para>
- /// </remarks>
- ///
- public String SfxExeWindowTitle
- {
- // workitem 12608
- get;
- set;
- }
-
- /// <summary>
- /// Additional options for the csc.exe compiler, when producing the SFX
- /// EXE.
- /// </summary>
- /// <exclude/>
- public string AdditionalCompilerSwitches
- {
- get; set;
- }
- }
-
-
-
-
- partial class ZipFile
- {
- class ExtractorSettings
- {
- public SelfExtractorFlavor Flavor;
- public List<string> ReferencedAssemblies;
- public List<string> CopyThroughResources;
- public List<string> ResourcesToCompile;
- }
-
-
- private static ExtractorSettings[] SettingsList = {
- new ExtractorSettings() {
- Flavor = SelfExtractorFlavor.WinFormsApplication,
- ReferencedAssemblies= new List<string>{
- "System.dll", "System.Windows.Forms.dll", "System.Drawing.dll"},
- CopyThroughResources = new List<string>{
- "Ionic.Zip.WinFormsSelfExtractorStub.resources",
- "Ionic.Zip.Forms.PasswordDialog.resources",
- "Ionic.Zip.Forms.ZipContentsDialog.resources"},
- ResourcesToCompile = new List<string>{
- "WinFormsSelfExtractorStub.cs",
- "WinFormsSelfExtractorStub.Designer.cs", // .Designer.cs?
- "PasswordDialog.cs",
- "PasswordDialog.Designer.cs", //.Designer.cs"
- "ZipContentsDialog.cs",
- "ZipContentsDialog.Designer.cs", //.Designer.cs"
- "FolderBrowserDialogEx.cs",
- }
- },
- new ExtractorSettings() {
- Flavor = SelfExtractorFlavor.ConsoleApplication,
- ReferencedAssemblies= new List<string> { "System.dll", },
- CopyThroughResources = null,
- ResourcesToCompile = new List<string>{"CommandLineSelfExtractorStub.cs"}
- }
- };
-
-
-
- //string _defaultExtractLocation;
- //string _postExtractCmdLine;
- // string _SetDefaultLocationCode =
- // "namespace OfficeOpenXml.Packaging.Ionic.Zip { internal partial class WinFormsSelfExtractorStub { partial void _SetDefaultExtractLocation() {" +
- // " txtExtractDirectory.Text = \"@@VALUE\"; } }}";
-
-
-
- /// <summary>
- /// Saves the ZipFile instance to a self-extracting zip archive.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// The generated exe image will execute on any machine that has the .NET
- /// Framework 2.0 installed on it. The generated exe image is also a
- /// valid ZIP file, readable with DotNetZip or another Zip library or tool
- /// such as WinZip.
- /// </para>
- ///
- /// <para>
- /// There are two "flavors" of self-extracting archive. The
- /// <c>WinFormsApplication</c> version will pop up a GUI and allow the
- /// user to select a target directory into which to extract. There's also
- /// a checkbox allowing the user to specify to overwrite existing files,
- /// and another checkbox to allow the user to request that Explorer be
- /// opened to see the extracted files after extraction. The other flavor
- /// is <c>ConsoleApplication</c>. A self-extractor generated with that
- /// flavor setting will run from the command line. It accepts command-line
- /// options to set the overwrite behavior, and to specify the target
- /// extraction directory.
- /// </para>
- ///
- /// <para>
- /// There are a few temporary files created during the saving to a
- /// self-extracting zip. These files are created in the directory pointed
- /// to by <see cref="ZipFile.TempFileFolder"/>, which defaults to <see
- /// cref="System.IO.Path.GetTempPath"/>. These temporary files are
- /// removed upon successful completion of this method.
- /// </para>
- ///
- /// <para>
- /// When a user runs the WinForms SFX, the user's personal directory (<see
- /// cref="Environment.SpecialFolder.Personal">Environment.SpecialFolder.Personal</see>)
- /// will be used as the default extract location. If you want to set the
- /// default extract location, you should use the other overload of
- /// <c>SaveSelfExtractor()</c>/ The user who runs the SFX will have the
- /// opportunity to change the extract directory before extracting. When
- /// the user runs the Command-Line SFX, the user must explicitly specify
- /// the directory to which to extract. The .NET Framework 2.0 is required
- /// on the computer when the self-extracting archive is run.
- /// </para>
- ///
- /// <para>
- /// NB: This method is not available in the version of DotNetZip build for
- /// the .NET Compact Framework, nor in the "Reduced" DotNetZip library.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// <code>
- /// string DirectoryPath = "c:\\Documents\\Project7";
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath));
- /// zip.Comment = "This will be embedded into a self-extracting console-based exe";
- /// zip.SaveSelfExtractor("archive.exe", SelfExtractorFlavor.ConsoleApplication);
- /// }
- /// </code>
- /// <code lang="VB">
- /// Dim DirectoryPath As String = "c:\Documents\Project7"
- /// Using zip As New ZipFile()
- /// zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath))
- /// zip.Comment = "This will be embedded into a self-extracting console-based exe"
- /// zip.SaveSelfExtractor("archive.exe", SelfExtractorFlavor.ConsoleApplication)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="exeToGenerate">
- /// a pathname, possibly fully qualified, to be created. Typically it
- /// will end in an .exe extension.</param>
- /// <param name="flavor">
- /// Indicates whether a Winforms or Console self-extractor is
- /// desired. </param>
- internal void SaveSelfExtractor(string exeToGenerate, SelfExtractorFlavor flavor)
- {
- SelfExtractorSaveOptions options = new SelfExtractorSaveOptions();
- options.Flavor = flavor;
- SaveSelfExtractor(exeToGenerate, options);
- }
-
-
-
- /// <summary>
- /// Saves the ZipFile instance to a self-extracting zip archive, using
- /// the specified save options.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method saves a self extracting archive, using the specified save
- /// options. These options include the flavor of the SFX, the default extract
- /// directory, the icon file, and so on. See the documentation
- /// for <see cref="SaveSelfExtractor(string , SelfExtractorFlavor)"/> for more
- /// details.
- /// </para>
- ///
- /// <para>
- /// The user who runs the SFX will have the opportunity to change the extract
- /// directory before extracting. If at the time of extraction, the specified
- /// directory does not exist, the SFX will create the directory before
- /// extracting the files.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// This example saves a WinForms-based self-extracting archive EXE that
- /// will use c:\ExtractHere as the default extract location. The C# code
- /// shows syntax for .NET 3.0, which uses an object initializer for
- /// the SelfExtractorOptions object.
- /// <code>
- /// string DirectoryPath = "c:\\Documents\\Project7";
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath));
- /// zip.Comment = "This will be embedded into a self-extracting WinForms-based exe";
- /// var options = new SelfExtractorOptions
- /// {
- /// Flavor = SelfExtractorFlavor.WinFormsApplication,
- /// DefaultExtractDirectory = "%USERPROFILE%\\ExtractHere",
- /// PostExtractCommandLine = ExeToRunAfterExtract,
- /// SfxExeWindowTitle = "My Custom Window Title",
- /// RemoveUnpackedFilesAfterExecute = true
- /// };
- /// zip.SaveSelfExtractor("archive.exe", options);
- /// }
- /// </code>
- /// <code lang="VB">
- /// Dim DirectoryPath As String = "c:\Documents\Project7"
- /// Using zip As New ZipFile()
- /// zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath))
- /// zip.Comment = "This will be embedded into a self-extracting console-based exe"
- /// Dim options As New SelfExtractorOptions()
- /// options.Flavor = SelfExtractorFlavor.WinFormsApplication
- /// options.DefaultExtractDirectory = "%USERPROFILE%\\ExtractHere"
- /// options.PostExtractCommandLine = ExeToRunAfterExtract
- /// options.SfxExeWindowTitle = "My Custom Window Title"
- /// options.RemoveUnpackedFilesAfterExecute = True
- /// zip.SaveSelfExtractor("archive.exe", options)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="exeToGenerate">The name of the EXE to generate.</param>
- /// <param name="options">provides the options for creating the
- /// Self-extracting archive.</param>
- internal void SaveSelfExtractor(string exeToGenerate, SelfExtractorSaveOptions options)
- {
- // Save an SFX that is both an EXE and a ZIP.
-
- // Check for the case where we are re-saving a zip archive
- // that was originally instantiated with a stream. In that case,
- // the _name will be null. If so, we set _writestream to null,
- // which insures that we'll cons up a new WriteStream (with a filesystem
- // file backing it) in the Save() method.
- if (_name == null)
- _writestream = null;
-
- _SavingSfx = true;
- _name = exeToGenerate;
- if (Directory.Exists(_name))
- throw new ZipException("Bad Directory", new System.ArgumentException("That name specifies an existing directory. Please specify a filename.", "exeToGenerate"));
- _contentsChanged = true;
- _fileAlreadyExists = File.Exists(_name);
-
- _SaveSfxStub(exeToGenerate, options);
-
- Save();
- _SavingSfx = false;
- }
-
-
-
-
- private static void ExtractResourceToFile(Assembly a, string resourceName, string filename)
- {
- int n = 0;
- byte[] bytes = new byte[1024];
- using (Stream instream = a.GetManifestResourceStream(resourceName))
- {
- if (instream == null)
- throw new ZipException(String.Format("missing resource '{0}'", resourceName));
-
- using (FileStream outstream = File.OpenWrite(filename))
- {
- do
- {
- n = instream.Read(bytes, 0, bytes.Length);
- outstream.Write(bytes, 0, n);
- } while (n > 0);
- }
- }
- }
-
-
- private void _SaveSfxStub(string exeToGenerate, SelfExtractorSaveOptions options)
- {
- string nameOfIconFile = null;
- string stubExe = null;
- string unpackedResourceDir = null;
- string tmpDir = null;
- try
- {
- if (File.Exists(exeToGenerate))
- {
- if (Verbose) StatusMessageTextWriter.WriteLine("The existing file ({0}) will be overwritten.", exeToGenerate);
- }
- if (!exeToGenerate.EndsWith(".exe"))
- {
- if (Verbose) StatusMessageTextWriter.WriteLine("Warning: The generated self-extracting file will not have an .exe extension.");
- }
-
- // workitem 10553
- tmpDir = TempFileFolder ?? Path.GetDirectoryName(exeToGenerate);
- stubExe = GenerateTempPathname(tmpDir, "exe");
-
- // get the Ionic.Zip assembly
- Assembly a1 = typeof(ZipFile).Assembly;
-
- using (var csharp = new Microsoft.CSharp.CSharpCodeProvider
- (new Dictionary<string,string>() { { "CompilerVersion", "v2.0" } })) {
-
- // The following is a perfect opportunity for a linq query, but
- // I cannot use it. DotNetZip needs to run on .NET 2.0,
- // and using LINQ would break that. Here's what it would look
- // like:
- //
- // var settings = (from x in SettingsList
- // where x.Flavor == flavor
- // select x).First();
-
- ExtractorSettings settings = null;
- foreach (var x in SettingsList)
- {
- if (x.Flavor == options.Flavor)
- {
- settings = x;
- break;
- }
- }
-
- // sanity check; should never happen
- if (settings == null)
- throw new BadStateException(String.Format("While saving a Self-Extracting Zip, Cannot find that flavor ({0})?", options.Flavor));
-
- // This is the list of referenced assemblies. Ionic.Zip is
- // needed here. Also if it is the winforms (gui) extractor, we
- // need other referenced assemblies, like
- // System.Windows.Forms.dll, etc.
- var cp = new System.CodeDom.Compiler.CompilerParameters();
- cp.ReferencedAssemblies.Add(a1.Location);
- if (settings.ReferencedAssemblies != null)
- foreach (string ra in settings.ReferencedAssemblies)
- cp.ReferencedAssemblies.Add(ra);
-
- cp.GenerateInMemory = false;
- cp.GenerateExecutable = true;
- cp.IncludeDebugInformation = false;
- cp.CompilerOptions = "";
-
- Assembly a2 = Assembly.GetExecutingAssembly();
-
- // Use this to concatenate all the source code resources into a
- // single module.
- var sb = new System.Text.StringBuilder();
-
- // In case there are compiler errors later, we allocate a source
- // file name now. If errors are detected, we'll spool the source
- // code as well as the errors (in comments) into that filename,
- // and throw an exception with the filename. Makes it easier to
- // diagnose. This should be rare; most errors happen only
- // during devlpmt of DotNetZip itself, but there are rare
- // occasions when they occur in other cases.
- string sourceFile = GenerateTempPathname(tmpDir, "cs");
-
-
- // // debugging: enumerate the resources in this assembly
- // Console.WriteLine("Resources in this assembly:");
- // foreach (string rsrc in a2.GetManifestResourceNames())
- // {
- // Console.WriteLine(rsrc);
- // }
- // Console.WriteLine();
-
-
- // all the source code is embedded in the DLL as a zip file.
- using (ZipFile zip = ZipFile.Read(a2.GetManifestResourceStream("Ionic.Zip.Resources.ZippedResources.zip")))
- {
- // // debugging: enumerate the files in the embedded zip
- // Console.WriteLine("Entries in the embbedded zip:");
- // foreach (ZipEntry entry in zip)
- // {
- // Console.WriteLine(entry.FileName);
- // }
- // Console.WriteLine();
-
- unpackedResourceDir = GenerateTempPathname(tmpDir, "tmp");
-
- if (String.IsNullOrEmpty(options.IconFile))
- {
- // Use the ico file that is embedded into the Ionic.Zip
- // DLL itself. To do this we must unpack the icon to
- // the filesystem, in order to specify it on the cmdline
- // of csc.exe. This method will remove the unpacked
- // file later.
- System.IO.Directory.CreateDirectory(unpackedResourceDir);
- ZipEntry e = zip["zippedFile.ico"];
- // Must not extract a readonly file - it will be impossible to
- // delete later.
- if ((e.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
- e.Attributes ^= FileAttributes.ReadOnly;
- e.Extract(unpackedResourceDir);
- nameOfIconFile = Path.Combine(unpackedResourceDir, "zippedFile.ico");
- cp.CompilerOptions += String.Format("/win32icon:\"{0}\"", nameOfIconFile);
- }
- else
- cp.CompilerOptions += String.Format("/win32icon:\"{0}\"", options.IconFile);
-
- cp.OutputAssembly = stubExe;
-
- if (options.Flavor == SelfExtractorFlavor.WinFormsApplication)
- cp.CompilerOptions += " /target:winexe";
-
- if (!String.IsNullOrEmpty(options.AdditionalCompilerSwitches))
- cp.CompilerOptions += " " + options.AdditionalCompilerSwitches;
-
- if (String.IsNullOrEmpty(cp.CompilerOptions))
- cp.CompilerOptions = null;
-
- if ((settings.CopyThroughResources != null) && (settings.CopyThroughResources.Count != 0))
- {
- if (!Directory.Exists(unpackedResourceDir)) System.IO.Directory.CreateDirectory(unpackedResourceDir);
- foreach (string re in settings.CopyThroughResources)
- {
- string filename = Path.Combine(unpackedResourceDir, re);
-
- ExtractResourceToFile(a2, re, filename);
- // add the file into the target assembly as an embedded resource
- cp.EmbeddedResources.Add(filename);
- }
- }
-
- // add the Ionic.Utils.Zip DLL as an embedded resource
- cp.EmbeddedResources.Add(a1.Location);
-
- // file header
- sb.Append("// " + Path.GetFileName(sourceFile) + "\n")
- .Append("// --------------------------------------------\n//\n")
- .Append("// This SFX source file was generated by DotNetZip ")
- .Append(ZipFile.LibraryVersion.ToString())
- .Append("\n// at ")
- .Append(System.DateTime.Now.ToString("yyyy MMMM dd HH:mm:ss"))
- .Append("\n//\n// --------------------------------------------\n\n\n");
-
- // assembly attributes
- if (!String.IsNullOrEmpty(options.Description))
- sb.Append("[assembly: System.Reflection.AssemblyTitle(\""
- + options.Description.Replace("\"", "")
- + "\")]\n");
- else
- sb.Append("[assembly: System.Reflection.AssemblyTitle(\"DotNetZip SFX Archive\")]\n");
-
- if (!String.IsNullOrEmpty(options.ProductVersion))
- sb.Append("[assembly: System.Reflection.AssemblyInformationalVersion(\""
- + options.ProductVersion.Replace("\"", "")
- + "\")]\n");
-
- // workitem
- string copyright =
- (String.IsNullOrEmpty(options.Copyright))
- ? "Extractor: Copyright � Dino Chiesa 2008-2011"
- : options.Copyright.Replace("\"", "");
-
- if (!String.IsNullOrEmpty(options.ProductName))
- sb.Append("[assembly: System.Reflection.AssemblyProduct(\"")
- .Append(options.ProductName.Replace("\"", ""))
- .Append("\")]\n");
- else
- sb.Append("[assembly: System.Reflection.AssemblyProduct(\"DotNetZip\")]\n");
-
-
- sb.Append("[assembly: System.Reflection.AssemblyCopyright(\"" + copyright + "\")]\n")
- .Append(String.Format("[assembly: System.Reflection.AssemblyVersion(\"{0}\")]\n", ZipFile.LibraryVersion.ToString()));
- if (options.FileVersion != null)
- sb.Append(String.Format("[assembly: System.Reflection.AssemblyFileVersion(\"{0}\")]\n",
- options.FileVersion.ToString()));
-
- sb.Append("\n\n\n");
-
- // Set the default extract location if it is available
- string extractLoc = options.DefaultExtractDirectory;
- if (extractLoc != null)
- {
- // remove double-quotes and replace slash with double-slash.
- // This, because the value is going to be embedded into a
- // cs file as a quoted string, and it needs to be escaped.
- extractLoc = extractLoc.Replace("\"", "").Replace("\\", "\\\\");
- }
-
- string postExCmdLine = options.PostExtractCommandLine;
- if (postExCmdLine != null)
- {
- postExCmdLine = postExCmdLine.Replace("\\", "\\\\");
- postExCmdLine = postExCmdLine.Replace("\"", "\\\"");
- }
-
-
- foreach (string rc in settings.ResourcesToCompile)
- {
- using (Stream s = zip[rc].OpenReader())
- {
- if (s == null)
- throw new ZipException(String.Format("missing resource '{0}'", rc));
- using (StreamReader sr = new StreamReader(s))
- {
- while (sr.Peek() >= 0)
- {
- string line = sr.ReadLine();
- if (extractLoc != null)
- line = line.Replace("@@EXTRACTLOCATION", extractLoc);
-
- line = line.Replace("@@REMOVE_AFTER_EXECUTE", options.RemoveUnpackedFilesAfterExecute.ToString());
- line = line.Replace("@@QUIET", options.Quiet.ToString());
- if (!String.IsNullOrEmpty(options.SfxExeWindowTitle))
-
- line = line.Replace("@@SFX_EXE_WINDOW_TITLE", options.SfxExeWindowTitle);
-
- line = line.Replace("@@EXTRACT_EXISTING_FILE", ((int)options.ExtractExistingFile).ToString());
-
- if (postExCmdLine != null)
- line = line.Replace("@@POST_UNPACK_CMD_LINE", postExCmdLine);
-
- sb.Append(line).Append("\n");
- }
- }
- sb.Append("\n\n");
- }
- }
- }
-
- string LiteralSource = sb.ToString();
-
-#if DEBUGSFX
- // for debugging only
- string sourceModule = GenerateTempPathname(tmpDir, "cs");
- using (StreamWriter sw = File.CreateText(sourceModule))
- {
- sw.Write(LiteralSource);
- }
- Console.WriteLine("source: {0}", sourceModule);
-#endif
-
- var cr = csharp.CompileAssemblyFromSource(cp, LiteralSource);
-
-
- if (cr == null)
- throw new SfxGenerationException("Cannot compile the extraction logic!");
-
- if (Verbose)
- foreach (string output in cr.Output)
- StatusMessageTextWriter.WriteLine(output);
-
- if (cr.Errors.Count != 0)
- {
- using (TextWriter tw = new StreamWriter(sourceFile))
- {
- // first, the source we compiled
- tw.Write(LiteralSource);
-
- // now, append the compile errors
- tw.Write("\n\n\n// ------------------------------------------------------------------\n");
- tw.Write("// Errors during compilation: \n//\n");
- string p = Path.GetFileName(sourceFile);
-
- foreach (System.CodeDom.Compiler.CompilerError error in cr.Errors)
- {
- tw.Write(String.Format("// {0}({1},{2}): {3} {4}: {5}\n//\n",
- p, // 0
- error.Line, // 1
- error.Column, // 2
- error.IsWarning ? "Warning" : "error", // 3
- error.ErrorNumber, // 4
- error.ErrorText)); // 5
- }
- }
- throw new SfxGenerationException(String.Format("Errors compiling the extraction logic! {0}", sourceFile));
- }
-
- OnSaveEvent(ZipProgressEventType.Saving_AfterCompileSelfExtractor);
-
- // Now, copy the resulting EXE image to the _writestream.
- // Because this stub exe is being saved first, the effect will be to
- // concatenate the exe and the zip data together.
- using (System.IO.Stream input = System.IO.File.OpenRead(stubExe))
- {
- byte[] buffer = new byte[4000];
- int n = 1;
- while (n != 0)
- {
- n = input.Read(buffer, 0, buffer.Length);
- if (n != 0)
- WriteStream.Write(buffer, 0, n);
- }
- }
- }
-
- OnSaveEvent(ZipProgressEventType.Saving_AfterSaveTempArchive);
- }
- finally
- {
- try
- {
- if (Directory.Exists(unpackedResourceDir))
- {
- try { Directory.Delete(unpackedResourceDir, true); }
- catch (System.IO.IOException exc1)
- {
- StatusMessageTextWriter.WriteLine("Warning: Exception: {0}", exc1);
- }
- }
- if (File.Exists(stubExe))
- {
- try { File.Delete(stubExe); }
- catch (System.IO.IOException exc1)
- {
- StatusMessageTextWriter.WriteLine("Warning: Exception: {0}", exc1);
- }
- }
- }
- catch (System.IO.IOException) { }
- }
-
- return;
-
- }
-
-
-
- internal static string GenerateTempPathname(string dir, string extension)
- {
- string candidate = null;
- String AppName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
- do
- {
- // workitem 13475
- string uuid = System.Guid.NewGuid().ToString();
-
- string Name = String.Format("{0}-{1}-{2}.{3}",
- AppName, System.DateTime.Now.ToString("yyyyMMMdd-HHmmss"),
- uuid, extension);
- candidate = System.IO.Path.Combine(dir, Name);
- } while (System.IO.File.Exists(candidate) || System.IO.Directory.Exists(candidate));
-
- // The candidate path does not exist as a file or directory.
- // It can now be created, as a file or directory.
- return candidate;
- }
-
- }
-#endif
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipFile.Selector.cs b/EPPlus/Packaging/DotNetZip/ZipFile.Selector.cs
deleted file mode 100644
index 3023f77..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipFile.Selector.cs
+++ /dev/null
@@ -1,1466 +0,0 @@
-// ZipFile.Selector.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009-2010 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-August-06 09:35:58>
-//
-// ------------------------------------------------------------------
-//
-// This module defines methods in the ZipFile class associated to the FileFilter
-// capability - selecting files to add into the archive, or selecting entries to
-// retrieve from the archive based on criteria including the filename, size, date, or
-// attributes. It is something like a "poor man's LINQ". I included it into DotNetZip
-// because not everyone has .NET 3.5 yet. When using DotNetZip on .NET 3.5, the LINQ
-// query/selection will be superior.
-//
-// These methods are segregated into a different module to facilitate easy exclusion for
-// those people who wish to have a smaller library without this function.
-//
-// ------------------------------------------------------------------
-
-
-using System;
-using System.IO;
-using System.Collections.Generic;
-using OfficeOpenXml.Packaging.Ionic.Zip;
-using System.Globalization;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
-
- partial class ZipFile
- {
- /// <summary>
- /// Adds to the ZipFile a set of files from the current working directory on
- /// disk, that conform to the specified criteria.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method selects files from the the current working directory matching
- /// the specified criteria, and adds them to the ZipFile.
- /// </para>
- ///
- /// <para>
- /// Specify the criteria in statements of 3 elements: a noun, an operator, and
- /// a value. Consider the string "name != *.doc" . The noun is "name". The
- /// operator is "!=", implying "Not Equal". The value is "*.doc". That
- /// criterion, in English, says "all files with a name that does not end in
- /// the .doc extension."
- /// </para>
- ///
- /// <para>
- /// Supported nouns include "name" (or "filename") for the filename; "atime",
- /// "mtime", and "ctime" for last access time, last modfied time, and created
- /// time of the file, respectively; "attributes" (or "attrs") for the file
- /// attributes; "size" (or "length") for the file length (uncompressed), and
- /// "type" for the type of object, either a file or a directory. The
- /// "attributes", "name" and "type" nouns both support = and != as operators.
- /// The "size", "atime", "mtime", and "ctime" nouns support = and !=, and
- /// >, >=, <, <= as well. The times are taken to be expressed in
- /// local time.
- /// </para>
- ///
- /// <para>
- /// Specify values for the file attributes as a string with one or more of the
- /// characters H,R,S,A,I,L in any order, implying file attributes of Hidden,
- /// ReadOnly, System, Archive, NotContextIndexed, and ReparsePoint (symbolic
- /// link) respectively.
- /// </para>
- ///
- /// <para>
- /// To specify a time, use YYYY-MM-DD-HH:mm:ss or YYYY/MM/DD-HH:mm:ss as the
- /// format. If you omit the HH:mm:ss portion, it is assumed to be 00:00:00
- /// (midnight).
- /// </para>
- ///
- /// <para>
- /// The value for a size criterion is expressed in integer quantities of bytes,
- /// kilobytes (use k or kb after the number), megabytes (m or mb), or gigabytes
- /// (g or gb).
- /// </para>
- ///
- /// <para>
- /// The value for a name is a pattern to match against the filename, potentially
- /// including wildcards. The pattern follows CMD.exe glob rules: * implies one
- /// or more of any character, while ? implies one character. If the name
- /// pattern contains any slashes, it is matched to the entire filename,
- /// including the path; otherwise, it is matched against only the filename
- /// without the path. This means a pattern of "*\*.*" matches all files one
- /// directory level deep, while a pattern of "*.*" matches all files in all
- /// directories.
- /// </para>
- ///
- /// <para>
- /// To specify a name pattern that includes spaces, use single quotes around the
- /// pattern. A pattern of "'* *.*'" will match all files that have spaces in
- /// the filename. The full criteria string for that would be "name = '* *.*'" .
- /// </para>
- ///
- /// <para>
- /// The value for a type criterion is either F (implying a file) or D (implying
- /// a directory).
- /// </para>
- ///
- /// <para>
- /// Some examples:
- /// </para>
- ///
- /// <list type="table">
- /// <listheader>
- /// <term>criteria</term>
- /// <description>Files retrieved</description>
- /// </listheader>
- ///
- /// <item>
- /// <term>name != *.xls </term>
- /// <description>any file with an extension that is not .xls
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>name = *.mp3 </term>
- /// <description>any file with a .mp3 extension.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>*.mp3</term>
- /// <description>(same as above) any file with a .mp3 extension.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>attributes = A </term>
- /// <description>all files whose attributes include the Archive bit.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>attributes != H </term>
- /// <description>all files whose attributes do not include the Hidden bit.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>mtime > 2009-01-01</term>
- /// <description>all files with a last modified time after January 1st, 2009.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>size > 2gb</term>
- /// <description>all files whose uncompressed size is greater than 2gb.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>type = D</term>
- /// <description>all directories in the filesystem. </description>
- /// </item>
- ///
- /// </list>
- ///
- /// <para>
- /// You can combine criteria with the conjunctions AND or OR. Using a string
- /// like "name = *.txt AND size >= 100k" for the selectionCriteria retrieves
- /// entries whose names end in .txt, and whose uncompressed size is greater than
- /// or equal to 100 kilobytes.
- /// </para>
- ///
- /// <para>
- /// For more complex combinations of criteria, you can use parenthesis to group
- /// clauses in the boolean logic. Without parenthesis, the precedence of the
- /// criterion atoms is determined by order of appearance. Unlike the C#
- /// language, the AND conjunction does not take precendence over the logical OR.
- /// This is important only in strings that contain 3 or more criterion atoms.
- /// In other words, "name = *.txt and size > 1000 or attributes = H" implies
- /// "((name = *.txt AND size > 1000) OR attributes = H)" while "attributes =
- /// H OR name = *.txt and size > 1000" evaluates to "((attributes = H OR name
- /// = *.txt) AND size > 1000)". When in doubt, use parenthesis.
- /// </para>
- ///
- /// <para>
- /// Using time properties requires some extra care. If you want to retrieve all
- /// entries that were last updated on 2009 February 14, specify a time range
- /// like so:"mtime >= 2009-02-14 AND mtime < 2009-02-15". Read this to
- /// say: all files updated after 12:00am on February 14th, until 12:00am on
- /// February 15th. You can use the same bracketing approach to specify any time
- /// period - a year, a month, a week, and so on.
- /// </para>
- ///
- /// <para>
- /// The syntax allows one special case: if you provide a string with no spaces, it is
- /// treated as a pattern to match for the filename. Therefore a string like "*.xls"
- /// will be equivalent to specifying "name = *.xls".
- /// </para>
- ///
- /// <para>
- /// There is no logic in this method that insures that the file inclusion
- /// criteria are internally consistent. For example, it's possible to specify
- /// criteria that says the file must have a size of less than 100 bytes, as well
- /// as a size that is greater than 1000 bytes. Obviously no file will ever
- /// satisfy such criteria, but this method does not detect such logical
- /// inconsistencies. The caller is responsible for insuring the criteria are
- /// sensible.
- /// </para>
- ///
- /// <para>
- /// Using this method, the file selection does not recurse into
- /// subdirectories, and the full path of the selected files is included in the
- /// entries added into the zip archive. If you don't like these behaviors,
- /// see the other overloads of this method.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// This example zips up all *.csv files in the current working directory.
- /// <code>
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// // To just match on filename wildcards,
- /// // use the shorthand form of the selectionCriteria string.
- /// zip.AddSelectedFiles("*.csv");
- /// zip.Save(PathToZipArchive);
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using zip As ZipFile = New ZipFile()
- /// zip.AddSelectedFiles("*.csv")
- /// zip.Save(PathToZipArchive)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="selectionCriteria">The criteria for file selection</param>
- public void AddSelectedFiles(String selectionCriteria)
- {
- this.AddSelectedFiles(selectionCriteria, ".", null, false);
- }
-
- /// <summary>
- /// Adds to the ZipFile a set of files from the disk that conform to the
- /// specified criteria, optionally recursing into subdirectories.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method selects files from the the current working directory matching
- /// the specified criteria, and adds them to the ZipFile. If
- /// <c>recurseDirectories</c> is true, files are also selected from
- /// subdirectories, and the directory structure in the filesystem is
- /// reproduced in the zip archive, rooted at the current working directory.
- /// </para>
- ///
- /// <para>
- /// Using this method, the full path of the selected files is included in the
- /// entries added into the zip archive. If you don't want this behavior, use
- /// one of the overloads of this method that allows the specification of a
- /// <c>directoryInArchive</c>.
- /// </para>
- ///
- /// <para>
- /// For details on the syntax for the selectionCriteria parameter, see <see
- /// cref="AddSelectedFiles(String)"/>.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example zips up all *.xml files in the current working directory, or any
- /// subdirectory, that are larger than 1mb.
- ///
- /// <code>
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// // Use a compound expression in the selectionCriteria string.
- /// zip.AddSelectedFiles("name = *.xml and size > 1024kb", true);
- /// zip.Save(PathToZipArchive);
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using zip As ZipFile = New ZipFile()
- /// ' Use a compound expression in the selectionCriteria string.
- /// zip.AddSelectedFiles("name = *.xml and size > 1024kb", true)
- /// zip.Save(PathToZipArchive)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="selectionCriteria">The criteria for file selection</param>
- ///
- /// <param name="recurseDirectories">
- /// If true, the file selection will recurse into subdirectories.
- /// </param>
- public void AddSelectedFiles(String selectionCriteria, bool recurseDirectories)
- {
- this.AddSelectedFiles(selectionCriteria, ".", null, recurseDirectories);
- }
-
- /// <summary>
- /// Adds to the ZipFile a set of files from a specified directory in the
- /// filesystem, that conform to the specified criteria.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method selects files that conform to the specified criteria, from the
- /// the specified directory on disk, and adds them to the ZipFile. The search
- /// does not recurse into subdirectores.
- /// </para>
- ///
- /// <para>
- /// Using this method, the full filesystem path of the files on disk is
- /// reproduced on the entries added to the zip file. If you don't want this
- /// behavior, use one of the other overloads of this method.
- /// </para>
- ///
- /// <para>
- /// For details on the syntax for the selectionCriteria parameter, see <see
- /// cref="AddSelectedFiles(String)"/>.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example zips up all *.xml files larger than 1mb in the directory
- /// given by "d:\rawdata".
- ///
- /// <code>
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// // Use a compound expression in the selectionCriteria string.
- /// zip.AddSelectedFiles("name = *.xml and size > 1024kb", "d:\\rawdata");
- /// zip.Save(PathToZipArchive);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As ZipFile = New ZipFile()
- /// ' Use a compound expression in the selectionCriteria string.
- /// zip.AddSelectedFiles("name = *.xml and size > 1024kb", "d:\rawdata)
- /// zip.Save(PathToZipArchive)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="selectionCriteria">The criteria for file selection</param>
- ///
- /// <param name="directoryOnDisk">
- /// The name of the directory on the disk from which to select files.
- /// </param>
- public void AddSelectedFiles(String selectionCriteria, String directoryOnDisk)
- {
- this.AddSelectedFiles(selectionCriteria, directoryOnDisk, null, false);
- }
-
-
- /// <summary>
- /// Adds to the ZipFile a set of files from the specified directory on disk,
- /// that conform to the specified criteria.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This method selects files from the the specified disk directory matching
- /// the specified selection criteria, and adds them to the ZipFile. If
- /// <c>recurseDirectories</c> is true, files are also selected from
- /// subdirectories.
- /// </para>
- ///
- /// <para>
- /// The full directory structure in the filesystem is reproduced on the
- /// entries added to the zip archive. If you don't want this behavior, use
- /// one of the overloads of this method that allows the specification of a
- /// <c>directoryInArchive</c>.
- /// </para>
- ///
- /// <para>
- /// For details on the syntax for the selectionCriteria parameter, see <see
- /// cref="AddSelectedFiles(String)"/>.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example zips up all *.csv files in the "files" directory, or any
- /// subdirectory, that have been saved since 2009 February 14th.
- ///
- /// <code>
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// // Use a compound expression in the selectionCriteria string.
- /// zip.AddSelectedFiles("name = *.csv and mtime > 2009-02-14", "files", true);
- /// zip.Save(PathToZipArchive);
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using zip As ZipFile = New ZipFile()
- /// ' Use a compound expression in the selectionCriteria string.
- /// zip.AddSelectedFiles("name = *.csv and mtime > 2009-02-14", "files", true)
- /// zip.Save(PathToZipArchive)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <example>
- /// This example zips up all files in the current working
- /// directory, and all its child directories, except those in
- /// the <c>excludethis</c> subdirectory.
- /// <code lang="VB">
- /// Using Zip As ZipFile = New ZipFile(zipfile)
- /// Zip.AddSelectedFfiles("name != 'excludethis\*.*'", datapath, True)
- /// Zip.Save()
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="selectionCriteria">The criteria for file selection</param>
- ///
- /// <param name="directoryOnDisk">
- /// The filesystem path from which to select files.
- /// </param>
- ///
- /// <param name="recurseDirectories">
- /// If true, the file selection will recurse into subdirectories.
- /// </param>
- public void AddSelectedFiles(String selectionCriteria, String directoryOnDisk, bool recurseDirectories)
- {
- this.AddSelectedFiles(selectionCriteria, directoryOnDisk, null, recurseDirectories);
- }
-
-
- /// <summary>
- /// Adds to the ZipFile a selection of files from the specified directory on
- /// disk, that conform to the specified criteria, and using a specified root
- /// path for entries added to the zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method selects files from the specified disk directory matching the
- /// specified selection criteria, and adds those files to the ZipFile, using
- /// the specified directory path in the archive. The search does not recurse
- /// into subdirectories. For details on the syntax for the selectionCriteria
- /// parameter, see <see cref="AddSelectedFiles(String)" />.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example zips up all *.psd files in the "photos" directory that have
- /// been saved since 2009 February 14th, and puts them all in a zip file,
- /// using the directory name of "content" in the zip archive itself. When the
- /// zip archive is unzipped, the folder containing the .psd files will be
- /// named "content".
- ///
- /// <code>
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// // Use a compound expression in the selectionCriteria string.
- /// zip.AddSelectedFiles("name = *.psd and mtime > 2009-02-14", "photos", "content");
- /// zip.Save(PathToZipArchive);
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using zip As ZipFile = New ZipFile
- /// zip.AddSelectedFiles("name = *.psd and mtime > 2009-02-14", "photos", "content")
- /// zip.Save(PathToZipArchive)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="selectionCriteria">
- /// The criteria for selection of files to add to the <c>ZipFile</c>.
- /// </param>
- ///
- /// <param name="directoryOnDisk">
- /// The path to the directory in the filesystem from which to select files.
- /// </param>
- ///
- /// <param name="directoryPathInArchive">
- /// Specifies a directory path to use to in place of the
- /// <c>directoryOnDisk</c>. This path may, or may not, correspond to a real
- /// directory in the current filesystem. If the files within the zip are
- /// later extracted, this is the path used for the extracted file. Passing
- /// null (nothing in VB) will use the path on the file name, if any; in other
- /// words it would use <c>directoryOnDisk</c>, plus any subdirectory. Passing
- /// the empty string ("") will insert the item at the root path within the
- /// archive.
- /// </param>
- public void AddSelectedFiles(String selectionCriteria,
- String directoryOnDisk,
- String directoryPathInArchive)
- {
- this.AddSelectedFiles(selectionCriteria, directoryOnDisk, directoryPathInArchive, false);
- }
-
- /// <summary>
- /// Adds to the ZipFile a selection of files from the specified directory on
- /// disk, that conform to the specified criteria, optionally recursing through
- /// subdirectories, and using a specified root path for entries added to the
- /// zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// This method selects files from the specified disk directory that match the
- /// specified selection criteria, and adds those files to the ZipFile, using
- /// the specified directory path in the archive. If <c>recurseDirectories</c>
- /// is true, files are also selected from subdirectories, and the directory
- /// structure in the filesystem is reproduced in the zip archive, rooted at
- /// the directory specified by <c>directoryOnDisk</c>. For details on the
- /// syntax for the selectionCriteria parameter, see <see
- /// cref="AddSelectedFiles(String)" />.
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example zips up all files that are NOT *.pst files, in the current
- /// working directory and any subdirectories.
- ///
- /// <code>
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true);
- /// zip.Save(PathToZipArchive);
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using zip As ZipFile = New ZipFile
- /// zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true)
- /// zip.Save(PathToZipArchive)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="selectionCriteria">
- /// The criteria for selection of files to add to the <c>ZipFile</c>.
- /// </param>
- ///
- /// <param name="directoryOnDisk">
- /// The path to the directory in the filesystem from which to select files.
- /// </param>
- ///
- /// <param name="directoryPathInArchive">
- /// Specifies a directory path to use to in place of the
- /// <c>directoryOnDisk</c>. This path may, or may not, correspond to a real
- /// directory in the current filesystem. If the files within the zip are
- /// later extracted, this is the path used for the extracted file. Passing
- /// null (nothing in VB) will use the path on the file name, if any; in other
- /// words it would use <c>directoryOnDisk</c>, plus any subdirectory. Passing
- /// the empty string ("") will insert the item at the root path within the
- /// archive.
- /// </param>
- ///
- /// <param name="recurseDirectories">
- /// If true, the method also scans subdirectories for files matching the
- /// criteria.
- /// </param>
- public void AddSelectedFiles(String selectionCriteria,
- String directoryOnDisk,
- String directoryPathInArchive,
- bool recurseDirectories)
- {
- _AddOrUpdateSelectedFiles(selectionCriteria,
- directoryOnDisk,
- directoryPathInArchive,
- recurseDirectories,
- false);
- }
-
- /// <summary>
- /// Updates the ZipFile with a selection of files from the disk that conform
- /// to the specified criteria.
- /// </summary>
- ///
- /// <remarks>
- /// This method selects files from the specified disk directory that match the
- /// specified selection criteria, and Updates the <c>ZipFile</c> with those
- /// files, using the specified directory path in the archive. If
- /// <c>recurseDirectories</c> is true, files are also selected from
- /// subdirectories, and the directory structure in the filesystem is
- /// reproduced in the zip archive, rooted at the directory specified by
- /// <c>directoryOnDisk</c>. For details on the syntax for the
- /// selectionCriteria parameter, see <see cref="AddSelectedFiles(String)" />.
- /// </remarks>
- ///
- /// <param name="selectionCriteria">
- /// The criteria for selection of files to add to the <c>ZipFile</c>.
- /// </param>
- ///
- /// <param name="directoryOnDisk">
- /// The path to the directory in the filesystem from which to select files.
- /// </param>
- ///
- /// <param name="directoryPathInArchive">
- /// Specifies a directory path to use to in place of the
- /// <c>directoryOnDisk</c>. This path may, or may not, correspond to a
- /// real directory in the current filesystem. If the files within the zip
- /// are later extracted, this is the path used for the extracted file.
- /// Passing null (nothing in VB) will use the path on the file name, if
- /// any; in other words it would use <c>directoryOnDisk</c>, plus any
- /// subdirectory. Passing the empty string ("") will insert the item at
- /// the root path within the archive.
- /// </param>
- ///
- /// <param name="recurseDirectories">
- /// If true, the method also scans subdirectories for files matching the criteria.
- /// </param>
- ///
- /// <seealso cref="AddSelectedFiles(String, String, String, bool)" />
- public void UpdateSelectedFiles(String selectionCriteria,
- String directoryOnDisk,
- String directoryPathInArchive,
- bool recurseDirectories)
- {
- _AddOrUpdateSelectedFiles(selectionCriteria,
- directoryOnDisk,
- directoryPathInArchive,
- recurseDirectories,
- true);
- }
-
-
- private string EnsureendInSlash(string s)
- {
- if (s.EndsWith("\\")) return s;
- return s + "\\";
- }
-
- private void _AddOrUpdateSelectedFiles(String selectionCriteria,
- String directoryOnDisk,
- String directoryPathInArchive,
- bool recurseDirectories,
- bool wantUpdate)
- {
- if (directoryOnDisk == null && (Directory.Exists(selectionCriteria)))
- {
- directoryOnDisk = selectionCriteria;
- selectionCriteria = "*.*";
- }
- else if (String.IsNullOrEmpty(directoryOnDisk))
- {
- directoryOnDisk = ".";
- }
-
- // workitem 9176
- while (directoryOnDisk.EndsWith("\\")) directoryOnDisk = directoryOnDisk.Substring(0, directoryOnDisk.Length - 1);
- if (Verbose) StatusMessageTextWriter.WriteLine("adding selection '{0}' from dir '{1}'...",
- selectionCriteria, directoryOnDisk);
- Ionic.FileSelector ff = new Ionic.FileSelector(selectionCriteria,
- AddDirectoryWillTraverseReparsePoints);
- var itemsToAdd = ff.SelectFiles(directoryOnDisk, recurseDirectories);
-
- if (Verbose) StatusMessageTextWriter.WriteLine("found {0} files...", itemsToAdd.Count);
-
- OnAddStarted();
-
- AddOrUpdateAction action = (wantUpdate) ? AddOrUpdateAction.AddOrUpdate : AddOrUpdateAction.AddOnly;
- foreach (var item in itemsToAdd)
- {
- // workitem 10153
- string dirInArchive = (directoryPathInArchive == null)
- ? null
- // workitem 12260
- : ReplaceLeadingDirectory(Path.GetDirectoryName(item),
- directoryOnDisk,
- directoryPathInArchive);
-
- if (File.Exists(item))
- {
- if (wantUpdate)
- this.UpdateFile(item, dirInArchive);
- else
- this.AddFile(item, dirInArchive);
- }
- else
- {
- // this adds "just" the directory, without recursing to the contained files
- AddOrUpdateDirectoryImpl(item, dirInArchive, action, false, 0);
- }
- }
-
- OnAddCompleted();
- }
-
-
- // workitem 12260
- private static string ReplaceLeadingDirectory(string original,
- string pattern,
- string replacement)
- {
- string upperString = original.ToUpper(CultureInfo.InvariantCulture);
- string upperPattern = pattern.ToUpper(CultureInfo.InvariantCulture);
- int p1 = upperString.IndexOf(upperPattern);
- if (p1 != 0) return original;
- return replacement + original.Substring(upperPattern.Length);
- }
-
-#if NOT
- private static string ReplaceEx(string original,
- string pattern,
- string replacement)
- {
- int count, position0, position1;
- count = position0 = position1 = 0;
- string upperString = original.ToUpper();
- string upperPattern = pattern.ToUpper();
- int inc = (original.Length/pattern.Length) *
- (replacement.Length-pattern.Length);
- char [] chars = new char[original.Length + Math.Max(0, inc)];
- while( (position1 = upperString.IndexOf(upperPattern,
- position0)) != -1 )
- {
- for ( int i=position0 ; i < position1 ; ++i )
- chars[count++] = original[i];
- for ( int i=0 ; i < replacement.Length ; ++i )
- chars[count++] = replacement[i];
- position0 = position1+pattern.Length;
- }
- if ( position0 == 0 ) return original;
- for ( int i=position0 ; i < original.Length ; ++i )
- chars[count++] = original[i];
- return new string(chars, 0, count);
- }
-#endif
-
- /// <summary>
- /// Retrieve entries from the zipfile by specified criteria.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method allows callers to retrieve the collection of entries from the zipfile
- /// that fit the specified criteria. The criteria are described in a string format, and
- /// can include patterns for the filename; constraints on the size of the entry;
- /// constraints on the last modified, created, or last accessed time for the file
- /// described by the entry; or the attributes of the entry.
- /// </para>
- ///
- /// <para>
- /// For details on the syntax for the selectionCriteria parameter, see <see
- /// cref="AddSelectedFiles(String)"/>.
- /// </para>
- ///
- /// <para>
- /// This method is intended for use with a ZipFile that has been read from storage.
- /// When creating a new ZipFile, this method will work only after the ZipArchive has
- /// been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip
- /// archive from storage.) Calling SelectEntries on a ZipFile that has not yet been
- /// saved will deliver undefined results.
- /// </para>
- /// </remarks>
- ///
- /// <exception cref="System.Exception">
- /// Thrown if selectionCriteria has an invalid syntax.
- /// </exception>
- ///
- /// <example>
- /// This example selects all the PhotoShop files from within an archive, and extracts them
- /// to the current working directory.
- /// <code>
- /// using (ZipFile zip1 = ZipFile.Read(ZipFileName))
- /// {
- /// var PhotoShopFiles = zip1.SelectEntries("*.psd");
- /// foreach (ZipEntry psd in PhotoShopFiles)
- /// {
- /// psd.Extract();
- /// }
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using zip1 As ZipFile = ZipFile.Read(ZipFileName)
- /// Dim PhotoShopFiles as ICollection(Of ZipEntry)
- /// PhotoShopFiles = zip1.SelectEntries("*.psd")
- /// Dim psd As ZipEntry
- /// For Each psd In PhotoShopFiles
- /// psd.Extract
- /// Next
- /// End Using
- /// </code>
- /// </example>
- /// <param name="selectionCriteria">the string that specifies which entries to select</param>
- /// <returns>a collection of ZipEntry objects that conform to the inclusion spec</returns>
- public ICollection<ZipEntry> SelectEntries(String selectionCriteria)
- {
- Ionic.FileSelector ff = new Ionic.FileSelector(selectionCriteria,
- AddDirectoryWillTraverseReparsePoints);
- return ff.SelectEntries(this);
- }
-
-
- /// <summary>
- /// Retrieve entries from the zipfile by specified criteria.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method allows callers to retrieve the collection of entries from the zipfile
- /// that fit the specified criteria. The criteria are described in a string format, and
- /// can include patterns for the filename; constraints on the size of the entry;
- /// constraints on the last modified, created, or last accessed time for the file
- /// described by the entry; or the attributes of the entry.
- /// </para>
- ///
- /// <para>
- /// For details on the syntax for the selectionCriteria parameter, see <see
- /// cref="AddSelectedFiles(String)"/>.
- /// </para>
- ///
- /// <para>
- /// This method is intended for use with a ZipFile that has been read from storage.
- /// When creating a new ZipFile, this method will work only after the ZipArchive has
- /// been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip
- /// archive from storage.) Calling SelectEntries on a ZipFile that has not yet been
- /// saved will deliver undefined results.
- /// </para>
- /// </remarks>
- ///
- /// <exception cref="System.Exception">
- /// Thrown if selectionCriteria has an invalid syntax.
- /// </exception>
- ///
- /// <example>
- /// <code>
- /// using (ZipFile zip1 = ZipFile.Read(ZipFileName))
- /// {
- /// var UpdatedPhotoShopFiles = zip1.SelectEntries("*.psd", "UpdatedFiles");
- /// foreach (ZipEntry e in UpdatedPhotoShopFiles)
- /// {
- /// // prompt for extract here
- /// if (WantExtract(e.FileName))
- /// e.Extract();
- /// }
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using zip1 As ZipFile = ZipFile.Read(ZipFileName)
- /// Dim UpdatedPhotoShopFiles As ICollection(Of ZipEntry) = zip1.SelectEntries("*.psd", "UpdatedFiles")
- /// Dim e As ZipEntry
- /// For Each e In UpdatedPhotoShopFiles
- /// ' prompt for extract here
- /// If Me.WantExtract(e.FileName) Then
- /// e.Extract
- /// End If
- /// Next
- /// End Using
- /// </code>
- /// </example>
- /// <param name="selectionCriteria">the string that specifies which entries to select</param>
- ///
- /// <param name="directoryPathInArchive">
- /// the directory in the archive from which to select entries. If null, then
- /// all directories in the archive are used.
- /// </param>
- ///
- /// <returns>a collection of ZipEntry objects that conform to the inclusion spec</returns>
- public ICollection<ZipEntry> SelectEntries(String selectionCriteria, string directoryPathInArchive)
- {
- Ionic.FileSelector ff = new Ionic.FileSelector(selectionCriteria,
- AddDirectoryWillTraverseReparsePoints);
- return ff.SelectEntries(this, directoryPathInArchive);
- }
-
-
-
- /// <summary>
- /// Remove entries from the zipfile by specified criteria.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method allows callers to remove the collection of entries from the zipfile
- /// that fit the specified criteria. The criteria are described in a string format, and
- /// can include patterns for the filename; constraints on the size of the entry;
- /// constraints on the last modified, created, or last accessed time for the file
- /// described by the entry; or the attributes of the entry.
- /// </para>
- ///
- /// <para>
- /// For details on the syntax for the selectionCriteria parameter, see <see
- /// cref="AddSelectedFiles(String)"/>.
- /// </para>
- ///
- /// <para>
- /// This method is intended for use with a ZipFile that has been read from storage.
- /// When creating a new ZipFile, this method will work only after the ZipArchive has
- /// been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip
- /// archive from storage.) Calling SelectEntries on a ZipFile that has not yet been
- /// saved will deliver undefined results.
- /// </para>
- /// </remarks>
- ///
- /// <exception cref="System.Exception">
- /// Thrown if selectionCriteria has an invalid syntax.
- /// </exception>
- ///
- /// <example>
- /// This example removes all entries in a zip file that were modified prior to January 1st, 2008.
- /// <code>
- /// using (ZipFile zip1 = ZipFile.Read(ZipFileName))
- /// {
- /// // remove all entries from prior to Jan 1, 2008
- /// zip1.RemoveEntries("mtime < 2008-01-01");
- /// // don't forget to save the archive!
- /// zip1.Save();
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using zip As ZipFile = ZipFile.Read(ZipFileName)
- /// ' remove all entries from prior to Jan 1, 2008
- /// zip1.RemoveEntries("mtime < 2008-01-01")
- /// ' do not forget to save the archive!
- /// zip1.Save
- /// End Using
- /// </code>
- /// </example>
- /// <param name="selectionCriteria">the string that specifies which entries to select</param>
- /// <returns>the number of entries removed</returns>
- public int RemoveSelectedEntries(String selectionCriteria)
- {
- var selection = this.SelectEntries(selectionCriteria);
- this.RemoveEntries(selection);
- return selection.Count;
- }
-
-
- /// <summary>
- /// Remove entries from the zipfile by specified criteria, and within the specified
- /// path in the archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method allows callers to remove the collection of entries from the zipfile
- /// that fit the specified criteria. The criteria are described in a string format, and
- /// can include patterns for the filename; constraints on the size of the entry;
- /// constraints on the last modified, created, or last accessed time for the file
- /// described by the entry; or the attributes of the entry.
- /// </para>
- ///
- /// <para>
- /// For details on the syntax for the selectionCriteria parameter, see <see
- /// cref="AddSelectedFiles(String)"/>.
- /// </para>
- ///
- /// <para>
- /// This method is intended for use with a ZipFile that has been read from storage.
- /// When creating a new ZipFile, this method will work only after the ZipArchive has
- /// been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip
- /// archive from storage.) Calling SelectEntries on a ZipFile that has not yet been
- /// saved will deliver undefined results.
- /// </para>
- /// </remarks>
- ///
- /// <exception cref="System.Exception">
- /// Thrown if selectionCriteria has an invalid syntax.
- /// </exception>
- ///
- /// <example>
- /// <code>
- /// using (ZipFile zip1 = ZipFile.Read(ZipFileName))
- /// {
- /// // remove all entries from prior to Jan 1, 2008
- /// zip1.RemoveEntries("mtime < 2008-01-01", "documents");
- /// // a call to ZipFile.Save will make the modifications permanent
- /// zip1.Save();
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using zip As ZipFile = ZipFile.Read(ZipFileName)
- /// ' remove all entries from prior to Jan 1, 2008
- /// zip1.RemoveEntries("mtime < 2008-01-01", "documents")
- /// ' a call to ZipFile.Save will make the modifications permanent
- /// zip1.Save
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="selectionCriteria">the string that specifies which entries to select</param>
- /// <param name="directoryPathInArchive">
- /// the directory in the archive from which to select entries. If null, then
- /// all directories in the archive are used.
- /// </param>
- /// <returns>the number of entries removed</returns>
- public int RemoveSelectedEntries(String selectionCriteria, string directoryPathInArchive)
- {
- var selection = this.SelectEntries(selectionCriteria, directoryPathInArchive);
- this.RemoveEntries(selection);
- return selection.Count;
- }
-
-
- /// <summary>
- /// Selects and Extracts a set of Entries from the ZipFile.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The entries are extracted into the current working directory.
- /// </para>
- ///
- /// <para>
- /// If any of the files to be extracted already exist, then the action taken is as
- /// specified in the <see cref="ZipEntry.ExtractExistingFile"/> property on the
- /// corresponding ZipEntry instance. By default, the action taken in this case is to
- /// throw an exception.
- /// </para>
- ///
- /// <para>
- /// For information on the syntax of the selectionCriteria string,
- /// see <see cref="AddSelectedFiles(String)" />.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// This example shows how extract all XML files modified after 15 January 2009.
- /// <code>
- /// using (ZipFile zip = ZipFile.Read(zipArchiveName))
- /// {
- /// zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15");
- /// }
- /// </code>
- /// </example>
- /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
- ///
- /// <seealso cref="ExtractSelectedEntries(String,ExtractExistingFileAction)"/>
- public void ExtractSelectedEntries(String selectionCriteria)
- {
- foreach (ZipEntry e in SelectEntries(selectionCriteria))
- {
- e.Password = _Password; // possibly null
- e.Extract();
- }
- }
-
-
- /// <summary>
- /// Selects and Extracts a set of Entries from the ZipFile.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The entries are extracted into the current working directory. When extraction would would
- /// overwrite an existing filesystem file, the action taken is as specified in the
- /// <paramref name="extractExistingFile"/> parameter.
- /// </para>
- ///
- /// <para>
- /// For information on the syntax of the string describing the entry selection criteria,
- /// see <see cref="AddSelectedFiles(String)" />.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// This example shows how extract all XML files modified after 15 January 2009,
- /// overwriting any existing files.
- /// <code>
- /// using (ZipFile zip = ZipFile.Read(zipArchiveName))
- /// {
- /// zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15",
- /// ExtractExistingFileAction.OverwriteSilently);
- /// }
- /// </code>
- /// </example>
- ///
- /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
- ///
- /// <param name="extractExistingFile">
- /// The action to take if extraction would overwrite an existing file.
- /// </param>
- internal void ExtractSelectedEntries(String selectionCriteria, ExtractExistingFileAction extractExistingFile)
- {
- foreach (ZipEntry e in SelectEntries(selectionCriteria))
- {
- e.Password = _Password; // possibly null
- e.Extract(extractExistingFile);
- }
- }
-
-
- /// <summary>
- /// Selects and Extracts a set of Entries from the ZipFile.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The entries are selected from the specified directory within the archive, and then
- /// extracted into the current working directory.
- /// </para>
- ///
- /// <para>
- /// If any of the files to be extracted already exist, then the action taken is as
- /// specified in the <see cref="ZipEntry.ExtractExistingFile"/> property on the
- /// corresponding ZipEntry instance. By default, the action taken in this case is to
- /// throw an exception.
- /// </para>
- ///
- /// <para>
- /// For information on the syntax of the string describing the entry selection criteria,
- /// see <see cref="AddSelectedFiles(String)" />.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// This example shows how extract all XML files modified after 15 January 2009,
- /// and writes them to the "unpack" directory.
- /// <code>
- /// using (ZipFile zip = ZipFile.Read(zipArchiveName))
- /// {
- /// zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15","unpack");
- /// }
- /// </code>
- /// </example>
- ///
- /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
- ///
- /// <param name="directoryPathInArchive">
- /// the directory in the archive from which to select entries. If null, then
- /// all directories in the archive are used.
- /// </param>
- ///
- /// <seealso cref="ExtractSelectedEntries(String,String,String,ExtractExistingFileAction)"/>
- public void ExtractSelectedEntries(String selectionCriteria, String directoryPathInArchive)
- {
- foreach (ZipEntry e in SelectEntries(selectionCriteria, directoryPathInArchive))
- {
- e.Password = _Password; // possibly null
- e.Extract();
- }
- }
-
-
- /// <summary>
- /// Selects and Extracts a set of Entries from the ZipFile.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The entries are extracted into the specified directory. If any of the files to be
- /// extracted already exist, an exception will be thrown.
- /// </para>
- /// <para>
- /// For information on the syntax of the string describing the entry selection criteria,
- /// see <see cref="AddSelectedFiles(String)" />.
- /// </para>
- /// </remarks>
- ///
- /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
- ///
- /// <param name="directoryInArchive">
- /// the directory in the archive from which to select entries. If null, then
- /// all directories in the archive are used.
- /// </param>
- ///
- /// <param name="extractDirectory">
- /// the directory on the disk into which to extract. It will be created
- /// if it does not exist.
- /// </param>
- public void ExtractSelectedEntries(String selectionCriteria, string directoryInArchive, string extractDirectory)
- {
- foreach (ZipEntry e in SelectEntries(selectionCriteria, directoryInArchive))
- {
- e.Password = _Password; // possibly null
- e.Extract(extractDirectory);
- }
- }
-
-
- /// <summary>
- /// Selects and Extracts a set of Entries from the ZipFile.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The entries are extracted into the specified directory. When extraction would would
- /// overwrite an existing filesystem file, the action taken is as specified in the
- /// <paramref name="extractExistingFile"/> parameter.
- /// </para>
- ///
- /// <para>
- /// For information on the syntax of the string describing the entry selection criteria,
- /// see <see cref="AddSelectedFiles(String)" />.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// This example shows how extract all files with an XML extension or with a size larger than 100,000 bytes,
- /// and puts them in the unpack directory. For any files that already exist in
- /// that destination directory, they will not be overwritten.
- /// <code>
- /// using (ZipFile zip = ZipFile.Read(zipArchiveName))
- /// {
- /// zip.ExtractSelectedEntries("name = *.xml or size > 100000",
- /// null,
- /// "unpack",
- /// ExtractExistingFileAction.DontOverwrite);
- /// }
- /// </code>
- /// </example>
- ///
- /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
- ///
- /// <param name="extractDirectory">
- /// The directory on the disk into which to extract. It will be created if it does not exist.
- /// </param>
- ///
- /// <param name="directoryPathInArchive">
- /// The directory in the archive from which to select entries. If null, then
- /// all directories in the archive are used.
- /// </param>
- ///
- /// <param name="extractExistingFile">
- /// The action to take if extraction would overwrite an existing file.
- /// </param>
- ///
- internal void ExtractSelectedEntries(String selectionCriteria, string directoryPathInArchive, string extractDirectory, ExtractExistingFileAction extractExistingFile)
- {
- foreach (ZipEntry e in SelectEntries(selectionCriteria, directoryPathInArchive))
- {
- e.Password = _Password; // possibly null
- e.Extract(extractDirectory, extractExistingFile);
- }
- }
-
- }
-
-}
-
-
-
-namespace OfficeOpenXml.Packaging.Ionic
-{
- internal abstract partial class SelectionCriterion
- {
- internal abstract bool Evaluate(ZipEntry entry);
- }
-
-
- internal partial class NameCriterion : SelectionCriterion
- {
- internal override bool Evaluate(ZipEntry entry)
- {
- // swap forward slashes in the entry.FileName for backslashes
- string transformedFileName = entry.FileName.Replace("/", "\\");
-
- return _Evaluate(transformedFileName);
- }
- }
-
-
- internal partial class SizeCriterion : SelectionCriterion
- {
- internal override bool Evaluate(ZipEntry entry)
- {
- return _Evaluate(entry.UncompressedSize);
- }
- }
-
- internal partial class TimeCriterion : SelectionCriterion
- {
- internal override bool Evaluate(ZipEntry entry)
- {
- DateTime x;
- switch (Which)
- {
- case WhichTime.atime:
- x = entry.AccessedTime;
- break;
- case WhichTime.mtime:
- x = entry.ModifiedTime;
- break;
- case WhichTime.ctime:
- x = entry.CreationTime;
- break;
- default: throw new ArgumentException("??time");
- }
- return _Evaluate(x);
- }
- }
-
-
- internal partial class TypeCriterion : SelectionCriterion
- {
- internal override bool Evaluate(ZipEntry entry)
- {
- bool result = (ObjectType == 'D')
- ? entry.IsDirectory
- : !entry.IsDirectory;
-
- if (Operator != ComparisonOperator.EqualTo)
- result = !result;
- return result;
- }
- }
-
-#if !SILVERLIGHT
- internal partial class AttributesCriterion : SelectionCriterion
- {
- internal override bool Evaluate(ZipEntry entry)
- {
- FileAttributes fileAttrs = entry.Attributes;
- return _Evaluate(fileAttrs);
- }
- }
-#endif
-
- internal partial class CompoundCriterion : SelectionCriterion
- {
- internal override bool Evaluate(ZipEntry entry)
- {
- bool result = Left.Evaluate(entry);
- switch (Conjunction)
- {
- case LogicalConjunction.AND:
- if (result)
- result = Right.Evaluate(entry);
- break;
- case LogicalConjunction.OR:
- if (!result)
- result = Right.Evaluate(entry);
- break;
- case LogicalConjunction.XOR:
- result ^= Right.Evaluate(entry);
- break;
- }
- return result;
- }
- }
-
-
-
- internal partial class FileSelector
- {
- private bool Evaluate(ZipEntry entry)
- {
- bool result = _Criterion.Evaluate(entry);
- return result;
- }
-
- /// <summary>
- /// Retrieve the ZipEntry items in the ZipFile that conform to the specified criteria.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// This method applies the criteria set in the FileSelector instance (as described in
- /// the <see cref="FileSelector.SelectionCriteria"/>) to the specified ZipFile. Using this
- /// method, for example, you can retrieve all entries from the given ZipFile that
- /// have filenames ending in .txt.
- /// </para>
- ///
- /// <para>
- /// Normally, applications would not call this method directly. This method is used
- /// by the ZipFile class.
- /// </para>
- ///
- /// <para>
- /// Using the appropriate SelectionCriteria, you can retrieve entries based on size,
- /// time, and attributes. See <see cref="FileSelector.SelectionCriteria"/> for a
- /// description of the syntax of the SelectionCriteria string.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="zip">The ZipFile from which to retrieve entries.</param>
- ///
- /// <returns>a collection of ZipEntry objects that conform to the criteria.</returns>
- public ICollection<ZipEntry> SelectEntries(ZipFile zip)
- {
- if (zip == null)
- throw new ArgumentNullException("zip");
-
- var list = new List<ZipEntry>();
-
- foreach (ZipEntry e in zip)
- {
- if (this.Evaluate(e))
- list.Add(e);
- }
-
- return list;
- }
-
-
- /// <summary>
- /// Retrieve the ZipEntry items in the ZipFile that conform to the specified criteria.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// This method applies the criteria set in the FileSelector instance (as described in
- /// the <see cref="FileSelector.SelectionCriteria"/>) to the specified ZipFile. Using this
- /// method, for example, you can retrieve all entries from the given ZipFile that
- /// have filenames ending in .txt.
- /// </para>
- ///
- /// <para>
- /// Normally, applications would not call this method directly. This method is used
- /// by the ZipFile class.
- /// </para>
- ///
- /// <para>
- /// This overload allows the selection of ZipEntry instances from the ZipFile to be restricted
- /// to entries contained within a particular directory in the ZipFile.
- /// </para>
- ///
- /// <para>
- /// Using the appropriate SelectionCriteria, you can retrieve entries based on size,
- /// time, and attributes. See <see cref="FileSelector.SelectionCriteria"/> for a
- /// description of the syntax of the SelectionCriteria string.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="zip">The ZipFile from which to retrieve entries.</param>
- ///
- /// <param name="directoryPathInArchive">
- /// the directory in the archive from which to select entries. If null, then
- /// all directories in the archive are used.
- /// </param>
- ///
- /// <returns>a collection of ZipEntry objects that conform to the criteria.</returns>
- public ICollection<ZipEntry> SelectEntries(ZipFile zip, string directoryPathInArchive)
- {
- if (zip == null)
- throw new ArgumentNullException("zip");
-
- var list = new List<ZipEntry>();
- // workitem 8559
- string slashSwapped = (directoryPathInArchive == null) ? null : directoryPathInArchive.Replace("/", "\\");
- // workitem 9174
- if (slashSwapped != null)
- {
- while (slashSwapped.EndsWith("\\"))
- slashSwapped = slashSwapped.Substring(0, slashSwapped.Length - 1);
- }
- foreach (ZipEntry e in zip)
- {
- if (directoryPathInArchive == null || (Path.GetDirectoryName(e.FileName) == directoryPathInArchive)
- || (Path.GetDirectoryName(e.FileName) == slashSwapped)) // workitem 8559
- if (this.Evaluate(e))
- list.Add(e);
- }
-
- return list;
- }
-
- }
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipFile.cs b/EPPlus/Packaging/DotNetZip/ZipFile.cs
deleted file mode 100644
index 7edaff5..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipFile.cs
+++ /dev/null
@@ -1,3909 +0,0 @@
-// ZipFile.cs
-//
-// Copyright (c) 2006-2010 Dino Chiesa
-// All rights reserved.
-//
-// This module is part of DotNetZip, a zipfile class library.
-// The class library reads and writes zip files, according to the format
-// described by PKware, at:
-// http://www.pkware.com/business_and_developers/developer/popups/appnote.txt
-//
-//
-// There are other Zip class libraries available.
-//
-// - it is possible to read and write zip files within .NET via the J# runtime.
-// But some people don't like to install the extra DLL, which is no longer
-// supported by MS. And also, the J# libraries don't support advanced zip
-// features, like ZIP64, spanned archives, or AES encryption.
-//
-// - There are third-party GPL and LGPL libraries available. Some people don't
-// like the license, and some of them don't support all the ZIP features, like AES.
-//
-// - Finally, there are commercial tools (From ComponentOne, XCeed, etc). But
-// some people don't want to incur the cost.
-//
-// This alternative implementation is **not** GPL licensed. It is free of cost, and
-// does not require J#. It does require .NET 2.0. It balances a good set of
-// features, with ease of use and speed of performance.
-//
-// This code is released under the Microsoft Public License .
-// See the License.txt for details.
-//
-//
-// NB: This implementation originally relied on the
-// System.IO.Compression.DeflateStream base class in the .NET Framework
-// v2.0 base class library, but now includes a managed-code port of Zlib.
-//
-// Thu, 08 Oct 2009 17:04
-//
-
-
-using System;
-using System.IO;
-using System.Collections.Generic;
-using Interop = System.Runtime.InteropServices;
-using OfficeOpenXml.Packaging.Ionic.Zlib;
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- /// <summary>
- /// The ZipFile type represents a zip archive file.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This is the main type in the DotNetZip class library. This class reads and
- /// writes zip files, as defined in the <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">specification
- /// for zip files described by PKWare</see>. The compression for this
- /// implementation is provided by a managed-code version of Zlib, included with
- /// DotNetZip in the classes in the Ionic.Zlib namespace.
- /// </para>
- ///
- /// <para>
- /// This class provides a general purpose zip file capability. Use it to read,
- /// create, or update zip files. When you want to create zip files using a
- /// <c>Stream</c> type to write the zip file, you may want to consider the <see
- /// cref="ZipOutputStream"/> class.
- /// </para>
- ///
- /// <para>
- /// Both the <c>ZipOutputStream</c> class and the <c>ZipFile</c> class can
- /// be used to create zip files. Both of them support many of the common zip
- /// features, including Unicode, different compression methods and levels,
- /// and ZIP64. They provide very similar performance when creating zip
- /// files.
- /// </para>
- ///
- /// <para>
- /// The <c>ZipFile</c> class is generally easier to use than
- /// <c>ZipOutputStream</c> and should be considered a higher-level interface. For
- /// example, when creating a zip file via calls to the <c>PutNextEntry()</c> and
- /// <c>Write()</c> methods on the <c>ZipOutputStream</c> class, the caller is
- /// responsible for opening the file, reading the bytes from the file, writing
- /// those bytes into the <c>ZipOutputStream</c>, setting the attributes on the
- /// <c>ZipEntry</c>, and setting the created, last modified, and last accessed
- /// timestamps on the zip entry. All of these things are done automatically by a
- /// call to <see cref="ZipFile.AddFile(string,string)">ZipFile.AddFile()</see>.
- /// For this reason, the <c>ZipOutputStream</c> is generally recommended for use
- /// only when your application emits arbitrary data, not necessarily data from a
- /// filesystem file, directly into a zip file, and does so using a <c>Stream</c>
- /// metaphor.
- /// </para>
- ///
- /// <para>
- /// Aside from the differences in programming model, there are other
- /// differences in capability between the two classes.
- /// </para>
- ///
- /// <list type="bullet">
- /// <item>
- /// <c>ZipFile</c> can be used to read and extract zip files, in addition to
- /// creating zip files. <c>ZipOutputStream</c> cannot read zip files. If you want
- /// to use a stream to read zip files, check out the ZipInputStream class.
- /// </item>
- ///
- /// <item>
- /// <c>ZipOutputStream</c> does not support the creation of segmented or spanned
- /// zip files.
- /// </item>
- ///
- /// <item>
- /// <c>ZipOutputStream</c> cannot produce a self-extracting archive.
- /// </item>
- /// </list>
- ///
- /// <para>
- /// Be aware that the <c>ZipFile</c> class implements the <see
- /// cref="System.IDisposable"/> interface. In order for <c>ZipFile</c> to
- /// produce a valid zip file, you use use it within a using clause (<c>Using</c>
- /// in VB), or call the <c>Dispose()</c> method explicitly. See the examples
- /// for how to employ a using clause.
- /// </para>
- ///
- /// </remarks>
- [Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00005")]
- [Interop.ComVisible(true)]
-#if !NETCF
- [Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)]
-#endif
- internal partial class ZipFile :
- System.Collections.IEnumerable,
- System.Collections.Generic.IEnumerable<ZipEntry>,
- IDisposable
- {
-
- #region public properties
-
- /// <summary>
- /// Indicates whether to perform a full scan of the zip file when reading it.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// You almost never want to use this property.
- /// </para>
- ///
- /// <para>
- /// When reading a zip file, if this flag is <c>true</c> (<c>True</c> in
- /// VB), the entire zip archive will be scanned and searched for entries.
- /// For large archives, this can take a very, long time. The much more
- /// efficient default behavior is to read the zip directory, which is
- /// stored at the end of the zip file. But, in some cases the directory is
- /// corrupted and you need to perform a full scan of the zip file to
- /// determine the contents of the zip file. This property lets you do
- /// that, when necessary.
- /// </para>
- ///
- /// <para>
- /// This flag is effective only when calling <see
- /// cref="Initialize(string)"/>. Normally you would read a ZipFile with the
- /// static <see cref="ZipFile.Read(String)">ZipFile.Read</see>
- /// method. But you can't set the <c>FullScan</c> property on the
- /// <c>ZipFile</c> instance when you use a static factory method like
- /// <c>ZipFile.Read</c>.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example shows how to read a zip file using the full scan approach,
- /// and then save it, thereby producing a corrected zip file.
- ///
- /// <code lang="C#">
- /// using (var zip = new ZipFile())
- /// {
- /// zip.FullScan = true;
- /// zip.Initialize(zipFileName);
- /// zip.Save(newName);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As New ZipFile
- /// zip.FullScan = True
- /// zip.Initialize(zipFileName)
- /// zip.Save(newName)
- /// End Using
- /// </code>
- /// </example>
- ///
- public bool FullScan
- {
- get;
- set;
- }
-
-
- /// <summary>
- /// Whether to sort the ZipEntries before saving the file.
- /// </summary>
- ///
- /// <remarks>
- /// The default is false. If you have a large number of zip entries, the sort
- /// alone can consume significant time.
- /// </remarks>
- ///
- /// <example>
- /// <code lang="C#">
- /// using (var zip = new ZipFile())
- /// {
- /// zip.AddFiles(filesToAdd);
- /// zip.SortEntriesBeforeSaving = true;
- /// zip.Save(name);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As New ZipFile
- /// zip.AddFiles(filesToAdd)
- /// zip.SortEntriesBeforeSaving = True
- /// zip.Save(name)
- /// End Using
- /// </code>
- /// </example>
- ///
- public bool SortEntriesBeforeSaving
- {
- get;
- set;
- }
-
-
-
- /// <summary>
- /// Indicates whether NTFS Reparse Points, like junctions, should be
- /// traversed during calls to <c>AddDirectory()</c>.
- /// </summary>
- ///
- /// <remarks>
- /// By default, calls to AddDirectory() will traverse NTFS reparse
- /// points, like mounted volumes, and directory junctions. An example
- /// of a junction is the "My Music" directory in Windows Vista. In some
- /// cases you may not want DotNetZip to traverse those directories. In
- /// that case, set this property to false.
- /// </remarks>
- ///
- /// <example>
- /// <code lang="C#">
- /// using (var zip = new ZipFile())
- /// {
- /// zip.AddDirectoryWillTraverseReparsePoints = false;
- /// zip.AddDirectory(dirToZip,"fodder");
- /// zip.Save(zipFileToCreate);
- /// }
- /// </code>
- /// </example>
- public bool AddDirectoryWillTraverseReparsePoints { get; set; }
-
-
- /// <summary>
- /// Size of the IO buffer used while saving.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// First, let me say that you really don't need to bother with this. It is
- /// here to allow for optimizations that you probably won't make! It will work
- /// fine if you don't set or get this property at all. Ok?
- /// </para>
- ///
- /// <para>
- /// Now that we have <em>that</em> out of the way, the fine print: This
- /// property affects the size of the buffer that is used for I/O for each
- /// entry contained in the zip file. When a file is read in to be compressed,
- /// it uses a buffer given by the size here. When you update a zip file, the
- /// data for unmodified entries is copied from the first zip file to the
- /// other, through a buffer given by the size here.
- /// </para>
- ///
- /// <para>
- /// Changing the buffer size affects a few things: first, for larger buffer
- /// sizes, the memory used by the <c>ZipFile</c>, obviously, will be larger
- /// during I/O operations. This may make operations faster for very much
- /// larger files. Last, for any given entry, when you use a larger buffer
- /// there will be fewer progress events during I/O operations, because there's
- /// one progress event generated for each time the buffer is filled and then
- /// emptied.
- /// </para>
- ///
- /// <para>
- /// The default buffer size is 8k. Increasing the buffer size may speed
- /// things up as you compress larger files. But there are no hard-and-fast
- /// rules here, eh? You won't know til you test it. And there will be a
- /// limit where ever larger buffers actually slow things down. So as I said
- /// in the beginning, it's probably best if you don't set or get this property
- /// at all.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// This example shows how you might set a large buffer size for efficiency when
- /// dealing with zip entries that are larger than 1gb.
- /// <code lang="C#">
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// zip.SaveProgress += this.zip1_SaveProgress;
- /// zip.AddDirectory(directoryToZip, "");
- /// zip.UseZip64WhenSaving = Zip64Option.Always;
- /// zip.BufferSize = 65536*8; // 65536 * 8 = 512k
- /// zip.Save(ZipFileToCreate);
- /// }
- /// </code>
- /// </example>
-
- public int BufferSize
- {
- get { return _BufferSize; }
- set { _BufferSize = value; }
- }
-
- /// <summary>
- /// Size of the work buffer to use for the ZLIB codec during compression.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// When doing ZLIB or Deflate compression, the library fills a buffer,
- /// then passes it to the compressor for compression. Then the library
- /// reads out the compressed bytes. This happens repeatedly until there
- /// is no more uncompressed data to compress. This property sets the
- /// size of the buffer that will be used for chunk-wise compression. In
- /// order for the setting to take effect, your application needs to set
- /// this property before calling one of the <c>ZipFile.Save()</c>
- /// overloads.
- /// </para>
- /// <para>
- /// Setting this affects the performance and memory efficiency of
- /// compression and decompression. For larger files, setting this to a
- /// larger size may improve compression performance, but the exact
- /// numbers vary depending on available memory, the size of the streams
- /// you are compressing, and a bunch of other variables. I don't have
- /// good firm recommendations on how to set it. You'll have to test it
- /// yourself. Or just leave it alone and accept the default.
- /// </para>
- /// </remarks>
- public int CodecBufferSize
- {
- get;
- set;
- }
-
- /// <summary>
- /// Indicates whether extracted files should keep their paths as
- /// stored in the zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This property affects Extraction. It is not used when creating zip
- /// archives.
- /// </para>
- ///
- /// <para>
- /// With this property set to <c>false</c>, the default, extracting entries
- /// from a zip file will create files in the filesystem that have the full
- /// path associated to the entry within the zip file. With this property set
- /// to <c>true</c>, extracting entries from the zip file results in files
- /// with no path: the folders are "flattened."
- /// </para>
- ///
- /// <para>
- /// An example: suppose the zip file contains entries /directory1/file1.txt and
- /// /directory2/file2.txt. With <c>FlattenFoldersOnExtract</c> set to false,
- /// the files created will be \directory1\file1.txt and \directory2\file2.txt.
- /// With the property set to true, the files created are file1.txt and file2.txt.
- /// </para>
- ///
- /// </remarks>
- public bool FlattenFoldersOnExtract
- {
- get;
- set;
- }
-
-
- /// <summary>
- /// The compression strategy to use for all entries.
- /// </summary>
- ///
- /// <remarks>
- /// Set the Strategy used by the ZLIB-compatible compressor, when
- /// compressing entries using the DEFLATE method. Different compression
- /// strategies work better on different sorts of data. The strategy
- /// parameter can affect the compression ratio and the speed of
- /// compression but not the correctness of the compresssion. For more
- /// information see <see
- /// cref="Ionic.Zlib.CompressionStrategy">Ionic.Zlib.CompressionStrategy</see>.
- /// </remarks>
- public CompressionStrategy Strategy
- {
- get { return _Strategy; }
- set { _Strategy = value; }
- }
-
-
- /// <summary>
- /// The name of the <c>ZipFile</c>, on disk.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// When the <c>ZipFile</c> instance was created by reading an archive using
- /// one of the <c>ZipFile.Read</c> methods, this property represents the name
- /// of the zip file that was read. When the <c>ZipFile</c> instance was
- /// created by using the no-argument constructor, this value is <c>null</c>
- /// (<c>Nothing</c> in VB).
- /// </para>
- ///
- /// <para>
- /// If you use the no-argument constructor, and you then explicitly set this
- /// property, when you call <see cref="ZipFile.Save()"/>, this name will
- /// specify the name of the zip file created. Doing so is equivalent to
- /// calling <see cref="ZipFile.Save(String)"/>. When instantiating a
- /// <c>ZipFile</c> by reading from a stream or byte array, the <c>Name</c>
- /// property remains <c>null</c>. When saving to a stream, the <c>Name</c>
- /// property is implicitly set to <c>null</c>.
- /// </para>
- /// </remarks>
- public string Name
- {
- get { return _name; }
- set { _name = value; }
- }
-
-
- /// <summary>
- /// Sets the compression level to be used for entries subsequently added to
- /// the zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Varying the compression level used on entries can affect the
- /// size-vs-speed tradeoff when compression and decompressing data streams
- /// or files.
- /// </para>
- ///
- /// <para>
- /// As with some other properties on the <c>ZipFile</c> class, like <see
- /// cref="Password"/>, <see cref="Encryption"/>, and <see
- /// cref="ZipErrorAction"/>, setting this property on a <c>ZipFile</c>
- /// instance will cause the specified <c>CompressionLevel</c> to be used on all
- /// <see cref="ZipEntry"/> items that are subsequently added to the
- /// <c>ZipFile</c> instance. If you set this property after you have added
- /// items to the <c>ZipFile</c>, but before you have called <c>Save()</c>,
- /// those items will not use the specified compression level.
- /// </para>
- ///
- /// <para>
- /// If you do not set this property, the default compression level is used,
- /// which normally gives a good balance of compression efficiency and
- /// compression speed. In some tests, using <c>BestCompression</c> can
- /// double the time it takes to compress, while delivering just a small
- /// increase in compression efficiency. This behavior will vary with the
- /// type of data you compress. If you are in doubt, just leave this setting
- /// alone, and accept the default.
- /// </para>
- /// </remarks>
- public OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel CompressionLevel
- {
- get;
- set;
- }
-
- /// <summary>
- /// The compression method for the zipfile.
- /// </summary>
- /// <remarks>
- /// <para>
- /// By default, the compression method is <c>CompressionMethod.Deflate.</c>
- /// </para>
- /// </remarks>
- /// <seealso cref="Ionic.Zip.CompressionMethod" />
- internal Ionic.Zip.CompressionMethod CompressionMethod
- {
- get
- {
- return _compressionMethod;
- }
- set
- {
- _compressionMethod = value;
- }
- }
-
-
-
- /// <summary>
- /// A comment attached to the zip archive.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This property is read/write. It allows the application to specify a
- /// comment for the <c>ZipFile</c>, or read the comment for the
- /// <c>ZipFile</c>. After setting this property, changes are only made
- /// permanent when you call a <c>Save()</c> method.
- /// </para>
- ///
- /// <para>
- /// According to <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's
- /// zip specification</see>, the comment is not encrypted, even if there is a
- /// password set on the zip file.
- /// </para>
- ///
- /// <para>
- /// The specification does not describe how to indicate the encoding used
- /// on a comment string. Many "compliant" zip tools and libraries use
- /// IBM437 as the code page for comments; DotNetZip, too, follows that
- /// practice. On the other hand, there are situations where you want a
- /// Comment to be encoded with something else, for example using code page
- /// 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the
- /// comment following the same procedure it follows for encoding
- /// filenames: (a) if <see cref="AlternateEncodingUsage"/> is
- /// <c>Never</c>, it uses the default encoding (IBM437). (b) if <see
- /// cref="AlternateEncodingUsage"/> is <c>Always</c>, it always uses the
- /// alternate encoding (<see cref="AlternateEncoding"/>). (c) if <see
- /// cref="AlternateEncodingUsage"/> is <c>AsNecessary</c>, it uses the
- /// alternate encoding only if the default encoding is not sufficient for
- /// encoding the comment - in other words if decoding the result does not
- /// produce the original string. This decision is taken at the time of
- /// the call to <c>ZipFile.Save()</c>.
- /// </para>
- ///
- /// <para>
- /// When creating a zip archive using this library, it is possible to change
- /// the value of <see cref="AlternateEncoding" /> between each
- /// entry you add, and between adding entries and the call to
- /// <c>Save()</c>. Don't do this. It will likely result in a zip file that is
- /// not readable by any tool or application. For best interoperability, leave
- /// <see cref="AlternateEncoding"/> alone, or specify it only
- /// once, before adding any entries to the <c>ZipFile</c> instance.
- /// </para>
- ///
- /// </remarks>
- public string Comment
- {
- get { return _Comment; }
- set
- {
- _Comment = value;
- _contentsChanged = true;
- }
- }
-
-
-
-
- /// <summary>
- /// Specifies whether the Creation, Access, and Modified times for entries
- /// added to the zip file will be emitted in “Windows format”
- /// when the zip archive is saved.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// An application creating a zip archive can use this flag to explicitly
- /// specify that the file times for the entries should or should not be stored
- /// in the zip archive in the format used by Windows. By default this flag is
- /// <c>true</c>, meaning the Windows-format times are stored in the zip
- /// archive.
- /// </para>
- ///
- /// <para>
- /// When adding an entry from a file or directory, the Creation (<see
- /// cref="ZipEntry.CreationTime"/>), Access (<see
- /// cref="ZipEntry.AccessedTime"/>), and Modified (<see
- /// cref="ZipEntry.ModifiedTime"/>) times for the given entry are
- /// automatically set from the filesystem values. When adding an entry from a
- /// stream or string, all three values are implicitly set to
- /// <c>DateTime.Now</c>. Applications can also explicitly set those times by
- /// calling <see cref="ZipEntry.SetEntryTimes(DateTime, DateTime,
- /// DateTime)"/>.
- /// </para>
- ///
- /// <para>
- /// <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's
- /// zip specification</see> describes multiple ways to format these times in a
- /// zip file. One is the format Windows applications normally use: 100ns ticks
- /// since January 1, 1601 UTC. The other is a format Unix applications typically
- /// use: seconds since January 1, 1970 UTC. Each format can be stored in an
- /// "extra field" in the zip entry when saving the zip archive. The former
- /// uses an extra field with a Header Id of 0x000A, while the latter uses a
- /// header ID of 0x5455, although you probably don't need to know that.
- /// </para>
- ///
- /// <para>
- /// Not all tools and libraries can interpret these fields. Windows
- /// compressed folders is one that can read the Windows Format timestamps,
- /// while I believe <see href="http://www.info-zip.org/">the Infozip
- /// tools</see> can read the Unix format timestamps. Some tools and libraries
- /// may be able to read only one or the other. DotNetZip can read or write
- /// times in either or both formats.
- /// </para>
- ///
- /// <para>
- /// The times stored are taken from <see cref="ZipEntry.ModifiedTime"/>, <see
- /// cref="ZipEntry.AccessedTime"/>, and <see cref="ZipEntry.CreationTime"/>.
- /// </para>
- ///
- /// <para>
- /// The value set here applies to all entries subsequently added to the
- /// <c>ZipFile</c>.
- /// </para>
- ///
- /// <para>
- /// This property is not mutually exclusive of the <see
- /// cref="EmitTimesInUnixFormatWhenSaving" /> property. It is possible and
- /// legal and valid to produce a zip file that contains timestamps encoded in
- /// the Unix format as well as in the Windows format, in addition to the <see
- /// cref="ZipEntry.LastModified">LastModified</see> time attached to each
- /// entry in the archive, a time that is always stored in "DOS format". And,
- /// notwithstanding the names PKWare uses for these time formats, any of them
- /// can be read and written by any computer, on any operating system. But,
- /// there are no guarantees that a program running on Mac or Linux will
- /// gracefully handle a zip file with "Windows" formatted times, or that an
- /// application that does not use DotNetZip but runs on Windows will be able to
- /// handle file times in Unix format.
- /// </para>
- ///
- /// <para>
- /// When in doubt, test. Sorry, I haven't got a complete list of tools and
- /// which sort of timestamps they can use and will tolerate. If you get any
- /// good information and would like to pass it on, please do so and I will
- /// include that information in this documentation.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// This example shows how to save a zip file that contains file timestamps
- /// in a format normally used by Unix.
- /// <code lang="C#">
- /// using (var zip = new ZipFile())
- /// {
- /// // produce a zip file the Mac will like
- /// zip.EmitTimesInWindowsFormatWhenSaving = false;
- /// zip.EmitTimesInUnixFormatWhenSaving = true;
- /// zip.AddDirectory(directoryToZip, "files");
- /// zip.Save(outputFile);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As New ZipFile
- /// '' produce a zip file the Mac will like
- /// zip.EmitTimesInWindowsFormatWhenSaving = False
- /// zip.EmitTimesInUnixFormatWhenSaving = True
- /// zip.AddDirectory(directoryToZip, "files")
- /// zip.Save(outputFile)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <seealso cref="ZipEntry.EmitTimesInWindowsFormatWhenSaving" />
- /// <seealso cref="EmitTimesInUnixFormatWhenSaving" />
- public bool EmitTimesInWindowsFormatWhenSaving
- {
- get
- {
- return _emitNtfsTimes;
- }
- set
- {
- _emitNtfsTimes = value;
- }
- }
-
-
- /// <summary>
- /// Specifies whether the Creation, Access, and Modified times
- /// for entries added to the zip file will be emitted in "Unix(tm)
- /// format" when the zip archive is saved.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// An application creating a zip archive can use this flag to explicitly
- /// specify that the file times for the entries should or should not be stored
- /// in the zip archive in the format used by Unix. By default this flag is
- /// <c>false</c>, meaning the Unix-format times are not stored in the zip
- /// archive.
- /// </para>
- ///
- /// <para>
- /// When adding an entry from a file or directory, the Creation (<see
- /// cref="ZipEntry.CreationTime"/>), Access (<see
- /// cref="ZipEntry.AccessedTime"/>), and Modified (<see
- /// cref="ZipEntry.ModifiedTime"/>) times for the given entry are
- /// automatically set from the filesystem values. When adding an entry from a
- /// stream or string, all three values are implicitly set to DateTime.Now.
- /// Applications can also explicitly set those times by calling <see
- /// cref="ZipEntry.SetEntryTimes(DateTime, DateTime, DateTime)"/>.
- /// </para>
- ///
- /// <para>
- /// <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's
- /// zip specification</see> describes multiple ways to format these times in a
- /// zip file. One is the format Windows applications normally use: 100ns ticks
- /// since January 1, 1601 UTC. The other is a format Unix applications
- /// typically use: seconds since January 1, 1970 UTC. Each format can be
- /// stored in an "extra field" in the zip entry when saving the zip
- /// archive. The former uses an extra field with a Header Id of 0x000A, while
- /// the latter uses a header ID of 0x5455, although you probably don't need to
- /// know that.
- /// </para>
- ///
- /// <para>
- /// Not all tools and libraries can interpret these fields. Windows
- /// compressed folders is one that can read the Windows Format timestamps,
- /// while I believe the <see href="http://www.info-zip.org/">Infozip</see>
- /// tools can read the Unix format timestamps. Some tools and libraries may be
- /// able to read only one or the other. DotNetZip can read or write times in
- /// either or both formats.
- /// </para>
- ///
- /// <para>
- /// The times stored are taken from <see cref="ZipEntry.ModifiedTime"/>, <see
- /// cref="ZipEntry.AccessedTime"/>, and <see cref="ZipEntry.CreationTime"/>.
- /// </para>
- ///
- /// <para>
- /// This property is not mutually exclusive of the <see
- /// cref="EmitTimesInWindowsFormatWhenSaving" /> property. It is possible and
- /// legal and valid to produce a zip file that contains timestamps encoded in
- /// the Unix format as well as in the Windows format, in addition to the <see
- /// cref="ZipEntry.LastModified">LastModified</see> time attached to each
- /// entry in the zip archive, a time that is always stored in "DOS
- /// format". And, notwithstanding the names PKWare uses for these time
- /// formats, any of them can be read and written by any computer, on any
- /// operating system. But, there are no guarantees that a program running on
- /// Mac or Linux will gracefully handle a zip file with "Windows" formatted
- /// times, or that an application that does not use DotNetZip but runs on
- /// Windows will be able to handle file times in Unix format.
- /// </para>
- ///
- /// <para>
- /// When in doubt, test. Sorry, I haven't got a complete list of tools and
- /// which sort of timestamps they can use and will tolerate. If you get any
- /// good information and would like to pass it on, please do so and I will
- /// include that information in this documentation.
- /// </para>
- /// </remarks>
- ///
- /// <seealso cref="ZipEntry.EmitTimesInUnixFormatWhenSaving" />
- /// <seealso cref="EmitTimesInWindowsFormatWhenSaving" />
- public bool EmitTimesInUnixFormatWhenSaving
- {
- get
- {
- return _emitUnixTimes;
- }
- set
- {
- _emitUnixTimes = value;
- }
- }
-
-
-
- /// <summary>
- /// Indicates whether verbose output is sent to the <see
- /// cref="StatusMessageTextWriter"/> during <c>AddXxx()</c> and
- /// <c>ReadXxx()</c> operations.
- /// </summary>
- ///
- /// <remarks>
- /// This is a <em>synthetic</em> property. It returns true if the <see
- /// cref="StatusMessageTextWriter"/> is non-null.
- /// </remarks>
- internal bool Verbose
- {
- get { return (_StatusMessageTextWriter != null); }
- }
-
-
- /// <summary>
- /// Returns true if an entry by the given name exists in the ZipFile.
- /// </summary>
- ///
- /// <param name='name'>the name of the entry to find</param>
- /// <returns>true if an entry with the given name exists; otherwise false.
- /// </returns>
- public bool ContainsEntry(string name)
- {
- // workitem 12534
- return _entries.ContainsKey(SharedUtilities.NormalizePathForUseInZipFile(name));
- }
-
-
-
- /// <summary>
- /// Indicates whether to perform case-sensitive matching on the filename when
- /// retrieving entries in the zipfile via the string-based indexer.
- /// </summary>
- ///
- /// <remarks>
- /// The default value is <c>false</c>, which means don't do case-sensitive
- /// matching. In other words, retrieving zip["ReadMe.Txt"] is the same as
- /// zip["readme.txt"]. It really makes sense to set this to <c>true</c> only
- /// if you are not running on Windows, which has case-insensitive
- /// filenames. But since this library is not built for non-Windows platforms,
- /// in most cases you should just leave this property alone.
- /// </remarks>
- public bool CaseSensitiveRetrieval
- {
- get
- {
- return _CaseSensitiveRetrieval;
- }
-
- set
- {
- // workitem 9868
- if (value != _CaseSensitiveRetrieval)
- {
- _CaseSensitiveRetrieval = value;
- _initEntriesDictionary();
- }
- }
- }
-
-
- /// <summary>
- /// Indicates whether to encode entry filenames and entry comments using Unicode
- /// (UTF-8).
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">The
- /// PKWare zip specification</see> provides for encoding file names and file
- /// comments in either the IBM437 code page, or in UTF-8. This flag selects
- /// the encoding according to that specification. By default, this flag is
- /// false, and filenames and comments are encoded into the zip file in the
- /// IBM437 codepage. Setting this flag to true will specify that filenames
- /// and comments that cannot be encoded with IBM437 will be encoded with
- /// UTF-8.
- /// </para>
- ///
- /// <para>
- /// Zip files created with strict adherence to the PKWare specification with
- /// respect to UTF-8 encoding can contain entries with filenames containing
- /// any combination of Unicode characters, including the full range of
- /// characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other
- /// alphabets. However, because at this time, the UTF-8 portion of the PKWare
- /// specification is not broadly supported by other zip libraries and
- /// utilities, such zip files may not be readable by your favorite zip tool or
- /// archiver. In other words, interoperability will decrease if you set this
- /// flag to true.
- /// </para>
- ///
- /// <para>
- /// In particular, Zip files created with strict adherence to the PKWare
- /// specification with respect to UTF-8 encoding will not work well with
- /// Explorer in Windows XP or Windows Vista, because Windows compressed
- /// folders, as far as I know, do not support UTF-8 in zip files. Vista can
- /// read the zip files, but shows the filenames incorrectly. Unpacking from
- /// Windows Vista Explorer will result in filenames that have rubbish
- /// characters in place of the high-order UTF-8 bytes.
- /// </para>
- ///
- /// <para>
- /// Also, zip files that use UTF-8 encoding will not work well with Java
- /// applications that use the java.util.zip classes, as of v5.0 of the Java
- /// runtime. The Java runtime does not correctly implement the PKWare
- /// specification in this regard.
- /// </para>
- ///
- /// <para>
- /// As a result, we have the unfortunate situation that "correct" behavior by
- /// the DotNetZip library with regard to Unicode encoding of filenames during
- /// zip creation will result in zip files that are readable by strictly
- /// compliant and current tools (for example the most recent release of the
- /// commercial WinZip tool); but these zip files will not be readable by
- /// various other tools or libraries, including Windows Explorer.
- /// </para>
- ///
- /// <para>
- /// The DotNetZip library can read and write zip files with UTF8-encoded
- /// entries, according to the PKware spec. If you use DotNetZip for both
- /// creating and reading the zip file, and you use UTF-8, there will be no
- /// loss of information in the filenames. For example, using a self-extractor
- /// created by this library will allow you to unpack files correctly with no
- /// loss of information in the filenames.
- /// </para>
- ///
- /// <para>
- /// If you do not set this flag, it will remain false. If this flag is false,
- /// your <c>ZipFile</c> will encode all filenames and comments using the
- /// IBM437 codepage. This can cause "loss of information" on some filenames,
- /// but the resulting zipfile will be more interoperable with other
- /// utilities. As an example of the loss of information, diacritics can be
- /// lost. The o-tilde character will be down-coded to plain o. The c with a
- /// cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c.
- /// Likewise, the O-stroke character (Unicode 248), used in Danish and
- /// Norwegian, will be down-coded to plain o. Chinese characters cannot be
- /// represented in codepage IBM437; when using the default encoding, Chinese
- /// characters in filenames will be represented as ?. These are all examples
- /// of "information loss".
- /// </para>
- ///
- /// <para>
- /// The loss of information associated to the use of the IBM437 encoding is
- /// inconvenient, and can also lead to runtime errors. For example, using
- /// IBM437, any sequence of 4 Chinese characters will be encoded as ????. If
- /// your application creates a <c>ZipFile</c>, then adds two files, each with
- /// names of four Chinese characters each, this will result in a duplicate
- /// filename exception. In the case where you add a single file with a name
- /// containing four Chinese characters, calling Extract() on the entry that
- /// has question marks in the filename will result in an exception, because
- /// the question mark is not legal for use within filenames on Windows. These
- /// are just a few examples of the problems associated to loss of information.
- /// </para>
- ///
- /// <para>
- /// This flag is independent of the encoding of the content within the entries
- /// in the zip file. Think of the zip file as a container - it supports an
- /// encoding. Within the container are other "containers" - the file entries
- /// themselves. The encoding within those entries is independent of the
- /// encoding of the zip archive container for those entries.
- /// </para>
- ///
- /// <para>
- /// Rather than specify the encoding in a binary fashion using this flag, an
- /// application can specify an arbitrary encoding via the <see
- /// cref="ProvisionalAlternateEncoding"/> property. Setting the encoding
- /// explicitly when creating zip archives will result in non-compliant zip
- /// files that, curiously, are fairly interoperable. The challenge is, the
- /// PKWare specification does not provide for a way to specify that an entry
- /// in a zip archive uses a code page that is neither IBM437 nor UTF-8.
- /// Therefore if you set the encoding explicitly when creating a zip archive,
- /// you must take care upon reading the zip archive to use the same code page.
- /// If you get it wrong, the behavior is undefined and may result in incorrect
- /// filenames, exceptions, stomach upset, hair loss, and acne.
- /// </para>
- /// </remarks>
- /// <seealso cref="ProvisionalAlternateEncoding"/>
- [Obsolete("Beginning with v1.9.1.6 of DotNetZip, this property is obsolete. It will be removed in a future version of the library. Your applications should use AlternateEncoding and AlternateEncodingUsage instead.")]
- public bool UseUnicodeAsNecessary
- {
- get
- {
- return (_alternateEncoding == System.Text.Encoding.GetEncoding("UTF-8")) &&
- (_alternateEncodingUsage == ZipOption.AsNecessary);
- }
- set
- {
- if (value)
- {
- _alternateEncoding = System.Text.Encoding.GetEncoding("UTF-8");
- _alternateEncodingUsage = ZipOption.AsNecessary;
-
- }
- else
- {
- _alternateEncoding = Ionic.Zip.ZipFile.DefaultEncoding;
- _alternateEncodingUsage = ZipOption.Never;
- }
- }
- }
-
-
- /// <summary>
- /// Specify whether to use ZIP64 extensions when saving a zip archive.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// When creating a zip file, the default value for the property is <see
- /// cref="Zip64Option.Never"/>. <see cref="Zip64Option.AsNecessary"/> is
- /// safest, in the sense that you will not get an Exception if a pre-ZIP64
- /// limit is exceeded.
- /// </para>
- ///
- /// <para>
- /// You may set the property at any time before calling Save().
- /// </para>
- ///
- /// <para>
- /// When reading a zip file via the <c>Zipfile.Read()</c> method, DotNetZip
- /// will properly read ZIP64-endowed zip archives, regardless of the value of
- /// this property. DotNetZip will always read ZIP64 archives. This property
- /// governs only whether DotNetZip will write them. Therefore, when updating
- /// archives, be careful about setting this property after reading an archive
- /// that may use ZIP64 extensions.
- /// </para>
- ///
- /// <para>
- /// An interesting question is, if you have set this property to
- /// <c>AsNecessary</c>, and then successfully saved, does the resulting
- /// archive use ZIP64 extensions or not? To learn this, check the <see
- /// cref="OutputUsedZip64"/> property, after calling <c>Save()</c>.
- /// </para>
- ///
- /// <para>
- /// Have you thought about
- /// <see href="http://cheeso.members.winisp.net/DotNetZipDonate.aspx">donating</see>?
- /// </para>
- ///
- /// </remarks>
- /// <seealso cref="RequiresZip64"/>
- internal Zip64Option UseZip64WhenSaving
- {
- get
- {
- return _zip64;
- }
- set
- {
- _zip64 = value;
- }
- }
-
-
-
- /// <summary>
- /// Indicates whether the archive requires ZIP64 extensions.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This property is <c>null</c> (or <c>Nothing</c> in VB) if the archive has
- /// not been saved, and there are fewer than 65334 <c>ZipEntry</c> items
- /// contained in the archive.
- /// </para>
- ///
- /// <para>
- /// The <c>Value</c> is true if any of the following four conditions holds:
- /// the uncompressed size of any entry is larger than 0xFFFFFFFF; the
- /// compressed size of any entry is larger than 0xFFFFFFFF; the relative
- /// offset of any entry within the zip archive is larger than 0xFFFFFFFF; or
- /// there are more than 65534 entries in the archive. (0xFFFFFFFF =
- /// 4,294,967,295). The result may not be known until a <c>Save()</c> is attempted
- /// on the zip archive. The Value of this <see cref="System.Nullable"/>
- /// property may be set only AFTER one of the Save() methods has been called.
- /// </para>
- ///
- /// <para>
- /// If none of the four conditions holds, and the archive has been saved, then
- /// the <c>Value</c> is false.
- /// </para>
- ///
- /// <para>
- /// A <c>Value</c> of false does not indicate that the zip archive, as saved,
- /// does not use ZIP64. It merely indicates that ZIP64 is not required. An
- /// archive may use ZIP64 even when not required if the <see
- /// cref="ZipFile.UseZip64WhenSaving"/> property is set to <see
- /// cref="Zip64Option.Always"/>, or if the <see
- /// cref="ZipFile.UseZip64WhenSaving"/> property is set to <see
- /// cref="Zip64Option.AsNecessary"/> and the output stream was not
- /// seekable. Use the <see cref="OutputUsedZip64"/> property to determine if
- /// the most recent <c>Save()</c> method resulted in an archive that utilized
- /// the ZIP64 extensions.
- /// </para>
- ///
- /// </remarks>
- /// <seealso cref="UseZip64WhenSaving"/>
- /// <seealso cref="OutputUsedZip64"/>
- public Nullable<bool> RequiresZip64
- {
- get
- {
- if (_entries.Count > 65534)
- return new Nullable<bool>(true);
-
- // If the <c>ZipFile</c> has not been saved or if the contents have changed, then
- // it is not known if ZIP64 is required.
- if (!_hasBeenSaved || _contentsChanged) return null;
-
- // Whether ZIP64 is required is knowable.
- foreach (ZipEntry e in _entries.Values)
- {
- if (e.RequiresZip64.Value) return new Nullable<bool>(true);
- }
-
- return new Nullable<bool>(false);
- }
- }
-
-
- /// <summary>
- /// Indicates whether the most recent <c>Save()</c> operation used ZIP64 extensions.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The use of ZIP64 extensions within an archive is not always necessary, and
- /// for interoperability concerns, it may be desired to NOT use ZIP64 if
- /// possible. The <see cref="ZipFile.UseZip64WhenSaving"/> property can be
- /// set to use ZIP64 extensions only when necessary. In those cases,
- /// Sometimes applications want to know whether a Save() actually used ZIP64
- /// extensions. Applications can query this read-only property to learn
- /// whether ZIP64 has been used in a just-saved <c>ZipFile</c>.
- /// </para>
- ///
- /// <para>
- /// The value is <c>null</c> (or <c>Nothing</c> in VB) if the archive has not
- /// been saved.
- /// </para>
- ///
- /// <para>
- /// Non-null values (<c>HasValue</c> is true) indicate whether ZIP64
- /// extensions were used during the most recent <c>Save()</c> operation. The
- /// ZIP64 extensions may have been used as required by any particular entry
- /// because of its uncompressed or compressed size, or because the archive is
- /// larger than 4294967295 bytes, or because there are more than 65534 entries
- /// in the archive, or because the <c>UseZip64WhenSaving</c> property was set
- /// to <see cref="Zip64Option.Always"/>, or because the
- /// <c>UseZip64WhenSaving</c> property was set to <see
- /// cref="Zip64Option.AsNecessary"/> and the output stream was not seekable.
- /// The value of this property does not indicate the reason the ZIP64
- /// extensions were used.
- /// </para>
- ///
- /// </remarks>
- /// <seealso cref="UseZip64WhenSaving"/>
- /// <seealso cref="RequiresZip64"/>
- public Nullable<bool> OutputUsedZip64
- {
- get
- {
- return _OutputUsesZip64;
- }
- }
-
-
- /// <summary>
- /// Indicates whether the most recent <c>Read()</c> operation read a zip file that uses
- /// ZIP64 extensions.
- /// </summary>
- ///
- /// <remarks>
- /// This property will return null (Nothing in VB) if you've added an entry after reading
- /// the zip file.
- /// </remarks>
- public Nullable<bool> InputUsesZip64
- {
- get
- {
- if (_entries.Count > 65534)
- return true;
-
- foreach (ZipEntry e in this)
- {
- // if any entry was added after reading the zip file, then the result is null
- if (e.Source != ZipEntrySource.ZipFile) return null;
-
- // if any entry read from the zip used zip64, then the result is true
- if (e._InputUsesZip64) return true;
- }
- return false;
- }
- }
-
-
- /// <summary>
- /// The text encoding to use when writing new entries to the <c>ZipFile</c>,
- /// for those entries that cannot be encoded with the default (IBM437)
- /// encoding; or, the text encoding that was used when reading the entries
- /// from the <c>ZipFile</c>.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// In <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">its
- /// zip specification</see>, PKWare describes two options for encoding
- /// filenames and comments: using IBM437 or UTF-8. But, some archiving tools
- /// or libraries do not follow the specification, and instead encode
- /// characters using the system default code page. For example, WinRAR when
- /// run on a machine in Shanghai may encode filenames with the Big-5 Chinese
- /// (950) code page. This behavior is contrary to the Zip specification, but
- /// it occurs anyway.
- /// </para>
- ///
- /// <para>
- /// When using DotNetZip to write zip archives that will be read by one of
- /// these other archivers, set this property to specify the code page to use
- /// when encoding the <see cref="ZipEntry.FileName"/> and <see
- /// cref="ZipEntry.Comment"/> for each <c>ZipEntry</c> in the zip file, for
- /// values that cannot be encoded with the default codepage for zip files,
- /// IBM437. This is why this property is "provisional". In all cases, IBM437
- /// is used where possible, in other words, where no loss of data would
- /// result. It is possible, therefore, to have a given entry with a
- /// <c>Comment</c> encoded in IBM437 and a <c>FileName</c> encoded with the
- /// specified "provisional" codepage.
- /// </para>
- ///
- /// <para>
- /// Be aware that a zip file created after you've explicitly set the <see
- /// cref="ProvisionalAlternateEncoding" /> property to a value other than
- /// IBM437 may not be compliant to the PKWare specification, and may not be
- /// readable by compliant archivers. On the other hand, many (most?)
- /// archivers are non-compliant and can read zip files created in arbitrary
- /// code pages. The trick is to use or specify the proper codepage when
- /// reading the zip.
- /// </para>
- ///
- /// <para>
- /// When creating a zip archive using this library, it is possible to change
- /// the value of <see cref="ProvisionalAlternateEncoding" /> between each
- /// entry you add, and between adding entries and the call to
- /// <c>Save()</c>. Don't do this. It will likely result in a zipfile that is
- /// not readable. For best interoperability, either leave <see
- /// cref="ProvisionalAlternateEncoding" /> alone, or specify it only once,
- /// before adding any entries to the <c>ZipFile</c> instance. There is one
- /// exception to this recommendation, described later.
- /// </para>
- ///
- /// <para>
- /// When using an arbitrary, non-UTF8 code page for encoding, there is no
- /// standard way for the creator application - whether DotNetZip, WinZip,
- /// WinRar, or something else - to formally specify in the zip file which
- /// codepage has been used for the entries. As a result, readers of zip files
- /// are not able to inspect the zip file and determine the codepage that was
- /// used for the entries contained within it. It is left to the application
- /// or user to determine the necessary codepage when reading zip files encoded
- /// this way. In other words, if you explicitly specify the codepage when you
- /// create the zipfile, you must explicitly specify the same codepage when
- /// reading the zipfile.
- /// </para>
- ///
- /// <para>
- /// The way you specify the code page to use when reading a zip file varies
- /// depending on the tool or library you use to read the zip. In DotNetZip,
- /// you use a ZipFile.Read() method that accepts an encoding parameter. It
- /// isn't possible with Windows Explorer, as far as I know, to specify an
- /// explicit codepage to use when reading a zip. If you use an incorrect
- /// codepage when reading a zipfile, you will get entries with filenames that
- /// are incorrect, and the incorrect filenames may even contain characters
- /// that are not legal for use within filenames in Windows. Extracting entries
- /// with illegal characters in the filenames will lead to exceptions. It's too
- /// bad, but this is just the way things are with code pages in zip
- /// files. Caveat Emptor.
- /// </para>
- ///
- /// <para>
- /// Example: Suppose you create a zipfile that contains entries with
- /// filenames that have Danish characters. If you use <see
- /// cref="ProvisionalAlternateEncoding" /> equal to "iso-8859-1" (cp 28591),
- /// the filenames will be correctly encoded in the zip. But, to read that
- /// zipfile correctly, you have to specify the same codepage at the time you
- /// read it. If try to read that zip file with Windows Explorer or another
- /// application that is not flexible with respect to the codepage used to
- /// decode filenames in zipfiles, you will get a filename like "Inf�.txt".
- /// </para>
- ///
- /// <para>
- /// When using DotNetZip to read a zip archive, and the zip archive uses an
- /// arbitrary code page, you must specify the encoding to use before or when
- /// the <c>Zipfile</c> is READ. This means you must use a <c>ZipFile.Read()</c>
- /// method that allows you to specify a System.Text.Encoding parameter. Setting
- /// the ProvisionalAlternateEncoding property after your application has read in
- /// the zip archive will not affect the entry names of entries that have already
- /// been read in.
- /// </para>
- ///
- /// <para>
- /// And now, the exception to the rule described above. One strategy for
- /// specifying the code page for a given zip file is to describe the code page
- /// in a human-readable form in the Zip comment. For example, the comment may
- /// read "Entries in this archive are encoded in the Big5 code page". For
- /// maximum interoperability, the zip comment in this case should be encoded
- /// in the default, IBM437 code page. In this case, the zip comment is
- /// encoded using a different page than the filenames. To do this, Specify
- /// <c>ProvisionalAlternateEncoding</c> to your desired region-specific code
- /// page, once before adding any entries, and then reset
- /// <c>ProvisionalAlternateEncoding</c> to IBM437 before setting the <see
- /// cref="Comment"/> property and calling Save().
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// This example shows how to read a zip file using the Big-5 Chinese code page
- /// (950), and extract each entry in the zip file. For this code to work as
- /// desired, the <c>Zipfile</c> must have been created using the big5 code page
- /// (CP950). This is typical, for example, when using WinRar on a machine with
- /// CP950 set as the default code page. In that case, the names of entries
- /// within the Zip archive will be stored in that code page, and reading the zip
- /// archive must be done using that code page. If the application did not use
- /// the correct code page in <c>ZipFile.Read()</c>, then names of entries within the
- /// zip archive would not be correctly retrieved.
- /// <code>
- /// using (var zip = ZipFile.Read(zipFileName, System.Text.Encoding.GetEncoding("big5")))
- /// {
- /// // retrieve and extract an entry using a name encoded with CP950
- /// zip[MyDesiredEntry].Extract("unpack");
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As ZipFile = ZipFile.Read(ZipToExtract, System.Text.Encoding.GetEncoding("big5"))
- /// ' retrieve and extract an entry using a name encoded with CP950
- /// zip(MyDesiredEntry).Extract("unpack")
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.DefaultEncoding">DefaultEncoding</seealso>
- [Obsolete("use AlternateEncoding instead.")]
- public System.Text.Encoding ProvisionalAlternateEncoding
- {
- get
- {
- if (_alternateEncodingUsage == ZipOption.AsNecessary)
- return _alternateEncoding;
- return null;
- }
- set
- {
- _alternateEncoding = value;
- _alternateEncodingUsage = ZipOption.AsNecessary;
- }
- }
-
-
- /// <summary>
- /// A Text Encoding to use when encoding the filenames and comments for
- /// all the ZipEntry items, during a ZipFile.Save() operation.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Whether the encoding specified here is used during the save depends
- /// on <see cref="AlternateEncodingUsage"/>.
- /// </para>
- /// </remarks>
- public System.Text.Encoding AlternateEncoding
- {
- get
- {
- return _alternateEncoding;
- }
- set
- {
- _alternateEncoding = value;
- }
- }
-
-
- /// <summary>
- /// A flag that tells if and when this instance should apply
- /// AlternateEncoding to encode the filenames and comments associated to
- /// of ZipEntry objects contained within this instance.
- /// </summary>
- internal ZipOption AlternateEncodingUsage
- {
- get
- {
- return _alternateEncodingUsage;
- }
- set
- {
- _alternateEncodingUsage = value;
- }
- }
-
-
- /// <summary>
- /// The default text encoding used in zip archives. It is numeric 437, also
- /// known as IBM437.
- /// </summary>
- /// <seealso cref="Ionic.Zip.ZipFile.ProvisionalAlternateEncoding"/>
- public static System.Text.Encoding DefaultEncoding
- {
- get
- {
- return _defaultEncoding;
- }
- }
-
-
- /// <summary>
- /// Gets or sets the <c>TextWriter</c> to which status messages are delivered
- /// for the instance.
- /// </summary>
- ///
- /// <remarks>
- /// If the TextWriter is set to a non-null value, then verbose output is sent
- /// to the <c>TextWriter</c> during <c>Add</c><c>, Read</c><c>, Save</c> and
- /// <c>Extract</c> operations. Typically, console applications might use
- /// <c>Console.Out</c> and graphical or headless applications might use a
- /// <c>System.IO.StringWriter</c>. The output of this is suitable for viewing
- /// by humans.
- /// </remarks>
- ///
- /// <example>
- /// <para>
- /// In this example, a console application instantiates a <c>ZipFile</c>, then
- /// sets the <c>StatusMessageTextWriter</c> to <c>Console.Out</c>. At that
- /// point, all verbose status messages for that <c>ZipFile</c> are sent to the
- /// console.
- /// </para>
- ///
- /// <code lang="C#">
- /// using (ZipFile zip= ZipFile.Read(FilePath))
- /// {
- /// zip.StatusMessageTextWriter= System.Console.Out;
- /// // messages are sent to the console during extraction
- /// zip.ExtractAll();
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As ZipFile = ZipFile.Read(FilePath)
- /// zip.StatusMessageTextWriter= System.Console.Out
- /// 'Status Messages will be sent to the console during extraction
- /// zip.ExtractAll()
- /// End Using
- /// </code>
- ///
- /// <para>
- /// In this example, a Windows Forms application instantiates a
- /// <c>ZipFile</c>, then sets the <c>StatusMessageTextWriter</c> to a
- /// <c>StringWriter</c>. At that point, all verbose status messages for that
- /// <c>ZipFile</c> are sent to the <c>StringWriter</c>.
- /// </para>
- ///
- /// <code lang="C#">
- /// var sw = new System.IO.StringWriter();
- /// using (ZipFile zip= ZipFile.Read(FilePath))
- /// {
- /// zip.StatusMessageTextWriter= sw;
- /// zip.ExtractAll();
- /// }
- /// Console.WriteLine("{0}", sw.ToString());
- /// </code>
- ///
- /// <code lang="VB">
- /// Dim sw as New System.IO.StringWriter
- /// Using zip As ZipFile = ZipFile.Read(FilePath)
- /// zip.StatusMessageTextWriter= sw
- /// zip.ExtractAll()
- /// End Using
- /// 'Status Messages are now available in sw
- ///
- /// </code>
- /// </example>
- public TextWriter StatusMessageTextWriter
- {
- get { return _StatusMessageTextWriter; }
- set { _StatusMessageTextWriter = value; }
- }
-
-
-
-
- /// <summary>
- /// Gets or sets the name for the folder to store the temporary file
- /// this library writes when saving a zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This library will create a temporary file when saving a Zip archive to a
- /// file. This file is written when calling one of the <c>Save()</c> methods
- /// that does not save to a stream, or one of the <c>SaveSelfExtractor()</c>
- /// methods.
- /// </para>
- ///
- /// <para>
- /// By default, the library will create the temporary file in the directory
- /// specified for the file itself, via the <see cref="Name"/> property or via
- /// the <see cref="ZipFile.Save(String)"/> method.
- /// </para>
- ///
- /// <para>
- /// Setting this property allows applications to override this default
- /// behavior, so that the library will create the temporary file in the
- /// specified folder. For example, to have the library create the temporary
- /// file in the current working directory, regardless where the <c>ZipFile</c>
- /// is saved, specfy ".". To revert to the default behavior, set this
- /// property to <c>null</c> (<c>Nothing</c> in VB).
- /// </para>
- ///
- /// <para>
- /// When setting the property to a non-null value, the folder specified must
- /// exist; if it does not an exception is thrown. The application should have
- /// write and delete permissions on the folder. The permissions are not
- /// explicitly checked ahead of time; if the application does not have the
- /// appropriate rights, an exception will be thrown at the time <c>Save()</c>
- /// is called.
- /// </para>
- ///
- /// <para>
- /// There is no temporary file created when reading a zip archive. When
- /// saving to a Stream, there is no temporary file created. For example, if
- /// the application is an ASP.NET application and calls <c>Save()</c>
- /// specifying the <c>Response.OutputStream</c> as the output stream, there is
- /// no temporary file created.
- /// </para>
- /// </remarks>
- ///
- /// <exception cref="System.IO.FileNotFoundException">
- /// Thrown when setting the property if the directory does not exist.
- /// </exception>
- ///
- public String TempFileFolder
- {
- get { return _TempFileFolder; }
-
- set
- {
- _TempFileFolder = value;
- if (value == null) return;
-
- if (!Directory.Exists(value))
- throw new FileNotFoundException(String.Format("That directory ({0}) does not exist.", value));
-
- }
- }
-
- /// <summary>
- /// Sets the password to be used on the <c>ZipFile</c> instance.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// When writing a zip archive, this password is applied to the entries, not
- /// to the zip archive itself. It applies to any <c>ZipEntry</c> subsequently
- /// added to the <c>ZipFile</c>, using one of the <c>AddFile</c>,
- /// <c>AddDirectory</c>, <c>AddEntry</c>, or <c>AddItem</c> methods, etc.
- /// When reading a zip archive, this property applies to any entry
- /// subsequently extracted from the <c>ZipFile</c> using one of the Extract
- /// methods on the <c>ZipFile</c> class.
- /// </para>
- ///
- /// <para>
- /// When writing a zip archive, keep this in mind: though the password is set
- /// on the ZipFile object, according to the Zip spec, the "directory" of the
- /// archive - in other words the list of entries or files contained in the archive - is
- /// not encrypted with the password, or protected in any way. If you set the
- /// Password property, the password actually applies to individual entries
- /// that are added to the archive, subsequent to the setting of this property.
- /// The list of filenames in the archive that is eventually created will
- /// appear in clear text, but the contents of the individual files are
- /// encrypted. This is how Zip encryption works.
- /// </para>
- ///
- /// <para>
- /// One simple way around this limitation is to simply double-wrap sensitive
- /// filenames: Store the files in a zip file, and then store that zip file
- /// within a second, "outer" zip file. If you apply a password to the outer
- /// zip file, then readers will be able to see that the outer zip file
- /// contains an inner zip file. But readers will not be able to read the
- /// directory or file list of the inner zip file.
- /// </para>
- ///
- /// <para>
- /// If you set the password on the <c>ZipFile</c>, and then add a set of files
- /// to the archive, then each entry is encrypted with that password. You may
- /// also want to change the password between adding different entries. If you
- /// set the password, add an entry, then set the password to <c>null</c>
- /// (<c>Nothing</c> in VB), and add another entry, the first entry is
- /// encrypted and the second is not. If you call <c>AddFile()</c>, then set
- /// the <c>Password</c> property, then call <c>ZipFile.Save</c>, the file
- /// added will not be password-protected, and no warning will be generated.
- /// </para>
- ///
- /// <para>
- /// When setting the Password, you may also want to explicitly set the <see
- /// cref="Encryption"/> property, to specify how to encrypt the entries added
- /// to the ZipFile. If you set the Password to a non-null value and do not
- /// set <see cref="Encryption"/>, then PKZip 2.0 ("Weak") encryption is used.
- /// This encryption is relatively weak but is very interoperable. If you set
- /// the password to a <c>null</c> value (<c>Nothing</c> in VB), Encryption is
- /// reset to None.
- /// </para>
- ///
- /// <para>
- /// All of the preceding applies to writing zip archives, in other words when
- /// you use one of the Save methods. To use this property when reading or an
- /// existing ZipFile, do the following: set the Password property on the
- /// <c>ZipFile</c>, then call one of the Extract() overloads on the <see
- /// cref="ZipEntry" />. In this case, the entry is extracted using the
- /// <c>Password</c> that is specified on the <c>ZipFile</c> instance. If you
- /// have not set the <c>Password</c> property, then the password is
- /// <c>null</c>, and the entry is extracted with no password.
- /// </para>
- ///
- /// <para>
- /// If you set the Password property on the <c>ZipFile</c>, then call
- /// <c>Extract()</c> an entry that has not been encrypted with a password, the
- /// password is not used for that entry, and the <c>ZipEntry</c> is extracted
- /// as normal. In other words, the password is used only if necessary.
- /// </para>
- ///
- /// <para>
- /// The <see cref="ZipEntry"/> class also has a <see
- /// cref="ZipEntry.Password">Password</see> property. It takes precedence
- /// over this property on the <c>ZipFile</c>. Typically, you would use the
- /// per-entry Password when most entries in the zip archive use one password,
- /// and a few entries use a different password. If all entries in the zip
- /// file use the same password, then it is simpler to just set this property
- /// on the <c>ZipFile</c> itself, whether creating a zip archive or extracting
- /// a zip archive.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// <para>
- /// This example creates a zip file, using password protection for the
- /// entries, and then extracts the entries from the zip file. When creating
- /// the zip file, the Readme.txt file is not protected with a password, but
- /// the other two are password-protected as they are saved. During extraction,
- /// each file is extracted with the appropriate password.
- /// </para>
- /// <code>
- /// // create a file with encryption
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// zip.AddFile("ReadMe.txt");
- /// zip.Password= "!Secret1";
- /// zip.AddFile("MapToTheSite-7440-N49th.png");
- /// zip.AddFile("2008-Regional-Sales-Report.pdf");
- /// zip.Save("EncryptedArchive.zip");
- /// }
- ///
- /// // extract entries that use encryption
- /// using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip"))
- /// {
- /// zip.Password= "!Secret1";
- /// zip.ExtractAll("extractDir");
- /// }
- ///
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As New ZipFile
- /// zip.AddFile("ReadMe.txt")
- /// zip.Password = "123456!"
- /// zip.AddFile("MapToTheSite-7440-N49th.png")
- /// zip.Password= "!Secret1";
- /// zip.AddFile("2008-Regional-Sales-Report.pdf")
- /// zip.Save("EncryptedArchive.zip")
- /// End Using
- ///
- ///
- /// ' extract entries that use encryption
- /// Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip"))
- /// zip.Password= "!Secret1"
- /// zip.ExtractAll("extractDir")
- /// End Using
- ///
- /// </code>
- ///
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.Encryption">ZipFile.Encryption</seealso>
- /// <seealso cref="ZipEntry.Password">ZipEntry.Password</seealso>
- public String Password
- {
- set
- {
- _Password = value;
- if (_Password == null)
- {
- Encryption = EncryptionAlgorithm.None;
- }
- else if (Encryption == EncryptionAlgorithm.None)
- {
- Encryption = EncryptionAlgorithm.PkzipWeak;
- }
- }
- private get
- {
- return _Password;
- }
- }
-
-
-
-
-
- /// <summary>
- /// The action the library should take when extracting a file that already
- /// exists.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This property affects the behavior of the Extract methods (one of the
- /// <c>Extract()</c> or <c>ExtractWithPassword()</c> overloads), when
- /// extraction would would overwrite an existing filesystem file. If you do
- /// not set this property, the library throws an exception when extracting an
- /// entry would overwrite an existing file.
- /// </para>
- ///
- /// <para>
- /// This property has no effect when extracting to a stream, or when the file
- /// to be extracted does not already exist.
- /// </para>
- /// </remarks>
- /// <seealso cref="ZipEntry.ExtractExistingFile"/>
- internal ExtractExistingFileAction ExtractExistingFile
- {
- get;
- set;
- }
-
-
- /// <summary>
- /// The action the library should take when an error is encountered while
- /// opening or reading files as they are saved into a zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Errors can occur as a file is being saved to the zip archive. For
- /// example, the File.Open may fail, or a File.Read may fail, because of
- /// lock conflicts or other reasons.
- /// </para>
- ///
- /// <para>
- /// The first problem might occur after having called AddDirectory() on a
- /// directory that contains a Clipper .dbf file; the file is locked by
- /// Clipper and cannot be opened for read by another process. An example of
- /// the second problem might occur when trying to zip a .pst file that is in
- /// use by Microsoft Outlook. Outlook locks a range on the file, which allows
- /// other processes to open the file, but not read it in its entirety.
- /// </para>
- ///
- /// <para>
- /// This property tells DotNetZip what you would like to do in the case of
- /// these errors. The primary options are: <c>ZipErrorAction.Throw</c> to
- /// throw an exception (this is the default behavior if you don't set this
- /// property); <c>ZipErrorAction.Skip</c> to Skip the file for which there
- /// was an error and continue saving; <c>ZipErrorAction.Retry</c> to Retry
- /// the entry that caused the problem; or
- /// <c>ZipErrorAction.InvokeErrorEvent</c> to invoke an event handler.
- /// </para>
- ///
- /// <para>
- /// This property is implicitly set to <c>ZipErrorAction.InvokeErrorEvent</c>
- /// if you add a handler to the <see cref="ZipError" /> event. If you set
- /// this property to something other than
- /// <c>ZipErrorAction.InvokeErrorEvent</c>, then the <c>ZipError</c>
- /// event is implicitly cleared. What it means is you can set one or the
- /// other (or neither), depending on what you want, but you never need to set
- /// both.
- /// </para>
- ///
- /// <para>
- /// As with some other properties on the <c>ZipFile</c> class, like <see
- /// cref="Password"/>, <see cref="Encryption"/>, and <see
- /// cref="CompressionLevel"/>, setting this property on a <c>ZipFile</c>
- /// instance will cause the specified <c>ZipErrorAction</c> to be used on all
- /// <see cref="ZipEntry"/> items that are subsequently added to the
- /// <c>ZipFile</c> instance. If you set this property after you have added
- /// items to the <c>ZipFile</c>, but before you have called <c>Save()</c>,
- /// those items will not use the specified error handling action.
- /// </para>
- ///
- /// <para>
- /// If you want to handle any errors that occur with any entry in the zip
- /// file in the same way, then set this property once, before adding any
- /// entries to the zip archive.
- /// </para>
- ///
- /// <para>
- /// If you set this property to <c>ZipErrorAction.Skip</c> and you'd like to
- /// learn which files may have been skipped after a <c>Save()</c>, you can
- /// set the <see cref="StatusMessageTextWriter" /> on the ZipFile before
- /// calling <c>Save()</c>. A message will be emitted into that writer for
- /// each skipped file, if any.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// This example shows how to tell DotNetZip to skip any files for which an
- /// error is generated during the Save().
- /// <code lang="VB">
- /// Public Sub SaveZipFile()
- /// Dim SourceFolder As String = "fodder"
- /// Dim DestFile As String = "eHandler.zip"
- /// Dim sw as New StringWriter
- /// Using zipArchive As ZipFile = New ZipFile
- /// ' Tell DotNetZip to skip any files for which it encounters an error
- /// zipArchive.ZipErrorAction = ZipErrorAction.Skip
- /// zipArchive.StatusMessageTextWriter = sw
- /// zipArchive.AddDirectory(SourceFolder)
- /// zipArchive.Save(DestFile)
- /// End Using
- /// ' examine sw here to see any messages
- /// End Sub
- ///
- /// </code>
- /// </example>
- ///
- /// <seealso cref="ZipEntry.ZipErrorAction"/>
- /// <seealso cref="Ionic.Zip.ZipFile.ZipError"/>
-
- internal ZipErrorAction ZipErrorAction
- {
- get
- {
- if (ZipError != null)
- _zipErrorAction = ZipErrorAction.InvokeErrorEvent;
- return _zipErrorAction;
- }
- set
- {
- _zipErrorAction = value;
- if (_zipErrorAction != ZipErrorAction.InvokeErrorEvent && ZipError != null)
- ZipError = null;
- }
- }
-
-
- /// <summary>
- /// The Encryption to use for entries added to the <c>ZipFile</c>.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Set this when creating a zip archive, or when updating a zip archive. The
- /// specified Encryption is applied to the entries subsequently added to the
- /// <c>ZipFile</c> instance. Applications do not need to set the
- /// <c>Encryption</c> property when reading or extracting a zip archive.
- /// </para>
- ///
- /// <para>
- /// If you set this to something other than EncryptionAlgorithm.None, you
- /// will also need to set the <see cref="Password"/>.
- /// </para>
- ///
- /// <para>
- /// As with some other properties on the <c>ZipFile</c> class, like <see
- /// cref="Password"/> and <see cref="CompressionLevel"/>, setting this
- /// property on a <c>ZipFile</c> instance will cause the specified
- /// <c>EncryptionAlgorithm</c> to be used on all <see cref="ZipEntry"/> items
- /// that are subsequently added to the <c>ZipFile</c> instance. In other
- /// words, if you set this property after you have added items to the
- /// <c>ZipFile</c>, but before you have called <c>Save()</c>, those items will
- /// not be encrypted or protected with a password in the resulting zip
- /// archive. To get a zip archive with encrypted entries, set this property,
- /// along with the <see cref="Password"/> property, before calling
- /// <c>AddFile</c>, <c>AddItem</c>, or <c>AddDirectory</c> (etc.) on the
- /// <c>ZipFile</c> instance.
- /// </para>
- ///
- /// <para>
- /// If you read a <c>ZipFile</c>, you can modify the <c>Encryption</c> on an
- /// encrypted entry, only by setting the <c>Encryption</c> property on the
- /// <c>ZipEntry</c> itself. Setting the <c>Encryption</c> property on the
- /// <c>ZipFile</c>, once it has been created via a call to
- /// <c>ZipFile.Read()</c>, does not affect entries that were previously read.
- /// </para>
- ///
- /// <para>
- /// For example, suppose you read a <c>ZipFile</c>, and there is an encrypted
- /// entry. Setting the <c>Encryption</c> property on that <c>ZipFile</c> and
- /// then calling <c>Save()</c> on the <c>ZipFile</c> does not update the
- /// <c>Encryption</c> used for the entries in the archive. Neither is an
- /// exception thrown. Instead, what happens during the <c>Save()</c> is that
- /// all previously existing entries are copied through to the new zip archive,
- /// with whatever encryption and password that was used when originally
- /// creating the zip archive. Upon re-reading that archive, to extract
- /// entries, applications should use the original password or passwords, if
- /// any.
- /// </para>
- ///
- /// <para>
- /// Suppose an application reads a <c>ZipFile</c>, and there is an encrypted
- /// entry. Setting the <c>Encryption</c> property on that <c>ZipFile</c> and
- /// then adding new entries (via <c>AddFile()</c>, <c>AddEntry()</c>, etc)
- /// and then calling <c>Save()</c> on the <c>ZipFile</c> does not update the
- /// <c>Encryption</c> on any of the entries that had previously been in the
- /// <c>ZipFile</c>. The <c>Encryption</c> property applies only to the
- /// newly-added entries.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// <para>
- /// This example creates a zip archive that uses encryption, and then extracts
- /// entries from the archive. When creating the zip archive, the ReadMe.txt
- /// file is zipped without using a password or encryption. The other files
- /// use encryption.
- /// </para>
- ///
- /// <code>
- /// // Create a zip archive with AES Encryption.
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// zip.AddFile("ReadMe.txt");
- /// zip.Encryption= EncryptionAlgorithm.WinZipAes256;
- /// zip.Password= "Top.Secret.No.Peeking!";
- /// zip.AddFile("7440-N49th.png");
- /// zip.AddFile("2008-Regional-Sales-Report.pdf");
- /// zip.Save("EncryptedArchive.zip");
- /// }
- ///
- /// // Extract a zip archive that uses AES Encryption.
- /// // You do not need to specify the algorithm during extraction.
- /// using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip"))
- /// {
- /// zip.Password= "Top.Secret.No.Peeking!";
- /// zip.ExtractAll("extractDirectory");
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// ' Create a zip that uses Encryption.
- /// Using zip As New ZipFile()
- /// zip.Encryption= EncryptionAlgorithm.WinZipAes256
- /// zip.Password= "Top.Secret.No.Peeking!"
- /// zip.AddFile("ReadMe.txt")
- /// zip.AddFile("7440-N49th.png")
- /// zip.AddFile("2008-Regional-Sales-Report.pdf")
- /// zip.Save("EncryptedArchive.zip")
- /// End Using
- ///
- /// ' Extract a zip archive that uses AES Encryption.
- /// ' You do not need to specify the algorithm during extraction.
- /// Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip"))
- /// zip.Password= "Top.Secret.No.Peeking!"
- /// zip.ExtractAll("extractDirectory")
- /// End Using
- /// </code>
- ///
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.Password">ZipFile.Password</seealso>
- /// <seealso cref="ZipEntry.Encryption">ZipEntry.Encryption</seealso>
- internal EncryptionAlgorithm Encryption
- {
- get
- {
- return _Encryption;
- }
- set
- {
- if (value == EncryptionAlgorithm.Unsupported)
- throw new InvalidOperationException("You may not set Encryption to that value.");
- _Encryption = value;
- }
- }
-
-
-
- /// <summary>
- /// A callback that allows the application to specify the compression level
- /// to use for entries subsequently added to the zip archive.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// With this callback, the DotNetZip library allows the application to
- /// determine whether compression will be used, at the time of the
- /// <c>Save</c>. This may be useful if the application wants to favor
- /// speed over size, and wants to defer the decision until the time of
- /// <c>Save</c>.
- /// </para>
- ///
- /// <para>
- /// Typically applications set the <see cref="CompressionLevel"/> property on
- /// the <c>ZipFile</c> or on each <c>ZipEntry</c> to determine the level of
- /// compression used. This is done at the time the entry is added to the
- /// <c>ZipFile</c>. Setting the property to
- /// <c>Ionic.Zlib.CompressionLevel.None</c> means no compression will be used.
- /// </para>
- ///
- /// <para>
- /// This callback allows the application to defer the decision on the
- /// <c>CompressionLevel</c> to use, until the time of the call to
- /// <c>ZipFile.Save()</c>. The callback is invoked once per <c>ZipEntry</c>,
- /// at the time the data for the entry is being written out as part of a
- /// <c>Save()</c> operation. The application can use whatever criteria it
- /// likes in determining the level to return. For example, an application may
- /// wish that no .mp3 files should be compressed, because they are already
- /// compressed and the extra compression is not worth the CPU time incurred,
- /// and so can return <c>None</c> for all .mp3 entries.
- /// </para>
- ///
- /// <para>
- /// The library determines whether compression will be attempted for an entry
- /// this way: If the entry is a zero length file, or a directory, no
- /// compression is used. Otherwise, if this callback is set, it is invoked
- /// and the <c>CompressionLevel</c> is set to the return value. If this
- /// callback has not been set, then the previously set value for
- /// <c>CompressionLevel</c> is used.
- /// </para>
- ///
- /// </remarks>
- public SetCompressionCallback SetCompression
- {
- get;
- set;
- }
-
-
- /// <summary>
- /// The maximum size of an output segment, when saving a split Zip file.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Set this to a non-zero value before calling <see cref="Save()"/> or <see
- /// cref="Save(String)"/> to specify that the ZipFile should be saved as a
- /// split archive, also sometimes called a spanned archive. Some also
- /// call them multi-file archives.
- /// </para>
- ///
- /// <para>
- /// A split zip archive is saved in a set of discrete filesystem files,
- /// rather than in a single file. This is handy when transmitting the
- /// archive in email or some other mechanism that has a limit to the size of
- /// each file. The first file in a split archive will be named
- /// <c>basename.z01</c>, the second will be named <c>basename.z02</c>, and
- /// so on. The final file is named <c>basename.zip</c>. According to the zip
- /// specification from PKWare, the minimum value is 65536, for a 64k segment
- /// size. The maximum number of segments allows in a split archive is 99.
- /// </para>
- ///
- /// <para>
- /// The value of this property determines the maximum size of a split
- /// segment when writing a split archive. For example, suppose you have a
- /// <c>ZipFile</c> that would save to a single file of 200k. If you set the
- /// <c>MaxOutputSegmentSize</c> to 65536 before calling <c>Save()</c>, you
- /// will get four distinct output files. On the other hand if you set this
- /// property to 256k, then you will get a single-file archive for that
- /// <c>ZipFile</c>.
- /// </para>
- ///
- /// <para>
- /// The size of each split output file will be as large as possible, up to
- /// the maximum size set here. The zip specification requires that some data
- /// fields in a zip archive may not span a split boundary, and an output
- /// segment may be smaller than the maximum if necessary to avoid that
- /// problem. Also, obviously the final segment of the archive may be smaller
- /// than the maximum segment size. Segments will never be larger than the
- /// value set with this property.
- /// </para>
- ///
- /// <para>
- /// You can save a split Zip file only when saving to a regular filesystem
- /// file. It's not possible to save a split zip file as a self-extracting
- /// archive, nor is it possible to save a split zip file to a stream. When
- /// saving to a SFX or to a Stream, this property is ignored.
- /// </para>
- ///
- /// <para>
- /// About interoperability: Split or spanned zip files produced by DotNetZip
- /// can be read by WinZip or PKZip, and vice-versa. Segmented zip files may
- /// not be readable by other tools, if those other tools don't support zip
- /// spanning or splitting. When in doubt, test. I don't believe Windows
- /// Explorer can extract a split archive.
- /// </para>
- ///
- /// <para>
- /// This property has no effect when reading a split archive. You can read
- /// a split archive in the normal way with DotNetZip.
- /// </para>
- ///
- /// <para>
- /// When saving a zip file, if you want a regular zip file rather than a
- /// split zip file, don't set this property, or set it to Zero.
- /// </para>
- ///
- /// <para>
- /// If you read a split archive, with <see cref="ZipFile.Read(string)"/> and
- /// then subsequently call <c>ZipFile.Save()</c>, unless you set this
- /// property before calling <c>Save()</c>, you will get a normal,
- /// single-file archive.
- /// </para>
- /// </remarks>
- ///
- /// <seealso cref="NumberOfSegmentsForMostRecentSave"/>
- public Int32 MaxOutputSegmentSize
- {
- get
- {
- return _maxOutputSegmentSize;
- }
- set
- {
- if (value < 65536 && value != 0)
- throw new ZipException("The minimum acceptable segment size is 65536.");
- _maxOutputSegmentSize = value;
- }
- }
-
-
- /// <summary>
- /// Returns the number of segments used in the most recent Save() operation.
- /// </summary>
- /// <remarks>
- /// <para>
- /// This is normally zero, unless you have set the <see
- /// cref="MaxOutputSegmentSize"/> property. If you have set <see
- /// cref="MaxOutputSegmentSize"/>, and then you save a file, after the call to
- /// Save() completes, you can read this value to learn the number of segments that
- /// were created.
- /// </para>
- /// <para>
- /// If you call Save("Archive.zip"), and it creates 5 segments, then you
- /// will have filesystem files named Archive.z01, Archive.z02, Archive.z03,
- /// Archive.z04, and Archive.zip, and the value of this property will be 5.
- /// </para>
- /// </remarks>
- /// <seealso cref="MaxOutputSegmentSize"/>
- public Int32 NumberOfSegmentsForMostRecentSave
- {
- get
- {
- return unchecked((Int32)_numberOfSegmentsForMostRecentSave + 1);
- }
- }
-
-
-#if !NETCF
- /// <summary>
- /// The size threshold for an entry, above which a parallel deflate is used.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// DotNetZip will use multiple threads to compress any ZipEntry,
- /// if the entry is larger than the given size. Zero means "always
- /// use parallel deflate", while -1 means "never use parallel
- /// deflate". The default value for this property is 512k. Aside
- /// from the special values of 0 and 1, the minimum value is 65536.
- /// </para>
- ///
- /// <para>
- /// If the entry size cannot be known before compression, as with a
- /// read-forward stream, then Parallel deflate will never be
- /// performed, unless the value of this property is zero.
- /// </para>
- ///
- /// <para>
- /// A parallel deflate operations will speed up the compression of
- /// large files, on computers with multiple CPUs or multiple CPU
- /// cores. For files above 1mb, on a dual core or dual-cpu (2p)
- /// machine, the time required to compress the file can be 70% of the
- /// single-threaded deflate. For very large files on 4p machines the
- /// compression can be done in 30% of the normal time. The downside
- /// is that parallel deflate consumes extra memory during the deflate,
- /// and the deflation is not as effective.
- /// </para>
- ///
- /// <para>
- /// Parallel deflate tends to yield slightly less compression when
- /// compared to as single-threaded deflate; this is because the original
- /// data stream is split into multiple independent buffers, each of which
- /// is compressed in parallel. But because they are treated
- /// independently, there is no opportunity to share compression
- /// dictionaries. For that reason, a deflated stream may be slightly
- /// larger when compressed using parallel deflate, as compared to a
- /// traditional single-threaded deflate. Sometimes the increase over the
- /// normal deflate is as much as 5% of the total compressed size. For
- /// larger files it can be as small as 0.1%.
- /// </para>
- ///
- /// <para>
- /// Multi-threaded compression does not give as much an advantage when
- /// using Encryption. This is primarily because encryption tends to slow
- /// down the entire pipeline. Also, multi-threaded compression gives less
- /// of an advantage when using lower compression levels, for example <see
- /// cref="Ionic.Zlib.CompressionLevel.BestSpeed"/>. You may have to
- /// perform some tests to determine the best approach for your situation.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <seealso cref="ParallelDeflateMaxBufferPairs"/>
- ///
- public long ParallelDeflateThreshold
- {
- set
- {
- if ((value != 0) && (value != -1) && (value < 64 * 1024))
- throw new ArgumentOutOfRangeException("ParallelDeflateThreshold should be -1, 0, or > 65536");
- _ParallelDeflateThreshold = value;
- }
- get
- {
- return _ParallelDeflateThreshold;
- }
- }
-
- /// <summary>
- /// The maximum number of buffer pairs to use when performing
- /// parallel compression.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This property sets an upper limit on the number of memory
- /// buffer pairs to create when performing parallel
- /// compression. The implementation of the parallel
- /// compression stream allocates multiple buffers to
- /// facilitate parallel compression. As each buffer fills up,
- /// the stream uses <see
- /// cref="System.Threading.ThreadPool.QueueUserWorkItem(System.Threading.WaitCallback)">
- /// ThreadPool.QueueUserWorkItem()</see> to compress those
- /// buffers in a background threadpool thread. After a buffer
- /// is compressed, it is re-ordered and written to the output
- /// stream.
- /// </para>
- ///
- /// <para>
- /// A higher number of buffer pairs enables a higher degree of
- /// parallelism, which tends to increase the speed of compression on
- /// multi-cpu computers. On the other hand, a higher number of buffer
- /// pairs also implies a larger memory consumption, more active worker
- /// threads, and a higher cpu utilization for any compression. This
- /// property enables the application to limit its memory consumption and
- /// CPU utilization behavior depending on requirements.
- /// </para>
- ///
- /// <para>
- /// For each compression "task" that occurs in parallel, there are 2
- /// buffers allocated: one for input and one for output. This property
- /// sets a limit for the number of pairs. The total amount of storage
- /// space allocated for buffering will then be (N*S*2), where N is the
- /// number of buffer pairs, S is the size of each buffer (<see
- /// cref="BufferSize"/>). By default, DotNetZip allocates 4 buffer
- /// pairs per CPU core, so if your machine has 4 cores, and you retain
- /// the default buffer size of 128k, then the
- /// ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer
- /// memory in total, or 4mb, in blocks of 128kb. If you then set this
- /// property to 8, then the number will be 8 * 2 * 128kb of buffer
- /// memory, or 2mb.
- /// </para>
- ///
- /// <para>
- /// CPU utilization will also go up with additional buffers, because a
- /// larger number of buffer pairs allows a larger number of background
- /// threads to compress in parallel. If you find that parallel
- /// compression is consuming too much memory or CPU, you can adjust this
- /// value downward.
- /// </para>
- ///
- /// <para>
- /// The default value is 16. Different values may deliver better or
- /// worse results, depending on your priorities and the dynamic
- /// performance characteristics of your storage and compute resources.
- /// </para>
- ///
- /// <para>
- /// This property is not the number of buffer pairs to use; it is an
- /// upper limit. An illustration: Suppose you have an application that
- /// uses the default value of this property (which is 16), and it runs
- /// on a machine with 2 CPU cores. In that case, DotNetZip will allocate
- /// 4 buffer pairs per CPU core, for a total of 8 pairs. The upper
- /// limit specified by this property has no effect.
- /// </para>
- ///
- /// <para>
- /// The application can set this value at any time
- /// before calling <c>ZipFile.Save()</c>.
- /// </para>
- /// </remarks>
- ///
- /// <seealso cref="ParallelDeflateThreshold"/>
- ///
- public int ParallelDeflateMaxBufferPairs
- {
- get
- {
- return _maxBufferPairs;
- }
- set
- {
- if (value < 4)
- throw new ArgumentOutOfRangeException("ParallelDeflateMaxBufferPairs",
- "Value must be 4 or greater.");
- _maxBufferPairs = value;
- }
- }
-#endif
-
-
- /// <summary>Provides a string representation of the instance.</summary>
- /// <returns>a string representation of the instance.</returns>
- public override String ToString()
- {
- return String.Format("ZipFile::{0}", Name);
- }
-
-
- /// <summary>
- /// Returns the version number on the DotNetZip assembly.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This property is exposed as a convenience. Callers could also get the
- /// version value by retrieving GetName().Version on the
- /// System.Reflection.Assembly object pointing to the DotNetZip
- /// assembly. But sometimes it is not clear which assembly is being loaded.
- /// This property makes it clear.
- /// </para>
- /// <para>
- /// This static property is primarily useful for diagnostic purposes.
- /// </para>
- /// </remarks>
- public static System.Version LibraryVersion
- {
- get
- {
- return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
- }
- }
-
- internal void NotifyEntryChanged()
- {
- _contentsChanged = true;
- }
-
-
- internal Stream StreamForDiskNumber(uint diskNumber)
- {
- if (diskNumber + 1 == this._diskNumberWithCd ||
- (diskNumber == 0 && this._diskNumberWithCd == 0))
- {
- //return (this.ReadStream as FileStream);
- return this.ReadStream;
- }
- return ZipSegmentedStream.ForReading(this._readName ?? this._name,
- diskNumber, _diskNumberWithCd);
- }
-
-
-
- // called by ZipEntry in ZipEntry.Extract(), when there is no stream set for the
- // ZipEntry.
- internal void Reset(bool whileSaving)
- {
- if (_JustSaved)
- {
- // read in the just-saved zip archive
- using (ZipFile x = new ZipFile())
- {
- // workitem 10735
- x._readName = x._name = whileSaving
- ? (this._readName ?? this._name)
- : this._name;
- x.AlternateEncoding = this.AlternateEncoding;
- x.AlternateEncodingUsage = this.AlternateEncodingUsage;
- ReadIntoInstance(x);
- // copy the contents of the entries.
- // cannot just replace the entries - the app may be holding them
- foreach (ZipEntry e1 in x)
- {
- foreach (ZipEntry e2 in this)
- {
- if (e1.FileName == e2.FileName)
- {
- e2.CopyMetaData(e1);
- break;
- }
- }
- }
- }
- _JustSaved = false;
- }
- }
-
-
- #endregion
-
- #region Constructors
-
- /// <summary>
- /// Creates a new <c>ZipFile</c> instance, using the specified filename.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Applications can use this constructor to create a new ZipFile for writing,
- /// or to slurp in an existing zip archive for read and update purposes.
- /// </para>
- ///
- /// <para>
- /// To create a new zip archive, an application can call this constructor,
- /// passing the name of a file that does not exist. The name may be a fully
- /// qualified path. Then the application can add directories or files to the
- /// <c>ZipFile</c> via <c>AddDirectory()</c>, <c>AddFile()</c>, <c>AddItem()</c>
- /// and then write the zip archive to the disk by calling <c>Save()</c>. The
- /// zip file is not actually opened and written to the disk until the
- /// application calls <c>ZipFile.Save()</c>. At that point the new zip file
- /// with the given name is created.
- /// </para>
- ///
- /// <para>
- /// If you won't know the name of the <c>Zipfile</c> until the time you call
- /// <c>ZipFile.Save()</c>, or if you plan to save to a stream (which has no
- /// name), then you should use the no-argument constructor.
- /// </para>
- ///
- /// <para>
- /// The application can also call this constructor to read an existing zip
- /// archive. passing the name of a valid zip file that does exist. But, it's
- /// better form to use the static <see cref="ZipFile.Read(String)"/> method,
- /// passing the name of the zip file, because using <c>ZipFile.Read()</c> in
- /// your code communicates very clearly what you are doing. In either case,
- /// the file is then read into the <c>ZipFile</c> instance. The app can then
- /// enumerate the entries or can modify the zip file, for example adding
- /// entries, removing entries, changing comments, and so on.
- /// </para>
- ///
- /// <para>
- /// One advantage to this parameterized constructor: it allows applications to
- /// use the same code to add items to a zip archive, regardless of whether the
- /// zip file exists.
- /// </para>
- ///
- /// <para>
- /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may
- /// not party on a single instance with multiple threads. You may have
- /// multiple threads that each use a distinct <c>ZipFile</c> instance, or you
- /// can synchronize multi-thread access to a single instance.
- /// </para>
- ///
- /// <para>
- /// By the way, since DotNetZip is so easy to use, don't you think <see
- /// href="http://cheeso.members.winisp.net/DotNetZipDonate.aspx">you should
- /// donate $5 or $10</see>?
- /// </para>
- ///
- /// </remarks>
- ///
- /// <exception cref="Ionic.Zip.ZipException">
- /// Thrown if name refers to an existing file that is not a valid zip file.
- /// </exception>
- ///
- /// <example>
- /// This example shows how to create a zipfile, and add a few files into it.
- /// <code>
- /// String ZipFileToCreate = "archive1.zip";
- /// String DirectoryToZip = "c:\\reports";
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// // Store all files found in the top level directory, into the zip archive.
- /// String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip);
- /// zip.AddFiles(filenames, "files");
- /// zip.Save(ZipFileToCreate);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Dim ZipFileToCreate As String = "archive1.zip"
- /// Dim DirectoryToZip As String = "c:\reports"
- /// Using zip As ZipFile = New ZipFile()
- /// Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip)
- /// zip.AddFiles(filenames, "files")
- /// zip.Save(ZipFileToCreate)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="fileName">The filename to use for the new zip archive.</param>
- ///
- public ZipFile(string fileName)
- {
- try
- {
- _InitInstance(fileName, null);
- }
- catch (Exception e1)
- {
- throw new ZipException(String.Format("Could not read {0} as a zip file", fileName), e1);
- }
- }
-
-
- /// <summary>
- /// Creates a new <c>ZipFile</c> instance, using the specified name for the
- /// filename, and the specified Encoding.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// See the documentation on the <see cref="ZipFile(String)">ZipFile
- /// constructor that accepts a single string argument</see> for basic
- /// information on all the <c>ZipFile</c> constructors.
- /// </para>
- ///
- /// <para>
- /// The Encoding is used as the default alternate encoding for entries with
- /// filenames or comments that cannot be encoded with the IBM437 code page.
- /// This is equivalent to setting the <see
- /// cref="ProvisionalAlternateEncoding"/> property on the <c>ZipFile</c>
- /// instance after construction.
- /// </para>
- ///
- /// <para>
- /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may
- /// not party on a single instance with multiple threads. You may have
- /// multiple threads that each use a distinct <c>ZipFile</c> instance, or you
- /// can synchronize multi-thread access to a single instance.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <exception cref="Ionic.Zip.ZipException">
- /// Thrown if name refers to an existing file that is not a valid zip file.
- /// </exception>
- ///
- /// <param name="fileName">The filename to use for the new zip archive.</param>
- /// <param name="encoding">The Encoding is used as the default alternate
- /// encoding for entries with filenames or comments that cannot be encoded
- /// with the IBM437 code page. </param>
- public ZipFile(string fileName, System.Text.Encoding encoding)
- {
- try
- {
- AlternateEncoding = encoding;
- AlternateEncodingUsage = ZipOption.Always;
- _InitInstance(fileName, null);
- }
- catch (Exception e1)
- {
- throw new ZipException(String.Format("{0} is not a valid zip file", fileName), e1);
- }
- }
-
-
-
- /// <summary>
- /// Create a zip file, without specifying a target filename or stream to save to.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// See the documentation on the <see cref="ZipFile(String)">ZipFile
- /// constructor that accepts a single string argument</see> for basic
- /// information on all the <c>ZipFile</c> constructors.
- /// </para>
- ///
- /// <para>
- /// After instantiating with this constructor and adding entries to the
- /// archive, the application should call <see cref="ZipFile.Save(String)"/> or
- /// <see cref="ZipFile.Save(System.IO.Stream)"/> to save to a file or a
- /// stream, respectively. The application can also set the <see cref="Name"/>
- /// property and then call the no-argument <see cref="Save()"/> method. (This
- /// is the preferred approach for applications that use the library through
- /// COM interop.) If you call the no-argument <see cref="Save()"/> method
- /// without having set the <c>Name</c> of the <c>ZipFile</c>, either through
- /// the parameterized constructor or through the explicit property , the
- /// Save() will throw, because there is no place to save the file. </para>
- ///
- /// <para>
- /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may
- /// have multiple threads that each use a distinct <c>ZipFile</c> instance, or
- /// you can synchronize multi-thread access to a single instance. </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// This example creates a Zip archive called Backup.zip, containing all the files
- /// in the directory DirectoryToZip. Files within subdirectories are not zipped up.
- /// <code>
- /// using (ZipFile zip = new ZipFile())
- /// {
- /// // Store all files found in the top level directory, into the zip archive.
- /// // note: this code does not recurse subdirectories!
- /// String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip);
- /// zip.AddFiles(filenames, "files");
- /// zip.Save("Backup.zip");
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As New ZipFile
- /// ' Store all files found in the top level directory, into the zip archive.
- /// ' note: this code does not recurse subdirectories!
- /// Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip)
- /// zip.AddFiles(filenames, "files")
- /// zip.Save("Backup.zip")
- /// End Using
- /// </code>
- /// </example>
- public ZipFile()
- {
- _InitInstance(null, null);
- }
-
-
- /// <summary>
- /// Create a zip file, specifying a text Encoding, but without specifying a
- /// target filename or stream to save to.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// See the documentation on the <see cref="ZipFile(String)">ZipFile
- /// constructor that accepts a single string argument</see> for basic
- /// information on all the <c>ZipFile</c> constructors.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="encoding">
- /// The Encoding is used as the default alternate encoding for entries with
- /// filenames or comments that cannot be encoded with the IBM437 code page.
- /// </param>
- public ZipFile(System.Text.Encoding encoding)
- {
- AlternateEncoding = encoding;
- AlternateEncodingUsage = ZipOption.Always;
- _InitInstance(null, null);
- }
-
-
- /// <summary>
- /// Creates a new <c>ZipFile</c> instance, using the specified name for the
- /// filename, and the specified status message writer.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// See the documentation on the <see cref="ZipFile(String)">ZipFile
- /// constructor that accepts a single string argument</see> for basic
- /// information on all the <c>ZipFile</c> constructors.
- /// </para>
- ///
- /// <para>
- /// This version of the constructor allows the caller to pass in a TextWriter,
- /// to which verbose messages will be written during extraction or creation of
- /// the zip archive. A console application may wish to pass
- /// System.Console.Out to get messages on the Console. A graphical or headless
- /// application may wish to capture the messages in a different
- /// <c>TextWriter</c>, for example, a <c>StringWriter</c>, and then display
- /// the messages in a TextBox, or generate an audit log of ZipFile operations.
- /// </para>
- ///
- /// <para>
- /// To encrypt the data for the files added to the <c>ZipFile</c> instance,
- /// set the Password property after creating the <c>ZipFile</c> instance.
- /// </para>
- ///
- /// <para>
- /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may
- /// not party on a single instance with multiple threads. You may have
- /// multiple threads that each use a distinct <c>ZipFile</c> instance, or you
- /// can synchronize multi-thread access to a single instance.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <exception cref="Ionic.Zip.ZipException">
- /// Thrown if name refers to an existing file that is not a valid zip file.
- /// </exception>
- ///
- /// <example>
- /// <code>
- /// using (ZipFile zip = new ZipFile("Backup.zip", Console.Out))
- /// {
- /// // Store all files found in the top level directory, into the zip archive.
- /// // note: this code does not recurse subdirectories!
- /// // Status messages will be written to Console.Out
- /// String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip);
- /// zip.AddFiles(filenames);
- /// zip.Save();
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As New ZipFile("Backup.zip", Console.Out)
- /// ' Store all files found in the top level directory, into the zip archive.
- /// ' note: this code does not recurse subdirectories!
- /// ' Status messages will be written to Console.Out
- /// Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip)
- /// zip.AddFiles(filenames)
- /// zip.Save()
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="fileName">The filename to use for the new zip archive.</param>
- /// <param name="statusMessageWriter">A TextWriter to use for writing
- /// verbose status messages.</param>
- public ZipFile(string fileName, TextWriter statusMessageWriter)
- {
- try
- {
- _InitInstance(fileName, statusMessageWriter);
- }
- catch (Exception e1)
- {
- throw new ZipException(String.Format("{0} is not a valid zip file", fileName), e1);
- }
- }
-
-
- /// <summary>
- /// Creates a new <c>ZipFile</c> instance, using the specified name for the
- /// filename, the specified status message writer, and the specified Encoding.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This constructor works like the <see cref="ZipFile(String)">ZipFile
- /// constructor that accepts a single string argument.</see> See that
- /// reference for detail on what this constructor does.
- /// </para>
- ///
- /// <para>
- /// This version of the constructor allows the caller to pass in a
- /// <c>TextWriter</c>, and an Encoding. The <c>TextWriter</c> will collect
- /// verbose messages that are generated by the library during extraction or
- /// creation of the zip archive. A console application may wish to pass
- /// <c>System.Console.Out</c> to get messages on the Console. A graphical or
- /// headless application may wish to capture the messages in a different
- /// <c>TextWriter</c>, for example, a <c>StringWriter</c>, and then display
- /// the messages in a <c>TextBox</c>, or generate an audit log of
- /// <c>ZipFile</c> operations.
- /// </para>
- ///
- /// <para>
- /// The <c>Encoding</c> is used as the default alternate encoding for entries
- /// with filenames or comments that cannot be encoded with the IBM437 code
- /// page. This is a equivalent to setting the <see
- /// cref="ProvisionalAlternateEncoding"/> property on the <c>ZipFile</c>
- /// instance after construction.
- /// </para>
- ///
- /// <para>
- /// To encrypt the data for the files added to the <c>ZipFile</c> instance,
- /// set the <c>Password</c> property after creating the <c>ZipFile</c>
- /// instance.
- /// </para>
- ///
- /// <para>
- /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may
- /// not party on a single instance with multiple threads. You may have
- /// multiple threads that each use a distinct <c>ZipFile</c> instance, or you
- /// can synchronize multi-thread access to a single instance.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <exception cref="Ionic.Zip.ZipException">
- /// Thrown if <c>fileName</c> refers to an existing file that is not a valid zip file.
- /// </exception>
- ///
- /// <param name="fileName">The filename to use for the new zip archive.</param>
- /// <param name="statusMessageWriter">A TextWriter to use for writing verbose
- /// status messages.</param>
- /// <param name="encoding">
- /// The Encoding is used as the default alternate encoding for entries with
- /// filenames or comments that cannot be encoded with the IBM437 code page.
- /// </param>
- public ZipFile(string fileName, TextWriter statusMessageWriter,
- System.Text.Encoding encoding)
- {
- try
- {
- AlternateEncoding = encoding;
- AlternateEncodingUsage = ZipOption.Always;
- _InitInstance(fileName, statusMessageWriter);
- }
- catch (Exception e1)
- {
- throw new ZipException(String.Format("{0} is not a valid zip file", fileName), e1);
- }
- }
-
-
-
-
- /// <summary>
- /// Initialize a <c>ZipFile</c> instance by reading in a zip file.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This method is primarily useful from COM Automation environments, when
- /// reading or extracting zip files. In COM, it is not possible to invoke
- /// parameterized constructors for a class. A COM Automation application can
- /// update a zip file by using the <see cref="ZipFile()">default (no argument)
- /// constructor</see>, then calling <c>Initialize()</c> to read the contents
- /// of an on-disk zip archive into the <c>ZipFile</c> instance.
- /// </para>
- ///
- /// <para>
- /// .NET applications are encouraged to use the <c>ZipFile.Read()</c> methods
- /// for better clarity.
- /// </para>
- ///
- /// </remarks>
- /// <param name="fileName">the name of the existing zip file to read in.</param>
- public void Initialize(string fileName)
- {
- try
- {
- _InitInstance(fileName, null);
- }
- catch (Exception e1)
- {
- throw new ZipException(String.Format("{0} is not a valid zip file", fileName), e1);
- }
- }
-
-
-
- private void _initEntriesDictionary()
- {
- // workitem 9868
- StringComparer sc = (CaseSensitiveRetrieval) ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase;
- _entries = (_entries == null)
- ? new Dictionary<String, ZipEntry>(sc)
- : new Dictionary<String, ZipEntry>(_entries, sc);
- }
-
-
- private void _InitInstance(string zipFileName, TextWriter statusMessageWriter)
- {
- // create a new zipfile
- _name = zipFileName;
- _StatusMessageTextWriter = statusMessageWriter;
- _contentsChanged = true;
- AddDirectoryWillTraverseReparsePoints = true; // workitem 8617
- CompressionLevel = OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel.Default;
-#if !NETCF
- ParallelDeflateThreshold = 512 * 1024;
-#endif
- // workitem 7685, 9868
- _initEntriesDictionary();
-
- if (File.Exists(_name))
- {
- if (FullScan)
- ReadIntoInstance_Orig(this);
- else
- ReadIntoInstance(this);
- this._fileAlreadyExists = true;
- }
-
- return;
- }
- #endregion
-
-
-
- #region Indexers and Collections
-
- private List<ZipEntry> ZipEntriesAsList
- {
- get
- {
- if (_zipEntriesAsList == null)
- _zipEntriesAsList = new List<ZipEntry>(_entries.Values);
- return _zipEntriesAsList;
- }
- }
-
- /// <summary>
- /// This is an integer indexer into the Zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This property is read-only.
- /// </para>
- ///
- /// <para>
- /// Internally, the <c>ZipEntry</c> instances that belong to the
- /// <c>ZipFile</c> are stored in a Dictionary. When you use this
- /// indexer the first time, it creates a read-only
- /// <c>List<ZipEntry></c> from the Dictionary.Values Collection.
- /// If at any time you modify the set of entries in the <c>ZipFile</c>,
- /// either by adding an entry, removing an entry, or renaming an
- /// entry, a new List will be created, and the numeric indexes for the
- /// remaining entries may be different.
- /// </para>
- ///
- /// <para>
- /// This means you cannot rename any ZipEntry from
- /// inside an enumeration of the zip file.
- /// </para>
- ///
- /// <param name="ix">
- /// The index value.
- /// </param>
- ///
- /// </remarks>
- ///
- /// <returns>
- /// The <c>ZipEntry</c> within the Zip archive at the specified index. If the
- /// entry does not exist in the archive, this indexer throws.
- /// </returns>
- ///
- public ZipEntry this[int ix]
- {
- // workitem 6402
- get
- {
- return ZipEntriesAsList[ix];
- }
- }
-
-
- /// <summary>
- /// This is a name-based indexer into the Zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This property is read-only.
- /// </para>
- ///
- /// <para>
- /// The <see cref="CaseSensitiveRetrieval"/> property on the <c>ZipFile</c>
- /// determines whether retrieval via this indexer is done via case-sensitive
- /// comparisons. By default, retrieval is not case sensitive. This makes
- /// sense on Windows, in which filesystems are not case sensitive.
- /// </para>
- ///
- /// <para>
- /// Regardless of case-sensitivity, it is not always the case that
- /// <c>this[value].FileName == value</c>. In other words, the <c>FileName</c>
- /// property of the <c>ZipEntry</c> retrieved with this indexer, may or may
- /// not be equal to the index value.
- /// </para>
- ///
- /// <para>
- /// This is because DotNetZip performs a normalization of filenames passed to
- /// this indexer, before attempting to retrieve the item. That normalization
- /// includes: removal of a volume letter and colon, swapping backward slashes
- /// for forward slashes. So, <c>zip["dir1\\entry1.txt"].FileName ==
- /// "dir1/entry.txt"</c>.
- /// </para>
- ///
- /// <para>
- /// Directory entries in the zip file may be retrieved via this indexer only
- /// with names that have a trailing slash. DotNetZip automatically appends a
- /// trailing slash to the names of any directory entries added to a zip.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// This example extracts only the entries in a zip file that are .txt files.
- /// <code>
- /// using (ZipFile zip = ZipFile.Read("PackedDocuments.zip"))
- /// {
- /// foreach (string s1 in zip.EntryFilenames)
- /// {
- /// if (s1.EndsWith(".txt"))
- /// zip[s1].Extract("textfiles");
- /// }
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip")
- /// Dim s1 As String
- /// For Each s1 In zip.EntryFilenames
- /// If s1.EndsWith(".txt") Then
- /// zip(s1).Extract("textfiles")
- /// End If
- /// Next
- /// End Using
- /// </code>
- /// </example>
- /// <seealso cref="Ionic.Zip.ZipFile.RemoveEntry(string)"/>
- ///
- /// <exception cref="System.ArgumentException">
- /// Thrown if the caller attempts to assign a non-null value to the indexer.
- /// </exception>
- ///
- /// <param name="fileName">
- /// The name of the file, including any directory path, to retrieve from the
- /// zip. The filename match is not case-sensitive by default; you can use the
- /// <see cref="CaseSensitiveRetrieval"/> property to change this behavior. The
- /// pathname can use forward-slashes or backward slashes.
- /// </param>
- ///
- /// <returns>
- /// The <c>ZipEntry</c> within the Zip archive, given by the specified
- /// filename. If the named entry does not exist in the archive, this indexer
- /// returns <c>null</c> (<c>Nothing</c> in VB).
- /// </returns>
- ///
- public ZipEntry this[String fileName]
- {
- get
- {
- var key = SharedUtilities.NormalizePathForUseInZipFile(fileName);
- if (_entries.ContainsKey(key))
- return _entries[key];
- // workitem 11056
- key = key.Replace("/", "\\");
- if (_entries.ContainsKey(key))
- return _entries[key];
- return null;
-
-#if MESSY
- foreach (ZipEntry e in _entries.Values)
- {
- if (this.CaseSensitiveRetrieval)
- {
- // check for the file match with a case-sensitive comparison.
- if (e.FileName == fileName) return e;
- // also check for equivalence
- if (fileName.Replace("\\", "/") == e.FileName) return e;
- if (e.FileName.Replace("\\", "/") == fileName) return e;
-
- // check for a difference only in trailing slash
- if (e.FileName.EndsWith("/"))
- {
- var fileNameNoSlash = e.FileName.Trim("/".ToCharArray());
- if (fileNameNoSlash == fileName) return e;
- // also check for equivalence
- if (fileName.Replace("\\", "/") == fileNameNoSlash) return e;
- if (fileNameNoSlash.Replace("\\", "/") == fileName) return e;
- }
-
- }
- else
- {
- // check for the file match in a case-insensitive manner.
- if (String.Compare(e.FileName, fileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e;
- // also check for equivalence
- if (String.Compare(fileName.Replace("\\", "/"), e.FileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e;
- if (String.Compare(e.FileName.Replace("\\", "/"), fileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e;
-
- // check for a difference only in trailing slash
- if (e.FileName.EndsWith("/"))
- {
- var fileNameNoSlash = e.FileName.Trim("/".ToCharArray());
-
- if (String.Compare(fileNameNoSlash, fileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e;
- // also check for equivalence
- if (String.Compare(fileName.Replace("\\", "/"), fileNameNoSlash, StringComparison.CurrentCultureIgnoreCase) == 0) return e;
- if (String.Compare(fileNameNoSlash.Replace("\\", "/"), fileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e;
-
- }
-
- }
-
- }
- return null;
-
-#endif
- }
- }
-
-
- /// <summary>
- /// The list of filenames for the entries contained within the zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// According to the ZIP specification, the names of the entries use forward
- /// slashes in pathnames. If you are scanning through the list, you may have
- /// to swap forward slashes for backslashes.
- /// </remarks>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.this[string]"/>
- ///
- /// <example>
- /// This example shows one way to test if a filename is already contained
- /// within a zip archive.
- /// <code>
- /// String zipFileToRead= "PackedDocuments.zip";
- /// string candidate = "DatedMaterial.xps";
- /// using (ZipFile zip = new ZipFile(zipFileToRead))
- /// {
- /// if (zip.EntryFilenames.Contains(candidate))
- /// Console.WriteLine("The file '{0}' exists in the zip archive '{1}'",
- /// candidate,
- /// zipFileName);
- /// else
- /// Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'",
- /// candidate,
- /// zipFileName);
- /// Console.WriteLine();
- /// }
- /// </code>
- /// <code lang="VB">
- /// Dim zipFileToRead As String = "PackedDocuments.zip"
- /// Dim candidate As String = "DatedMaterial.xps"
- /// Using zip As ZipFile.Read(ZipFileToRead)
- /// If zip.EntryFilenames.Contains(candidate) Then
- /// Console.WriteLine("The file '{0}' exists in the zip archive '{1}'", _
- /// candidate, _
- /// zipFileName)
- /// Else
- /// Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'", _
- /// candidate, _
- /// zipFileName)
- /// End If
- /// Console.WriteLine
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <returns>
- /// The list of strings for the filenames contained within the Zip archive.
- /// </returns>
- ///
- public System.Collections.Generic.ICollection<String> EntryFileNames
- {
- get
- {
- return _entries.Keys;
- }
- }
-
-
- /// <summary>
- /// Returns the readonly collection of entries in the Zip archive.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// If there are no entries in the current <c>ZipFile</c>, the value returned is a
- /// non-null zero-element collection. If there are entries in the zip file,
- /// the elements are returned in no particular order.
- /// </para>
- /// <para>
- /// This is the implied enumerator on the <c>ZipFile</c> class. If you use a
- /// <c>ZipFile</c> instance in a context that expects an enumerator, you will
- /// get this collection.
- /// </para>
- /// </remarks>
- /// <seealso cref="EntriesSorted"/>
- public System.Collections.Generic.ICollection<ZipEntry> Entries
- {
- get
- {
- return _entries.Values;
- }
- }
-
-
- /// <summary>
- /// Returns a readonly collection of entries in the Zip archive, sorted by FileName.
- /// </summary>
- ///
- /// <remarks>
- /// If there are no entries in the current <c>ZipFile</c>, the value returned
- /// is a non-null zero-element collection. If there are entries in the zip
- /// file, the elements are returned sorted by the name of the entry.
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example fills a Windows Forms ListView with the entries in a zip file.
- ///
- /// <code lang="C#">
- /// using (ZipFile zip = ZipFile.Read(zipFile))
- /// {
- /// foreach (ZipEntry entry in zip.EntriesSorted)
- /// {
- /// ListViewItem item = new ListViewItem(n.ToString());
- /// n++;
- /// string[] subitems = new string[] {
- /// entry.FileName.Replace("/","\\"),
- /// entry.LastModified.ToString("yyyy-MM-dd HH:mm:ss"),
- /// entry.UncompressedSize.ToString(),
- /// String.Format("{0,5:F0}%", entry.CompressionRatio),
- /// entry.CompressedSize.ToString(),
- /// (entry.UsesEncryption) ? "Y" : "N",
- /// String.Format("{0:X8}", entry.Crc)};
- ///
- /// foreach (String s in subitems)
- /// {
- /// ListViewItem.ListViewSubItem subitem = new ListViewItem.ListViewSubItem();
- /// subitem.Text = s;
- /// item.SubItems.Add(subitem);
- /// }
- ///
- /// this.listView1.Items.Add(item);
- /// }
- /// }
- /// </code>
- /// </example>
- ///
- /// <seealso cref="Entries"/>
- public System.Collections.Generic.ICollection<ZipEntry> EntriesSorted
- {
- get
- {
- var coll = new System.Collections.Generic.List<ZipEntry>();
- foreach (var e in this.Entries)
- {
- coll.Add(e);
- }
- StringComparison sc = (CaseSensitiveRetrieval) ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
-
- coll.Sort((x, y) => { return String.Compare(x.FileName, y.FileName, sc); });
- return coll.AsReadOnly();
- }
- }
-
-
- /// <summary>
- /// Returns the number of entries in the Zip archive.
- /// </summary>
- public int Count
- {
- get
- {
- return _entries.Count;
- }
- }
-
-
-
- /// <summary>
- /// Removes the given <c>ZipEntry</c> from the zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// After calling <c>RemoveEntry</c>, the application must call <c>Save</c> to
- /// make the changes permanent.
- /// </para>
- /// </remarks>
- ///
- /// <exception cref="System.ArgumentException">
- /// Thrown if the specified <c>ZipEntry</c> does not exist in the <c>ZipFile</c>.
- /// </exception>
- ///
- /// <example>
- /// In this example, all entries in the zip archive dating from before
- /// December 31st, 2007, are removed from the archive. This is actually much
- /// easier if you use the RemoveSelectedEntries method. But I needed an
- /// example for RemoveEntry, so here it is.
- /// <code>
- /// String ZipFileToRead = "ArchiveToModify.zip";
- /// System.DateTime Threshold = new System.DateTime(2007,12,31);
- /// using (ZipFile zip = ZipFile.Read(ZipFileToRead))
- /// {
- /// var EntriesToRemove = new System.Collections.Generic.List<ZipEntry>();
- /// foreach (ZipEntry e in zip)
- /// {
- /// if (e.LastModified < Threshold)
- /// {
- /// // We cannot remove the entry from the list, within the context of
- /// // an enumeration of said list.
- /// // So we add the doomed entry to a list to be removed later.
- /// EntriesToRemove.Add(e);
- /// }
- /// }
- ///
- /// // actually remove the doomed entries.
- /// foreach (ZipEntry zombie in EntriesToRemove)
- /// zip.RemoveEntry(zombie);
- ///
- /// zip.Comment= String.Format("This zip archive was updated at {0}.",
- /// System.DateTime.Now.ToString("G"));
- ///
- /// // save with a different name
- /// zip.Save("Archive-Updated.zip");
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Dim ZipFileToRead As String = "ArchiveToModify.zip"
- /// Dim Threshold As New DateTime(2007, 12, 31)
- /// Using zip As ZipFile = ZipFile.Read(ZipFileToRead)
- /// Dim EntriesToRemove As New System.Collections.Generic.List(Of ZipEntry)
- /// Dim e As ZipEntry
- /// For Each e In zip
- /// If (e.LastModified < Threshold) Then
- /// ' We cannot remove the entry from the list, within the context of
- /// ' an enumeration of said list.
- /// ' So we add the doomed entry to a list to be removed later.
- /// EntriesToRemove.Add(e)
- /// End If
- /// Next
- ///
- /// ' actually remove the doomed entries.
- /// Dim zombie As ZipEntry
- /// For Each zombie In EntriesToRemove
- /// zip.RemoveEntry(zombie)
- /// Next
- /// zip.Comment = String.Format("This zip archive was updated at {0}.", DateTime.Now.ToString("G"))
- /// 'save as a different name
- /// zip.Save("Archive-Updated.zip")
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="entry">
- /// The <c>ZipEntry</c> to remove from the zip.
- /// </param>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.RemoveSelectedEntries(string)"/>
- ///
- public void RemoveEntry(ZipEntry entry)
- {
- //if (!_entries.Values.Contains(entry))
- // throw new ArgumentException("The entry you specified does not exist in the zip archive.");
- if (entry == null)
- throw new ArgumentNullException("entry");
-
- _entries.Remove(SharedUtilities.NormalizePathForUseInZipFile(entry.FileName));
- _zipEntriesAsList = null;
-
-#if NOTNEEDED
- if (_direntries != null)
- {
- bool FoundAndRemovedDirEntry = false;
- foreach (ZipDirEntry de1 in _direntries)
- {
- if (entry.FileName == de1.FileName)
- {
- _direntries.Remove(de1);
- FoundAndRemovedDirEntry = true;
- break;
- }
- }
-
- if (!FoundAndRemovedDirEntry)
- throw new BadStateException("The entry to be removed was not found in the directory.");
- }
-#endif
- _contentsChanged = true;
- }
-
-
-
-
- /// <summary>
- /// Removes the <c>ZipEntry</c> with the given filename from the zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// After calling <c>RemoveEntry</c>, the application must call <c>Save</c> to
- /// make the changes permanent.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <exception cref="System.InvalidOperationException">
- /// Thrown if the <c>ZipFile</c> is not updatable.
- /// </exception>
- ///
- /// <exception cref="System.ArgumentException">
- /// Thrown if a <c>ZipEntry</c> with the specified filename does not exist in
- /// the <c>ZipFile</c>.
- /// </exception>
- ///
- /// <example>
- ///
- /// This example shows one way to remove an entry with a given filename from
- /// an existing zip archive.
- ///
- /// <code>
- /// String zipFileToRead= "PackedDocuments.zip";
- /// string candidate = "DatedMaterial.xps";
- /// using (ZipFile zip = ZipFile.Read(zipFileToRead))
- /// {
- /// if (zip.EntryFilenames.Contains(candidate))
- /// {
- /// zip.RemoveEntry(candidate);
- /// zip.Comment= String.Format("The file '{0}' has been removed from this archive.",
- /// Candidate);
- /// zip.Save();
- /// }
- /// }
- /// </code>
- /// <code lang="VB">
- /// Dim zipFileToRead As String = "PackedDocuments.zip"
- /// Dim candidate As String = "DatedMaterial.xps"
- /// Using zip As ZipFile = ZipFile.Read(zipFileToRead)
- /// If zip.EntryFilenames.Contains(candidate) Then
- /// zip.RemoveEntry(candidate)
- /// zip.Comment = String.Format("The file '{0}' has been removed from this archive.", Candidate)
- /// zip.Save
- /// End If
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="fileName">
- /// The name of the file, including any directory path, to remove from the zip.
- /// The filename match is not case-sensitive by default; you can use the
- /// <c>CaseSensitiveRetrieval</c> property to change this behavior. The
- /// pathname can use forward-slashes or backward slashes.
- /// </param>
- ///
- public void RemoveEntry(String fileName)
- {
- string modifiedName = ZipEntry.NameInArchive(fileName, null);
- ZipEntry e = this[modifiedName];
- if (e == null)
- throw new ArgumentException("The entry you specified was not found in the zip archive.");
-
- RemoveEntry(e);
- }
-
-
- #endregion
-
- #region Destructors and Disposers
-
- // /// <summary>
- // /// This is the class Destructor, which gets called implicitly when the instance
- // /// is destroyed. Because the <c>ZipFile</c> type implements IDisposable, this
- // /// method calls Dispose(false).
- // /// </summary>
- // ~ZipFile()
- // {
- // // call Dispose with false. Since we're in the
- // // destructor call, the managed resources will be
- // // disposed of anyways.
- // Dispose(false);
- // }
-
- /// <summary>
- /// Closes the read and write streams associated
- /// to the <c>ZipFile</c>, if necessary.
- /// </summary>
- ///
- /// <remarks>
- /// The Dispose() method is generally employed implicitly, via a <c>using(..) {..}</c>
- /// statement. (<c>Using...End Using</c> in VB) If you do not employ a using
- /// statement, insure that your application calls Dispose() explicitly. For
- /// example, in a Powershell application, or an application that uses the COM
- /// interop interface, you must call Dispose() explicitly.
- /// </remarks>
- ///
- /// <example>
- /// This example extracts an entry selected by name, from the Zip file to the
- /// Console.
- /// <code>
- /// using (ZipFile zip = ZipFile.Read(zipfile))
- /// {
- /// foreach (ZipEntry e in zip)
- /// {
- /// if (WantThisEntry(e.FileName))
- /// zip.Extract(e.FileName, Console.OpenStandardOutput());
- /// }
- /// } // Dispose() is called implicitly here.
- /// </code>
- ///
- /// <code lang="VB">
- /// Using zip As ZipFile = ZipFile.Read(zipfile)
- /// Dim e As ZipEntry
- /// For Each e In zip
- /// If WantThisEntry(e.FileName) Then
- /// zip.Extract(e.FileName, Console.OpenStandardOutput())
- /// End If
- /// Next
- /// End Using ' Dispose is implicity called here
- /// </code>
- /// </example>
- public void Dispose()
- {
- // dispose of the managed and unmanaged resources
- Dispose(true);
-
- // tell the GC that the Finalize process no longer needs
- // to be run for this object.
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// Disposes any managed resources, if the flag is set, then marks the
- /// instance disposed. This method is typically not called explicitly from
- /// application code.
- /// </summary>
- ///
- /// <remarks>
- /// Applications should call <see cref="Dispose()">the no-arg Dispose method</see>.
- /// </remarks>
- ///
- /// <param name="disposeManagedResources">
- /// indicates whether the method should dispose streams or not.
- /// </param>
- protected virtual void Dispose(bool disposeManagedResources)
- {
- if (!this._disposed)
- {
- if (disposeManagedResources)
- {
- // dispose managed resources
- if (_ReadStreamIsOurs)
- {
- if (_readstream != null)
- {
- // workitem 7704
-#if NETCF
- _readstream.Close();
-#else
- _readstream.Dispose();
-#endif
- _readstream = null;
- }
- }
- // only dispose the writestream if there is a backing file
- if ((_temporaryFileName != null) && (_name != null))
- if (_writestream != null)
- {
- // workitem 7704
-#if NETCF
- _writestream.Close();
-#else
- _writestream.Dispose();
-#endif
- _writestream = null;
- }
-
-#if !NETCF
- // workitem 10030
- if (this.ParallelDeflater != null)
- {
- this.ParallelDeflater.Dispose();
- this.ParallelDeflater = null;
- }
-#endif
- }
- this._disposed = true;
- }
- }
- #endregion
-
-
- #region private properties
-
- internal Stream ReadStream
- {
- get
- {
- if (_readstream == null)
- {
- if (_readName != null || _name !=null)
- {
- _readstream = File.Open(_readName ?? _name,
- FileMode.Open,
- FileAccess.Read,
- FileShare.Read | FileShare.Write);
- _ReadStreamIsOurs = true;
- }
- }
- return _readstream;
- }
- }
-
-
-
- private Stream WriteStream
- {
- // workitem 9763
- get
- {
- if (_writestream != null) return _writestream;
- if (_name == null) return _writestream;
-
- if (_maxOutputSegmentSize != 0)
- {
- _writestream = ZipSegmentedStream.ForWriting(this._name, _maxOutputSegmentSize);
- return _writestream;
- }
-
- SharedUtilities.CreateAndOpenUniqueTempFile(TempFileFolder ?? Path.GetDirectoryName(_name),
- out _writestream,
- out _temporaryFileName);
- return _writestream;
- }
- set
- {
- if (value != null)
- throw new ZipException("Cannot set the stream to a non-null value.");
- _writestream = null;
- }
- }
- #endregion
-
- #region private fields
- private TextWriter _StatusMessageTextWriter;
- private bool _CaseSensitiveRetrieval;
- private Stream _readstream;
- private Stream _writestream;
- private UInt16 _versionMadeBy;
- private UInt16 _versionNeededToExtract;
- private UInt32 _diskNumberWithCd;
- private Int32 _maxOutputSegmentSize;
- private UInt32 _numberOfSegmentsForMostRecentSave;
- private ZipErrorAction _zipErrorAction;
- private bool _disposed;
- //private System.Collections.Generic.List<ZipEntry> _entries;
- private System.Collections.Generic.Dictionary<String, ZipEntry> _entries;
- private List<ZipEntry> _zipEntriesAsList;
- private string _name;
- private string _readName;
- private string _Comment;
- internal string _Password;
- private bool _emitNtfsTimes = true;
- private bool _emitUnixTimes;
- private Ionic.Zlib.CompressionStrategy _Strategy = Ionic.Zlib.CompressionStrategy.Default;
- private Ionic.Zip.CompressionMethod _compressionMethod = Ionic.Zip.CompressionMethod.Deflate;
- private bool _fileAlreadyExists;
- private string _temporaryFileName;
- private bool _contentsChanged;
- private bool _hasBeenSaved;
- private String _TempFileFolder;
- private bool _ReadStreamIsOurs = true;
- private object LOCK = new object();
- private bool _saveOperationCanceled;
- private bool _extractOperationCanceled;
- private bool _addOperationCanceled;
- private EncryptionAlgorithm _Encryption;
- private bool _JustSaved;
- private long _locEndOfCDS = -1;
- private uint _OffsetOfCentralDirectory;
- private Int64 _OffsetOfCentralDirectory64;
- private Nullable<bool> _OutputUsesZip64;
- internal bool _inExtractAll;
- private System.Text.Encoding _alternateEncoding = System.Text.Encoding.ASCII; // UTF-8
- private ZipOption _alternateEncodingUsage = ZipOption.Never;
- private static System.Text.Encoding _defaultEncoding = System.Text.Encoding.ASCII;
-
- private int _BufferSize = BufferSizeDefault;
-
-#if !NETCF
- internal Ionic.Zlib.ParallelDeflateOutputStream ParallelDeflater;
- private long _ParallelDeflateThreshold;
- private int _maxBufferPairs = 16;
-#endif
-
- internal Zip64Option _zip64 = Zip64Option.Default;
-#pragma warning disable 649
- private bool _SavingSfx;
-#pragma warning restore 649
-
- /// <summary>
- /// Default size of the buffer used for IO.
- /// </summary>
- public static readonly int BufferSizeDefault = 32768;
-
- #endregion
- }
-
- /// <summary>
- /// Options for using ZIP64 extensions when saving zip archives.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// Designed many years ago, the <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">original zip
- /// specification from PKWARE</see> allowed for 32-bit quantities for the
- /// compressed and uncompressed sizes of zip entries, as well as a 32-bit quantity
- /// for specifying the length of the zip archive itself, and a maximum of 65535
- /// entries. These limits are now regularly exceeded in many backup and archival
- /// scenarios. Recently, PKWare added extensions to the original zip spec, called
- /// "ZIP64 extensions", to raise those limitations. This property governs whether
- /// DotNetZip will use those extensions when writing zip archives. The use of
- /// these extensions is optional and explicit in DotNetZip because, despite the
- /// status of ZIP64 as a bona fide standard, many other zip tools and libraries do
- /// not support ZIP64, and therefore a zip file with ZIP64 extensions may be
- /// unreadable by some of those other tools.
- /// </para>
- ///
- /// <para>
- /// Set this property to <see cref="Zip64Option.Always"/> to always use ZIP64
- /// extensions when saving, regardless of whether your zip archive needs it.
- /// Suppose you add 5 files, each under 100k, to a ZipFile. If you specify Always
- /// for this flag, you will get a ZIP64 archive, though the archive does not need
- /// to use ZIP64 because none of the original zip limits had been exceeded.
- /// </para>
- ///
- /// <para>
- /// Set this property to <see cref="Zip64Option.Never"/> to tell the DotNetZip
- /// library to never use ZIP64 extensions. This is useful for maximum
- /// compatibility and interoperability, at the expense of the capability of
- /// handling large files or large archives. NB: Windows Explorer in Windows XP
- /// and Windows Vista cannot currently extract files from a zip64 archive, so if
- /// you want to guarantee that a zip archive produced by this library will work in
- /// Windows Explorer, use <c>Never</c>. If you set this property to <see
- /// cref="Zip64Option.Never"/>, and your application creates a zip that would
- /// exceed one of the Zip limits, the library will throw an exception while saving
- /// the zip file.
- /// </para>
- ///
- /// <para>
- /// Set this property to <see cref="Zip64Option.AsNecessary"/> to tell the
- /// DotNetZip library to use the ZIP64 extensions when required by the
- /// entry. After the file is compressed, the original and compressed sizes are
- /// checked, and if they exceed the limits described above, then zip64 can be
- /// used. That is the general idea, but there is an additional wrinkle when saving
- /// to a non-seekable device, like the ASP.NET <c>Response.OutputStream</c>, or
- /// <c>Console.Out</c>. When using non-seekable streams for output, the entry
- /// header - which indicates whether zip64 is in use - is emitted before it is
- /// known if zip64 is necessary. It is only after all entries have been saved
- /// that it can be known if ZIP64 will be required. On seekable output streams,
- /// after saving all entries, the library can seek backward and re-emit the zip
- /// file header to be consistent with the actual ZIP64 requirement. But using a
- /// non-seekable output stream, the library cannot seek backward, so the header
- /// can never be changed. In other words, the archive's use of ZIP64 extensions is
- /// not alterable after the header is emitted. Therefore, when saving to
- /// non-seekable streams, using <see cref="Zip64Option.AsNecessary"/> is the same
- /// as using <see cref="Zip64Option.Always"/>: it will always produce a zip
- /// archive that uses ZIP64 extensions.
- /// </para>
- ///
- /// </remarks>
- internal enum Zip64Option
- {
- /// <summary>
- /// The default behavior, which is "Never".
- /// (For COM clients, this is a 0 (zero).)
- /// </summary>
- Default = 0,
- /// <summary>
- /// Do not use ZIP64 extensions when writing zip archives.
- /// (For COM clients, this is a 0 (zero).)
- /// </summary>
- Never = 0,
- /// <summary>
- /// Use ZIP64 extensions when writing zip archives, as necessary.
- /// For example, when a single entry exceeds 0xFFFFFFFF in size, or when the archive as a whole
- /// exceeds 0xFFFFFFFF in size, or when there are more than 65535 entries in an archive.
- /// (For COM clients, this is a 1.)
- /// </summary>
- AsNecessary = 1,
- /// <summary>
- /// Always use ZIP64 extensions when writing zip archives, even when unnecessary.
- /// (For COM clients, this is a 2.)
- /// </summary>
- Always
- }
-
-
- /// <summary>
- /// An enum representing the values on a three-way toggle switch
- /// for various options in the library. This might be used to
- /// specify whether to employ a particular text encoding, or to use
- /// ZIP64 extensions, or some other option.
- /// </summary>
- internal enum ZipOption
- {
- /// <summary>
- /// The default behavior. This is the same as "Never".
- /// (For COM clients, this is a 0 (zero).)
- /// </summary>
- Default = 0,
- /// <summary>
- /// Never use the associated option.
- /// (For COM clients, this is a 0 (zero).)
- /// </summary>
- Never = 0,
- /// <summary>
- /// Use the associated behavior "as necessary."
- /// (For COM clients, this is a 1.)
- /// </summary>
- AsNecessary = 1,
- /// <summary>
- /// Use the associated behavior Always, whether necessary or not.
- /// (For COM clients, this is a 2.)
- /// </summary>
- Always
- }
-
-
- enum AddOrUpdateAction
- {
- AddOnly = 0,
- AddOrUpdate
- }
-
-}
-
-
-
-// ==================================================================
-//
-// Information on the ZIP format:
-//
-// From
-// http://www.pkware.com/documents/casestudies/APPNOTE.TXT
-//
-// Overall .ZIP file format:
-//
-// [local file header 1]
-// [file data 1]
-// [data descriptor 1] ** sometimes
-// .
-// .
-// .
-// [local file header n]
-// [file data n]
-// [data descriptor n] ** sometimes
-// [archive decryption header]
-// [archive extra data record]
-// [central directory]
-// [zip64 end of central directory record]
-// [zip64 end of central directory locator]
-// [end of central directory record]
-//
-// Local File Header format:
-// local file header signature ... 4 bytes (0x04034b50)
-// version needed to extract ..... 2 bytes
-// general purpose bit field ..... 2 bytes
-// compression method ............ 2 bytes
-// last mod file time ............ 2 bytes
-// last mod file date............. 2 bytes
-// crc-32 ........................ 4 bytes
-// compressed size................ 4 bytes
-// uncompressed size.............. 4 bytes
-// file name length............... 2 bytes
-// extra field length ............ 2 bytes
-// file name varies
-// extra field varies
-//
-//
-// Data descriptor: (used only when bit 3 of the general purpose bitfield is set)
-// (although, I have found zip files where bit 3 is not set, yet this descriptor is present!)
-// local file header signature 4 bytes (0x08074b50) ** sometimes!!! Not always
-// crc-32 4 bytes
-// compressed size 4 bytes
-// uncompressed size 4 bytes
-//
-//
-// Central directory structure:
-//
-// [file header 1]
-// .
-// .
-// .
-// [file header n]
-// [digital signature]
-//
-//
-// File header: (This is a ZipDirEntry)
-// central file header signature 4 bytes (0x02014b50)
-// version made by 2 bytes
-// version needed to extract 2 bytes
-// general purpose bit flag 2 bytes
-// compression method 2 bytes
-// last mod file time 2 bytes
-// last mod file date 2 bytes
-// crc-32 4 bytes
-// compressed size 4 bytes
-// uncompressed size 4 bytes
-// file name length 2 bytes
-// extra field length 2 bytes
-// file comment length 2 bytes
-// disk number start 2 bytes
-// internal file attributes ** 2 bytes
-// external file attributes *** 4 bytes
-// relative offset of local header 4 bytes
-// file name (variable size)
-// extra field (variable size)
-// file comment (variable size)
-//
-// ** The internal file attributes, near as I can tell,
-// uses 0x01 for a file and a 0x00 for a directory.
-//
-// ***The external file attributes follows the MS-DOS file attribute byte, described here:
-// at http://support.microsoft.com/kb/q125019/
-// 0x0010 => directory
-// 0x0020 => file
-//
-//
-// End of central directory record:
-//
-// end of central dir signature 4 bytes (0x06054b50)
-// number of this disk 2 bytes
-// number of the disk with the
-// start of the central directory 2 bytes
-// total number of entries in the
-// central directory on this disk 2 bytes
-// total number of entries in
-// the central directory 2 bytes
-// size of the central directory 4 bytes
-// offset of start of central
-// directory with respect to
-// the starting disk number 4 bytes
-// .ZIP file comment length 2 bytes
-// .ZIP file comment (variable size)
-//
-// date and time are packed values, as MSDOS did them
-// time: bits 0-4 : seconds (divided by 2)
-// 5-10: minute
-// 11-15: hour
-// date bits 0-4 : day
-// 5-8: month
-// 9-15 year (since 1980)
-//
-// see http://msdn.microsoft.com/en-us/library/ms724274(VS.85).aspx
-
diff --git a/EPPlus/Packaging/DotNetZip/ZipFile.x-IEnumerable.cs b/EPPlus/Packaging/DotNetZip/ZipFile.x-IEnumerable.cs
deleted file mode 100644
index bb607b1..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipFile.x-IEnumerable.cs
+++ /dev/null
@@ -1,154 +0,0 @@
-// ZipFile.x-IEnumerable.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2006, 2007, 2008, 2009 Dino Chiesa and Microsoft Corporation.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2009-December-26 15:13:26>
-//
-// ------------------------------------------------------------------
-//
-// This module defines smoe methods for IEnumerable support. It is
-// particularly important for COM to have these things in a separate module.
-//
-// ------------------------------------------------------------------
-
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
-
- // For some weird reason, the method with the DispId(-4) attribute, which is used as
- // the _NewEnum() method, and which is required to get enumeration to work from COM
- // environments like VBScript and Javascript (etc) must be the LAST MEMBER in the
- // source. In the event of Partial classes, it needs to be the last member defined
- // in the last source module. The source modules are ordered alphabetically by
- // filename. Not sure why this is true. In any case, we put the enumeration stuff
- // here in this oddly-named module, for this reason.
- //
-
-
-
- internal partial class ZipFile
- {
-
-
-
-
- /// <summary>
- /// Generic IEnumerator support, for use of a ZipFile in an enumeration.
- /// </summary>
- ///
- /// <remarks>
- /// You probably do not want to call <c>GetEnumerator</c> explicitly. Instead
- /// it is implicitly called when you use a <see langword="foreach"/> loop in C#, or a
- /// <c>For Each</c> loop in VB.NET.
- /// </remarks>
- ///
- /// <example>
- /// This example reads a zipfile of a given name, then enumerates the
- /// entries in that zip file, and displays the information about each
- /// entry on the Console.
- /// <code>
- /// using (ZipFile zip = ZipFile.Read(zipfile))
- /// {
- /// bool header = true;
- /// foreach (ZipEntry e in zip)
- /// {
- /// if (header)
- /// {
- /// System.Console.WriteLine("Zipfile: {0}", zip.Name);
- /// System.Console.WriteLine("Version Needed: 0x{0:X2}", e.VersionNeeded);
- /// System.Console.WriteLine("BitField: 0x{0:X2}", e.BitField);
- /// System.Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod);
- /// System.Console.WriteLine("\n{1,-22} {2,-6} {3,4} {4,-8} {0}",
- /// "Filename", "Modified", "Size", "Ratio", "Packed");
- /// System.Console.WriteLine(new System.String('-', 72));
- /// header = false;
- /// }
- ///
- /// System.Console.WriteLine("{1,-22} {2,-6} {3,4:F0}% {4,-8} {0}",
- /// e.FileName,
- /// e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"),
- /// e.UncompressedSize,
- /// e.CompressionRatio,
- /// e.CompressedSize);
- ///
- /// e.Extract();
- /// }
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Dim ZipFileToExtract As String = "c:\foo.zip"
- /// Using zip As ZipFile = ZipFile.Read(ZipFileToExtract)
- /// Dim header As Boolean = True
- /// Dim e As ZipEntry
- /// For Each e In zip
- /// If header Then
- /// Console.WriteLine("Zipfile: {0}", zip.Name)
- /// Console.WriteLine("Version Needed: 0x{0:X2}", e.VersionNeeded)
- /// Console.WriteLine("BitField: 0x{0:X2}", e.BitField)
- /// Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod)
- /// Console.WriteLine(ChrW(10) & "{1,-22} {2,-6} {3,4} {4,-8} {0}", _
- /// "Filename", "Modified", "Size", "Ratio", "Packed" )
- /// Console.WriteLine(New String("-"c, 72))
- /// header = False
- /// End If
- /// Console.WriteLine("{1,-22} {2,-6} {3,4:F0}% {4,-8} {0}", _
- /// e.FileName, _
- /// e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), _
- /// e.UncompressedSize, _
- /// e.CompressionRatio, _
- /// e.CompressedSize )
- /// e.Extract
- /// Next
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <returns>A generic enumerator suitable for use within a foreach loop.</returns>
- public System.Collections.Generic.IEnumerator<ZipEntry> GetEnumerator()
- {
- foreach (ZipEntry e in _entries.Values)
- yield return e;
- }
-
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
-
- /// <summary>
- /// An IEnumerator, for use of a ZipFile in a foreach construct.
- /// </summary>
- ///
- /// <remarks>
- /// This method is included for COM support. An application generally does not call
- /// this method directly. It is called implicitly by COM clients when enumerating
- /// the entries in the ZipFile instance. In VBScript, this is done with a <c>For Each</c>
- /// statement. In Javascript, this is done with <c>new Enumerator(zipfile)</c>.
- /// </remarks>
- ///
- /// <returns>
- /// The IEnumerator over the entries in the ZipFile.
- /// </returns>
- [System.Runtime.InteropServices.DispId(-4)]
- public System.Collections.IEnumerator GetNewEnum() // the name of this method is not significant
- {
- return GetEnumerator();
- }
-
- }
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipInputStream.cs b/EPPlus/Packaging/DotNetZip/ZipInputStream.cs
deleted file mode 100644
index 30d15ad..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipInputStream.cs
+++ /dev/null
@@ -1,829 +0,0 @@
-// ZipInputStream.cs
-//
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009-2010 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-July-31 14:48:30>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the ZipInputStream class, which is a stream metaphor for
-// reading zip files. This class does not depend on Ionic.Zip.ZipFile, but rather
-// stands alongside it as an alternative "container" for ZipEntry, when reading zips.
-//
-// It adds one interesting method to the normal "stream" interface: GetNextEntry.
-//
-// ------------------------------------------------------------------
-//
-
-using System;
-using System.Threading;
-using System.Collections.Generic;
-using System.IO;
-using Ionic.Zip;
-using OfficeOpenXml.Packaging.Ionic.Zip;
-using OfficeOpenXml.Packaging.Ionic.Crc;
-
-namespace Ionic.Zip
-{
- /// <summary>
- /// Provides a stream metaphor for reading zip files.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This class provides an alternative programming model for reading zip files to
- /// the one enabled by the <see cref="ZipFile"/> class. Use this when reading zip
- /// files, as an alternative to the <see cref="ZipFile"/> class, when you would
- /// like to use a Stream class to read the file.
- /// </para>
- ///
- /// <para>
- /// Some application designs require a readable stream for input. This stream can
- /// be used to read a zip file, and extract entries.
- /// </para>
- ///
- /// <para>
- /// Both the <c>ZipInputStream</c> class and the <c>ZipFile</c> class can be used
- /// to read and extract zip files. Both of them support many of the common zip
- /// features, including Unicode, different compression levels, and ZIP64. The
- /// programming models differ. For example, when extracting entries via calls to
- /// the <c>GetNextEntry()</c> and <c>Read()</c> methods on the
- /// <c>ZipInputStream</c> class, the caller is responsible for creating the file,
- /// writing the bytes into the file, setting the attributes on the file, and
- /// setting the created, last modified, and last accessed timestamps on the
- /// file. All of these things are done automatically by a call to <see
- /// cref="ZipEntry.Extract()">ZipEntry.Extract()</see>. For this reason, the
- /// <c>ZipInputStream</c> is generally recommended for when your application wants
- /// to extract the data, without storing that data into a file.
- /// </para>
- ///
- /// <para>
- /// Aside from the obvious differences in programming model, there are some
- /// differences in capability between the <c>ZipFile</c> class and the
- /// <c>ZipInputStream</c> class.
- /// </para>
- ///
- /// <list type="bullet">
- /// <item>
- /// <c>ZipFile</c> can be used to create or update zip files, or read and
- /// extract zip files. <c>ZipInputStream</c> can be used only to read and
- /// extract zip files. If you want to use a stream to create zip files, check
- /// out the <see cref="ZipOutputStream"/>.
- /// </item>
- ///
- /// <item>
- /// <c>ZipInputStream</c> cannot read segmented or spanned
- /// zip files.
- /// </item>
- ///
- /// <item>
- /// <c>ZipInputStream</c> will not read Zip file comments.
- /// </item>
- ///
- /// <item>
- /// When reading larger files, <c>ZipInputStream</c> will always underperform
- /// <c>ZipFile</c>. This is because the <c>ZipInputStream</c> does a full scan on the
- /// zip file, while the <c>ZipFile</c> class reads the central directory of the
- /// zip file.
- /// </item>
- ///
- /// </list>
- ///
- /// </remarks>
- internal class ZipInputStream : Stream
- {
- /// <summary>
- /// Create a <c>ZipInputStream</c>, wrapping it around an existing stream.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// While the <see cref="ZipFile"/> class is generally easier
- /// to use, this class provides an alternative to those
- /// applications that want to read from a zipfile directly,
- /// using a <see cref="System.IO.Stream"/>.
- /// </para>
- ///
- /// <para>
- /// Both the <c>ZipInputStream</c> class and the <c>ZipFile</c> class can be used
- /// to read and extract zip files. Both of them support many of the common zip
- /// features, including Unicode, different compression levels, and ZIP64. The
- /// programming models differ. For example, when extracting entries via calls to
- /// the <c>GetNextEntry()</c> and <c>Read()</c> methods on the
- /// <c>ZipInputStream</c> class, the caller is responsible for creating the file,
- /// writing the bytes into the file, setting the attributes on the file, and
- /// setting the created, last modified, and last accessed timestamps on the
- /// file. All of these things are done automatically by a call to <see
- /// cref="ZipEntry.Extract()">ZipEntry.Extract()</see>. For this reason, the
- /// <c>ZipInputStream</c> is generally recommended for when your application wants
- /// to extract the data, without storing that data into a file.
- /// </para>
- ///
- /// <para>
- /// Aside from the obvious differences in programming model, there are some
- /// differences in capability between the <c>ZipFile</c> class and the
- /// <c>ZipInputStream</c> class.
- /// </para>
- ///
- /// <list type="bullet">
- /// <item>
- /// <c>ZipFile</c> can be used to create or update zip files, or read and extract
- /// zip files. <c>ZipInputStream</c> can be used only to read and extract zip
- /// files. If you want to use a stream to create zip files, check out the <see
- /// cref="ZipOutputStream"/>.
- /// </item>
- ///
- /// <item>
- /// <c>ZipInputStream</c> cannot read segmented or spanned
- /// zip files.
- /// </item>
- ///
- /// <item>
- /// <c>ZipInputStream</c> will not read Zip file comments.
- /// </item>
- ///
- /// <item>
- /// When reading larger files, <c>ZipInputStream</c> will always underperform
- /// <c>ZipFile</c>. This is because the <c>ZipInputStream</c> does a full scan on the
- /// zip file, while the <c>ZipFile</c> class reads the central directory of the
- /// zip file.
- /// </item>
- ///
- /// </list>
- ///
- /// </remarks>
- ///
- /// <param name="stream">
- /// The stream to read. It must be readable. This stream will be closed at
- /// the time the <c>ZipInputStream</c> is closed.
- /// </param>
- ///
- /// <example>
- ///
- /// This example shows how to read a zip file, and extract entries, using the
- /// <c>ZipInputStream</c> class.
- ///
- /// <code lang="C#">
- /// private void Unzip()
- /// {
- /// byte[] buffer= new byte[2048];
- /// int n;
- /// using (var raw = File.Open(inputFileName, FileMode.Open, FileAccess.Read))
- /// {
- /// using (var input= new ZipInputStream(raw))
- /// {
- /// ZipEntry e;
- /// while (( e = input.GetNextEntry()) != null)
- /// {
- /// if (e.IsDirectory) continue;
- /// string outputPath = Path.Combine(extractDir, e.FileName);
- /// using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite))
- /// {
- /// while ((n= input.Read(buffer, 0, buffer.Length)) > 0)
- /// {
- /// output.Write(buffer,0,n);
- /// }
- /// }
- /// }
- /// }
- /// }
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Private Sub UnZip()
- /// Dim inputFileName As String = "MyArchive.zip"
- /// Dim extractDir As String = "extract"
- /// Dim buffer As Byte() = New Byte(2048) {}
- /// Using raw As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read)
- /// Using input As ZipInputStream = New ZipInputStream(raw)
- /// Dim e As ZipEntry
- /// Do While (Not e = input.GetNextEntry Is Nothing)
- /// If Not e.IsDirectory Then
- /// Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _
- /// FileMode.Create, FileAccess.ReadWrite)
- /// Dim n As Integer
- /// Do While (n = input.Read(buffer, 0, buffer.Length) > 0)
- /// output.Write(buffer, 0, n)
- /// Loop
- /// End Using
- /// End If
- /// Loop
- /// End Using
- /// End Using
- /// End Sub
- /// </code>
- /// </example>
- public ZipInputStream(Stream stream) : this (stream, false) { }
-
-
-
- /// <summary>
- /// Create a <c>ZipInputStream</c>, given the name of an existing zip file.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This constructor opens a <c>FileStream</c> for the given zipfile, and
- /// wraps a <c>ZipInputStream</c> around that. See the documentation for the
- /// <see cref="ZipInputStream(Stream)"/> constructor for full details.
- /// </para>
- ///
- /// <para>
- /// While the <see cref="ZipFile"/> class is generally easier
- /// to use, this class provides an alternative to those
- /// applications that want to read from a zipfile directly,
- /// using a <see cref="System.IO.Stream"/>.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="fileName">
- /// The name of the filesystem file to read.
- /// </param>
- ///
- /// <example>
- ///
- /// This example shows how to read a zip file, and extract entries, using the
- /// <c>ZipInputStream</c> class.
- ///
- /// <code lang="C#">
- /// private void Unzip()
- /// {
- /// byte[] buffer= new byte[2048];
- /// int n;
- /// using (var input= new ZipInputStream(inputFileName))
- /// {
- /// ZipEntry e;
- /// while (( e = input.GetNextEntry()) != null)
- /// {
- /// if (e.IsDirectory) continue;
- /// string outputPath = Path.Combine(extractDir, e.FileName);
- /// using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite))
- /// {
- /// while ((n= input.Read(buffer, 0, buffer.Length)) > 0)
- /// {
- /// output.Write(buffer,0,n);
- /// }
- /// }
- /// }
- /// }
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Private Sub UnZip()
- /// Dim inputFileName As String = "MyArchive.zip"
- /// Dim extractDir As String = "extract"
- /// Dim buffer As Byte() = New Byte(2048) {}
- /// Using input As ZipInputStream = New ZipInputStream(inputFileName)
- /// Dim e As ZipEntry
- /// Do While (Not e = input.GetNextEntry Is Nothing)
- /// If Not e.IsDirectory Then
- /// Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _
- /// FileMode.Create, FileAccess.ReadWrite)
- /// Dim n As Integer
- /// Do While (n = input.Read(buffer, 0, buffer.Length) > 0)
- /// output.Write(buffer, 0, n)
- /// Loop
- /// End Using
- /// End If
- /// Loop
- /// End Using
- /// End Sub
- /// </code>
- /// </example>
- public ZipInputStream(String fileName)
- {
- Stream stream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read );
- _Init(stream, false, fileName);
- }
-
-
- /// <summary>
- /// Create a <c>ZipInputStream</c>, explicitly specifying whether to
- /// keep the underlying stream open.
- /// </summary>
- ///
- /// <remarks>
- /// See the documentation for the <see
- /// cref="ZipInputStream(Stream)">ZipInputStream(Stream)</see>
- /// constructor for a discussion of the class, and an example of how to use the class.
- /// </remarks>
- ///
- /// <param name="stream">
- /// The stream to read from. It must be readable.
- /// </param>
- ///
- /// <param name="leaveOpen">
- /// true if the application would like the stream
- /// to remain open after the <c>ZipInputStream</c> has been closed.
- /// </param>
- public ZipInputStream(Stream stream, bool leaveOpen)
- {
- _Init(stream, leaveOpen, null);
- }
-
- private void _Init(Stream stream, bool leaveOpen, string name)
- {
- _inputStream = stream;
- if (!_inputStream.CanRead)
- throw new ZipException("The stream must be readable.");
- _container= new ZipContainer(this);
- _provisionalAlternateEncoding = System.Text.Encoding.ASCII;
- _leaveUnderlyingStreamOpen = leaveOpen;
- _findRequired= true;
- _name = name ?? "(stream)";
- }
-
-
- /// <summary>Provides a string representation of the instance.</summary>
- /// <remarks>
- /// <para>
- /// This can be useful for debugging purposes.
- /// </para>
- /// </remarks>
- /// <returns>a string representation of the instance.</returns>
- public override String ToString()
- {
- return String.Format ("ZipInputStream::{0}(leaveOpen({1})))", _name, _leaveUnderlyingStreamOpen);
- }
-
-
- /// <summary>
- /// The text encoding to use when reading entries into the zip archive, for
- /// those entries whose filenames or comments cannot be encoded with the
- /// default (IBM437) encoding.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// In <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">its
- /// zip specification</see>, PKWare describes two options for encoding
- /// filenames and comments: using IBM437 or UTF-8. But, some archiving tools
- /// or libraries do not follow the specification, and instead encode
- /// characters using the system default code page. For example, WinRAR when
- /// run on a machine in Shanghai may encode filenames with the Big-5 Chinese
- /// (950) code page. This behavior is contrary to the Zip specification, but
- /// it occurs anyway.
- /// </para>
- ///
- /// <para>
- /// When using DotNetZip to read zip archives that use something other than
- /// UTF-8 or IBM437, set this property to specify the code page to use when
- /// reading encoded filenames and comments for each <c>ZipEntry</c> in the zip
- /// file.
- /// </para>
- ///
- /// <para>
- /// This property is "provisional". When the entry in the zip archive is not
- /// explicitly marked as using UTF-8, then IBM437 is used to decode filenames
- /// and comments. If a loss of data would result from using IBM436 -
- /// specifically when encoding and decoding is not reflexive - the codepage
- /// specified here is used. It is possible, therefore, to have a given entry
- /// with a <c>Comment</c> encoded in IBM437 and a <c>FileName</c> encoded with
- /// the specified "provisional" codepage.
- /// </para>
- ///
- /// <para>
- /// When a zip file uses an arbitrary, non-UTF8 code page for encoding, there
- /// is no standard way for the reader application - whether DotNetZip, WinZip,
- /// WinRar, or something else - to know which codepage has been used for the
- /// entries. Readers of zip files are not able to inspect the zip file and
- /// determine the codepage that was used for the entries contained within it.
- /// It is left to the application or user to determine the necessary codepage
- /// when reading zip files encoded this way. If you use an incorrect codepage
- /// when reading a zipfile, you will get entries with filenames that are
- /// incorrect, and the incorrect filenames may even contain characters that
- /// are not legal for use within filenames in Windows. Extracting entries with
- /// illegal characters in the filenames will lead to exceptions. It's too bad,
- /// but this is just the way things are with code pages in zip files. Caveat
- /// Emptor.
- /// </para>
- ///
- /// </remarks>
- public System.Text.Encoding ProvisionalAlternateEncoding
- {
- get
- {
- return _provisionalAlternateEncoding;
- }
- set
- {
- _provisionalAlternateEncoding = value;
- }
- }
-
-
- /// <summary>
- /// Size of the work buffer to use for the ZLIB codec during decompression.
- /// </summary>
- ///
- /// <remarks>
- /// Setting this affects the performance and memory efficiency of compression
- /// and decompression. For larger files, setting this to a larger size may
- /// improve performance, but the exact numbers vary depending on available
- /// memory, and a bunch of other variables. I don't have good firm
- /// recommendations on how to set it. You'll have to test it yourself. Or
- /// just leave it alone and accept the default.
- /// </remarks>
- public int CodecBufferSize
- {
- get;
- set;
- }
-
-
- /// <summary>
- /// Sets the password to be used on the <c>ZipInputStream</c> instance.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// When reading a zip archive, this password is used to read and decrypt the
- /// entries that are encrypted within the zip file. When entries within a zip
- /// file use different passwords, set the appropriate password for the entry
- /// before the first call to <c>Read()</c> for each entry.
- /// </para>
- ///
- /// <para>
- /// When reading an entry that is not encrypted, the value of this property is
- /// ignored.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example uses the ZipInputStream to read and extract entries from a
- /// zip file, using a potentially different password for each entry.
- ///
- /// <code lang="C#">
- /// byte[] buffer= new byte[2048];
- /// int n;
- /// using (var raw = File.Open(_inputFileName, FileMode.Open, FileAccess.Read ))
- /// {
- /// using (var input= new ZipInputStream(raw))
- /// {
- /// ZipEntry e;
- /// while (( e = input.GetNextEntry()) != null)
- /// {
- /// input.Password = PasswordForEntry(e.FileName);
- /// if (e.IsDirectory) continue;
- /// string outputPath = Path.Combine(_extractDir, e.FileName);
- /// using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite))
- /// {
- /// while ((n= input.Read(buffer,0,buffer.Length)) > 0)
- /// {
- /// output.Write(buffer,0,n);
- /// }
- /// }
- /// }
- /// }
- /// }
- ///
- /// </code>
- /// </example>
- public String Password
- {
- set
- {
- if (_closed)
- {
- _exceptionPending = true;
- throw new System.InvalidOperationException("The stream has been closed.");
- }
- _Password = value;
- }
- }
-
-
- private void SetupStream()
- {
- // Seek to the correct posn in the file, and open a
- // stream that can be read.
- _crcStream= _currentEntry.InternalOpenReader(_Password);
- _LeftToRead = _crcStream.Length;
- _needSetup = false;
- }
-
-
-
- internal Stream ReadStream
- {
- get
- {
- return _inputStream;
- }
- }
-
-
- /// <summary>
- /// Read the data from the stream into the buffer.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The data for the zipentry will be decrypted and uncompressed, as
- /// necessary, before being copied into the buffer.
- /// </para>
- ///
- /// <para>
- /// You must set the <see cref="Password"/> property before calling
- /// <c>Read()</c> the first time for an encrypted entry. To determine if an
- /// entry is encrypted and requires a password, check the <see
- /// cref="ZipEntry.Encryption">ZipEntry.Encryption</see> property.
- /// </para>
- /// </remarks>
- ///
- /// <param name="buffer">The buffer to hold the data read from the stream.</param>
- /// <param name="offset">the offset within the buffer to copy the first byte read.</param>
- /// <param name="count">the number of bytes to read.</param>
- /// <returns>the number of bytes read, after decryption and decompression.</returns>
- public override int Read(byte[] buffer, int offset, int count)
- {
- if (_closed)
- {
- _exceptionPending = true;
- throw new System.InvalidOperationException("The stream has been closed.");
- }
-
- if (_needSetup)
- SetupStream();
-
- if (_LeftToRead == 0) return 0;
-
- int len = (_LeftToRead > count) ? count : (int)_LeftToRead;
- int n = _crcStream.Read(buffer, offset, len);
-
- _LeftToRead -= n;
-
- if (_LeftToRead == 0)
- {
- int CrcResult = _crcStream.Crc;
- _currentEntry.VerifyCrcAfterExtract(CrcResult);
- _inputStream.Seek(_endOfEntry, SeekOrigin.Begin);
- // workitem 10178
- SharedUtilities.Workaround_Ladybug318918(_inputStream);
- }
-
- return n;
- }
-
-
-
- /// <summary>
- /// Read the next entry from the zip file.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Call this method just before calling <see cref="Read(byte[], int, int)"/>,
- /// to position the pointer in the zip file to the next entry that can be
- /// read. Subsequent calls to <c>Read()</c>, will decrypt and decompress the
- /// data in the zip file, until <c>Read()</c> returns 0.
- /// </para>
- ///
- /// <para>
- /// Each time you call <c>GetNextEntry()</c>, the pointer in the wrapped
- /// stream is moved to the next entry in the zip file. If you call <see
- /// cref="Seek(long, SeekOrigin)"/>, and thus re-position the pointer within
- /// the file, you will need to call <c>GetNextEntry()</c> again, to insure
- /// that the file pointer is positioned at the beginning of a zip entry.
- /// </para>
- ///
- /// <para>
- /// This method returns the <c>ZipEntry</c>. Using a stream approach, you will
- /// read the raw bytes for an entry in a zip file via calls to <c>Read()</c>.
- /// Alternatively, you can extract an entry into a file, or a stream, by
- /// calling <see cref="ZipEntry.Extract()"/>, or one of its siblings.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <returns>
- /// The <c>ZipEntry</c> read. Returns null (or Nothing in VB) if there are no more
- /// entries in the zip file.
- /// </returns>
- ///
- public ZipEntry GetNextEntry()
- {
- if (_findRequired)
- {
- // find the next signature
- long d = SharedUtilities.FindSignature(_inputStream, ZipConstants.ZipEntrySignature);
- if (d == -1) return null;
- // back up 4 bytes: ReadEntry assumes the file pointer is positioned before the entry signature
- _inputStream.Seek(-4, SeekOrigin.Current);
- // workitem 10178
- SharedUtilities.Workaround_Ladybug318918(_inputStream);
- }
- // workitem 10923
- else if (_firstEntry)
- {
- // we've already read one entry.
- // Seek to the end of it.
- _inputStream.Seek(_endOfEntry, SeekOrigin.Begin);
- SharedUtilities.Workaround_Ladybug318918(_inputStream);
- }
-
- _currentEntry = ZipEntry.ReadEntry(_container, !_firstEntry);
- // ReadEntry leaves the file position after all the entry
- // data and the optional bit-3 data descriptpr. This is
- // where the next entry would normally start.
- _endOfEntry = _inputStream.Position;
- _firstEntry = true;
- _needSetup = true;
- _findRequired= false;
- return _currentEntry;
- }
-
-
- /// <summary>
- /// Dispose the stream.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method disposes the ZipInputStream. It may also close the
- /// underlying stream, depending on which constructor was used.
- /// </para>
- ///
- /// <para>
- /// Typically the application will call <c>Dispose()</c> implicitly, via
- /// a <c>using</c> statement in C#, or a <c>Using</c> statement in VB.
- /// </para>
- ///
- /// <para>
- /// Application code won't call this code directly. This method may
- /// be invoked in two distinct scenarios. If disposing == true, the
- /// method has been called directly or indirectly by a user's code,
- /// for example via the public Dispose() method. In this case, both
- /// managed and unmanaged resources can be referenced and disposed.
- /// If disposing == false, the method has been called by the runtime
- /// from inside the object finalizer and this method should not
- /// reference other objects; in that case only unmanaged resources
- /// must be referenced or disposed.
- /// </para>
- /// </remarks>
- ///
- /// <param name="disposing">
- /// true if the Dispose method was invoked by user code.
- /// </param>
- protected override void Dispose(bool disposing)
- {
- if (_closed) return;
-
- if (disposing) // not called from finalizer
- {
- // When ZipInputStream is used within a using clause, and an
- // exception is thrown, Close() is invoked. But we don't want to
- // try to write anything in that case. Eventually the exception
- // will be propagated to the application.
- if (_exceptionPending) return;
-
- if (!_leaveUnderlyingStreamOpen)
- {
-#if NETCF
- _inputStream.Close();
-#else
- _inputStream.Dispose();
-#endif
- }
- }
- _closed= true;
- }
-
-
- /// <summary>
- /// Always returns true.
- /// </summary>
- public override bool CanRead { get { return true; }}
-
- /// <summary>
- /// Returns the value of <c>CanSeek</c> for the underlying (wrapped) stream.
- /// </summary>
- public override bool CanSeek { get { return _inputStream.CanSeek; } }
-
- /// <summary>
- /// Always returns false.
- /// </summary>
- public override bool CanWrite { get { return false; } }
-
- /// <summary>
- /// Returns the length of the underlying stream.
- /// </summary>
- public override long Length { get { return _inputStream.Length; }}
-
- /// <summary>
- /// Gets or sets the position of the underlying stream.
- /// </summary>
- /// <remarks>
- /// Setting the position is equivalent to calling <c>Seek(value, SeekOrigin.Begin)</c>.
- /// </remarks>
- public override long Position
- {
- get { return _inputStream.Position;}
- set { Seek(value, SeekOrigin.Begin); }
- }
-
- /// <summary>
- /// This is a no-op.
- /// </summary>
- public override void Flush()
- {
- throw new NotSupportedException("Flush");
- }
-
-
- /// <summary>
- /// This method always throws a NotSupportedException.
- /// </summary>
- /// <param name="buffer">ignored</param>
- /// <param name="offset">ignored</param>
- /// <param name="count">ignored</param>
- public override void Write(byte[] buffer, int offset, int count)
- {
- throw new NotSupportedException("Write");
- }
-
-
- /// <summary>
- /// This method seeks in the underlying stream.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Call this method if you want to seek around within the zip file for random access.
- /// </para>
- ///
- /// <para>
- /// Applications can intermix calls to <c>Seek()</c> with calls to <see
- /// cref="GetNextEntry()"/>. After a call to <c>Seek()</c>,
- /// <c>GetNextEntry()</c> will get the next <c>ZipEntry</c> that falls after
- /// the current position in the input stream. You're on your own for finding
- /// out just where to seek in the stream, to get to the various entries.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="offset">the offset point to seek to</param>
- /// <param name="origin">the reference point from which to seek</param>
- /// <returns>The new position</returns>
- public override long Seek(long offset, SeekOrigin origin)
- {
- _findRequired= true;
- var x = _inputStream.Seek(offset, origin);
- // workitem 10178
- SharedUtilities.Workaround_Ladybug318918(_inputStream);
- return x;
- }
-
- /// <summary>
- /// This method always throws a NotSupportedException.
- /// </summary>
- /// <param name="value">ignored</param>
- public override void SetLength(long value)
- {
- throw new NotSupportedException();
- }
-
-
- private Stream _inputStream;
- private System.Text.Encoding _provisionalAlternateEncoding;
- private ZipEntry _currentEntry;
- private bool _firstEntry;
- private bool _needSetup;
- private ZipContainer _container;
- private CrcCalculatorStream _crcStream;
- private Int64 _LeftToRead;
- internal String _Password;
- private Int64 _endOfEntry;
- private string _name;
-
- private bool _leaveUnderlyingStreamOpen;
- private bool _closed;
- private bool _findRequired;
- private bool _exceptionPending;
- }
-
-
-
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipOutputStream.cs b/EPPlus/Packaging/DotNetZip/ZipOutputStream.cs
deleted file mode 100644
index 6ad801a..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipOutputStream.cs
+++ /dev/null
@@ -1,1818 +0,0 @@
-// ZipOutputStream.cs
-//
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-July-28 06:34:30>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the ZipOutputStream class, which is a stream metaphor for
-// generating zip files. This class does not depend on Ionic.Zip.ZipFile, but rather
-// stands alongside it as an alternative "container" for ZipEntry. It replicates a
-// subset of the properties, including these:
-//
-// - Comment
-// - Encryption
-// - Password
-// - CodecBufferSize
-// - CompressionLevel
-// - CompressionMethod
-// - EnableZip64 (UseZip64WhenSaving)
-// - IgnoreCase (!CaseSensitiveRetrieval)
-//
-// It adds these novel methods:
-//
-// - PutNextEntry
-//
-//
-// ------------------------------------------------------------------
-//
-
-using System;
-using System.Threading;
-using System.Collections.Generic;
-using System.IO;
-using Ionic.Zip;
-using OfficeOpenXml.Packaging.Ionic.Zlib;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- /// <summary>
- /// Provides a stream metaphor for generating zip files.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This class writes zip files, as defined in the <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">specification
- /// for zip files described by PKWare</see>. The compression for this
- /// implementation is provided by a managed-code version of Zlib, included with
- /// DotNetZip in the classes in the Ionic.Zlib namespace.
- /// </para>
- ///
- /// <para>
- /// This class provides an alternative programming model to the one enabled by the
- /// <see cref="ZipFile"/> class. Use this when creating zip files, as an
- /// alternative to the <see cref="ZipFile"/> class, when you would like to use a
- /// <c>Stream</c> type to write the zip file.
- /// </para>
- ///
- /// <para>
- /// Both the <c>ZipOutputStream</c> class and the <c>ZipFile</c> class can be used
- /// to create zip files. Both of them support many of the common zip features,
- /// including Unicode, different compression levels, and ZIP64. They provide
- /// very similar performance when creating zip files.
- /// </para>
- ///
- /// <para>
- /// The <c>ZipFile</c> class is generally easier to use than
- /// <c>ZipOutputStream</c> and should be considered a higher-level interface. For
- /// example, when creating a zip file via calls to the <c>PutNextEntry()</c> and
- /// <c>Write()</c> methods on the <c>ZipOutputStream</c> class, the caller is
- /// responsible for opening the file, reading the bytes from the file, writing
- /// those bytes into the <c>ZipOutputStream</c>, setting the attributes on the
- /// <c>ZipEntry</c>, and setting the created, last modified, and last accessed
- /// timestamps on the zip entry. All of these things are done automatically by a
- /// call to <see cref="ZipFile.AddFile(string,string)">ZipFile.AddFile()</see>.
- /// For this reason, the <c>ZipOutputStream</c> is generally recommended for use
- /// only when your application emits arbitrary data, not necessarily data from a
- /// filesystem file, directly into a zip file, and does so using a <c>Stream</c>
- /// metaphor.
- /// </para>
- ///
- /// <para>
- /// Aside from the differences in programming model, there are other
- /// differences in capability between the two classes.
- /// </para>
- ///
- /// <list type="bullet">
- /// <item>
- /// <c>ZipFile</c> can be used to read and extract zip files, in addition to
- /// creating zip files. <c>ZipOutputStream</c> cannot read zip files. If you want
- /// to use a stream to read zip files, check out the <see cref="ZipInputStream"/> class.
- /// </item>
- ///
- /// <item>
- /// <c>ZipOutputStream</c> does not support the creation of segmented or spanned
- /// zip files.
- /// </item>
- ///
- /// <item>
- /// <c>ZipOutputStream</c> cannot produce a self-extracting archive.
- /// </item>
- /// </list>
- ///
- /// <para>
- /// Be aware that the <c>ZipOutputStream</c> class implements the <see
- /// cref="System.IDisposable"/> interface. In order for
- /// <c>ZipOutputStream</c> to produce a valid zip file, you use use it within
- /// a using clause (<c>Using</c> in VB), or call the <c>Dispose()</c> method
- /// explicitly. See the examples for how to employ a using clause.
- /// </para>
- ///
- /// <para>
- /// Also, a note regarding compression performance: On the desktop .NET
- /// Framework, DotNetZip can use a multi-threaded compression implementation
- /// that provides significant speed increases on large files, over 300k or so,
- /// at the cost of increased memory use at runtime. (The output of the
- /// compression is almost exactly the same size). But, the multi-threaded
- /// approach incurs a performance hit on smaller files. There's no way for the
- /// ZipOutputStream to know whether parallel compression will be beneficial,
- /// because the ZipOutputStream does not know how much data you will write
- /// through the stream. You may wish to set the <see
- /// cref="ParallelDeflateThreshold"/> property to zero, if you are compressing
- /// large files through <c>ZipOutputStream</c>. This will cause parallel
- /// compression to be used, always.
- /// </para>
- /// </remarks>
- internal class ZipOutputStream : Stream
- {
- /// <summary>
- /// Create a ZipOutputStream, wrapping an existing stream.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The <see cref="ZipFile"/> class is generally easier to use when creating
- /// zip files. The ZipOutputStream offers a different metaphor for creating a
- /// zip file, based on the <see cref="System.IO.Stream"/> class.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="stream">
- /// The stream to wrap. It must be writable. This stream will be closed at
- /// the time the ZipOutputStream is closed.
- /// </param>
- ///
- /// <example>
- ///
- /// This example shows how to create a zip file, using the
- /// ZipOutputStream class.
- ///
- /// <code lang="C#">
- /// private void Zipup()
- /// {
- /// if (filesToZip.Count == 0)
- /// {
- /// System.Console.WriteLine("Nothing to do.");
- /// return;
- /// }
- ///
- /// using (var raw = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite ))
- /// {
- /// using (var output= new ZipOutputStream(raw))
- /// {
- /// output.Password = "VerySecret!";
- /// output.Encryption = EncryptionAlgorithm.WinZipAes256;
- ///
- /// foreach (string inputFileName in filesToZip)
- /// {
- /// System.Console.WriteLine("file: {0}", inputFileName);
- ///
- /// output.PutNextEntry(inputFileName);
- /// using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Write ))
- /// {
- /// byte[] buffer= new byte[2048];
- /// int n;
- /// while ((n= input.Read(buffer,0,buffer.Length)) > 0)
- /// {
- /// output.Write(buffer,0,n);
- /// }
- /// }
- /// }
- /// }
- /// }
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Private Sub Zipup()
- /// Dim outputFileName As String = "XmlData.zip"
- /// Dim filesToZip As String() = Directory.GetFiles(".", "*.xml")
- /// If (filesToZip.Length = 0) Then
- /// Console.WriteLine("Nothing to do.")
- /// Else
- /// Using raw As FileStream = File.Open(outputFileName, FileMode.Create, FileAccess.ReadWrite)
- /// Using output As ZipOutputStream = New ZipOutputStream(raw)
- /// output.Password = "VerySecret!"
- /// output.Encryption = EncryptionAlgorithm.WinZipAes256
- /// Dim inputFileName As String
- /// For Each inputFileName In filesToZip
- /// Console.WriteLine("file: {0}", inputFileName)
- /// output.PutNextEntry(inputFileName)
- /// Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
- /// Dim n As Integer
- /// Dim buffer As Byte() = New Byte(2048) {}
- /// Do While (n = input.Read(buffer, 0, buffer.Length) > 0)
- /// output.Write(buffer, 0, n)
- /// Loop
- /// End Using
- /// Next
- /// End Using
- /// End Using
- /// End If
- /// End Sub
- /// </code>
- /// </example>
- public ZipOutputStream(Stream stream) : this(stream, false) { }
-
-
- /// <summary>
- /// Create a ZipOutputStream that writes to a filesystem file.
- /// </summary>
- ///
- /// <remarks>
- /// The <see cref="ZipFile"/> class is generally easier to use when creating
- /// zip files. The ZipOutputStream offers a different metaphor for creating a
- /// zip file, based on the <see cref="System.IO.Stream"/> class.
- /// </remarks>
- ///
- /// <param name="fileName">
- /// The name of the zip file to create.
- /// </param>
- ///
- /// <example>
- ///
- /// This example shows how to create a zip file, using the
- /// ZipOutputStream class.
- ///
- /// <code lang="C#">
- /// private void Zipup()
- /// {
- /// if (filesToZip.Count == 0)
- /// {
- /// System.Console.WriteLine("Nothing to do.");
- /// return;
- /// }
- ///
- /// using (var output= new ZipOutputStream(outputFileName))
- /// {
- /// output.Password = "VerySecret!";
- /// output.Encryption = EncryptionAlgorithm.WinZipAes256;
- ///
- /// foreach (string inputFileName in filesToZip)
- /// {
- /// System.Console.WriteLine("file: {0}", inputFileName);
- ///
- /// output.PutNextEntry(inputFileName);
- /// using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read,
- /// FileShare.Read | FileShare.Write ))
- /// {
- /// byte[] buffer= new byte[2048];
- /// int n;
- /// while ((n= input.Read(buffer,0,buffer.Length)) > 0)
- /// {
- /// output.Write(buffer,0,n);
- /// }
- /// }
- /// }
- /// }
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Private Sub Zipup()
- /// Dim outputFileName As String = "XmlData.zip"
- /// Dim filesToZip As String() = Directory.GetFiles(".", "*.xml")
- /// If (filesToZip.Length = 0) Then
- /// Console.WriteLine("Nothing to do.")
- /// Else
- /// Using output As ZipOutputStream = New ZipOutputStream(outputFileName)
- /// output.Password = "VerySecret!"
- /// output.Encryption = EncryptionAlgorithm.WinZipAes256
- /// Dim inputFileName As String
- /// For Each inputFileName In filesToZip
- /// Console.WriteLine("file: {0}", inputFileName)
- /// output.PutNextEntry(inputFileName)
- /// Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
- /// Dim n As Integer
- /// Dim buffer As Byte() = New Byte(2048) {}
- /// Do While (n = input.Read(buffer, 0, buffer.Length) > 0)
- /// output.Write(buffer, 0, n)
- /// Loop
- /// End Using
- /// Next
- /// End Using
- /// End If
- /// End Sub
- /// </code>
- /// </example>
- public ZipOutputStream(String fileName)
- {
- Stream stream = File.Open(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
- _Init(stream, false, fileName);
- }
-
-
- /// <summary>
- /// Create a ZipOutputStream.
- /// </summary>
- ///
- /// <remarks>
- /// See the documentation for the <see
- /// cref="ZipOutputStream(Stream)">ZipOutputStream(Stream)</see>
- /// constructor for an example.
- /// </remarks>
- ///
- /// <param name="stream">
- /// The stream to wrap. It must be writable.
- /// </param>
- ///
- /// <param name="leaveOpen">
- /// true if the application would like the stream
- /// to remain open after the <c>ZipOutputStream</c> has been closed.
- /// </param>
- public ZipOutputStream(Stream stream, bool leaveOpen)
- {
- _Init(stream, leaveOpen, null);
- }
-
- private void _Init(Stream stream, bool leaveOpen, string name)
- {
- // workitem 9307
- _outputStream = stream.CanRead ? stream : new CountingStream(stream);
- CompressionLevel = OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel.Default;
- CompressionMethod = OfficeOpenXml.Packaging.Ionic.Zip.CompressionMethod.Deflate;
- _encryption = EncryptionAlgorithm.None;
- _entriesWritten = new Dictionary<String, ZipEntry>(StringComparer.Ordinal);
- _zip64 = Zip64Option.Never;
- _leaveUnderlyingStreamOpen = leaveOpen;
- Strategy = Ionic.Zlib.CompressionStrategy.Default;
- _name = name ?? "(stream)";
-#if !NETCF
- ParallelDeflateThreshold = -1L;
-#endif
- }
-
-
- /// <summary>Provides a string representation of the instance.</summary>
- /// <remarks>
- /// <para>
- /// This can be useful for debugging purposes.
- /// </para>
- /// </remarks>
- /// <returns>a string representation of the instance.</returns>
- public override String ToString()
- {
- return String.Format ("ZipOutputStream::{0}(leaveOpen({1})))", _name, _leaveUnderlyingStreamOpen);
- }
-
-
- /// <summary>
- /// Sets the password to be used on the <c>ZipOutputStream</c> instance.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// When writing a zip archive, this password is applied to the entries, not
- /// to the zip archive itself. It applies to any <c>ZipEntry</c> subsequently
- /// written to the <c>ZipOutputStream</c>.
- /// </para>
- ///
- /// <para>
- /// Using a password does not encrypt or protect the "directory" of the
- /// archive - the list of entries contained in the archive. If you set the
- /// <c>Password</c> property, the password actually applies to individual
- /// entries that are added to the archive, subsequent to the setting of this
- /// property. The list of filenames in the archive that is eventually created
- /// will appear in clear text, but the contents of the individual files are
- /// encrypted. This is how Zip encryption works.
- /// </para>
- ///
- /// <para>
- /// If you set this property, and then add a set of entries to the archive via
- /// calls to <c>PutNextEntry</c>, then each entry is encrypted with that
- /// password. You may also want to change the password between adding
- /// different entries. If you set the password, add an entry, then set the
- /// password to <c>null</c> (<c>Nothing</c> in VB), and add another entry, the
- /// first entry is encrypted and the second is not.
- /// </para>
- ///
- /// <para>
- /// When setting the <c>Password</c>, you may also want to explicitly set the <see
- /// cref="Encryption"/> property, to specify how to encrypt the entries added
- /// to the ZipFile. If you set the <c>Password</c> to a non-null value and do not
- /// set <see cref="Encryption"/>, then PKZip 2.0 ("Weak") encryption is used.
- /// This encryption is relatively weak but is very interoperable. If
- /// you set the password to a <c>null</c> value (<c>Nothing</c> in VB),
- /// <c>Encryption</c> is reset to None.
- /// </para>
- ///
- /// <para>
- /// Special case: if you wrap a ZipOutputStream around a non-seekable stream,
- /// and use encryption, and emit an entry of zero bytes, the <c>Close()</c> or
- /// <c>PutNextEntry()</c> following the entry will throw an exception.
- /// </para>
- ///
- /// </remarks>
- public String Password
- {
- set
- {
- if (_disposed)
- {
- _exceptionPending = true;
- throw new System.InvalidOperationException("The stream has been closed.");
- }
-
- _password = value;
- if (_password == null)
- {
- _encryption = EncryptionAlgorithm.None;
- }
- else if (_encryption == EncryptionAlgorithm.None)
- {
- _encryption = EncryptionAlgorithm.PkzipWeak;
- }
- }
- }
-
-
- /// <summary>
- /// The Encryption to use for entries added to the <c>ZipOutputStream</c>.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The specified Encryption is applied to the entries subsequently
- /// written to the <c>ZipOutputStream</c> instance.
- /// </para>
- ///
- /// <para>
- /// If you set this to something other than
- /// EncryptionAlgorithm.None, you will also need to set the
- /// <see cref="Password"/> to a non-null, non-empty value in
- /// order to actually get encryption on the entry.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <seealso cref="Password">ZipOutputStream.Password</seealso>
- /// <seealso cref="ZipEntry.Encryption">ZipEntry.Encryption</seealso>
- public EncryptionAlgorithm Encryption
- {
- get
- {
- return _encryption;
- }
- set
- {
- if (_disposed)
- {
- _exceptionPending = true;
- throw new System.InvalidOperationException("The stream has been closed.");
- }
- if (value == EncryptionAlgorithm.Unsupported)
- {
- _exceptionPending = true;
- throw new InvalidOperationException("You may not set Encryption to that value.");
- }
- _encryption = value;
- }
- }
-
-
- /// <summary>
- /// Size of the work buffer to use for the ZLIB codec during compression.
- /// </summary>
- ///
- /// <remarks>
- /// Setting this may affect performance. For larger files, setting this to a
- /// larger size may improve performance, but I'm not sure. Sorry, I don't
- /// currently have good recommendations on how to set it. You can test it if
- /// you like.
- /// </remarks>
- public int CodecBufferSize
- {
- get;
- set;
- }
-
-
- /// <summary>
- /// The compression strategy to use for all entries.
- /// </summary>
- ///
- /// <remarks>
- /// Set the Strategy used by the ZLIB-compatible compressor, when compressing
- /// data for the entries in the zip archive. Different compression strategies
- /// work better on different sorts of data. The strategy parameter can affect
- /// the compression ratio and the speed of compression but not the correctness
- /// of the compresssion. For more information see <see
- /// cref="Ionic.Zlib.CompressionStrategy "/>.
- /// </remarks>
- public CompressionStrategy Strategy
- {
- get;
- set;
- }
-
-
- /// <summary>
- /// The type of timestamp attached to the ZipEntry.
- /// </summary>
- ///
- /// <remarks>
- /// Set this in order to specify the kind of timestamp that should be emitted
- /// into the zip file for each entry.
- /// </remarks>
- public ZipEntryTimestamp Timestamp
- {
- get
- {
- return _timestamp;
- }
- set
- {
- if (_disposed)
- {
- _exceptionPending = true;
- throw new System.InvalidOperationException("The stream has been closed.");
- }
- _timestamp = value;
- }
- }
-
-
- /// <summary>
- /// Sets the compression level to be used for entries subsequently added to
- /// the zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Varying the compression level used on entries can affect the
- /// size-vs-speed tradeoff when compression and decompressing data streams
- /// or files.
- /// </para>
- ///
- /// <para>
- /// As with some other properties on the <c>ZipOutputStream</c> class, like <see
- /// cref="Password"/>, and <see cref="Encryption"/>,
- /// setting this property on a <c>ZipOutputStream</c>
- /// instance will cause the specified <c>CompressionLevel</c> to be used on all
- /// <see cref="ZipEntry"/> items that are subsequently added to the
- /// <c>ZipOutputStream</c> instance.
- /// </para>
- ///
- /// <para>
- /// If you do not set this property, the default compression level is used,
- /// which normally gives a good balance of compression efficiency and
- /// compression speed. In some tests, using <c>BestCompression</c> can
- /// double the time it takes to compress, while delivering just a small
- /// increase in compression efficiency. This behavior will vary with the
- /// type of data you compress. If you are in doubt, just leave this setting
- /// alone, and accept the default.
- /// </para>
- /// </remarks>
- public OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel CompressionLevel
- {
- get;
- set;
- }
-
- /// <summary>
- /// The compression method used on each entry added to the ZipOutputStream.
- /// </summary>
- public CompressionMethod CompressionMethod
- {
- get;
- set;
- }
-
-
- /// <summary>
- /// A comment attached to the zip archive.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// The application sets this property to specify a comment to be embedded
- /// into the generated zip archive.
- /// </para>
- ///
- /// <para>
- /// According to <see
- /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's
- /// zip specification</see>, the comment is not encrypted, even if there is a
- /// password set on the zip file.
- /// </para>
- ///
- /// <para>
- /// The specification does not describe how to indicate the encoding used
- /// on a comment string. Many "compliant" zip tools and libraries use
- /// IBM437 as the code page for comments; DotNetZip, too, follows that
- /// practice. On the other hand, there are situations where you want a
- /// Comment to be encoded with something else, for example using code page
- /// 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the
- /// comment following the same procedure it follows for encoding
- /// filenames: (a) if <see cref="AlternateEncodingUsage"/> is
- /// <c>Never</c>, it uses the default encoding (IBM437). (b) if <see
- /// cref="AlternateEncodingUsage"/> is <c>Always</c>, it always uses the
- /// alternate encoding (<see cref="AlternateEncoding"/>). (c) if <see
- /// cref="AlternateEncodingUsage"/> is <c>AsNecessary</c>, it uses the
- /// alternate encoding only if the default encoding is not sufficient for
- /// encoding the comment - in other words if decoding the result does not
- /// produce the original string. This decision is taken at the time of
- /// the call to <c>ZipFile.Save()</c>.
- /// </para>
- ///
- /// </remarks>
- public string Comment
- {
- get { return _comment; }
- set
- {
- if (_disposed)
- {
- _exceptionPending = true;
- throw new System.InvalidOperationException("The stream has been closed.");
- }
- _comment = value;
- }
- }
-
-
-
- /// <summary>
- /// Specify whether to use ZIP64 extensions when saving a zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The default value for the property is <see
- /// cref="Zip64Option.Never"/>. <see cref="Zip64Option.AsNecessary"/> is
- /// safest, in the sense that you will not get an Exception if a
- /// pre-ZIP64 limit is exceeded.
- /// </para>
- ///
- /// <para>
- /// You must set this property before calling <c>Write()</c>.
- /// </para>
- ///
- /// </remarks>
- public Zip64Option EnableZip64
- {
- get
- {
- return _zip64;
- }
- set
- {
- if (_disposed)
- {
- _exceptionPending = true;
- throw new System.InvalidOperationException("The stream has been closed.");
- }
- _zip64 = value;
- }
- }
-
-
- /// <summary>
- /// Indicates whether ZIP64 extensions were used when saving the zip archive.
- /// </summary>
- ///
- /// <remarks>
- /// The value is defined only after the <c>ZipOutputStream</c> has been closed.
- /// </remarks>
- public bool OutputUsedZip64
- {
- get
- {
- return _anyEntriesUsedZip64 || _directoryNeededZip64;
- }
- }
-
-
- /// <summary>
- /// Whether the ZipOutputStream should use case-insensitive comparisons when
- /// checking for uniqueness of zip entries.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Though the zip specification doesn't prohibit zipfiles with duplicate
- /// entries, Sane zip files have no duplicates, and the DotNetZip library
- /// cannot create zip files with duplicate entries. If an application attempts
- /// to call <see cref="PutNextEntry(String)"/> with a name that duplicates one
- /// already used within the archive, the library will throw an Exception.
- /// </para>
- /// <para>
- /// This property allows the application to specify whether the
- /// ZipOutputStream instance considers ordinal case when checking for
- /// uniqueness of zip entries.
- /// </para>
- /// </remarks>
- public bool IgnoreCase
- {
- get
- {
- return !_DontIgnoreCase;
- }
-
- set
- {
- _DontIgnoreCase = !value;
- }
-
- }
-
-
- /// <summary>
- /// Indicates whether to encode entry filenames and entry comments using
- /// Unicode (UTF-8).
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">The
- /// PKWare zip specification</see> provides for encoding file names and file
- /// comments in either the IBM437 code page, or in UTF-8. This flag selects
- /// the encoding according to that specification. By default, this flag is
- /// false, and filenames and comments are encoded into the zip file in the
- /// IBM437 codepage. Setting this flag to true will specify that filenames
- /// and comments that cannot be encoded with IBM437 will be encoded with
- /// UTF-8.
- /// </para>
- ///
- /// <para>
- /// Zip files created with strict adherence to the PKWare specification with
- /// respect to UTF-8 encoding can contain entries with filenames containing
- /// any combination of Unicode characters, including the full range of
- /// characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other
- /// alphabets. However, because at this time, the UTF-8 portion of the PKWare
- /// specification is not broadly supported by other zip libraries and
- /// utilities, such zip files may not be readable by your favorite zip tool or
- /// archiver. In other words, interoperability will decrease if you set this
- /// flag to true.
- /// </para>
- ///
- /// <para>
- /// In particular, Zip files created with strict adherence to the PKWare
- /// specification with respect to UTF-8 encoding will not work well with
- /// Explorer in Windows XP or Windows Vista, because Windows compressed
- /// folders, as far as I know, do not support UTF-8 in zip files. Vista can
- /// read the zip files, but shows the filenames incorrectly. Unpacking from
- /// Windows Vista Explorer will result in filenames that have rubbish
- /// characters in place of the high-order UTF-8 bytes.
- /// </para>
- ///
- /// <para>
- /// Also, zip files that use UTF-8 encoding will not work well with Java
- /// applications that use the java.util.zip classes, as of v5.0 of the Java
- /// runtime. The Java runtime does not correctly implement the PKWare
- /// specification in this regard.
- /// </para>
- ///
- /// <para>
- /// As a result, we have the unfortunate situation that "correct" behavior by
- /// the DotNetZip library with regard to Unicode encoding of filenames during
- /// zip creation will result in zip files that are readable by strictly
- /// compliant and current tools (for example the most recent release of the
- /// commercial WinZip tool); but these zip files will not be readable by
- /// various other tools or libraries, including Windows Explorer.
- /// </para>
- ///
- /// <para>
- /// The DotNetZip library can read and write zip files with UTF8-encoded
- /// entries, according to the PKware spec. If you use DotNetZip for both
- /// creating and reading the zip file, and you use UTF-8, there will be no
- /// loss of information in the filenames. For example, using a self-extractor
- /// created by this library will allow you to unpack files correctly with no
- /// loss of information in the filenames.
- /// </para>
- ///
- /// <para>
- /// If you do not set this flag, it will remain false. If this flag is false,
- /// the <c>ZipOutputStream</c> will encode all filenames and comments using
- /// the IBM437 codepage. This can cause "loss of information" on some
- /// filenames, but the resulting zipfile will be more interoperable with other
- /// utilities. As an example of the loss of information, diacritics can be
- /// lost. The o-tilde character will be down-coded to plain o. The c with a
- /// cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c.
- /// Likewise, the O-stroke character (Unicode 248), used in Danish and
- /// Norwegian, will be down-coded to plain o. Chinese characters cannot be
- /// represented in codepage IBM437; when using the default encoding, Chinese
- /// characters in filenames will be represented as ?. These are all examples
- /// of "information loss".
- /// </para>
- ///
- /// <para>
- /// The loss of information associated to the use of the IBM437 encoding is
- /// inconvenient, and can also lead to runtime errors. For example, using
- /// IBM437, any sequence of 4 Chinese characters will be encoded as ????. If
- /// your application creates a <c>ZipOutputStream</c>, does not set the
- /// encoding, then adds two files, each with names of four Chinese characters
- /// each, this will result in a duplicate filename exception. In the case
- /// where you add a single file with a name containing four Chinese
- /// characters, the zipfile will save properly, but extracting that file
- /// later, with any zip tool, will result in an error, because the question
- /// mark is not legal for use within filenames on Windows. These are just a
- /// few examples of the problems associated to loss of information.
- /// </para>
- ///
- /// <para>
- /// This flag is independent of the encoding of the content within the entries
- /// in the zip file. Think of the zip file as a container - it supports an
- /// encoding. Within the container are other "containers" - the file entries
- /// themselves. The encoding within those entries is independent of the
- /// encoding of the zip archive container for those entries.
- /// </para>
- ///
- /// <para>
- /// Rather than specify the encoding in a binary fashion using this flag, an
- /// application can specify an arbitrary encoding via the <see
- /// cref="ProvisionalAlternateEncoding"/> property. Setting the encoding
- /// explicitly when creating zip archives will result in non-compliant zip
- /// files that, curiously, are fairly interoperable. The challenge is, the
- /// PKWare specification does not provide for a way to specify that an entry
- /// in a zip archive uses a code page that is neither IBM437 nor UTF-8.
- /// Therefore if you set the encoding explicitly when creating a zip archive,
- /// you must take care upon reading the zip archive to use the same code page.
- /// If you get it wrong, the behavior is undefined and may result in incorrect
- /// filenames, exceptions, stomach upset, hair loss, and acne.
- /// </para>
- /// </remarks>
- /// <seealso cref="ProvisionalAlternateEncoding"/>
- [Obsolete("Beginning with v1.9.1.6 of DotNetZip, this property is obsolete. It will be removed in a future version of the library. Use AlternateEncoding and AlternateEncodingUsage instead.")]
- public bool UseUnicodeAsNecessary
- {
- get
- {
- return (_alternateEncoding == System.Text.Encoding.UTF8) &&
- (AlternateEncodingUsage == ZipOption.AsNecessary);
- }
- set
- {
- if (value)
- {
- _alternateEncoding = System.Text.Encoding.UTF8;
- _alternateEncodingUsage = ZipOption.AsNecessary;
-
- }
- else
- {
- _alternateEncoding = Ionic.Zip.ZipOutputStream.DefaultEncoding;
- _alternateEncodingUsage = ZipOption.Never;
- }
- }
- }
-
-
- /// <summary>
- /// The text encoding to use when emitting entries into the zip archive, for
- /// those entries whose filenames or comments cannot be encoded with the
- /// default (IBM437) encoding.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// In <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">its
- /// zip specification</see>, PKWare describes two options for encoding
- /// filenames and comments: using IBM437 or UTF-8. But, some archiving tools
- /// or libraries do not follow the specification, and instead encode
- /// characters using the system default code page. For example, WinRAR when
- /// run on a machine in Shanghai may encode filenames with the Big-5 Chinese
- /// (950) code page. This behavior is contrary to the Zip specification, but
- /// it occurs anyway.
- /// </para>
- ///
- /// <para>
- /// When using DotNetZip to write zip archives that will be read by one of
- /// these other archivers, set this property to specify the code page to use
- /// when encoding the <see cref="ZipEntry.FileName"/> and <see
- /// cref="ZipEntry.Comment"/> for each <c>ZipEntry</c> in the zip file, for
- /// values that cannot be encoded with the default codepage for zip files,
- /// IBM437. This is why this property is "provisional". In all cases, IBM437
- /// is used where possible, in other words, where no loss of data would
- /// result. It is possible, therefore, to have a given entry with a
- /// <c>Comment</c> encoded in IBM437 and a <c>FileName</c> encoded with the
- /// specified "provisional" codepage.
- /// </para>
- ///
- /// <para>
- /// Be aware that a zip file created after you've explicitly set the
- /// <c>ProvisionalAlternateEncoding</c> property to a value other than
- /// IBM437 may not be compliant to the PKWare specification, and may not be
- /// readable by compliant archivers. On the other hand, many (most?)
- /// archivers are non-compliant and can read zip files created in arbitrary
- /// code pages. The trick is to use or specify the proper codepage when
- /// reading the zip.
- /// </para>
- ///
- /// <para>
- /// When creating a zip archive using this library, it is possible to change
- /// the value of <c>ProvisionalAlternateEncoding</c> between each entry you
- /// add, and between adding entries and the call to <c>Close()</c>. Don't do
- /// this. It will likely result in a zipfile that is not readable. For best
- /// interoperability, either leave <c>ProvisionalAlternateEncoding</c>
- /// alone, or specify it only once, before adding any entries to the
- /// <c>ZipOutputStream</c> instance. There is one exception to this
- /// recommendation, described later.
- /// </para>
- ///
- /// <para>
- /// When using an arbitrary, non-UTF8 code page for encoding, there is no
- /// standard way for the creator application - whether DotNetZip, WinZip,
- /// WinRar, or something else - to formally specify in the zip file which
- /// codepage has been used for the entries. As a result, readers of zip files
- /// are not able to inspect the zip file and determine the codepage that was
- /// used for the entries contained within it. It is left to the application
- /// or user to determine the necessary codepage when reading zip files encoded
- /// this way. If you use an incorrect codepage when reading a zipfile, you
- /// will get entries with filenames that are incorrect, and the incorrect
- /// filenames may even contain characters that are not legal for use within
- /// filenames in Windows. Extracting entries with illegal characters in the
- /// filenames will lead to exceptions. It's too bad, but this is just the way
- /// things are with code pages in zip files. Caveat Emptor.
- /// </para>
- ///
- /// <para>
- /// One possible approach for specifying the code page for a given zip file is
- /// to describe the code page in a human-readable form in the Zip comment. For
- /// example, the comment may read "Entries in this archive are encoded in the
- /// Big5 code page". For maximum interoperability, the zip comment in this
- /// case should be encoded in the default, IBM437 code page. In this case,
- /// the zip comment is encoded using a different page than the filenames. To
- /// do this, Specify <c>ProvisionalAlternateEncoding</c> to your desired
- /// region-specific code page, once before adding any entries, and then set
- /// the <see cref="Comment"/> property and reset
- /// <c>ProvisionalAlternateEncoding</c> to IBM437 before calling <c>Close()</c>.
- /// </para>
- /// </remarks>
- [Obsolete("use AlternateEncoding and AlternateEncodingUsage instead.")]
- public System.Text.Encoding ProvisionalAlternateEncoding
- {
- get
- {
- if (_alternateEncodingUsage == ZipOption.AsNecessary)
- return _alternateEncoding;
- return null;
- }
- set
- {
- _alternateEncoding = value;
- _alternateEncodingUsage = ZipOption.AsNecessary;
- }
- }
-
- /// <summary>
- /// A Text Encoding to use when encoding the filenames and comments for
- /// all the ZipEntry items, during a ZipFile.Save() operation.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Whether the encoding specified here is used during the save depends
- /// on <see cref="AlternateEncodingUsage"/>.
- /// </para>
- /// </remarks>
- public System.Text.Encoding AlternateEncoding
- {
- get
- {
- return _alternateEncoding;
- }
- set
- {
- _alternateEncoding = value;
- }
- }
-
- /// <summary>
- /// A flag that tells if and when this instance should apply
- /// AlternateEncoding to encode the filenames and comments associated to
- /// of ZipEntry objects contained within this instance.
- /// </summary>
- public ZipOption AlternateEncodingUsage
- {
- get
- {
- return _alternateEncodingUsage;
- }
- set
- {
- _alternateEncodingUsage = value;
- }
- }
-
- /// <summary>
- /// The default text encoding used in zip archives. It is numeric 437, also
- /// known as IBM437.
- /// </summary>
- /// <seealso cref="Ionic.Zip.ZipFile.ProvisionalAlternateEncoding"/>
- public static System.Text.Encoding DefaultEncoding
- {
- get
- {
- return System.Text.Encoding.ASCII;
- }
- }
-
-
-#if !NETCF
- /// <summary>
- /// The size threshold for an entry, above which a parallel deflate is used.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// DotNetZip will use multiple threads to compress any ZipEntry, when
- /// the <c>CompressionMethod</c> is Deflate, and if the entry is
- /// larger than the given size. Zero means "always use parallel
- /// deflate", while -1 means "never use parallel deflate".
- /// </para>
- ///
- /// <para>
- /// If the entry size cannot be known before compression, as with any entry
- /// added via a ZipOutputStream, then Parallel deflate will never be
- /// performed, unless the value of this property is zero.
- /// </para>
- ///
- /// <para>
- /// A parallel deflate operations will speed up the compression of
- /// large files, on computers with multiple CPUs or multiple CPU
- /// cores. For files above 1mb, on a dual core or dual-cpu (2p)
- /// machine, the time required to compress the file can be 70% of the
- /// single-threaded deflate. For very large files on 4p machines the
- /// compression can be done in 30% of the normal time. The downside
- /// is that parallel deflate consumes extra memory during the deflate,
- /// and the deflation is slightly less effective.
- /// </para>
- ///
- /// <para>
- /// Parallel deflate tends to not be as effective as single-threaded deflate
- /// because the original data stream is split into multiple independent
- /// buffers, each of which is compressed in parallel. But because they are
- /// treated independently, there is no opportunity to share compression
- /// dictionaries, and additional framing bytes must be added to the output
- /// stream. For that reason, a deflated stream may be slightly larger when
- /// compressed using parallel deflate, as compared to a traditional
- /// single-threaded deflate. For files of about 512k, the increase over the
- /// normal deflate is as much as 5% of the total compressed size. For larger
- /// files, the difference can be as small as 0.1%.
- /// </para>
- ///
- /// <para>
- /// Multi-threaded compression does not give as much an advantage when using
- /// Encryption. This is primarily because encryption tends to slow down
- /// the entire pipeline. Also, multi-threaded compression gives less of an
- /// advantage when using lower compression levels, for example <see
- /// cref="Ionic.Zlib.CompressionLevel.BestSpeed"/>. You may have to perform
- /// some tests to determine the best approach for your situation.
- /// </para>
- ///
- /// <para>
- /// The default value for this property is -1, which means parallel
- /// compression will not be performed unless you set it to zero.
- /// </para>
- ///
- /// </remarks>
- public long ParallelDeflateThreshold
- {
- set
- {
- if ((value != 0) && (value != -1) && (value < 64 * 1024))
- throw new ArgumentOutOfRangeException("value must be greater than 64k, or 0, or -1");
- _ParallelDeflateThreshold = value;
- }
- get
- {
- return _ParallelDeflateThreshold;
- }
- }
-
-
- /// <summary>
- /// The maximum number of buffer pairs to use when performing
- /// parallel compression.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This property sets an upper limit on the number of memory
- /// buffer pairs to create when performing parallel
- /// compression. The implementation of the parallel
- /// compression stream allocates multiple buffers to
- /// facilitate parallel compression. As each buffer fills up,
- /// the stream uses <see
- /// cref="System.Threading.ThreadPool.QueueUserWorkItem(WaitCallback)">
- /// ThreadPool.QueueUserWorkItem()</see> to compress those
- /// buffers in a background threadpool thread. After a buffer
- /// is compressed, it is re-ordered and written to the output
- /// stream.
- /// </para>
- ///
- /// <para>
- /// A higher number of buffer pairs enables a higher degree of
- /// parallelism, which tends to increase the speed of compression on
- /// multi-cpu computers. On the other hand, a higher number of buffer
- /// pairs also implies a larger memory consumption, more active worker
- /// threads, and a higher cpu utilization for any compression. This
- /// property enables the application to limit its memory consumption and
- /// CPU utilization behavior depending on requirements.
- /// </para>
- ///
- /// <para>
- /// For each compression "task" that occurs in parallel, there are 2
- /// buffers allocated: one for input and one for output. This property
- /// sets a limit for the number of pairs. The total amount of storage
- /// space allocated for buffering will then be (N*S*2), where N is the
- /// number of buffer pairs, S is the size of each buffer (<see
- /// cref="CodecBufferSize"/>). By default, DotNetZip allocates 4 buffer
- /// pairs per CPU core, so if your machine has 4 cores, and you retain
- /// the default buffer size of 128k, then the
- /// ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer
- /// memory in total, or 4mb, in blocks of 128kb. If you then set this
- /// property to 8, then the number will be 8 * 2 * 128kb of buffer
- /// memory, or 2mb.
- /// </para>
- ///
- /// <para>
- /// CPU utilization will also go up with additional buffers, because a
- /// larger number of buffer pairs allows a larger number of background
- /// threads to compress in parallel. If you find that parallel
- /// compression is consuming too much memory or CPU, you can adjust this
- /// value downward.
- /// </para>
- ///
- /// <para>
- /// The default value is 16. Different values may deliver better or
- /// worse results, depending on your priorities and the dynamic
- /// performance characteristics of your storage and compute resources.
- /// </para>
- ///
- /// <para>
- /// This property is not the number of buffer pairs to use; it is an
- /// upper limit. An illustration: Suppose you have an application that
- /// uses the default value of this property (which is 16), and it runs
- /// on a machine with 2 CPU cores. In that case, DotNetZip will allocate
- /// 4 buffer pairs per CPU core, for a total of 8 pairs. The upper
- /// limit specified by this property has no effect.
- /// </para>
- ///
- /// <para>
- /// The application can set this value at any time, but it is
- /// effective only if set before calling
- /// <c>ZipOutputStream.Write()</c> for the first time.
- /// </para>
- /// </remarks>
- ///
- /// <seealso cref="ParallelDeflateThreshold"/>
- ///
- public int ParallelDeflateMaxBufferPairs
- {
- get
- {
- return _maxBufferPairs;
- }
- set
- {
- if (value < 4)
- throw new ArgumentOutOfRangeException("ParallelDeflateMaxBufferPairs",
- "Value must be 4 or greater.");
- _maxBufferPairs = value;
- }
- }
-#endif
-
-
- private void InsureUniqueEntry(ZipEntry ze1)
- {
- if (_entriesWritten.ContainsKey(ze1.FileName))
- {
- _exceptionPending = true;
- throw new ArgumentException(String.Format("The entry '{0}' already exists in the zip archive.", ze1.FileName));
- }
- }
-
-
- internal Stream OutputStream
- {
- get
- {
- return _outputStream;
- }
- }
-
- internal String Name
- {
- get
- {
- return _name;
- }
- }
-
- /// <summary>
- /// Returns true if an entry by the given name has already been written
- /// to the ZipOutputStream.
- /// </summary>
- ///
- /// <param name="name">
- /// The name of the entry to scan for.
- /// </param>
- ///
- /// <returns>
- /// true if an entry by the given name has already been written.
- /// </returns>
- public bool ContainsEntry(string name)
- {
- return _entriesWritten.ContainsKey(SharedUtilities.NormalizePathForUseInZipFile(name));
- }
-
-
- /// <summary>
- /// Write the data from the buffer to the stream.
- /// </summary>
- ///
- /// <remarks>
- /// As the application writes data into this stream, the data may be
- /// compressed and encrypted before being written out to the underlying
- /// stream, depending on the settings of the <see cref="CompressionLevel"/>
- /// and the <see cref="Encryption"/> properties.
- /// </remarks>
- ///
- /// <param name="buffer">The buffer holding data to write to the stream.</param>
- /// <param name="offset">the offset within that data array to find the first byte to write.</param>
- /// <param name="count">the number of bytes to write.</param>
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (_disposed)
- {
- _exceptionPending = true;
- throw new System.InvalidOperationException("The stream has been closed.");
- }
-
- if (buffer==null)
- {
- _exceptionPending = true;
- throw new System.ArgumentNullException("buffer");
- }
-
- if (_currentEntry == null)
- {
- _exceptionPending = true;
- throw new System.InvalidOperationException("You must call PutNextEntry() before calling Write().");
- }
-
- if (_currentEntry.IsDirectory)
- {
- _exceptionPending = true;
- throw new System.InvalidOperationException("You cannot Write() data for an entry that is a directory.");
- }
-
- if (_needToWriteEntryHeader)
- _InitiateCurrentEntry(false);
-
- if (count != 0)
- _entryOutputStream.Write(buffer, offset, count);
- }
-
-
-
- /// <summary>
- /// Specify the name of the next entry that will be written to the zip file.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// Call this method just before calling <see cref="Write(byte[], int, int)"/>, to
- /// specify the name of the entry that the next set of bytes written to
- /// the <c>ZipOutputStream</c> belongs to. All subsequent calls to <c>Write</c>,
- /// until the next call to <c>PutNextEntry</c>,
- /// will be inserted into the named entry in the zip file.
- /// </para>
- ///
- /// <para>
- /// If the <paramref name="entryName"/> used in <c>PutNextEntry()</c> ends in
- /// a slash, then the entry added is marked as a directory. Because directory
- /// entries do not contain data, a call to <c>Write()</c>, before an
- /// intervening additional call to <c>PutNextEntry()</c>, will throw an
- /// exception.
- /// </para>
- ///
- /// <para>
- /// If you don't call <c>Write()</c> between two calls to
- /// <c>PutNextEntry()</c>, the first entry is inserted into the zip file as a
- /// file of zero size. This may be what you want.
- /// </para>
- ///
- /// <para>
- /// Because <c>PutNextEntry()</c> closes out the prior entry, if any, this
- /// method may throw if there is a problem with the prior entry.
- /// </para>
- ///
- /// <para>
- /// This method returns the <c>ZipEntry</c>. You can modify public properties
- /// on the <c>ZipEntry</c>, such as <see cref="ZipEntry.Encryption"/>, <see
- /// cref="ZipEntry.Password"/>, and so on, until the first call to
- /// <c>ZipOutputStream.Write()</c>, or until the next call to
- /// <c>PutNextEntry()</c>. If you modify the <c>ZipEntry</c> <em>after</em>
- /// having called <c>Write()</c>, you may get a runtime exception, or you may
- /// silently get an invalid zip archive.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example shows how to create a zip file, using the
- /// <c>ZipOutputStream</c> class.
- ///
- /// <code>
- /// private void Zipup()
- /// {
- /// using (FileStream fs raw = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite ))
- /// {
- /// using (var output= new ZipOutputStream(fs))
- /// {
- /// output.Password = "VerySecret!";
- /// output.Encryption = EncryptionAlgorithm.WinZipAes256;
- /// output.PutNextEntry("entry1.txt");
- /// byte[] buffer= System.Text.Encoding.ASCII.GetBytes("This is the content for entry #1.");
- /// output.Write(buffer,0,buffer.Length);
- /// output.PutNextEntry("entry2.txt"); // this will be zero length
- /// output.PutNextEntry("entry3.txt");
- /// buffer= System.Text.Encoding.ASCII.GetBytes("This is the content for entry #3.");
- /// output.Write(buffer,0,buffer.Length);
- /// }
- /// }
- /// }
- /// </code>
- /// </example>
- ///
- /// <param name="entryName">
- /// The name of the entry to be added, including any path to be used
- /// within the zip file.
- /// </param>
- ///
- /// <returns>
- /// The ZipEntry created.
- /// </returns>
- ///
- public ZipEntry PutNextEntry(String entryName)
- {
- if (String.IsNullOrEmpty(entryName))
- throw new ArgumentNullException("entryName");
-
- if (_disposed)
- {
- _exceptionPending = true;
- throw new System.InvalidOperationException("The stream has been closed.");
- }
-
- _FinishCurrentEntry();
- _currentEntry = ZipEntry.CreateForZipOutputStream(entryName);
- _currentEntry._container = new ZipContainer(this);
- _currentEntry._BitField |= 0x0008; // workitem 8932
- _currentEntry.SetEntryTimes(DateTime.Now, DateTime.Now, DateTime.Now);
- _currentEntry.CompressionLevel = this.CompressionLevel;
- _currentEntry.CompressionMethod = this.CompressionMethod;
- _currentEntry.Password = _password; // workitem 13909
- _currentEntry.Encryption = this.Encryption;
- // workitem 12634
- _currentEntry.AlternateEncoding = this.AlternateEncoding;
- _currentEntry.AlternateEncodingUsage = this.AlternateEncodingUsage;
-
- if (entryName.EndsWith("/")) _currentEntry.MarkAsDirectory();
-
- _currentEntry.EmitTimesInWindowsFormatWhenSaving = ((_timestamp & ZipEntryTimestamp.Windows) != 0);
- _currentEntry.EmitTimesInUnixFormatWhenSaving = ((_timestamp & ZipEntryTimestamp.Unix) != 0);
- InsureUniqueEntry(_currentEntry);
- _needToWriteEntryHeader = true;
-
- return _currentEntry;
- }
-
-
-
- private void _InitiateCurrentEntry(bool finishing)
- {
- // If finishing==true, this means we're initiating the entry at the time of
- // Close() or PutNextEntry(). If this happens, it means no data was written
- // for the entry - Write() was never called. (The usual case us to call
- // _InitiateCurrentEntry(bool) from within Write().) If finishing==true,
- // the entry could be either a zero-byte file or a directory.
-
- _entriesWritten.Add(_currentEntry.FileName,_currentEntry);
- _entryCount++; // could use _entriesWritten.Count, but I don't want to incur
- // the cost.
-
- if (_entryCount > 65534 && _zip64 == Zip64Option.Never)
- {
- _exceptionPending = true;
- throw new System.InvalidOperationException("Too many entries. Consider setting ZipOutputStream.EnableZip64.");
- }
-
- // Write out the header.
- //
- // If finishing, and encryption is in use, then we don't want to emit the
- // normal encryption header. Signal that with a cycle=99 to turn off
- // encryption for zero-byte entries or directories.
- //
- // If finishing, then we know the stream length is zero. Else, unknown
- // stream length. Passing stream length == 0 allows an optimization so as
- // not to setup an encryption or deflation stream, when stream length is
- // zero.
-
- _currentEntry.WriteHeader(_outputStream, finishing ? 99 : 0);
- _currentEntry.StoreRelativeOffset();
-
- if (!_currentEntry.IsDirectory)
- {
- _currentEntry.WriteSecurityMetadata(_outputStream);
- _currentEntry.PrepOutputStream(_outputStream,
- finishing ? 0 : -1,
- out _outputCounter,
- out _encryptor,
- out _deflater,
- out _entryOutputStream);
- }
- _needToWriteEntryHeader = false;
- }
-
-
-
- private void _FinishCurrentEntry()
- {
- if (_currentEntry != null)
- {
- if (_needToWriteEntryHeader)
- _InitiateCurrentEntry(true); // an empty entry - no writes
-
- _currentEntry.FinishOutputStream(_outputStream, _outputCounter, _encryptor, _deflater, _entryOutputStream);
- _currentEntry.PostProcessOutput(_outputStream);
- // workitem 12964
- if (_currentEntry.OutputUsedZip64!=null)
- _anyEntriesUsedZip64 |= _currentEntry.OutputUsedZip64.Value;
-
- // reset all the streams
- _outputCounter = null; _encryptor = _deflater = null; _entryOutputStream = null;
- }
- }
-
-
-
- /// <summary>
- /// Dispose the stream
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method writes the Zip Central directory, then closes the stream. The
- /// application must call Dispose() (or Close) in order to produce a valid zip file.
- /// </para>
- ///
- /// <para>
- /// Typically the application will call <c>Dispose()</c> implicitly, via a <c>using</c>
- /// statement in C#, or a <c>Using</c> statement in VB.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="disposing">set this to true, always.</param>
- protected override void Dispose(bool disposing)
- {
- if (_disposed) return;
-
- if (disposing) // not called from finalizer
- {
- // handle pending exceptions
- if (!_exceptionPending)
- {
- _FinishCurrentEntry();
- _directoryNeededZip64 = ZipOutput.WriteCentralDirectoryStructure(_outputStream,
- _entriesWritten.Values,
- 1, // _numberOfSegmentsForMostRecentSave,
- _zip64,
- Comment,
- new ZipContainer(this));
- Stream wrappedStream = null;
- CountingStream cs = _outputStream as CountingStream;
- if (cs != null)
- {
- wrappedStream = cs.WrappedStream;
-#if NETCF
- cs.Close();
-#else
- cs.Dispose();
-#endif
- }
- else
- {
- wrappedStream = _outputStream;
- }
-
- if (!_leaveUnderlyingStreamOpen)
- {
-#if NETCF
- wrappedStream.Close();
-#else
- wrappedStream.Dispose();
-#endif
- }
- _outputStream = null;
- }
- }
- _disposed = true;
- }
-
-
-
- /// <summary>
- /// Always returns false.
- /// </summary>
- public override bool CanRead { get { return false; } }
-
- /// <summary>
- /// Always returns false.
- /// </summary>
- public override bool CanSeek { get { return false; } }
-
- /// <summary>
- /// Always returns true.
- /// </summary>
- public override bool CanWrite { get { return true; } }
-
- /// <summary>
- /// Always returns a NotSupportedException.
- /// </summary>
- public override long Length { get { throw new NotSupportedException(); } }
-
- /// <summary>
- /// Setting this property always returns a NotSupportedException. Getting it
- /// returns the value of the Position on the underlying stream.
- /// </summary>
- public override long Position
- {
- get { return _outputStream.Position; }
- set { throw new NotSupportedException(); }
- }
-
- /// <summary>
- /// This is a no-op.
- /// </summary>
- public override void Flush() { }
-
- /// <summary>
- /// This method always throws a NotSupportedException.
- /// </summary>
- /// <param name="buffer">ignored</param>
- /// <param name="offset">ignored</param>
- /// <param name="count">ignored</param>
- /// <returns>nothing</returns>
- public override int Read(byte[] buffer, int offset, int count)
- {
- throw new NotSupportedException("Read");
- }
-
- /// <summary>
- /// This method always throws a NotSupportedException.
- /// </summary>
- /// <param name="offset">ignored</param>
- /// <param name="origin">ignored</param>
- /// <returns>nothing</returns>
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotSupportedException("Seek");
- }
-
- /// <summary>
- /// This method always throws a NotSupportedException.
- /// </summary>
- /// <param name="value">ignored</param>
- public override void SetLength(long value)
- {
- throw new NotSupportedException();
- }
-
-
- private EncryptionAlgorithm _encryption;
- private ZipEntryTimestamp _timestamp;
- internal String _password;
- private String _comment;
- private Stream _outputStream;
- private ZipEntry _currentEntry;
- internal Zip64Option _zip64;
- private Dictionary<String, ZipEntry> _entriesWritten;
- private int _entryCount;
- private ZipOption _alternateEncodingUsage = ZipOption.Never;
- private System.Text.Encoding _alternateEncoding
- = System.Text.Encoding.ASCII; // default = IBM437
-
- private bool _leaveUnderlyingStreamOpen;
- private bool _disposed;
- private bool _exceptionPending; // **see note below
- private bool _anyEntriesUsedZip64, _directoryNeededZip64;
- private CountingStream _outputCounter;
- private Stream _encryptor;
- private Stream _deflater;
- private Ionic.Crc.CrcCalculatorStream _entryOutputStream;
- private bool _needToWriteEntryHeader;
- private string _name;
- private bool _DontIgnoreCase;
-#if !NETCF
- internal ParallelDeflateOutputStream ParallelDeflater;
- private long _ParallelDeflateThreshold;
- private int _maxBufferPairs = 16;
-#endif
-
- // **Note regarding exceptions:
-
- // When ZipOutputStream is employed within a using clause, which
- // is the typical scenario, and an exception is thrown within
- // the scope of the using, Close()/Dispose() is invoked
- // implicitly before processing the initial exception. In that
- // case, _exceptionPending is true, and we don't want to try to
- // write anything in the Close/Dispose logic. Doing so can
- // cause additional exceptions that mask the original one. So,
- // the _exceptionPending flag is used to track that, and to
- // allow the original exception to be propagated to the
- // application without extra "noise."
-
- }
-
-
-
- internal class ZipContainer
- {
- private ZipFile _zf;
- private ZipOutputStream _zos;
- private ZipInputStream _zis;
-
- public ZipContainer(Object o)
- {
- _zf = (o as ZipFile);
- _zos = (o as ZipOutputStream);
- _zis = (o as ZipInputStream);
- }
-
- public ZipFile ZipFile
- {
- get { return _zf; }
- }
-
- public ZipOutputStream ZipOutputStream
- {
- get { return _zos; }
- }
-
- public string Name
- {
- get
- {
- if (_zf != null) return _zf.Name;
- if (_zis != null) throw new NotSupportedException();
- return _zos.Name;
- }
- }
-
- public string Password
- {
- get
- {
- if (_zf != null) return _zf._Password;
- if (_zis != null) return _zis._Password;
- return _zos._password;
- }
- }
-
- public Zip64Option Zip64
- {
- get
- {
- if (_zf != null) return _zf._zip64;
- if (_zis != null) throw new NotSupportedException();
- return _zos._zip64;
- }
- }
-
- public int BufferSize
- {
- get
- {
- if (_zf != null) return _zf.BufferSize;
- if (_zis != null) throw new NotSupportedException();
- return 0;
- }
- }
-
-#if !NETCF
- public Ionic.Zlib.ParallelDeflateOutputStream ParallelDeflater
- {
- get
- {
- if (_zf != null) return _zf.ParallelDeflater;
- if (_zis != null) return null;
- return _zos.ParallelDeflater;
- }
- set
- {
- if (_zf != null) _zf.ParallelDeflater = value;
- else if (_zos != null) _zos.ParallelDeflater = value;
- }
- }
-
- public long ParallelDeflateThreshold
- {
- get
- {
- if (_zf != null) return _zf.ParallelDeflateThreshold;
- return _zos.ParallelDeflateThreshold;
- }
- }
- public int ParallelDeflateMaxBufferPairs
- {
- get
- {
- if (_zf != null) return _zf.ParallelDeflateMaxBufferPairs;
- return _zos.ParallelDeflateMaxBufferPairs;
- }
- }
-#endif
-
- public int CodecBufferSize
- {
- get
- {
- if (_zf != null) return _zf.CodecBufferSize;
- if (_zis != null) return _zis.CodecBufferSize;
- return _zos.CodecBufferSize;
- }
- }
-
- public Ionic.Zlib.CompressionStrategy Strategy
- {
- get
- {
- if (_zf != null) return _zf.Strategy;
- return _zos.Strategy;
- }
- }
-
- public Zip64Option UseZip64WhenSaving
- {
- get
- {
- if (_zf != null) return _zf.UseZip64WhenSaving;
- return _zos.EnableZip64;
- }
- }
-
- public System.Text.Encoding AlternateEncoding
- {
- get
- {
- if (_zf != null) return _zf.AlternateEncoding;
- if (_zos!=null) return _zos.AlternateEncoding;
- return null;
- }
- }
- public System.Text.Encoding DefaultEncoding
- {
- get
- {
- if (_zf != null) return ZipFile.DefaultEncoding;
- if (_zos!=null) return ZipOutputStream.DefaultEncoding;
- return null;
- }
- }
- public ZipOption AlternateEncodingUsage
- {
- get
- {
- if (_zf != null) return _zf.AlternateEncodingUsage;
- if (_zos!=null) return _zos.AlternateEncodingUsage;
- return ZipOption.Never; // n/a
- }
- }
-
- public Stream ReadStream
- {
- get
- {
- if (_zf != null) return _zf.ReadStream;
- return _zis.ReadStream;
- }
- }
- }
-
-}
diff --git a/EPPlus/Packaging/DotNetZip/ZipSegmentedStream.cs b/EPPlus/Packaging/DotNetZip/ZipSegmentedStream.cs
deleted file mode 100644
index 4afc634..0000000
--- a/EPPlus/Packaging/DotNetZip/ZipSegmentedStream.cs
+++ /dev/null
@@ -1,571 +0,0 @@
-// ZipSegmentedStream.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009-2011 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-July-13 22:25:45>
-//
-// ------------------------------------------------------------------
-//
-// This module defines logic for zip streams that span disk files.
-//
-// ------------------------------------------------------------------
-
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zip
-{
- internal class ZipSegmentedStream : System.IO.Stream
- {
- enum RwMode
- {
- None = 0,
- ReadOnly = 1,
- Write = 2,
- //Update = 3
- }
-
- private RwMode rwMode;
- private bool _exceptionPending; // **see note below
- private string _baseName;
- private string _baseDir;
- //private bool _isDisposed;
- private string _currentName;
- private string _currentTempName;
- private uint _currentDiskNumber;
- private uint _maxDiskNumber;
- private int _maxSegmentSize;
- private System.IO.Stream _innerStream;
-
- // **Note regarding exceptions:
- //
- // When ZipSegmentedStream is employed within a using clause,
- // which is the typical scenario, and an exception is thrown
- // within the scope of the using, Dispose() is invoked
- // implicitly before processing the initial exception. If that
- // happens, this class sets _exceptionPending to true, and then
- // within the Dispose(bool), takes special action as
- // appropriate. Need to be careful: any additional exceptions
- // will mask the original one.
-
- private ZipSegmentedStream() : base()
- {
- _exceptionPending = false;
- }
-
- public static ZipSegmentedStream ForReading(string name,
- uint initialDiskNumber,
- uint maxDiskNumber)
- {
- ZipSegmentedStream zss = new ZipSegmentedStream()
- {
- rwMode = RwMode.ReadOnly,
- CurrentSegment = initialDiskNumber,
- _maxDiskNumber = maxDiskNumber,
- _baseName = name,
- };
-
- // Console.WriteLine("ZSS: ForReading ({0})",
- // Path.GetFileName(zss.CurrentName));
-
- zss._SetReadStream();
-
- return zss;
- }
-
-
- public static ZipSegmentedStream ForWriting(string name, int maxSegmentSize)
- {
- ZipSegmentedStream zss = new ZipSegmentedStream()
- {
- rwMode = RwMode.Write,
- CurrentSegment = 0,
- _baseName = name,
- _maxSegmentSize = maxSegmentSize,
- _baseDir = Path.GetDirectoryName(name)
- };
-
- // workitem 9522
- if (zss._baseDir=="") zss._baseDir=".";
-
- zss._SetWriteStream(0);
-
- // Console.WriteLine("ZSS: ForWriting ({0})",
- // Path.GetFileName(zss.CurrentName));
-
- return zss;
- }
-
-
- /// <summary>
- /// Sort-of like a factory method, ForUpdate is used only when
- /// the application needs to update the zip entry metadata for
- /// a segmented zip file, when the starting segment is earlier
- /// than the ending segment, for a particular entry.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The update is always contiguous, never rolls over. As a
- /// result, this method doesn't need to return a ZSS; it can
- /// simply return a FileStream. That's why it's "sort of"
- /// like a Factory method.
- /// </para>
- /// <para>
- /// Caller must Close/Dispose the stream object returned by
- /// this method.
- /// </para>
- /// </remarks>
- public static Stream ForUpdate(string name, uint diskNumber)
- {
- if (diskNumber >= 99)
- throw new ArgumentOutOfRangeException("diskNumber");
-
- string fname =
- String.Format("{0}.z{1:D2}",
- Path.Combine(Path.GetDirectoryName(name),
- Path.GetFileNameWithoutExtension(name)),
- diskNumber + 1);
-
- // Console.WriteLine("ZSS: ForUpdate ({0})",
- // Path.GetFileName(fname));
-
- // This class assumes that the update will not expand the
- // size of the segment. Update is used only for an in-place
- // update of zip metadata. It never will try to write beyond
- // the end of a segment.
-
- return File.Open(fname,
- FileMode.Open,
- FileAccess.ReadWrite,
- FileShare.None);
- }
-
- public bool ContiguousWrite
- {
- get;
- set;
- }
-
-
- public UInt32 CurrentSegment
- {
- get
- {
- return _currentDiskNumber;
- }
- private set
- {
- _currentDiskNumber = value;
- _currentName = null; // it will get updated next time referenced
- }
- }
-
- /// <summary>
- /// Name of the filesystem file corresponding to the current segment.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The name is not always the name currently being used in the
- /// filesystem. When rwMode is RwMode.Write, the filesystem file has a
- /// temporary name until the stream is closed or until the next segment is
- /// started.
- /// </para>
- /// </remarks>
- public String CurrentName
- {
- get
- {
- if (_currentName==null)
- _currentName = _NameForSegment(CurrentSegment);
-
- return _currentName;
- }
- }
-
-
- public String CurrentTempName
- {
- get
- {
- return _currentTempName;
- }
- }
-
- private string _NameForSegment(uint diskNumber)
- {
- if (diskNumber >= 99)
- {
- _exceptionPending = true;
- throw new OverflowException("The number of zip segments would exceed 99.");
- }
-
- return String.Format("{0}.z{1:D2}",
- Path.Combine(Path.GetDirectoryName(_baseName),
- Path.GetFileNameWithoutExtension(_baseName)),
- diskNumber + 1);
- }
-
-
- // Returns the segment that WILL be current if writing
- // a block of the given length.
- // This isn't exactly true. It could roll over beyond
- // this number.
- public UInt32 ComputeSegment(int length)
- {
- if (_innerStream.Position + length > _maxSegmentSize)
- // the block will go AT LEAST into the next segment
- return CurrentSegment + 1;
-
- // it will fit in the current segment
- return CurrentSegment;
- }
-
-
- public override String ToString()
- {
- return String.Format("{0}[{1}][{2}], pos=0x{3:X})",
- "ZipSegmentedStream", CurrentName,
- rwMode.ToString(),
- this.Position);
- }
-
-
- private void _SetReadStream()
- {
- if (_innerStream != null)
- {
-#if NETCF
- _innerStream.Close();
-#else
- _innerStream.Dispose();
-#endif
- }
-
- if (CurrentSegment + 1 == _maxDiskNumber)
- _currentName = _baseName;
-
- // Console.WriteLine("ZSS: SRS ({0})",
- // Path.GetFileName(CurrentName));
-
- _innerStream = File.OpenRead(CurrentName);
- }
-
-
- /// <summary>
- /// Read from the stream
- /// </summary>
- /// <param name="buffer">the buffer to read</param>
- /// <param name="offset">the offset at which to start</param>
- /// <param name="count">the number of bytes to read</param>
- /// <returns>the number of bytes actually read</returns>
- public override int Read(byte[] buffer, int offset, int count)
- {
- if (rwMode != RwMode.ReadOnly)
- {
- _exceptionPending = true;
- throw new InvalidOperationException("Stream Error: Cannot Read.");
- }
-
- int r = _innerStream.Read(buffer, offset, count);
- int r1 = r;
-
- while (r1 != count)
- {
- if (_innerStream.Position != _innerStream.Length)
- {
- _exceptionPending = true;
- throw new ZipException(String.Format("Read error in file {0}", CurrentName));
-
- }
-
- if (CurrentSegment + 1 == _maxDiskNumber)
- return r; // no more to read
-
- CurrentSegment++;
- _SetReadStream();
- offset += r1;
- count -= r1;
- r1 = _innerStream.Read(buffer, offset, count);
- r += r1;
- }
- return r;
- }
-
-
-
- private void _SetWriteStream(uint increment)
- {
- if (_innerStream != null)
- {
-#if NETCF
- _innerStream.Close();
-#else
- _innerStream.Dispose();
-#endif
- if (File.Exists(CurrentName))
- File.Delete(CurrentName);
- File.Move(_currentTempName, CurrentName);
- // Console.WriteLine("ZSS: SWS close ({0})",
- // Path.GetFileName(CurrentName));
- }
-
- if (increment > 0)
- CurrentSegment += increment;
-
- SharedUtilities.CreateAndOpenUniqueTempFile(_baseDir,
- out _innerStream,
- out _currentTempName);
-
- // Console.WriteLine("ZSS: SWS open ({0})",
- // Path.GetFileName(_currentTempName));
-
- if (CurrentSegment == 0)
- _innerStream.Write(BitConverter.GetBytes(ZipConstants.SplitArchiveSignature), 0, 4);
- }
-
-
- /// <summary>
- /// Write to the stream.
- /// </summary>
- /// <param name="buffer">the buffer from which to write</param>
- /// <param name="offset">the offset at which to start writing</param>
- /// <param name="count">the number of bytes to write</param>
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (rwMode != RwMode.Write)
- {
- _exceptionPending = true;
- throw new InvalidOperationException("Stream Error: Cannot Write.");
- }
-
-
- if (ContiguousWrite)
- {
- // enough space for a contiguous write?
- if (_innerStream.Position + count > _maxSegmentSize)
- _SetWriteStream(1);
- }
- else
- {
- while (_innerStream.Position + count > _maxSegmentSize)
- {
- int c = unchecked(_maxSegmentSize - (int)_innerStream.Position);
- _innerStream.Write(buffer, offset, c);
- _SetWriteStream(1);
- count -= c;
- offset += c;
- }
- }
-
- _innerStream.Write(buffer, offset, count);
- }
-
-
- public long TruncateBackward(uint diskNumber, long offset)
- {
- // Console.WriteLine("***ZSS.Trunc to disk {0}", diskNumber);
- // Console.WriteLine("***ZSS.Trunc: current disk {0}", CurrentSegment);
- if (diskNumber >= 99)
- throw new ArgumentOutOfRangeException("diskNumber");
-
- if (rwMode != RwMode.Write)
- {
- _exceptionPending = true;
- throw new ZipException("bad state.");
- }
-
- // Seek back in the segmented stream to a (maybe) prior segment.
-
- // Check if it is the same segment. If it is, very simple.
- if (diskNumber == CurrentSegment)
- {
- var x =_innerStream.Seek(offset, SeekOrigin.Begin);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_innerStream);
- return x;
- }
-
- // Seeking back to a prior segment.
- // The current segment and any intervening segments must be removed.
- // First, close the current segment, and then remove it.
- if (_innerStream != null)
- {
-#if NETCF
- _innerStream.Close();
-#else
- _innerStream.Dispose();
-#endif
- if (File.Exists(_currentTempName))
- File.Delete(_currentTempName);
- }
-
- // Now, remove intervening segments.
- for (uint j= CurrentSegment-1; j > diskNumber; j--)
- {
- string s = _NameForSegment(j);
- // Console.WriteLine("***ZSS.Trunc: removing file {0}", s);
- if (File.Exists(s))
- File.Delete(s);
- }
-
- // now, open the desired segment. It must exist.
- CurrentSegment = diskNumber;
-
- // get a new temp file, try 3 times:
- for (int i = 0; i < 3; i++)
- {
- try
- {
- _currentTempName = SharedUtilities.InternalGetTempFileName();
- // move the .z0x file back to a temp name
- File.Move(CurrentName, _currentTempName);
- break; // workitem 12403
- }
- catch(IOException)
- {
- if (i == 2) throw;
- }
- }
-
- // open it
- _innerStream = new FileStream(_currentTempName, FileMode.Open);
-
- var r = _innerStream.Seek(offset, SeekOrigin.Begin);
-
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_innerStream);
-
- return r;
- }
-
-
-
- public override bool CanRead
- {
- get
- {
- return (rwMode == RwMode.ReadOnly &&
- (_innerStream != null) &&
- _innerStream.CanRead);
- }
- }
-
-
- public override bool CanSeek
- {
- get
- {
- return (_innerStream != null) &&
- _innerStream.CanSeek;
- }
- }
-
-
- public override bool CanWrite
- {
- get
- {
- return (rwMode == RwMode.Write) &&
- (_innerStream != null) &&
- _innerStream.CanWrite;
- }
- }
-
- public override void Flush()
- {
- _innerStream.Flush();
- }
-
- public override long Length
- {
- get
- {
- return _innerStream.Length;
- }
- }
-
- public override long Position
- {
- get { return _innerStream.Position; }
- set { _innerStream.Position = value; }
- }
-
- public override long Seek(long offset, System.IO.SeekOrigin origin)
- {
- var x = _innerStream.Seek(offset, origin);
- // workitem 10178
- Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_innerStream);
- return x;
- }
-
- public override void SetLength(long value)
- {
- if (rwMode != RwMode.Write)
- {
- _exceptionPending = true;
- throw new InvalidOperationException();
- }
- _innerStream.SetLength(value);
- }
-
-
- protected override void Dispose(bool disposing)
- {
- // this gets called by Stream.Close()
-
- // if (_isDisposed) return;
- // _isDisposed = true;
- //Console.WriteLine("Dispose (mode={0})\n", rwMode.ToString());
-
- try
- {
- if (_innerStream != null)
- {
-#if NETCF
- _innerStream.Close();
-#else
- _innerStream.Dispose();
-#endif
- //_innerStream = null;
- if (rwMode == RwMode.Write)
- {
- if (_exceptionPending)
- {
- // possibly could try to clean up all the
- // temp files created so far...
- }
- else
- {
- // // move the final temp file to the .zNN name
- // if (File.Exists(CurrentName))
- // File.Delete(CurrentName);
- // if (File.Exists(_currentTempName))
- // File.Move(_currentTempName, CurrentName);
- }
- }
- }
- }
- finally
- {
- base.Dispose(disposing);
- }
- }
-
- }
-
-}
\ No newline at end of file
diff --git a/EPPlus/Packaging/DotNetZip/Zlib/Deflate.cs b/EPPlus/Packaging/DotNetZip/Zlib/Deflate.cs
deleted file mode 100644
index d5d32ad..0000000
--- a/EPPlus/Packaging/DotNetZip/Zlib/Deflate.cs
+++ /dev/null
@@ -1,1879 +0,0 @@
-// Deflate.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-August-03 19:52:15>
-//
-// ------------------------------------------------------------------
-//
-// This module defines logic for handling the Deflate or compression.
-//
-// This code is based on multiple sources:
-// - the original zlib v1.2.3 source, which is Copyright (C) 1995-2005 Jean-loup Gailly.
-// - the original jzlib, which is Copyright (c) 2000-2003 ymnk, JCraft,Inc.
-//
-// However, this code is significantly different from both.
-// The object model is not the same, and many of the behaviors are different.
-//
-// In keeping with the license for these other works, the copyrights for
-// jzlib and zlib are here.
-//
-// -----------------------------------------------------------------------
-// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-//
-// 2. 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.
-//
-// 3. The names of the authors may not be used to endorse or promote products
-// derived from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
-// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
-//
-// -----------------------------------------------------------------------
-//
-// This program is based on zlib-1.1.3; credit to authors
-// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
-// and contributors of zlib.
-//
-// -----------------------------------------------------------------------
-
-
-using System;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zlib
-{
-
- internal enum BlockState
- {
- NeedMore = 0, // block not completed, need more input or more output
- BlockDone, // block flush performed
- FinishStarted, // finish started, need only more output at next deflate
- FinishDone // finish done, accept no more input or output
- }
-
- internal enum DeflateFlavor
- {
- Store,
- Fast,
- Slow
- }
-
- internal sealed class DeflateManager
- {
- private static readonly int MEM_LEVEL_MAX = 9;
- private static readonly int MEM_LEVEL_DEFAULT = 8;
-
- internal delegate BlockState CompressFunc(FlushType flush);
-
- internal class Config
- {
- // Use a faster search when the previous match is longer than this
- internal int GoodLength; // reduce lazy search above this match length
-
- // Attempt to find a better match only when the current match is
- // strictly smaller than this value. This mechanism is used only for
- // compression levels >= 4. For levels 1,2,3: MaxLazy is actually
- // MaxInsertLength. (See DeflateFast)
-
- internal int MaxLazy; // do not perform lazy search above this match length
-
- internal int NiceLength; // quit search above this match length
-
- // To speed up deflation, hash chains are never searched beyond this
- // length. A higher limit improves compression ratio but degrades the speed.
-
- internal int MaxChainLength;
-
- internal DeflateFlavor Flavor;
-
- private Config(int goodLength, int maxLazy, int niceLength, int maxChainLength, DeflateFlavor flavor)
- {
- this.GoodLength = goodLength;
- this.MaxLazy = maxLazy;
- this.NiceLength = niceLength;
- this.MaxChainLength = maxChainLength;
- this.Flavor = flavor;
- }
-
- public static Config Lookup(CompressionLevel level)
- {
- return Table[(int)level];
- }
-
-
- static Config()
- {
- Table = new Config[] {
- new Config(0, 0, 0, 0, DeflateFlavor.Store),
- new Config(4, 4, 8, 4, DeflateFlavor.Fast),
- new Config(4, 5, 16, 8, DeflateFlavor.Fast),
- new Config(4, 6, 32, 32, DeflateFlavor.Fast),
-
- new Config(4, 4, 16, 16, DeflateFlavor.Slow),
- new Config(8, 16, 32, 32, DeflateFlavor.Slow),
- new Config(8, 16, 128, 128, DeflateFlavor.Slow),
- new Config(8, 32, 128, 256, DeflateFlavor.Slow),
- new Config(32, 128, 258, 1024, DeflateFlavor.Slow),
- new Config(32, 258, 258, 4096, DeflateFlavor.Slow),
- };
- }
-
- private static readonly Config[] Table;
- }
-
-
- private CompressFunc DeflateFunction;
-
- private static readonly System.String[] _ErrorMessage = new System.String[]
- {
- "need dictionary",
- "stream end",
- "",
- "file error",
- "stream error",
- "data error",
- "insufficient memory",
- "buffer error",
- "incompatible version",
- ""
- };
-
- // preset dictionary flag in zlib header
- private static readonly int PRESET_DICT = 0x20;
-
- private static readonly int INIT_STATE = 42;
- private static readonly int BUSY_STATE = 113;
- private static readonly int FINISH_STATE = 666;
-
- // The deflate compression method
- private static readonly int Z_DEFLATED = 8;
-
- private static readonly int STORED_BLOCK = 0;
- private static readonly int STATIC_TREES = 1;
- private static readonly int DYN_TREES = 2;
-
- // The three kinds of block type
- private static readonly int Z_BINARY = 0;
- private static readonly int Z_ASCII = 1;
- private static readonly int Z_UNKNOWN = 2;
-
- private static readonly int Buf_size = 8 * 2;
-
- private static readonly int MIN_MATCH = 3;
- private static readonly int MAX_MATCH = 258;
-
- private static readonly int MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
-
- private static readonly int HEAP_SIZE = (2 * InternalConstants.L_CODES + 1);
-
- private static readonly int END_BLOCK = 256;
-
- internal ZlibCodec _codec; // the zlib encoder/decoder
- internal int status; // as the name implies
- internal byte[] pending; // output still pending - waiting to be compressed
- internal int nextPending; // index of next pending byte to output to the stream
- internal int pendingCount; // number of bytes in the pending buffer
-
- internal sbyte data_type; // UNKNOWN, BINARY or ASCII
- internal int last_flush; // value of flush param for previous deflate call
-
- internal int w_size; // LZ77 window size (32K by default)
- internal int w_bits; // log2(w_size) (8..16)
- internal int w_mask; // w_size - 1
-
- //internal byte[] dictionary;
- internal byte[] window;
-
- // Sliding window. Input bytes are read into the second half of the window,
- // and move to the first half later to keep a dictionary of at least wSize
- // bytes. With this organization, matches are limited to a distance of
- // wSize-MAX_MATCH bytes, but this ensures that IO is always
- // performed with a length multiple of the block size.
- //
- // To do: use the user input buffer as sliding window.
-
- internal int window_size;
- // Actual size of window: 2*wSize, except when the user input buffer
- // is directly used as sliding window.
-
- internal short[] prev;
- // Link to older string with same hash index. To limit the size of this
- // array to 64K, this link is maintained only for the last 32K strings.
- // An index in this array is thus a window index modulo 32K.
-
- internal short[] head; // Heads of the hash chains or NIL.
-
- internal int ins_h; // hash index of string to be inserted
- internal int hash_size; // number of elements in hash table
- internal int hash_bits; // log2(hash_size)
- internal int hash_mask; // hash_size-1
-
- // Number of bits by which ins_h must be shifted at each input
- // step. It must be such that after MIN_MATCH steps, the oldest
- // byte no longer takes part in the hash key, that is:
- // hash_shift * MIN_MATCH >= hash_bits
- internal int hash_shift;
-
- // Window position at the beginning of the current output block. Gets
- // negative when the window is moved backwards.
-
- internal int block_start;
-
- Config config;
- internal int match_length; // length of best match
- internal int prev_match; // previous match
- internal int match_available; // set if previous match exists
- internal int strstart; // start of string to insert into.....????
- internal int match_start; // start of matching string
- internal int lookahead; // number of valid bytes ahead in window
-
- // Length of the best match at previous step. Matches not greater than this
- // are discarded. This is used in the lazy match evaluation.
- internal int prev_length;
-
- // Insert new strings in the hash table only if the match length is not
- // greater than this length. This saves time but degrades compression.
- // max_insert_length is used only for compression levels <= 3.
-
- internal CompressionLevel compressionLevel; // compression level (1..9)
- internal CompressionStrategy compressionStrategy; // favor or force Huffman coding
-
-
- internal short[] dyn_ltree; // literal and length tree
- internal short[] dyn_dtree; // distance tree
- internal short[] bl_tree; // Huffman tree for bit lengths
-
- internal Tree treeLiterals = new Tree(); // desc for literal tree
- internal Tree treeDistances = new Tree(); // desc for distance tree
- internal Tree treeBitLengths = new Tree(); // desc for bit length tree
-
- // number of codes at each bit length for an optimal tree
- internal short[] bl_count = new short[InternalConstants.MAX_BITS + 1];
-
- // heap used to build the Huffman trees
- internal int[] heap = new int[2 * InternalConstants.L_CODES + 1];
-
- internal int heap_len; // number of elements in the heap
- internal int heap_max; // element of largest frequency
-
- // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
- // The same heap array is used to build all trees.
-
- // Depth of each subtree used as tie breaker for trees of equal frequency
- internal sbyte[] depth = new sbyte[2 * InternalConstants.L_CODES + 1];
-
- internal int _lengthOffset; // index for literals or lengths
-
-
- // Size of match buffer for literals/lengths. There are 4 reasons for
- // limiting lit_bufsize to 64K:
- // - frequencies can be kept in 16 bit counters
- // - if compression is not successful for the first block, all input
- // data is still in the window so we can still emit a stored block even
- // when input comes from standard input. (This can also be done for
- // all blocks if lit_bufsize is not greater than 32K.)
- // - if compression is not successful for a file smaller than 64K, we can
- // even emit a stored file instead of a stored block (saving 5 bytes).
- // This is applicable only for zip (not gzip or zlib).
- // - creating new Huffman trees less frequently may not provide fast
- // adaptation to changes in the input data statistics. (Take for
- // example a binary file with poorly compressible code followed by
- // a highly compressible string table.) Smaller buffer sizes give
- // fast adaptation but have of course the overhead of transmitting
- // trees more frequently.
-
- internal int lit_bufsize;
-
- internal int last_lit; // running index in l_buf
-
- // Buffer for distances. To simplify the code, d_buf and l_buf have
- // the same number of elements. To use different lengths, an extra flag
- // array would be necessary.
-
- internal int _distanceOffset; // index into pending; points to distance data??
-
- internal int opt_len; // bit length of current block with optimal trees
- internal int static_len; // bit length of current block with static trees
- internal int matches; // number of string matches in current block
- internal int last_eob_len; // bit length of EOB code for last block
-
- // Output buffer. bits are inserted starting at the bottom (least
- // significant bits).
- internal short bi_buf;
-
- // Number of valid bits in bi_buf. All bits above the last valid bit
- // are always zero.
- internal int bi_valid;
-
-
- internal DeflateManager()
- {
- dyn_ltree = new short[HEAP_SIZE * 2];
- dyn_dtree = new short[(2 * InternalConstants.D_CODES + 1) * 2]; // distance tree
- bl_tree = new short[(2 * InternalConstants.BL_CODES + 1) * 2]; // Huffman tree for bit lengths
- }
-
-
- // lm_init
- private void _InitializeLazyMatch()
- {
- window_size = 2 * w_size;
-
- // clear the hash - workitem 9063
- Array.Clear(head, 0, hash_size);
- //for (int i = 0; i < hash_size; i++) head[i] = 0;
-
- config = Config.Lookup(compressionLevel);
- SetDeflater();
-
- strstart = 0;
- block_start = 0;
- lookahead = 0;
- match_length = prev_length = MIN_MATCH - 1;
- match_available = 0;
- ins_h = 0;
- }
-
- // Initialize the tree data structures for a new zlib stream.
- private void _InitializeTreeData()
- {
- treeLiterals.dyn_tree = dyn_ltree;
- treeLiterals.staticTree = StaticTree.Literals;
-
- treeDistances.dyn_tree = dyn_dtree;
- treeDistances.staticTree = StaticTree.Distances;
-
- treeBitLengths.dyn_tree = bl_tree;
- treeBitLengths.staticTree = StaticTree.BitLengths;
-
- bi_buf = 0;
- bi_valid = 0;
- last_eob_len = 8; // enough lookahead for inflate
-
- // Initialize the first block of the first file:
- _InitializeBlocks();
- }
-
- internal void _InitializeBlocks()
- {
- // Initialize the trees.
- for (int i = 0; i < InternalConstants.L_CODES; i++)
- dyn_ltree[i * 2] = 0;
- for (int i = 0; i < InternalConstants.D_CODES; i++)
- dyn_dtree[i * 2] = 0;
- for (int i = 0; i < InternalConstants.BL_CODES; i++)
- bl_tree[i * 2] = 0;
-
- dyn_ltree[END_BLOCK * 2] = 1;
- opt_len = static_len = 0;
- last_lit = matches = 0;
- }
-
- // Restore the heap property by moving down the tree starting at node k,
- // exchanging a node with the smallest of its two sons if necessary, stopping
- // when the heap property is re-established (each father smaller than its
- // two sons).
- internal void pqdownheap(short[] tree, int k)
- {
- int v = heap[k];
- int j = k << 1; // left son of k
- while (j <= heap_len)
- {
- // Set j to the smallest of the two sons:
- if (j < heap_len && _IsSmaller(tree, heap[j + 1], heap[j], depth))
- {
- j++;
- }
- // Exit if v is smaller than both sons
- if (_IsSmaller(tree, v, heap[j], depth))
- break;
-
- // Exchange v with the smallest son
- heap[k] = heap[j]; k = j;
- // And continue down the tree, setting j to the left son of k
- j <<= 1;
- }
- heap[k] = v;
- }
-
- internal static bool _IsSmaller(short[] tree, int n, int m, sbyte[] depth)
- {
- short tn2 = tree[n * 2];
- short tm2 = tree[m * 2];
- return (tn2 < tm2 || (tn2 == tm2 && depth[n] <= depth[m]));
- }
-
-
- // Scan a literal or distance tree to determine the frequencies of the codes
- // in the bit length tree.
- internal void scan_tree(short[] tree, int max_code)
- {
- int n; // iterates over all tree elements
- int prevlen = -1; // last emitted length
- int curlen; // length of current code
- int nextlen = (int)tree[0 * 2 + 1]; // length of next code
- int count = 0; // repeat count of the current code
- int max_count = 7; // max repeat count
- int min_count = 4; // min repeat count
-
- if (nextlen == 0)
- {
- max_count = 138; min_count = 3;
- }
- tree[(max_code + 1) * 2 + 1] = (short)0x7fff; // guard //??
-
- for (n = 0; n <= max_code; n++)
- {
- curlen = nextlen; nextlen = (int)tree[(n + 1) * 2 + 1];
- if (++count < max_count && curlen == nextlen)
- {
- continue;
- }
- else if (count < min_count)
- {
- bl_tree[curlen * 2] = (short)(bl_tree[curlen * 2] + count);
- }
- else if (curlen != 0)
- {
- if (curlen != prevlen)
- bl_tree[curlen * 2]++;
- bl_tree[InternalConstants.REP_3_6 * 2]++;
- }
- else if (count <= 10)
- {
- bl_tree[InternalConstants.REPZ_3_10 * 2]++;
- }
- else
- {
- bl_tree[InternalConstants.REPZ_11_138 * 2]++;
- }
- count = 0; prevlen = curlen;
- if (nextlen == 0)
- {
- max_count = 138; min_count = 3;
- }
- else if (curlen == nextlen)
- {
- max_count = 6; min_count = 3;
- }
- else
- {
- max_count = 7; min_count = 4;
- }
- }
- }
-
- // Construct the Huffman tree for the bit lengths and return the index in
- // bl_order of the last bit length code to send.
- internal int build_bl_tree()
- {
- int max_blindex; // index of last bit length code of non zero freq
-
- // Determine the bit length frequencies for literal and distance trees
- scan_tree(dyn_ltree, treeLiterals.max_code);
- scan_tree(dyn_dtree, treeDistances.max_code);
-
- // Build the bit length tree:
- treeBitLengths.build_tree(this);
- // opt_len now includes the length of the tree representations, except
- // the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
-
- // Determine the number of bit length codes to send. The pkzip format
- // requires that at least 4 bit length codes be sent. (appnote.txt says
- // 3 but the actual value used is 4.)
- for (max_blindex = InternalConstants.BL_CODES - 1; max_blindex >= 3; max_blindex--)
- {
- if (bl_tree[Tree.bl_order[max_blindex] * 2 + 1] != 0)
- break;
- }
- // Update opt_len to include the bit length tree and counts
- opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
-
- return max_blindex;
- }
-
-
- // Send the header for a block using dynamic Huffman trees: the counts, the
- // lengths of the bit length codes, the literal tree and the distance tree.
- // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
- internal void send_all_trees(int lcodes, int dcodes, int blcodes)
- {
- int rank; // index in bl_order
-
- send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt
- send_bits(dcodes - 1, 5);
- send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt
- for (rank = 0; rank < blcodes; rank++)
- {
- send_bits(bl_tree[Tree.bl_order[rank] * 2 + 1], 3);
- }
- send_tree(dyn_ltree, lcodes - 1); // literal tree
- send_tree(dyn_dtree, dcodes - 1); // distance tree
- }
-
- // Send a literal or distance tree in compressed form, using the codes in
- // bl_tree.
- internal void send_tree(short[] tree, int max_code)
- {
- int n; // iterates over all tree elements
- int prevlen = -1; // last emitted length
- int curlen; // length of current code
- int nextlen = tree[0 * 2 + 1]; // length of next code
- int count = 0; // repeat count of the current code
- int max_count = 7; // max repeat count
- int min_count = 4; // min repeat count
-
- if (nextlen == 0)
- {
- max_count = 138; min_count = 3;
- }
-
- for (n = 0; n <= max_code; n++)
- {
- curlen = nextlen; nextlen = tree[(n + 1) * 2 + 1];
- if (++count < max_count && curlen == nextlen)
- {
- continue;
- }
- else if (count < min_count)
- {
- do
- {
- send_code(curlen, bl_tree);
- }
- while (--count != 0);
- }
- else if (curlen != 0)
- {
- if (curlen != prevlen)
- {
- send_code(curlen, bl_tree); count--;
- }
- send_code(InternalConstants.REP_3_6, bl_tree);
- send_bits(count - 3, 2);
- }
- else if (count <= 10)
- {
- send_code(InternalConstants.REPZ_3_10, bl_tree);
- send_bits(count - 3, 3);
- }
- else
- {
- send_code(InternalConstants.REPZ_11_138, bl_tree);
- send_bits(count - 11, 7);
- }
- count = 0; prevlen = curlen;
- if (nextlen == 0)
- {
- max_count = 138; min_count = 3;
- }
- else if (curlen == nextlen)
- {
- max_count = 6; min_count = 3;
- }
- else
- {
- max_count = 7; min_count = 4;
- }
- }
- }
-
- // Output a block of bytes on the stream.
- // IN assertion: there is enough room in pending_buf.
- private void put_bytes(byte[] p, int start, int len)
- {
- Array.Copy(p, start, pending, pendingCount, len);
- pendingCount += len;
- }
-
-#if NOTNEEDED
- private void put_byte(byte c)
- {
- pending[pendingCount++] = c;
- }
- internal void put_short(int b)
- {
- unchecked
- {
- pending[pendingCount++] = (byte)b;
- pending[pendingCount++] = (byte)(b >> 8);
- }
- }
- internal void putShortMSB(int b)
- {
- unchecked
- {
- pending[pendingCount++] = (byte)(b >> 8);
- pending[pendingCount++] = (byte)b;
- }
- }
-#endif
-
- internal void send_code(int c, short[] tree)
- {
- int c2 = c * 2;
- send_bits((tree[c2] & 0xffff), (tree[c2 + 1] & 0xffff));
- }
-
- internal void send_bits(int value, int length)
- {
- int len = length;
- unchecked
- {
- if (bi_valid > (int)Buf_size - len)
- {
- //int val = value;
- // bi_buf |= (val << bi_valid);
-
- bi_buf |= (short)((value << bi_valid) & 0xffff);
- //put_short(bi_buf);
- pending[pendingCount++] = (byte)bi_buf;
- pending[pendingCount++] = (byte)(bi_buf >> 8);
-
-
- bi_buf = (short)((uint)value >> (Buf_size - bi_valid));
- bi_valid += len - Buf_size;
- }
- else
- {
- // bi_buf |= (value) << bi_valid;
- bi_buf |= (short)((value << bi_valid) & 0xffff);
- bi_valid += len;
- }
- }
- }
-
- // Send one empty static block to give enough lookahead for inflate.
- // This takes 10 bits, of which 7 may remain in the bit buffer.
- // The current inflate code requires 9 bits of lookahead. If the
- // last two codes for the previous block (real code plus EOB) were coded
- // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
- // the last real code. In this case we send two empty static blocks instead
- // of one. (There are no problems if the previous block is stored or fixed.)
- // To simplify the code, we assume the worst case of last real code encoded
- // on one bit only.
- internal void _tr_align()
- {
- send_bits(STATIC_TREES << 1, 3);
- send_code(END_BLOCK, StaticTree.lengthAndLiteralsTreeCodes);
-
- bi_flush();
-
- // Of the 10 bits for the empty block, we have already sent
- // (10 - bi_valid) bits. The lookahead for the last real code (before
- // the EOB of the previous block) was thus at least one plus the length
- // of the EOB plus what we have just sent of the empty static block.
- if (1 + last_eob_len + 10 - bi_valid < 9)
- {
- send_bits(STATIC_TREES << 1, 3);
- send_code(END_BLOCK, StaticTree.lengthAndLiteralsTreeCodes);
- bi_flush();
- }
- last_eob_len = 7;
- }
-
-
- // Save the match info and tally the frequency counts. Return true if
- // the current block must be flushed.
- internal bool _tr_tally(int dist, int lc)
- {
- pending[_distanceOffset + last_lit * 2] = unchecked((byte) ( (uint)dist >> 8 ) );
- pending[_distanceOffset + last_lit * 2 + 1] = unchecked((byte)dist);
- pending[_lengthOffset + last_lit] = unchecked((byte)lc);
- last_lit++;
-
- if (dist == 0)
- {
- // lc is the unmatched char
- dyn_ltree[lc * 2]++;
- }
- else
- {
- matches++;
- // Here, lc is the match length - MIN_MATCH
- dist--; // dist = match distance - 1
- dyn_ltree[(Tree.LengthCode[lc] + InternalConstants.LITERALS + 1) * 2]++;
- dyn_dtree[Tree.DistanceCode(dist) * 2]++;
- }
-
- if ((last_lit & 0x1fff) == 0 && (int)compressionLevel > 2)
- {
- // Compute an upper bound for the compressed length
- int out_length = last_lit << 3;
- int in_length = strstart - block_start;
- int dcode;
- for (dcode = 0; dcode < InternalConstants.D_CODES; dcode++)
- {
- out_length = (int)(out_length + (int)dyn_dtree[dcode * 2] * (5L + Tree.ExtraDistanceBits[dcode]));
- }
- out_length >>= 3;
- if ((matches < (last_lit / 2)) && out_length < in_length / 2)
- return true;
- }
-
- return (last_lit == lit_bufsize - 1) || (last_lit == lit_bufsize);
- // dinoch - wraparound?
- // We avoid equality with lit_bufsize because of wraparound at 64K
- // on 16 bit machines and because stored blocks are restricted to
- // 64K-1 bytes.
- }
-
-
-
- // Send the block data compressed using the given Huffman trees
- internal void send_compressed_block(short[] ltree, short[] dtree)
- {
- int distance; // distance of matched string
- int lc; // match length or unmatched char (if dist == 0)
- int lx = 0; // running index in l_buf
- int code; // the code to send
- int extra; // number of extra bits to send
-
- if (last_lit != 0)
- {
- do
- {
- int ix = _distanceOffset + lx * 2;
- distance = ((pending[ix] << 8) & 0xff00) |
- (pending[ix + 1] & 0xff);
- lc = (pending[_lengthOffset + lx]) & 0xff;
- lx++;
-
- if (distance == 0)
- {
- send_code(lc, ltree); // send a literal byte
- }
- else
- {
- // literal or match pair
- // Here, lc is the match length - MIN_MATCH
- code = Tree.LengthCode[lc];
-
- // send the length code
- send_code(code + InternalConstants.LITERALS + 1, ltree);
- extra = Tree.ExtraLengthBits[code];
- if (extra != 0)
- {
- // send the extra length bits
- lc -= Tree.LengthBase[code];
- send_bits(lc, extra);
- }
- distance--; // dist is now the match distance - 1
- code = Tree.DistanceCode(distance);
-
- // send the distance code
- send_code(code, dtree);
-
- extra = Tree.ExtraDistanceBits[code];
- if (extra != 0)
- {
- // send the extra distance bits
- distance -= Tree.DistanceBase[code];
- send_bits(distance, extra);
- }
- }
-
- // Check that the overlay between pending and d_buf+l_buf is ok:
- }
- while (lx < last_lit);
- }
-
- send_code(END_BLOCK, ltree);
- last_eob_len = ltree[END_BLOCK * 2 + 1];
- }
-
-
-
- // Set the data type to ASCII or BINARY, using a crude approximation:
- // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
- // IN assertion: the fields freq of dyn_ltree are set and the total of all
- // frequencies does not exceed 64K (to fit in an int on 16 bit machines).
- internal void set_data_type()
- {
- int n = 0;
- int ascii_freq = 0;
- int bin_freq = 0;
- while (n < 7)
- {
- bin_freq += dyn_ltree[n * 2]; n++;
- }
- while (n < 128)
- {
- ascii_freq += dyn_ltree[n * 2]; n++;
- }
- while (n < InternalConstants.LITERALS)
- {
- bin_freq += dyn_ltree[n * 2]; n++;
- }
- data_type = (sbyte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
- }
-
-
-
- // Flush the bit buffer, keeping at most 7 bits in it.
- internal void bi_flush()
- {
- if (bi_valid == 16)
- {
- pending[pendingCount++] = (byte)bi_buf;
- pending[pendingCount++] = (byte)(bi_buf >> 8);
- bi_buf = 0;
- bi_valid = 0;
- }
- else if (bi_valid >= 8)
- {
- //put_byte((byte)bi_buf);
- pending[pendingCount++] = (byte)bi_buf;
- bi_buf >>= 8;
- bi_valid -= 8;
- }
- }
-
- // Flush the bit buffer and align the output on a byte boundary
- internal void bi_windup()
- {
- if (bi_valid > 8)
- {
- pending[pendingCount++] = (byte)bi_buf;
- pending[pendingCount++] = (byte)(bi_buf >> 8);
- }
- else if (bi_valid > 0)
- {
- //put_byte((byte)bi_buf);
- pending[pendingCount++] = (byte)bi_buf;
- }
- bi_buf = 0;
- bi_valid = 0;
- }
-
- // Copy a stored block, storing first the length and its
- // one's complement if requested.
- internal void copy_block(int buf, int len, bool header)
- {
- bi_windup(); // align on byte boundary
- last_eob_len = 8; // enough lookahead for inflate
-
- if (header)
- unchecked
- {
- //put_short((short)len);
- pending[pendingCount++] = (byte)len;
- pending[pendingCount++] = (byte)(len >> 8);
- //put_short((short)~len);
- pending[pendingCount++] = (byte)~len;
- pending[pendingCount++] = (byte)(~len >> 8);
- }
-
- put_bytes(window, buf, len);
- }
-
- internal void flush_block_only(bool eof)
- {
- _tr_flush_block(block_start >= 0 ? block_start : -1, strstart - block_start, eof);
- block_start = strstart;
- _codec.flush_pending();
- }
-
- // Copy without compression as much as possible from the input stream, return
- // the current block state.
- // This function does not insert new strings in the dictionary since
- // uncompressible data is probably not useful. This function is used
- // only for the level=0 compression option.
- // NOTE: this function should be optimized to avoid extra copying from
- // window to pending_buf.
- internal BlockState DeflateNone(FlushType flush)
- {
- // Stored blocks are limited to 0xffff bytes, pending is limited
- // to pending_buf_size, and each stored block has a 5 byte header:
-
- int max_block_size = 0xffff;
- int max_start;
-
- if (max_block_size > pending.Length - 5)
- {
- max_block_size = pending.Length - 5;
- }
-
- // Copy as much as possible from input to output:
- while (true)
- {
- // Fill the window as much as possible:
- if (lookahead <= 1)
- {
- _fillWindow();
- if (lookahead == 0 && flush == FlushType.None)
- return BlockState.NeedMore;
- if (lookahead == 0)
- break; // flush the current block
- }
-
- strstart += lookahead;
- lookahead = 0;
-
- // Emit a stored block if pending will be full:
- max_start = block_start + max_block_size;
- if (strstart == 0 || strstart >= max_start)
- {
- // strstart == 0 is possible when wraparound on 16-bit machine
- lookahead = (int)(strstart - max_start);
- strstart = (int)max_start;
-
- flush_block_only(false);
- if (_codec.AvailableBytesOut == 0)
- return BlockState.NeedMore;
- }
-
- // Flush if we may have to slide, otherwise block_start may become
- // negative and the data will be gone:
- if (strstart - block_start >= w_size - MIN_LOOKAHEAD)
- {
- flush_block_only(false);
- if (_codec.AvailableBytesOut == 0)
- return BlockState.NeedMore;
- }
- }
-
- flush_block_only(flush == FlushType.Finish);
- if (_codec.AvailableBytesOut == 0)
- return (flush == FlushType.Finish) ? BlockState.FinishStarted : BlockState.NeedMore;
-
- return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone;
- }
-
-
- // Send a stored block
- internal void _tr_stored_block(int buf, int stored_len, bool eof)
- {
- send_bits((STORED_BLOCK << 1) + (eof ? 1 : 0), 3); // send block type
- copy_block(buf, stored_len, true); // with header
- }
-
- // Determine the best encoding for the current block: dynamic trees, static
- // trees or store, and output the encoded block to the zip file.
- internal void _tr_flush_block(int buf, int stored_len, bool eof)
- {
- int opt_lenb, static_lenb; // opt_len and static_len in bytes
- int max_blindex = 0; // index of last bit length code of non zero freq
-
- // Build the Huffman trees unless a stored block is forced
- if (compressionLevel > 0)
- {
- // Check if the file is ascii or binary
- if (data_type == Z_UNKNOWN)
- set_data_type();
-
- // Construct the literal and distance trees
- treeLiterals.build_tree(this);
-
- treeDistances.build_tree(this);
-
- // At this point, opt_len and static_len are the total bit lengths of
- // the compressed block data, excluding the tree representations.
-
- // Build the bit length tree for the above two trees, and get the index
- // in bl_order of the last bit length code to send.
- max_blindex = build_bl_tree();
-
- // Determine the best encoding. Compute first the block length in bytes
- opt_lenb = (opt_len + 3 + 7) >> 3;
- static_lenb = (static_len + 3 + 7) >> 3;
-
- if (static_lenb <= opt_lenb)
- opt_lenb = static_lenb;
- }
- else
- {
- opt_lenb = static_lenb = stored_len + 5; // force a stored block
- }
-
- if (stored_len + 4 <= opt_lenb && buf != -1)
- {
- // 4: two words for the lengths
- // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
- // Otherwise we can't have processed more than WSIZE input bytes since
- // the last block flush, because compression would have been
- // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
- // transform a block into a stored block.
- _tr_stored_block(buf, stored_len, eof);
- }
- else if (static_lenb == opt_lenb)
- {
- send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3);
- send_compressed_block(StaticTree.lengthAndLiteralsTreeCodes, StaticTree.distTreeCodes);
- }
- else
- {
- send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3);
- send_all_trees(treeLiterals.max_code + 1, treeDistances.max_code + 1, max_blindex + 1);
- send_compressed_block(dyn_ltree, dyn_dtree);
- }
-
- // The above check is made mod 2^32, for files larger than 512 MB
- // and uLong implemented on 32 bits.
-
- _InitializeBlocks();
-
- if (eof)
- {
- bi_windup();
- }
- }
-
- // Fill the window when the lookahead becomes insufficient.
- // Updates strstart and lookahead.
- //
- // IN assertion: lookahead < MIN_LOOKAHEAD
- // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
- // At least one byte has been read, or avail_in == 0; reads are
- // performed for at least two bytes (required for the zip translate_eol
- // option -- not supported here).
- private void _fillWindow()
- {
- int n, m;
- int p;
- int more; // Amount of free space at the end of the window.
-
- do
- {
- more = (window_size - lookahead - strstart);
-
- // Deal with !@#$% 64K limit:
- if (more == 0 && strstart == 0 && lookahead == 0)
- {
- more = w_size;
- }
- else if (more == -1)
- {
- // Very unlikely, but possible on 16 bit machine if strstart == 0
- // and lookahead == 1 (input done one byte at time)
- more--;
-
- // If the window is almost full and there is insufficient lookahead,
- // move the upper half to the lower one to make room in the upper half.
- }
- else if (strstart >= w_size + w_size - MIN_LOOKAHEAD)
- {
- Array.Copy(window, w_size, window, 0, w_size);
- match_start -= w_size;
- strstart -= w_size; // we now have strstart >= MAX_DIST
- block_start -= w_size;
-
- // Slide the hash table (could be avoided with 32 bit values
- // at the expense of memory usage). We slide even when level == 0
- // to keep the hash table consistent if we switch back to level > 0
- // later. (Using level 0 permanently is not an optimal usage of
- // zlib, so we don't care about this pathological case.)
-
- n = hash_size;
- p = n;
- do
- {
- m = (head[--p] & 0xffff);
- head[p] = (short)((m >= w_size) ? (m - w_size) : 0);
- }
- while (--n != 0);
-
- n = w_size;
- p = n;
- do
- {
- m = (prev[--p] & 0xffff);
- prev[p] = (short)((m >= w_size) ? (m - w_size) : 0);
- // If n is not on any hash chain, prev[n] is garbage but
- // its value will never be used.
- }
- while (--n != 0);
- more += w_size;
- }
-
- if (_codec.AvailableBytesIn == 0)
- return;
-
- // If there was no sliding:
- // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
- // more == window_size - lookahead - strstart
- // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
- // => more >= window_size - 2*WSIZE + 2
- // In the BIG_MEM or MMAP case (not yet supported),
- // window_size == input_size + MIN_LOOKAHEAD &&
- // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
- // Otherwise, window_size == 2*WSIZE so more >= 2.
- // If there was sliding, more >= WSIZE. So in all cases, more >= 2.
-
- n = _codec.read_buf(window, strstart + lookahead, more);
- lookahead += n;
-
- // Initialize the hash value now that we have some input:
- if (lookahead >= MIN_MATCH)
- {
- ins_h = window[strstart] & 0xff;
- ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask;
- }
- // If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
- // but this is not important since only literal bytes will be emitted.
- }
- while (lookahead < MIN_LOOKAHEAD && _codec.AvailableBytesIn != 0);
- }
-
- // Compress as much as possible from the input stream, return the current
- // block state.
- // This function does not perform lazy evaluation of matches and inserts
- // new strings in the dictionary only for unmatched strings or for short
- // matches. It is used only for the fast compression options.
- internal BlockState DeflateFast(FlushType flush)
- {
- // short hash_head = 0; // head of the hash chain
- int hash_head = 0; // head of the hash chain
- bool bflush; // set if current block must be flushed
-
- while (true)
- {
- // Make sure that we always have enough lookahead, except
- // at the end of the input file. We need MAX_MATCH bytes
- // for the next match, plus MIN_MATCH bytes to insert the
- // string following the next match.
- if (lookahead < MIN_LOOKAHEAD)
- {
- _fillWindow();
- if (lookahead < MIN_LOOKAHEAD && flush == FlushType.None)
- {
- return BlockState.NeedMore;
- }
- if (lookahead == 0)
- break; // flush the current block
- }
-
- // Insert the string window[strstart .. strstart+2] in the
- // dictionary, and set hash_head to the head of the hash chain:
- if (lookahead >= MIN_MATCH)
- {
- ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
-
- // prev[strstart&w_mask]=hash_head=head[ins_h];
- hash_head = (head[ins_h] & 0xffff);
- prev[strstart & w_mask] = head[ins_h];
- head[ins_h] = unchecked((short)strstart);
- }
-
- // Find the longest match, discarding those <= prev_length.
- // At this point we have always match_length < MIN_MATCH
-
- if (hash_head != 0L && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD)
- {
- // To simplify the code, we prevent matches with the string
- // of window index 0 (in particular we have to avoid a match
- // of the string with itself at the start of the input file).
- if (compressionStrategy != CompressionStrategy.HuffmanOnly)
- {
- match_length = longest_match(hash_head);
- }
- // longest_match() sets match_start
- }
- if (match_length >= MIN_MATCH)
- {
- // check_match(strstart, match_start, match_length);
-
- bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH);
-
- lookahead -= match_length;
-
- // Insert new strings in the hash table only if the match length
- // is not too large. This saves time but degrades compression.
- if (match_length <= config.MaxLazy && lookahead >= MIN_MATCH)
- {
- match_length--; // string at strstart already in hash table
- do
- {
- strstart++;
-
- ins_h = ((ins_h << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
- // prev[strstart&w_mask]=hash_head=head[ins_h];
- hash_head = (head[ins_h] & 0xffff);
- prev[strstart & w_mask] = head[ins_h];
- head[ins_h] = unchecked((short)strstart);
-
- // strstart never exceeds WSIZE-MAX_MATCH, so there are
- // always MIN_MATCH bytes ahead.
- }
- while (--match_length != 0);
- strstart++;
- }
- else
- {
- strstart += match_length;
- match_length = 0;
- ins_h = window[strstart] & 0xff;
-
- ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask;
- // If lookahead < MIN_MATCH, ins_h is garbage, but it does not
- // matter since it will be recomputed at next deflate call.
- }
- }
- else
- {
- // No match, output a literal byte
-
- bflush = _tr_tally(0, window[strstart] & 0xff);
- lookahead--;
- strstart++;
- }
- if (bflush)
- {
- flush_block_only(false);
- if (_codec.AvailableBytesOut == 0)
- return BlockState.NeedMore;
- }
- }
-
- flush_block_only(flush == FlushType.Finish);
- if (_codec.AvailableBytesOut == 0)
- {
- if (flush == FlushType.Finish)
- return BlockState.FinishStarted;
- else
- return BlockState.NeedMore;
- }
- return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone;
- }
-
- // Same as above, but achieves better compression. We use a lazy
- // evaluation for matches: a match is finally adopted only if there is
- // no better match at the next window position.
- internal BlockState DeflateSlow(FlushType flush)
- {
- // short hash_head = 0; // head of hash chain
- int hash_head = 0; // head of hash chain
- bool bflush; // set if current block must be flushed
-
- // Process the input block.
- while (true)
- {
- // Make sure that we always have enough lookahead, except
- // at the end of the input file. We need MAX_MATCH bytes
- // for the next match, plus MIN_MATCH bytes to insert the
- // string following the next match.
-
- if (lookahead < MIN_LOOKAHEAD)
- {
- _fillWindow();
- if (lookahead < MIN_LOOKAHEAD && flush == FlushType.None)
- return BlockState.NeedMore;
-
- if (lookahead == 0)
- break; // flush the current block
- }
-
- // Insert the string window[strstart .. strstart+2] in the
- // dictionary, and set hash_head to the head of the hash chain:
-
- if (lookahead >= MIN_MATCH)
- {
- ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
- // prev[strstart&w_mask]=hash_head=head[ins_h];
- hash_head = (head[ins_h] & 0xffff);
- prev[strstart & w_mask] = head[ins_h];
- head[ins_h] = unchecked((short)strstart);
- }
-
- // Find the longest match, discarding those <= prev_length.
- prev_length = match_length;
- prev_match = match_start;
- match_length = MIN_MATCH - 1;
-
- if (hash_head != 0 && prev_length < config.MaxLazy &&
- ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD)
- {
- // To simplify the code, we prevent matches with the string
- // of window index 0 (in particular we have to avoid a match
- // of the string with itself at the start of the input file).
-
- if (compressionStrategy != CompressionStrategy.HuffmanOnly)
- {
- match_length = longest_match(hash_head);
- }
- // longest_match() sets match_start
-
- if (match_length <= 5 && (compressionStrategy == CompressionStrategy.Filtered ||
- (match_length == MIN_MATCH && strstart - match_start > 4096)))
- {
-
- // If prev_match is also MIN_MATCH, match_start is garbage
- // but we will ignore the current match anyway.
- match_length = MIN_MATCH - 1;
- }
- }
-
- // If there was a match at the previous step and the current
- // match is not better, output the previous match:
- if (prev_length >= MIN_MATCH && match_length <= prev_length)
- {
- int max_insert = strstart + lookahead - MIN_MATCH;
- // Do not insert strings in hash table beyond this.
-
- // check_match(strstart-1, prev_match, prev_length);
-
- bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH);
-
- // Insert in hash table all strings up to the end of the match.
- // strstart-1 and strstart are already inserted. If there is not
- // enough lookahead, the last two strings are not inserted in
- // the hash table.
- lookahead -= (prev_length - 1);
- prev_length -= 2;
- do
- {
- if (++strstart <= max_insert)
- {
- ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
- //prev[strstart&w_mask]=hash_head=head[ins_h];
- hash_head = (head[ins_h] & 0xffff);
- prev[strstart & w_mask] = head[ins_h];
- head[ins_h] = unchecked((short)strstart);
- }
- }
- while (--prev_length != 0);
- match_available = 0;
- match_length = MIN_MATCH - 1;
- strstart++;
-
- if (bflush)
- {
- flush_block_only(false);
- if (_codec.AvailableBytesOut == 0)
- return BlockState.NeedMore;
- }
- }
- else if (match_available != 0)
- {
-
- // If there was no match at the previous position, output a
- // single literal. If there was a match but the current match
- // is longer, truncate the previous match to a single literal.
-
- bflush = _tr_tally(0, window[strstart - 1] & 0xff);
-
- if (bflush)
- {
- flush_block_only(false);
- }
- strstart++;
- lookahead--;
- if (_codec.AvailableBytesOut == 0)
- return BlockState.NeedMore;
- }
- else
- {
- // There is no previous match to compare with, wait for
- // the next step to decide.
-
- match_available = 1;
- strstart++;
- lookahead--;
- }
- }
-
- if (match_available != 0)
- {
- bflush = _tr_tally(0, window[strstart - 1] & 0xff);
- match_available = 0;
- }
- flush_block_only(flush == FlushType.Finish);
-
- if (_codec.AvailableBytesOut == 0)
- {
- if (flush == FlushType.Finish)
- return BlockState.FinishStarted;
- else
- return BlockState.NeedMore;
- }
-
- return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone;
- }
-
-
- internal int longest_match(int cur_match)
- {
- int chain_length = config.MaxChainLength; // max hash chain length
- int scan = strstart; // current string
- int match; // matched string
- int len; // length of current match
- int best_len = prev_length; // best match length so far
- int limit = strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0;
-
- int niceLength = config.NiceLength;
-
- // Stop when cur_match becomes <= limit. To simplify the code,
- // we prevent matches with the string of window index 0.
-
- int wmask = w_mask;
-
- int strend = strstart + MAX_MATCH;
- byte scan_end1 = window[scan + best_len - 1];
- byte scan_end = window[scan + best_len];
-
- // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
- // It is easy to get rid of this optimization if necessary.
-
- // Do not waste too much time if we already have a good match:
- if (prev_length >= config.GoodLength)
- {
- chain_length >>= 2;
- }
-
- // Do not look for matches beyond the end of the input. This is necessary
- // to make deflate deterministic.
- if (niceLength > lookahead)
- niceLength = lookahead;
-
- do
- {
- match = cur_match;
-
- // Skip to next match if the match length cannot increase
- // or if the match length is less than 2:
- if (window[match + best_len] != scan_end ||
- window[match + best_len - 1] != scan_end1 ||
- window[match] != window[scan] ||
- window[++match] != window[scan + 1])
- continue;
-
- // The check at best_len-1 can be removed because it will be made
- // again later. (This heuristic is not always a win.)
- // It is not necessary to compare scan[2] and match[2] since they
- // are always equal when the other bytes match, given that
- // the hash keys are equal and that HASH_BITS >= 8.
- scan += 2; match++;
-
- // We check for insufficient lookahead only every 8th comparison;
- // the 256th check will be made at strstart+258.
- do
- {
- }
- while (window[++scan] == window[++match] &&
- window[++scan] == window[++match] &&
- window[++scan] == window[++match] &&
- window[++scan] == window[++match] &&
- window[++scan] == window[++match] &&
- window[++scan] == window[++match] &&
- window[++scan] == window[++match] &&
- window[++scan] == window[++match] && scan < strend);
-
- len = MAX_MATCH - (int)(strend - scan);
- scan = strend - MAX_MATCH;
-
- if (len > best_len)
- {
- match_start = cur_match;
- best_len = len;
- if (len >= niceLength)
- break;
- scan_end1 = window[scan + best_len - 1];
- scan_end = window[scan + best_len];
- }
- }
- while ((cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length != 0);
-
- if (best_len <= lookahead)
- return best_len;
- return lookahead;
- }
-
-
- private bool Rfc1950BytesEmitted = false;
- private bool _WantRfc1950HeaderBytes = true;
- internal bool WantRfc1950HeaderBytes
- {
- get { return _WantRfc1950HeaderBytes; }
- set { _WantRfc1950HeaderBytes = value; }
- }
-
-
- internal int Initialize(ZlibCodec codec, CompressionLevel level)
- {
- return Initialize(codec, level, ZlibConstants.WindowBitsMax);
- }
-
- internal int Initialize(ZlibCodec codec, CompressionLevel level, int bits)
- {
- return Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, CompressionStrategy.Default);
- }
-
- internal int Initialize(ZlibCodec codec, CompressionLevel level, int bits, CompressionStrategy compressionStrategy)
- {
- return Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, compressionStrategy);
- }
-
- internal int Initialize(ZlibCodec codec, CompressionLevel level, int windowBits, int memLevel, CompressionStrategy strategy)
- {
- _codec = codec;
- _codec.Message = null;
-
- // validation
- if (windowBits < 9 || windowBits > 15)
- throw new ZlibException("windowBits must be in the range 9..15.");
-
- if (memLevel < 1 || memLevel > MEM_LEVEL_MAX)
- throw new ZlibException(String.Format("memLevel must be in the range 1.. {0}", MEM_LEVEL_MAX));
-
- _codec.dstate = this;
-
- w_bits = windowBits;
- w_size = 1 << w_bits;
- w_mask = w_size - 1;
-
- hash_bits = memLevel + 7;
- hash_size = 1 << hash_bits;
- hash_mask = hash_size - 1;
- hash_shift = ((hash_bits + MIN_MATCH - 1) / MIN_MATCH);
-
- window = new byte[w_size * 2];
- prev = new short[w_size];
- head = new short[hash_size];
-
- // for memLevel==8, this will be 16384, 16k
- lit_bufsize = 1 << (memLevel + 6);
-
- // Use a single array as the buffer for data pending compression,
- // the output distance codes, and the output length codes (aka tree).
- // orig comment: This works just fine since the average
- // output size for (length,distance) codes is <= 24 bits.
- pending = new byte[lit_bufsize * 4];
- _distanceOffset = lit_bufsize;
- _lengthOffset = (1 + 2) * lit_bufsize;
-
- // So, for memLevel 8, the length of the pending buffer is 65536. 64k.
- // The first 16k are pending bytes.
- // The middle slice, of 32k, is used for distance codes.
- // The final 16k are length codes.
-
- this.compressionLevel = level;
- this.compressionStrategy = strategy;
-
- Reset();
- return ZlibConstants.Z_OK;
- }
-
-
- internal void Reset()
- {
- _codec.TotalBytesIn = _codec.TotalBytesOut = 0;
- _codec.Message = null;
- //strm.data_type = Z_UNKNOWN;
-
- pendingCount = 0;
- nextPending = 0;
-
- Rfc1950BytesEmitted = false;
-
- status = (WantRfc1950HeaderBytes) ? INIT_STATE : BUSY_STATE;
- _codec._Adler32 = Adler.Adler32(0, null, 0, 0);
-
- last_flush = (int)FlushType.None;
-
- _InitializeTreeData();
- _InitializeLazyMatch();
- }
-
-
- internal int End()
- {
- if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE)
- {
- return ZlibConstants.Z_STREAM_ERROR;
- }
- // Deallocate in reverse order of allocations:
- pending = null;
- head = null;
- prev = null;
- window = null;
- // free
- // dstate=null;
- return status == BUSY_STATE ? ZlibConstants.Z_DATA_ERROR : ZlibConstants.Z_OK;
- }
-
-
- private void SetDeflater()
- {
- switch (config.Flavor)
- {
- case DeflateFlavor.Store:
- DeflateFunction = DeflateNone;
- break;
- case DeflateFlavor.Fast:
- DeflateFunction = DeflateFast;
- break;
- case DeflateFlavor.Slow:
- DeflateFunction = DeflateSlow;
- break;
- }
- }
-
-
- internal int SetParams(CompressionLevel level, CompressionStrategy strategy)
- {
- int result = ZlibConstants.Z_OK;
-
- if (compressionLevel != level)
- {
- Config newConfig = Config.Lookup(level);
-
- // change in the deflate flavor (Fast vs slow vs none)?
- if (newConfig.Flavor != config.Flavor && _codec.TotalBytesIn != 0)
- {
- // Flush the last buffer:
- result = _codec.Deflate(FlushType.Partial);
- }
-
- compressionLevel = level;
- config = newConfig;
- SetDeflater();
- }
-
- // no need to flush with change in strategy? Really?
- compressionStrategy = strategy;
-
- return result;
- }
-
-
- internal int SetDictionary(byte[] dictionary)
- {
- int length = dictionary.Length;
- int index = 0;
-
- if (dictionary == null || status != INIT_STATE)
- throw new ZlibException("Stream error.");
-
- _codec._Adler32 = Adler.Adler32(_codec._Adler32, dictionary, 0, dictionary.Length);
-
- if (length < MIN_MATCH)
- return ZlibConstants.Z_OK;
- if (length > w_size - MIN_LOOKAHEAD)
- {
- length = w_size - MIN_LOOKAHEAD;
- index = dictionary.Length - length; // use the tail of the dictionary
- }
- Array.Copy(dictionary, index, window, 0, length);
- strstart = length;
- block_start = length;
-
- // Insert all strings in the hash table (except for the last two bytes).
- // s->lookahead stays null, so s->ins_h will be recomputed at the next
- // call of fill_window.
-
- ins_h = window[0] & 0xff;
- ins_h = (((ins_h) << hash_shift) ^ (window[1] & 0xff)) & hash_mask;
-
- for (int n = 0; n <= length - MIN_MATCH; n++)
- {
- ins_h = (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
- prev[n & w_mask] = head[ins_h];
- head[ins_h] = (short)n;
- }
- return ZlibConstants.Z_OK;
- }
-
-
-
- internal int Deflate(FlushType flush)
- {
- int old_flush;
-
- if (_codec.OutputBuffer == null ||
- (_codec.InputBuffer == null && _codec.AvailableBytesIn != 0) ||
- (status == FINISH_STATE && flush != FlushType.Finish))
- {
- _codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_STREAM_ERROR)];
- throw new ZlibException(String.Format("Something is fishy. [{0}]", _codec.Message));
- }
- if (_codec.AvailableBytesOut == 0)
- {
- _codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)];
- throw new ZlibException("OutputBuffer is full (AvailableBytesOut == 0)");
- }
-
- old_flush = last_flush;
- last_flush = (int)flush;
-
- // Write the zlib (rfc1950) header bytes
- if (status == INIT_STATE)
- {
- int header = (Z_DEFLATED + ((w_bits - 8) << 4)) << 8;
- int level_flags = (((int)compressionLevel - 1) & 0xff) >> 1;
-
- if (level_flags > 3)
- level_flags = 3;
- header |= (level_flags << 6);
- if (strstart != 0)
- header |= PRESET_DICT;
- header += 31 - (header % 31);
-
- status = BUSY_STATE;
- //putShortMSB(header);
- unchecked
- {
- pending[pendingCount++] = (byte)(header >> 8);
- pending[pendingCount++] = (byte)header;
- }
- // Save the adler32 of the preset dictionary:
- if (strstart != 0)
- {
- pending[pendingCount++] = (byte)((_codec._Adler32 & 0xFF000000) >> 24);
- pending[pendingCount++] = (byte)((_codec._Adler32 & 0x00FF0000) >> 16);
- pending[pendingCount++] = (byte)((_codec._Adler32 & 0x0000FF00) >> 8);
- pending[pendingCount++] = (byte)(_codec._Adler32 & 0x000000FF);
- }
- _codec._Adler32 = Adler.Adler32(0, null, 0, 0);
- }
-
- // Flush as much pending output as possible
- if (pendingCount != 0)
- {
- _codec.flush_pending();
- if (_codec.AvailableBytesOut == 0)
- {
- //System.out.println(" avail_out==0");
- // Since avail_out is 0, deflate will be called again with
- // more output space, but possibly with both pending and
- // avail_in equal to zero. There won't be anything to do,
- // but this is not an error situation so make sure we
- // return OK instead of BUF_ERROR at next call of deflate:
- last_flush = -1;
- return ZlibConstants.Z_OK;
- }
-
- // Make sure there is something to do and avoid duplicate consecutive
- // flushes. For repeated and useless calls with Z_FINISH, we keep
- // returning Z_STREAM_END instead of Z_BUFF_ERROR.
- }
- else if (_codec.AvailableBytesIn == 0 &&
- (int)flush <= old_flush &&
- flush != FlushType.Finish)
- {
- // workitem 8557
- //
- // Not sure why this needs to be an error. pendingCount == 0, which
- // means there's nothing to deflate. And the caller has not asked
- // for a FlushType.Finish, but... that seems very non-fatal. We
- // can just say "OK" and do nothing.
-
- // _codec.Message = z_errmsg[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)];
- // throw new ZlibException("AvailableBytesIn == 0 && flush<=old_flush && flush != FlushType.Finish");
-
- return ZlibConstants.Z_OK;
- }
-
- // User must not provide more input after the first FINISH:
- if (status == FINISH_STATE && _codec.AvailableBytesIn != 0)
- {
- _codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)];
- throw new ZlibException("status == FINISH_STATE && _codec.AvailableBytesIn != 0");
- }
-
- // Start a new block or continue the current one.
- if (_codec.AvailableBytesIn != 0 || lookahead != 0 || (flush != FlushType.None && status != FINISH_STATE))
- {
- BlockState bstate = DeflateFunction(flush);
-
- if (bstate == BlockState.FinishStarted || bstate == BlockState.FinishDone)
- {
- status = FINISH_STATE;
- }
- if (bstate == BlockState.NeedMore || bstate == BlockState.FinishStarted)
- {
- if (_codec.AvailableBytesOut == 0)
- {
- last_flush = -1; // avoid BUF_ERROR next call, see above
- }
- return ZlibConstants.Z_OK;
- // If flush != Z_NO_FLUSH && avail_out == 0, the next call
- // of deflate should use the same flush parameter to make sure
- // that the flush is complete. So we don't have to output an
- // empty block here, this will be done at next call. This also
- // ensures that for a very small output buffer, we emit at most
- // one empty block.
- }
-
- if (bstate == BlockState.BlockDone)
- {
- if (flush == FlushType.Partial)
- {
- _tr_align();
- }
- else
- {
- // FlushType.Full or FlushType.Sync
- _tr_stored_block(0, 0, false);
- // For a full flush, this empty block will be recognized
- // as a special marker by inflate_sync().
- if (flush == FlushType.Full)
- {
- // clear hash (forget the history)
- for (int i = 0; i < hash_size; i++)
- head[i] = 0;
- }
- }
- _codec.flush_pending();
- if (_codec.AvailableBytesOut == 0)
- {
- last_flush = -1; // avoid BUF_ERROR at next call, see above
- return ZlibConstants.Z_OK;
- }
- }
- }
-
- if (flush != FlushType.Finish)
- return ZlibConstants.Z_OK;
-
- if (!WantRfc1950HeaderBytes || Rfc1950BytesEmitted)
- return ZlibConstants.Z_STREAM_END;
-
- // Write the zlib trailer (adler32)
- pending[pendingCount++] = (byte)((_codec._Adler32 & 0xFF000000) >> 24);
- pending[pendingCount++] = (byte)((_codec._Adler32 & 0x00FF0000) >> 16);
- pending[pendingCount++] = (byte)((_codec._Adler32 & 0x0000FF00) >> 8);
- pending[pendingCount++] = (byte)(_codec._Adler32 & 0x000000FF);
- //putShortMSB((int)(SharedUtils.URShift(_codec._Adler32, 16)));
- //putShortMSB((int)(_codec._Adler32 & 0xffff));
-
- _codec.flush_pending();
-
- // If avail_out is zero, the application will call deflate again
- // to flush the rest.
-
- Rfc1950BytesEmitted = true; // write the trailer only once!
-
- return pendingCount != 0 ? ZlibConstants.Z_OK : ZlibConstants.Z_STREAM_END;
- }
-
- }
-}
\ No newline at end of file
diff --git a/EPPlus/Packaging/DotNetZip/Zlib/DeflateStream.cs b/EPPlus/Packaging/DotNetZip/Zlib/DeflateStream.cs
deleted file mode 100644
index c846469..0000000
--- a/EPPlus/Packaging/DotNetZip/Zlib/DeflateStream.cs
+++ /dev/null
@@ -1,740 +0,0 @@
-// DeflateStream.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009-2010 Dino Chiesa.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-July-31 14:48:11>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the DeflateStream class, which can be used as a replacement for
-// the System.IO.Compression.DeflateStream class in the .NET BCL.
-//
-// ------------------------------------------------------------------
-
-
-using System;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zlib
-{
- /// <summary>
- /// A class for compressing and decompressing streams using the Deflate algorithm.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// The DeflateStream is a <see
- /// href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator</see> on a <see
- /// cref="System.IO.Stream"/>. It adds DEFLATE compression or decompression to any
- /// stream.
- /// </para>
- ///
- /// <para>
- /// Using this stream, applications can compress or decompress data via stream
- /// <c>Read</c> and <c>Write</c> operations. Either compresssion or decompression
- /// can occur through either reading or writing. The compression format used is
- /// DEFLATE, which is documented in <see
- /// href="http://www.ietf.org/rfc/rfc1951.txt">IETF RFC 1951</see>, "DEFLATE
- /// Compressed Data Format Specification version 1.3.".
- /// </para>
- ///
- /// <para>
- /// This class is similar to <see cref="ZlibStream"/>, except that
- /// <c>ZlibStream</c> adds the <see href="http://www.ietf.org/rfc/rfc1950.txt">RFC
- /// 1950 - ZLIB</see> framing bytes to a compressed stream when compressing, or
- /// expects the RFC1950 framing bytes when decompressing. The <c>DeflateStream</c>
- /// does not.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <seealso cref="ZlibStream" />
- /// <seealso cref="GZipStream" />
- public class DeflateStream : System.IO.Stream
- {
- internal ZlibBaseStream _baseStream;
- internal System.IO.Stream _innerStream;
- bool _disposed;
-
- /// <summary>
- /// Create a DeflateStream using the specified CompressionMode.
- /// </summary>
- ///
- /// <remarks>
- /// When mode is <c>CompressionMode.Compress</c>, the DeflateStream will use
- /// the default compression level. The "captive" stream will be closed when
- /// the DeflateStream is closed.
- /// </remarks>
- ///
- /// <example>
- /// This example uses a DeflateStream to compress data from a file, and writes
- /// the compressed data to another file.
- /// <code>
- /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
- /// {
- /// using (var raw = System.IO.File.Create(fileToCompress + ".deflated"))
- /// {
- /// using (Stream compressor = new DeflateStream(raw, CompressionMode.Compress))
- /// {
- /// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
- /// int n;
- /// while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
- /// {
- /// compressor.Write(buffer, 0, n);
- /// }
- /// }
- /// }
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using input As Stream = File.OpenRead(fileToCompress)
- /// Using raw As FileStream = File.Create(fileToCompress & ".deflated")
- /// Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress)
- /// Dim buffer As Byte() = New Byte(4096) {}
- /// Dim n As Integer = -1
- /// Do While (n <> 0)
- /// If (n > 0) Then
- /// compressor.Write(buffer, 0, n)
- /// End If
- /// n = input.Read(buffer, 0, buffer.Length)
- /// Loop
- /// End Using
- /// End Using
- /// End Using
- /// </code>
- /// </example>
- /// <param name="stream">The stream which will be read or written.</param>
- /// <param name="mode">Indicates whether the DeflateStream will compress or decompress.</param>
- public DeflateStream(System.IO.Stream stream, CompressionMode mode)
- : this(stream, mode, CompressionLevel.Default, false)
- {
- }
-
- /// <summary>
- /// Create a DeflateStream using the specified CompressionMode and the specified CompressionLevel.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// When mode is <c>CompressionMode.Decompress</c>, the level parameter is
- /// ignored. The "captive" stream will be closed when the DeflateStream is
- /// closed.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example uses a DeflateStream to compress data from a file, and writes
- /// the compressed data to another file.
- ///
- /// <code>
- /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
- /// {
- /// using (var raw = System.IO.File.Create(fileToCompress + ".deflated"))
- /// {
- /// using (Stream compressor = new DeflateStream(raw,
- /// CompressionMode.Compress,
- /// CompressionLevel.BestCompression))
- /// {
- /// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
- /// int n= -1;
- /// while (n != 0)
- /// {
- /// if (n > 0)
- /// compressor.Write(buffer, 0, n);
- /// n= input.Read(buffer, 0, buffer.Length);
- /// }
- /// }
- /// }
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using input As Stream = File.OpenRead(fileToCompress)
- /// Using raw As FileStream = File.Create(fileToCompress & ".deflated")
- /// Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression)
- /// Dim buffer As Byte() = New Byte(4096) {}
- /// Dim n As Integer = -1
- /// Do While (n <> 0)
- /// If (n > 0) Then
- /// compressor.Write(buffer, 0, n)
- /// End If
- /// n = input.Read(buffer, 0, buffer.Length)
- /// Loop
- /// End Using
- /// End Using
- /// End Using
- /// </code>
- /// </example>
- /// <param name="stream">The stream to be read or written while deflating or inflating.</param>
- /// <param name="mode">Indicates whether the <c>DeflateStream</c> will compress or decompress.</param>
- /// <param name="level">A tuning knob to trade speed for effectiveness.</param>
- public DeflateStream(System.IO.Stream stream, CompressionMode mode, CompressionLevel level)
- : this(stream, mode, level, false)
- {
- }
-
- /// <summary>
- /// Create a <c>DeflateStream</c> using the specified
- /// <c>CompressionMode</c>, and explicitly specify whether the
- /// stream should be left open after Deflation or Inflation.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This constructor allows the application to request that the captive stream
- /// remain open after the deflation or inflation occurs. By default, after
- /// <c>Close()</c> is called on the stream, the captive stream is also
- /// closed. In some cases this is not desired, for example if the stream is a
- /// memory stream that will be re-read after compression. Specify true for
- /// the <paramref name="leaveOpen"/> parameter to leave the stream open.
- /// </para>
- ///
- /// <para>
- /// The <c>DeflateStream</c> will use the default compression level.
- /// </para>
- ///
- /// <para>
- /// See the other overloads of this constructor for example code.
- /// </para>
- /// </remarks>
- ///
- /// <param name="stream">
- /// The stream which will be read or written. This is called the
- /// "captive" stream in other places in this documentation.
- /// </param>
- ///
- /// <param name="mode">
- /// Indicates whether the <c>DeflateStream</c> will compress or decompress.
- /// </param>
- ///
- /// <param name="leaveOpen">true if the application would like the stream to
- /// remain open after inflation/deflation.</param>
- public DeflateStream(System.IO.Stream stream, CompressionMode mode, bool leaveOpen)
- : this(stream, mode, CompressionLevel.Default, leaveOpen)
- {
- }
-
- /// <summary>
- /// Create a <c>DeflateStream</c> using the specified <c>CompressionMode</c>
- /// and the specified <c>CompressionLevel</c>, and explicitly specify whether
- /// the stream should be left open after Deflation or Inflation.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// When mode is <c>CompressionMode.Decompress</c>, the level parameter is ignored.
- /// </para>
- ///
- /// <para>
- /// This constructor allows the application to request that the captive stream
- /// remain open after the deflation or inflation occurs. By default, after
- /// <c>Close()</c> is called on the stream, the captive stream is also
- /// closed. In some cases this is not desired, for example if the stream is a
- /// <see cref="System.IO.MemoryStream"/> that will be re-read after
- /// compression. Specify true for the <paramref name="leaveOpen"/> parameter
- /// to leave the stream open.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example shows how to use a <c>DeflateStream</c> to compress data from
- /// a file, and store the compressed data into another file.
- ///
- /// <code>
- /// using (var output = System.IO.File.Create(fileToCompress + ".deflated"))
- /// {
- /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
- /// {
- /// using (Stream compressor = new DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, true))
- /// {
- /// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
- /// int n= -1;
- /// while (n != 0)
- /// {
- /// if (n > 0)
- /// compressor.Write(buffer, 0, n);
- /// n= input.Read(buffer, 0, buffer.Length);
- /// }
- /// }
- /// }
- /// // can write additional data to the output stream here
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using output As FileStream = File.Create(fileToCompress & ".deflated")
- /// Using input As Stream = File.OpenRead(fileToCompress)
- /// Using compressor As Stream = New DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, True)
- /// Dim buffer As Byte() = New Byte(4096) {}
- /// Dim n As Integer = -1
- /// Do While (n <> 0)
- /// If (n > 0) Then
- /// compressor.Write(buffer, 0, n)
- /// End If
- /// n = input.Read(buffer, 0, buffer.Length)
- /// Loop
- /// End Using
- /// End Using
- /// ' can write additional data to the output stream here.
- /// End Using
- /// </code>
- /// </example>
- /// <param name="stream">The stream which will be read or written.</param>
- /// <param name="mode">Indicates whether the DeflateStream will compress or decompress.</param>
- /// <param name="leaveOpen">true if the application would like the stream to remain open after inflation/deflation.</param>
- /// <param name="level">A tuning knob to trade speed for effectiveness.</param>
- public DeflateStream(System.IO.Stream stream, CompressionMode mode, CompressionLevel level, bool leaveOpen)
- {
- _innerStream = stream;
- _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.DEFLATE, leaveOpen);
- }
-
- #region Zlib properties
-
- /// <summary>
- /// This property sets the flush behavior on the stream.
- /// </summary>
- /// <remarks> See the ZLIB documentation for the meaning of the flush behavior.
- /// </remarks>
- virtual public FlushType FlushMode
- {
- get { return (this._baseStream._flushMode); }
- set
- {
- if (_disposed) throw new ObjectDisposedException("DeflateStream");
- this._baseStream._flushMode = value;
- }
- }
-
- /// <summary>
- /// The size of the working buffer for the compression codec.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The working buffer is used for all stream operations. The default size is
- /// 1024 bytes. The minimum size is 128 bytes. You may get better performance
- /// with a larger buffer. Then again, you might not. You would have to test
- /// it.
- /// </para>
- ///
- /// <para>
- /// Set this before the first call to <c>Read()</c> or <c>Write()</c> on the
- /// stream. If you try to set it afterwards, it will throw.
- /// </para>
- /// </remarks>
- public int BufferSize
- {
- get
- {
- return this._baseStream._bufferSize;
- }
- set
- {
- if (_disposed) throw new ObjectDisposedException("DeflateStream");
- if (this._baseStream._workingBuffer != null)
- throw new ZlibException("The working buffer is already set.");
- if (value < ZlibConstants.WorkingBufferSizeMin)
- throw new ZlibException(String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, ZlibConstants.WorkingBufferSizeMin));
- this._baseStream._bufferSize = value;
- }
- }
-
- /// <summary>
- /// The ZLIB strategy to be used during compression.
- /// </summary>
- ///
- /// <remarks>
- /// By tweaking this parameter, you may be able to optimize the compression for
- /// data with particular characteristics.
- /// </remarks>
- public CompressionStrategy Strategy
- {
- get
- {
- return this._baseStream.Strategy;
- }
- set
- {
- if (_disposed) throw new ObjectDisposedException("DeflateStream");
- this._baseStream.Strategy = value;
- }
- }
-
- /// <summary> Returns the total number of bytes input so far.</summary>
- virtual public long TotalIn
- {
- get
- {
- return this._baseStream._z.TotalBytesIn;
- }
- }
-
- /// <summary> Returns the total number of bytes output so far.</summary>
- virtual public long TotalOut
- {
- get
- {
- return this._baseStream._z.TotalBytesOut;
- }
- }
-
- #endregion
-
- #region System.IO.Stream methods
- /// <summary>
- /// Dispose the stream.
- /// </summary>
- /// <remarks>
- /// <para>
- /// This may or may not result in a <c>Close()</c> call on the captive
- /// stream. See the constructors that have a <c>leaveOpen</c> parameter
- /// for more information.
- /// </para>
- /// <para>
- /// Application code won't call this code directly. This method may be
- /// invoked in two distinct scenarios. If disposing == true, the method
- /// has been called directly or indirectly by a user's code, for example
- /// via the public Dispose() method. In this case, both managed and
- /// unmanaged resources can be referenced and disposed. If disposing ==
- /// false, the method has been called by the runtime from inside the
- /// object finalizer and this method should not reference other objects;
- /// in that case only unmanaged resources must be referenced or
- /// disposed.
- /// </para>
- /// </remarks>
- /// <param name="disposing">
- /// true if the Dispose method was invoked by user code.
- /// </param>
- protected override void Dispose(bool disposing)
- {
- try
- {
- if (!_disposed)
- {
- if (disposing && (this._baseStream != null))
- this._baseStream.Close();
- _disposed = true;
- }
- }
- finally
- {
- base.Dispose(disposing);
- }
- }
-
-
-
- /// <summary>
- /// Indicates whether the stream can be read.
- /// </summary>
- /// <remarks>
- /// The return value depends on whether the captive stream supports reading.
- /// </remarks>
- public override bool CanRead
- {
- get
- {
- if (_disposed) throw new ObjectDisposedException("DeflateStream");
- return _baseStream._stream.CanRead;
- }
- }
-
- /// <summary>
- /// Indicates whether the stream supports Seek operations.
- /// </summary>
- /// <remarks>
- /// Always returns false.
- /// </remarks>
- public override bool CanSeek
- {
- get { return false; }
- }
-
-
- /// <summary>
- /// Indicates whether the stream can be written.
- /// </summary>
- /// <remarks>
- /// The return value depends on whether the captive stream supports writing.
- /// </remarks>
- public override bool CanWrite
- {
- get
- {
- if (_disposed) throw new ObjectDisposedException("DeflateStream");
- return _baseStream._stream.CanWrite;
- }
- }
-
- /// <summary>
- /// Flush the stream.
- /// </summary>
- public override void Flush()
- {
- if (_disposed) throw new ObjectDisposedException("DeflateStream");
- _baseStream.Flush();
- }
-
- /// <summary>
- /// Reading this property always throws a <see cref="NotImplementedException"/>.
- /// </summary>
- public override long Length
- {
- get { throw new NotImplementedException(); }
- }
-
- /// <summary>
- /// The position of the stream pointer.
- /// </summary>
- ///
- /// <remarks>
- /// Setting this property always throws a <see
- /// cref="NotImplementedException"/>. Reading will return the total bytes
- /// written out, if used in writing, or the total bytes read in, if used in
- /// reading. The count may refer to compressed bytes or uncompressed bytes,
- /// depending on how you've used the stream.
- /// </remarks>
- public override long Position
- {
- get
- {
- if (this._baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Writer)
- return this._baseStream._z.TotalBytesOut;
- if (this._baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Reader)
- return this._baseStream._z.TotalBytesIn;
- return 0;
- }
- set { throw new NotImplementedException(); }
- }
-
- /// <summary>
- /// Read data from the stream.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// If you wish to use the <c>DeflateStream</c> to compress data while
- /// reading, you can create a <c>DeflateStream</c> with
- /// <c>CompressionMode.Compress</c>, providing an uncompressed data stream.
- /// Then call Read() on that <c>DeflateStream</c>, and the data read will be
- /// compressed as you read. If you wish to use the <c>DeflateStream</c> to
- /// decompress data while reading, you can create a <c>DeflateStream</c> with
- /// <c>CompressionMode.Decompress</c>, providing a readable compressed data
- /// stream. Then call Read() on that <c>DeflateStream</c>, and the data read
- /// will be decompressed as you read.
- /// </para>
- ///
- /// <para>
- /// A <c>DeflateStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but not both.
- /// </para>
- ///
- /// </remarks>
- /// <param name="buffer">The buffer into which the read data should be placed.</param>
- /// <param name="offset">the offset within that data array to put the first byte read.</param>
- /// <param name="count">the number of bytes to read.</param>
- /// <returns>the number of bytes actually read</returns>
- public override int Read(byte[] buffer, int offset, int count)
- {
- if (_disposed) throw new ObjectDisposedException("DeflateStream");
- return _baseStream.Read(buffer, offset, count);
- }
-
-
- /// <summary>
- /// Calling this method always throws a <see cref="NotImplementedException"/>.
- /// </summary>
- /// <param name="offset">this is irrelevant, since it will always throw!</param>
- /// <param name="origin">this is irrelevant, since it will always throw!</param>
- /// <returns>irrelevant!</returns>
- public override long Seek(long offset, System.IO.SeekOrigin origin)
- {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Calling this method always throws a <see cref="NotImplementedException"/>.
- /// </summary>
- /// <param name="value">this is irrelevant, since it will always throw!</param>
- public override void SetLength(long value)
- {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Write data to the stream.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// If you wish to use the <c>DeflateStream</c> to compress data while
- /// writing, you can create a <c>DeflateStream</c> with
- /// <c>CompressionMode.Compress</c>, and a writable output stream. Then call
- /// <c>Write()</c> on that <c>DeflateStream</c>, providing uncompressed data
- /// as input. The data sent to the output stream will be the compressed form
- /// of the data written. If you wish to use the <c>DeflateStream</c> to
- /// decompress data while writing, you can create a <c>DeflateStream</c> with
- /// <c>CompressionMode.Decompress</c>, and a writable output stream. Then
- /// call <c>Write()</c> on that stream, providing previously compressed
- /// data. The data sent to the output stream will be the decompressed form of
- /// the data written.
- /// </para>
- ///
- /// <para>
- /// A <c>DeflateStream</c> can be used for <c>Read()</c> or <c>Write()</c>,
- /// but not both.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="buffer">The buffer holding data to write to the stream.</param>
- /// <param name="offset">the offset within that data array to find the first byte to write.</param>
- /// <param name="count">the number of bytes to write.</param>
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (_disposed) throw new ObjectDisposedException("DeflateStream");
- _baseStream.Write(buffer, offset, count);
- }
- #endregion
-
-
-
-
- /// <summary>
- /// Compress a string into a byte array using DEFLATE (RFC 1951).
- /// </summary>
- ///
- /// <remarks>
- /// Uncompress it with <see cref="DeflateStream.UncompressString(byte[])"/>.
- /// </remarks>
- ///
- /// <seealso cref="DeflateStream.UncompressString(byte[])">DeflateStream.UncompressString(byte[])</seealso>
- /// <seealso cref="DeflateStream.CompressBuffer(byte[])">DeflateStream.CompressBuffer(byte[])</seealso>
- /// <seealso cref="GZipStream.CompressString(string)">GZipStream.CompressString(string)</seealso>
- /// <seealso cref="ZlibStream.CompressString(string)">ZlibStream.CompressString(string)</seealso>
- ///
- /// <param name="s">
- /// A string to compress. The string will first be encoded
- /// using UTF8, then compressed.
- /// </param>
- ///
- /// <returns>The string in compressed form</returns>
- public static byte[] CompressString(String s)
- {
- using (var ms = new System.IO.MemoryStream())
- {
- System.IO.Stream compressor =
- new DeflateStream(ms, CompressionMode.Compress, CompressionLevel.BestCompression);
- ZlibBaseStream.CompressString(s, compressor);
- return ms.ToArray();
- }
- }
-
-
- /// <summary>
- /// Compress a byte array into a new byte array using DEFLATE.
- /// </summary>
- ///
- /// <remarks>
- /// Uncompress it with <see cref="DeflateStream.UncompressBuffer(byte[])"/>.
- /// </remarks>
- ///
- /// <seealso cref="DeflateStream.CompressString(string)">DeflateStream.CompressString(string)</seealso>
- /// <seealso cref="DeflateStream.UncompressBuffer(byte[])">DeflateStream.UncompressBuffer(byte[])</seealso>
- /// <seealso cref="GZipStream.CompressBuffer(byte[])">GZipStream.CompressBuffer(byte[])</seealso>
- /// <seealso cref="ZlibStream.CompressBuffer(byte[])">ZlibStream.CompressBuffer(byte[])</seealso>
- ///
- /// <param name="b">
- /// A buffer to compress.
- /// </param>
- ///
- /// <returns>The data in compressed form</returns>
- public static byte[] CompressBuffer(byte[] b)
- {
- using (var ms = new System.IO.MemoryStream())
- {
- System.IO.Stream compressor =
- new DeflateStream( ms, CompressionMode.Compress, CompressionLevel.BestCompression );
-
- ZlibBaseStream.CompressBuffer(b, compressor);
- return ms.ToArray();
- }
- }
-
-
- /// <summary>
- /// Uncompress a DEFLATE'd byte array into a single string.
- /// </summary>
- ///
- /// <seealso cref="DeflateStream.CompressString(String)">DeflateStream.CompressString(String)</seealso>
- /// <seealso cref="DeflateStream.UncompressBuffer(byte[])">DeflateStream.UncompressBuffer(byte[])</seealso>
- /// <seealso cref="GZipStream.UncompressString(byte[])">GZipStream.UncompressString(byte[])</seealso>
- /// <seealso cref="ZlibStream.UncompressString(byte[])">ZlibStream.UncompressString(byte[])</seealso>
- ///
- /// <param name="compressed">
- /// A buffer containing DEFLATE-compressed data.
- /// </param>
- ///
- /// <returns>The uncompressed string</returns>
- public static String UncompressString(byte[] compressed)
- {
- using (var input = new System.IO.MemoryStream(compressed))
- {
- System.IO.Stream decompressor =
- new DeflateStream(input, CompressionMode.Decompress);
-
- return ZlibBaseStream.UncompressString(compressed, decompressor);
- }
- }
-
-
- /// <summary>
- /// Uncompress a DEFLATE'd byte array into a byte array.
- /// </summary>
- ///
- /// <seealso cref="DeflateStream.CompressBuffer(byte[])">DeflateStream.CompressBuffer(byte[])</seealso>
- /// <seealso cref="DeflateStream.UncompressString(byte[])">DeflateStream.UncompressString(byte[])</seealso>
- /// <seealso cref="GZipStream.UncompressBuffer(byte[])">GZipStream.UncompressBuffer(byte[])</seealso>
- /// <seealso cref="ZlibStream.UncompressBuffer(byte[])">ZlibStream.UncompressBuffer(byte[])</seealso>
- ///
- /// <param name="compressed">
- /// A buffer containing data that has been compressed with DEFLATE.
- /// </param>
- ///
- /// <returns>The data in uncompressed form</returns>
- public static byte[] UncompressBuffer(byte[] compressed)
- {
- using (var input = new System.IO.MemoryStream(compressed))
- {
- System.IO.Stream decompressor =
- new DeflateStream( input, CompressionMode.Decompress );
-
- return ZlibBaseStream.UncompressBuffer(compressed, decompressor);
- }
- }
-
- }
-
-}
-
diff --git a/EPPlus/Packaging/DotNetZip/Zlib/GZipStream.cs b/EPPlus/Packaging/DotNetZip/Zlib/GZipStream.cs
deleted file mode 100644
index a83a496..0000000
--- a/EPPlus/Packaging/DotNetZip/Zlib/GZipStream.cs
+++ /dev/null
@@ -1,1033 +0,0 @@
-// GZipStream.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-August-08 18:14:39>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the GZipStream class, which can be used as a replacement for
-// the System.IO.Compression.GZipStream class in the .NET BCL. NB: The design is not
-// completely OO clean: there is some intelligence in the ZlibBaseStream that reads the
-// GZip header.
-//
-// ------------------------------------------------------------------
-
-
-using System;
-using System.IO;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zlib
-{
- /// <summary>
- /// A class for compressing and decompressing GZIP streams.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// The <c>GZipStream</c> is a <see
- /// href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator</see> on a
- /// <see cref="Stream"/>. It adds GZIP compression or decompression to any
- /// stream.
- /// </para>
- ///
- /// <para>
- /// Like the <c>System.IO.Compression.GZipStream</c> in the .NET Base Class Library, the
- /// <c>Ionic.Zlib.GZipStream</c> can compress while writing, or decompress while
- /// reading, but not vice versa. The compression method used is GZIP, which is
- /// documented in <see href="http://www.ietf.org/rfc/rfc1952.txt">IETF RFC
- /// 1952</see>, "GZIP file format specification version 4.3".</para>
- ///
- /// <para>
- /// A <c>GZipStream</c> can be used to decompress data (through <c>Read()</c>) or
- /// to compress data (through <c>Write()</c>), but not both.
- /// </para>
- ///
- /// <para>
- /// If you wish to use the <c>GZipStream</c> to compress data, you must wrap it
- /// around a write-able stream. As you call <c>Write()</c> on the <c>GZipStream</c>, the
- /// data will be compressed into the GZIP format. If you want to decompress data,
- /// you must wrap the <c>GZipStream</c> around a readable stream that contains an
- /// IETF RFC 1952-compliant stream. The data will be decompressed as you call
- /// <c>Read()</c> on the <c>GZipStream</c>.
- /// </para>
- ///
- /// <para>
- /// Though the GZIP format allows data from multiple files to be concatenated
- /// together, this stream handles only a single segment of GZIP format, typically
- /// representing a single file.
- /// </para>
- ///
- /// <para>
- /// This class is similar to <see cref="ZlibStream"/> and <see cref="DeflateStream"/>.
- /// <c>ZlibStream</c> handles RFC1950-compliant streams. <see cref="DeflateStream"/>
- /// handles RFC1951-compliant streams. This class handles RFC1952-compliant streams.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <seealso cref="DeflateStream" />
- /// <seealso cref="ZlibStream" />
- public class GZipStream : System.IO.Stream
- {
- // GZip format
- // source: http://tools.ietf.org/html/rfc1952
- //
- // header id: 2 bytes 1F 8B
- // compress method 1 byte 8= DEFLATE (none other supported)
- // flag 1 byte bitfield (See below)
- // mtime 4 bytes time_t (seconds since jan 1, 1970 UTC of the file.
- // xflg 1 byte 2 = max compress used , 4 = max speed (can be ignored)
- // OS 1 byte OS for originating archive. set to 0xFF in compression.
- // extra field length 2 bytes optional - only if FEXTRA is set.
- // extra field varies
- // filename varies optional - if FNAME is set. zero terminated. ISO-8859-1.
- // file comment varies optional - if FCOMMENT is set. zero terminated. ISO-8859-1.
- // crc16 1 byte optional - present only if FHCRC bit is set
- // compressed data varies
- // CRC32 4 bytes
- // isize 4 bytes data size modulo 2^32
- //
- // FLG (FLaGs)
- // bit 0 FTEXT - indicates file is ASCII text (can be safely ignored)
- // bit 1 FHCRC - there is a CRC16 for the header immediately following the header
- // bit 2 FEXTRA - extra fields are present
- // bit 3 FNAME - the zero-terminated filename is present. encoding; ISO-8859-1.
- // bit 4 FCOMMENT - a zero-terminated file comment is present. encoding: ISO-8859-1
- // bit 5 reserved
- // bit 6 reserved
- // bit 7 reserved
- //
- // On consumption:
- // Extra field is a bunch of nonsense and can be safely ignored.
- // Header CRC and OS, likewise.
- //
- // on generation:
- // all optional fields get 0, except for the OS, which gets 255.
- //
-
-
-
- /// <summary>
- /// The comment on the GZIP stream.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The GZIP format allows for each file to optionally have an associated
- /// comment stored with the file. The comment is encoded with the ISO-8859-1
- /// code page. To include a comment in a GZIP stream you create, set this
- /// property before calling <c>Write()</c> for the first time on the
- /// <c>GZipStream</c>.
- /// </para>
- ///
- /// <para>
- /// When using <c>GZipStream</c> to decompress, you can retrieve this property
- /// after the first call to <c>Read()</c>. If no comment has been set in the
- /// GZIP bytestream, the Comment property will return <c>null</c>
- /// (<c>Nothing</c> in VB).
- /// </para>
- /// </remarks>
- public String Comment
- {
- get
- {
- return _Comment;
- }
- set
- {
- if (_disposed) throw new ObjectDisposedException("GZipStream");
- _Comment = value;
- }
- }
-
- /// <summary>
- /// The FileName for the GZIP stream.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// The GZIP format optionally allows each file to have an associated
- /// filename. When compressing data (through <c>Write()</c>), set this
- /// FileName before calling <c>Write()</c> the first time on the <c>GZipStream</c>.
- /// The actual filename is encoded into the GZIP bytestream with the
- /// ISO-8859-1 code page, according to RFC 1952. It is the application's
- /// responsibility to insure that the FileName can be encoded and decoded
- /// correctly with this code page.
- /// </para>
- ///
- /// <para>
- /// When decompressing (through <c>Read()</c>), you can retrieve this value
- /// any time after the first <c>Read()</c>. In the case where there was no filename
- /// encoded into the GZIP bytestream, the property will return <c>null</c> (<c>Nothing</c>
- /// in VB).
- /// </para>
- /// </remarks>
- public String FileName
- {
- get { return _FileName; }
- set
- {
- if (_disposed) throw new ObjectDisposedException("GZipStream");
- _FileName = value;
- if (_FileName == null) return;
- if (_FileName.IndexOf("/") != -1)
- {
- _FileName = _FileName.Replace("/", "\\");
- }
- if (_FileName.EndsWith("\\"))
- throw new Exception("Illegal filename");
- if (_FileName.IndexOf("\\") != -1)
- {
- // trim any leading path
- _FileName = Path.GetFileName(_FileName);
- }
- }
- }
-
- /// <summary>
- /// The last modified time for the GZIP stream.
- /// </summary>
- ///
- /// <remarks>
- /// GZIP allows the storage of a last modified time with each GZIP entry.
- /// When compressing data, you can set this before the first call to
- /// <c>Write()</c>. When decompressing, you can retrieve this value any time
- /// after the first call to <c>Read()</c>.
- /// </remarks>
- public DateTime? LastModified;
-
- /// <summary>
- /// The CRC on the GZIP stream.
- /// </summary>
- /// <remarks>
- /// This is used for internal error checking. You probably don't need to look at this property.
- /// </remarks>
- public int Crc32 { get { return _Crc32; } }
-
- private int _headerByteCount;
- internal ZlibBaseStream _baseStream;
- bool _disposed;
- bool _firstReadDone;
- string _FileName;
- string _Comment;
- int _Crc32;
-
-
- /// <summary>
- /// Create a <c>GZipStream</c> using the specified <c>CompressionMode</c>.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// When mode is <c>CompressionMode.Compress</c>, the <c>GZipStream</c> will use the
- /// default compression level.
- /// </para>
- ///
- /// <para>
- /// As noted in the class documentation, the <c>CompressionMode</c> (Compress
- /// or Decompress) also establishes the "direction" of the stream. A
- /// <c>GZipStream</c> with <c>CompressionMode.Compress</c> works only through
- /// <c>Write()</c>. A <c>GZipStream</c> with
- /// <c>CompressionMode.Decompress</c> works only through <c>Read()</c>.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// This example shows how to use a GZipStream to compress data.
- /// <code>
- /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
- /// {
- /// using (var raw = System.IO.File.Create(outputFile))
- /// {
- /// using (Stream compressor = new GZipStream(raw, CompressionMode.Compress))
- /// {
- /// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
- /// int n;
- /// while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
- /// {
- /// compressor.Write(buffer, 0, n);
- /// }
- /// }
- /// }
- /// }
- /// </code>
- /// <code lang="VB">
- /// Dim outputFile As String = (fileToCompress & ".compressed")
- /// Using input As Stream = File.OpenRead(fileToCompress)
- /// Using raw As FileStream = File.Create(outputFile)
- /// Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress)
- /// Dim buffer As Byte() = New Byte(4096) {}
- /// Dim n As Integer = -1
- /// Do While (n <> 0)
- /// If (n > 0) Then
- /// compressor.Write(buffer, 0, n)
- /// End If
- /// n = input.Read(buffer, 0, buffer.Length)
- /// Loop
- /// End Using
- /// End Using
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <example>
- /// This example shows how to use a GZipStream to uncompress a file.
- /// <code>
- /// private void GunZipFile(string filename)
- /// {
- /// if (!filename.EndsWith(".gz))
- /// throw new ArgumentException("filename");
- /// var DecompressedFile = filename.Substring(0,filename.Length-3);
- /// byte[] working = new byte[WORKING_BUFFER_SIZE];
- /// int n= 1;
- /// using (System.IO.Stream input = System.IO.File.OpenRead(filename))
- /// {
- /// using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true))
- /// {
- /// using (var output = System.IO.File.Create(DecompressedFile))
- /// {
- /// while (n !=0)
- /// {
- /// n= decompressor.Read(working, 0, working.Length);
- /// if (n > 0)
- /// {
- /// output.Write(working, 0, n);
- /// }
- /// }
- /// }
- /// }
- /// }
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Private Sub GunZipFile(ByVal filename as String)
- /// If Not (filename.EndsWith(".gz)) Then
- /// Throw New ArgumentException("filename")
- /// End If
- /// Dim DecompressedFile as String = filename.Substring(0,filename.Length-3)
- /// Dim working(WORKING_BUFFER_SIZE) as Byte
- /// Dim n As Integer = 1
- /// Using input As Stream = File.OpenRead(filename)
- /// Using decompressor As Stream = new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, True)
- /// Using output As Stream = File.Create(UncompressedFile)
- /// Do
- /// n= decompressor.Read(working, 0, working.Length)
- /// If n > 0 Then
- /// output.Write(working, 0, n)
- /// End IF
- /// Loop While (n > 0)
- /// End Using
- /// End Using
- /// End Using
- /// End Sub
- /// </code>
- /// </example>
- ///
- /// <param name="stream">The stream which will be read or written.</param>
- /// <param name="mode">Indicates whether the GZipStream will compress or decompress.</param>
- public GZipStream(Stream stream, CompressionMode mode)
- : this(stream, mode, CompressionLevel.Default, false)
- {
- }
-
- /// <summary>
- /// Create a <c>GZipStream</c> using the specified <c>CompressionMode</c> and
- /// the specified <c>CompressionLevel</c>.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// The <c>CompressionMode</c> (Compress or Decompress) also establishes the
- /// "direction" of the stream. A <c>GZipStream</c> with
- /// <c>CompressionMode.Compress</c> works only through <c>Write()</c>. A
- /// <c>GZipStream</c> with <c>CompressionMode.Decompress</c> works only
- /// through <c>Read()</c>.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example shows how to use a <c>GZipStream</c> to compress a file into a .gz file.
- ///
- /// <code>
- /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
- /// {
- /// using (var raw = System.IO.File.Create(fileToCompress + ".gz"))
- /// {
- /// using (Stream compressor = new GZipStream(raw,
- /// CompressionMode.Compress,
- /// CompressionLevel.BestCompression))
- /// {
- /// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
- /// int n;
- /// while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
- /// {
- /// compressor.Write(buffer, 0, n);
- /// }
- /// }
- /// }
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using input As Stream = File.OpenRead(fileToCompress)
- /// Using raw As FileStream = File.Create(fileToCompress & ".gz")
- /// Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression)
- /// Dim buffer As Byte() = New Byte(4096) {}
- /// Dim n As Integer = -1
- /// Do While (n <> 0)
- /// If (n > 0) Then
- /// compressor.Write(buffer, 0, n)
- /// End If
- /// n = input.Read(buffer, 0, buffer.Length)
- /// Loop
- /// End Using
- /// End Using
- /// End Using
- /// </code>
- /// </example>
- /// <param name="stream">The stream to be read or written while deflating or inflating.</param>
- /// <param name="mode">Indicates whether the <c>GZipStream</c> will compress or decompress.</param>
- /// <param name="level">A tuning knob to trade speed for effectiveness.</param>
- public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level)
- : this(stream, mode, level, false)
- {
- }
-
- /// <summary>
- /// Create a <c>GZipStream</c> using the specified <c>CompressionMode</c>, and
- /// explicitly specify whether the stream should be left open after Deflation
- /// or Inflation.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This constructor allows the application to request that the captive stream
- /// remain open after the deflation or inflation occurs. By default, after
- /// <c>Close()</c> is called on the stream, the captive stream is also
- /// closed. In some cases this is not desired, for example if the stream is a
- /// memory stream that will be re-read after compressed data has been written
- /// to it. Specify true for the <paramref name="leaveOpen"/> parameter to leave
- /// the stream open.
- /// </para>
- ///
- /// <para>
- /// The <see cref="CompressionMode"/> (Compress or Decompress) also
- /// establishes the "direction" of the stream. A <c>GZipStream</c> with
- /// <c>CompressionMode.Compress</c> works only through <c>Write()</c>. A <c>GZipStream</c>
- /// with <c>CompressionMode.Decompress</c> works only through <c>Read()</c>.
- /// </para>
- ///
- /// <para>
- /// The <c>GZipStream</c> will use the default compression level. If you want
- /// to specify the compression level, see <see cref="GZipStream(Stream,
- /// CompressionMode, CompressionLevel, bool)"/>.
- /// </para>
- ///
- /// <para>
- /// See the other overloads of this constructor for example code.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="stream">
- /// The stream which will be read or written. This is called the "captive"
- /// stream in other places in this documentation.
- /// </param>
- ///
- /// <param name="mode">Indicates whether the GZipStream will compress or decompress.
- /// </param>
- ///
- /// <param name="leaveOpen">
- /// true if the application would like the base stream to remain open after
- /// inflation/deflation.
- /// </param>
- public GZipStream(Stream stream, CompressionMode mode, bool leaveOpen)
- : this(stream, mode, CompressionLevel.Default, leaveOpen)
- {
- }
-
- /// <summary>
- /// Create a <c>GZipStream</c> using the specified <c>CompressionMode</c> and the
- /// specified <c>CompressionLevel</c>, and explicitly specify whether the
- /// stream should be left open after Deflation or Inflation.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This constructor allows the application to request that the captive stream
- /// remain open after the deflation or inflation occurs. By default, after
- /// <c>Close()</c> is called on the stream, the captive stream is also
- /// closed. In some cases this is not desired, for example if the stream is a
- /// memory stream that will be re-read after compressed data has been written
- /// to it. Specify true for the <paramref name="leaveOpen"/> parameter to
- /// leave the stream open.
- /// </para>
- ///
- /// <para>
- /// As noted in the class documentation, the <c>CompressionMode</c> (Compress
- /// or Decompress) also establishes the "direction" of the stream. A
- /// <c>GZipStream</c> with <c>CompressionMode.Compress</c> works only through
- /// <c>Write()</c>. A <c>GZipStream</c> with <c>CompressionMode.Decompress</c> works only
- /// through <c>Read()</c>.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// This example shows how to use a <c>GZipStream</c> to compress data.
- /// <code>
- /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
- /// {
- /// using (var raw = System.IO.File.Create(outputFile))
- /// {
- /// using (Stream compressor = new GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression, true))
- /// {
- /// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
- /// int n;
- /// while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
- /// {
- /// compressor.Write(buffer, 0, n);
- /// }
- /// }
- /// }
- /// }
- /// </code>
- /// <code lang="VB">
- /// Dim outputFile As String = (fileToCompress & ".compressed")
- /// Using input As Stream = File.OpenRead(fileToCompress)
- /// Using raw As FileStream = File.Create(outputFile)
- /// Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression, True)
- /// Dim buffer As Byte() = New Byte(4096) {}
- /// Dim n As Integer = -1
- /// Do While (n <> 0)
- /// If (n > 0) Then
- /// compressor.Write(buffer, 0, n)
- /// End If
- /// n = input.Read(buffer, 0, buffer.Length)
- /// Loop
- /// End Using
- /// End Using
- /// End Using
- /// </code>
- /// </example>
- /// <param name="stream">The stream which will be read or written.</param>
- /// <param name="mode">Indicates whether the GZipStream will compress or decompress.</param>
- /// <param name="leaveOpen">true if the application would like the stream to remain open after inflation/deflation.</param>
- /// <param name="level">A tuning knob to trade speed for effectiveness.</param>
- public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level, bool leaveOpen)
- {
- _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.GZIP, leaveOpen);
- }
-
- #region Zlib properties
-
- /// <summary>
- /// This property sets the flush behavior on the stream.
- /// </summary>
- virtual public FlushType FlushMode
- {
- get { return (this._baseStream._flushMode); }
- set {
- if (_disposed) throw new ObjectDisposedException("GZipStream");
- this._baseStream._flushMode = value;
- }
- }
-
- /// <summary>
- /// The size of the working buffer for the compression codec.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The working buffer is used for all stream operations. The default size is
- /// 1024 bytes. The minimum size is 128 bytes. You may get better performance
- /// with a larger buffer. Then again, you might not. You would have to test
- /// it.
- /// </para>
- ///
- /// <para>
- /// Set this before the first call to <c>Read()</c> or <c>Write()</c> on the
- /// stream. If you try to set it afterwards, it will throw.
- /// </para>
- /// </remarks>
- public int BufferSize
- {
- get
- {
- return this._baseStream._bufferSize;
- }
- set
- {
- if (_disposed) throw new ObjectDisposedException("GZipStream");
- if (this._baseStream._workingBuffer != null)
- throw new ZlibException("The working buffer is already set.");
- if (value < ZlibConstants.WorkingBufferSizeMin)
- throw new ZlibException(String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, ZlibConstants.WorkingBufferSizeMin));
- this._baseStream._bufferSize = value;
- }
- }
-
-
- /// <summary> Returns the total number of bytes input so far.</summary>
- virtual public long TotalIn
- {
- get
- {
- return this._baseStream._z.TotalBytesIn;
- }
- }
-
- /// <summary> Returns the total number of bytes output so far.</summary>
- virtual public long TotalOut
- {
- get
- {
- return this._baseStream._z.TotalBytesOut;
- }
- }
-
- #endregion
-
- #region Stream methods
-
- /// <summary>
- /// Dispose the stream.
- /// </summary>
- /// <remarks>
- /// <para>
- /// This may or may not result in a <c>Close()</c> call on the captive
- /// stream. See the constructors that have a <c>leaveOpen</c> parameter
- /// for more information.
- /// </para>
- /// <para>
- /// This method may be invoked in two distinct scenarios. If disposing
- /// == true, the method has been called directly or indirectly by a
- /// user's code, for example via the public Dispose() method. In this
- /// case, both managed and unmanaged resources can be referenced and
- /// disposed. If disposing == false, the method has been called by the
- /// runtime from inside the object finalizer and this method should not
- /// reference other objects; in that case only unmanaged resources must
- /// be referenced or disposed.
- /// </para>
- /// </remarks>
- /// <param name="disposing">
- /// indicates whether the Dispose method was invoked by user code.
- /// </param>
- protected override void Dispose(bool disposing)
- {
- try
- {
- if (!_disposed)
- {
- if (disposing && (this._baseStream != null))
- {
- this._baseStream.Close();
- this._Crc32 = _baseStream.Crc32;
- }
- _disposed = true;
- }
- }
- finally
- {
- base.Dispose(disposing);
- }
- }
-
-
- /// <summary>
- /// Indicates whether the stream can be read.
- /// </summary>
- /// <remarks>
- /// The return value depends on whether the captive stream supports reading.
- /// </remarks>
- public override bool CanRead
- {
- get
- {
- if (_disposed) throw new ObjectDisposedException("GZipStream");
- return _baseStream._stream.CanRead;
- }
- }
-
- /// <summary>
- /// Indicates whether the stream supports Seek operations.
- /// </summary>
- /// <remarks>
- /// Always returns false.
- /// </remarks>
- public override bool CanSeek
- {
- get { return false; }
- }
-
-
- /// <summary>
- /// Indicates whether the stream can be written.
- /// </summary>
- /// <remarks>
- /// The return value depends on whether the captive stream supports writing.
- /// </remarks>
- public override bool CanWrite
- {
- get
- {
- if (_disposed) throw new ObjectDisposedException("GZipStream");
- return _baseStream._stream.CanWrite;
- }
- }
-
- /// <summary>
- /// Flush the stream.
- /// </summary>
- public override void Flush()
- {
- if (_disposed) throw new ObjectDisposedException("GZipStream");
- _baseStream.Flush();
- }
-
- /// <summary>
- /// Reading this property always throws a <see cref="NotImplementedException"/>.
- /// </summary>
- public override long Length
- {
- get { throw new NotImplementedException(); }
- }
-
- /// <summary>
- /// The position of the stream pointer.
- /// </summary>
- ///
- /// <remarks>
- /// Setting this property always throws a <see
- /// cref="NotImplementedException"/>. Reading will return the total bytes
- /// written out, if used in writing, or the total bytes read in, if used in
- /// reading. The count may refer to compressed bytes or uncompressed bytes,
- /// depending on how you've used the stream.
- /// </remarks>
- public override long Position
- {
- get
- {
- if (this._baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Writer)
- return this._baseStream._z.TotalBytesOut + _headerByteCount;
- if (this._baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Reader)
- return this._baseStream._z.TotalBytesIn + this._baseStream._gzipHeaderByteCount;
- return 0;
- }
-
- set { throw new NotImplementedException(); }
- }
-
- /// <summary>
- /// Read and decompress data from the source stream.
- /// </summary>
- ///
- /// <remarks>
- /// With a <c>GZipStream</c>, decompression is done through reading.
- /// </remarks>
- ///
- /// <example>
- /// <code>
- /// byte[] working = new byte[WORKING_BUFFER_SIZE];
- /// using (System.IO.Stream input = System.IO.File.OpenRead(_CompressedFile))
- /// {
- /// using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true))
- /// {
- /// using (var output = System.IO.File.Create(_DecompressedFile))
- /// {
- /// int n;
- /// while ((n= decompressor.Read(working, 0, working.Length)) !=0)
- /// {
- /// output.Write(working, 0, n);
- /// }
- /// }
- /// }
- /// }
- /// </code>
- /// </example>
- /// <param name="buffer">The buffer into which the decompressed data should be placed.</param>
- /// <param name="offset">the offset within that data array to put the first byte read.</param>
- /// <param name="count">the number of bytes to read.</param>
- /// <returns>the number of bytes actually read</returns>
- public override int Read(byte[] buffer, int offset, int count)
- {
- if (_disposed) throw new ObjectDisposedException("GZipStream");
- int n = _baseStream.Read(buffer, offset, count);
-
- // Console.WriteLine("GZipStream::Read(buffer, off({0}), c({1}) = {2}", offset, count, n);
- // Console.WriteLine( Util.FormatByteArray(buffer, offset, n) );
-
- if (!_firstReadDone)
- {
- _firstReadDone = true;
- FileName = _baseStream._GzipFileName;
- Comment = _baseStream._GzipComment;
- }
- return n;
- }
-
-
-
- /// <summary>
- /// Calling this method always throws a <see cref="NotImplementedException"/>.
- /// </summary>
- /// <param name="offset">irrelevant; it will always throw!</param>
- /// <param name="origin">irrelevant; it will always throw!</param>
- /// <returns>irrelevant!</returns>
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Calling this method always throws a <see cref="NotImplementedException"/>.
- /// </summary>
- /// <param name="value">irrelevant; this method will always throw!</param>
- public override void SetLength(long value)
- {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Write data to the stream.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// If you wish to use the <c>GZipStream</c> to compress data while writing,
- /// you can create a <c>GZipStream</c> with <c>CompressionMode.Compress</c>, and a
- /// writable output stream. Then call <c>Write()</c> on that <c>GZipStream</c>,
- /// providing uncompressed data as input. The data sent to the output stream
- /// will be the compressed form of the data written.
- /// </para>
- ///
- /// <para>
- /// A <c>GZipStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but not
- /// both. Writing implies compression. Reading implies decompression.
- /// </para>
- ///
- /// </remarks>
- /// <param name="buffer">The buffer holding data to write to the stream.</param>
- /// <param name="offset">the offset within that data array to find the first byte to write.</param>
- /// <param name="count">the number of bytes to write.</param>
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (_disposed) throw new ObjectDisposedException("GZipStream");
- if (_baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Undefined)
- {
- //Console.WriteLine("GZipStream: First write");
- if (_baseStream._wantCompress)
- {
- // first write in compression, therefore, emit the GZIP header
- _headerByteCount = EmitHeader();
- }
- else
- {
- throw new InvalidOperationException();
- }
- }
-
- _baseStream.Write(buffer, offset, count);
- }
- #endregion
-
-
- internal static readonly System.DateTime _unixEpoch = new System.DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
-#if SILVERLIGHT || NETCF
- internal static readonly System.Text.Encoding iso8859dash1 = new Ionic.Encoding.Iso8859Dash1Encoding();
-#else
- internal static readonly System.Text.Encoding iso8859dash1 = System.Text.Encoding.GetEncoding("iso-8859-1");
-#endif
-
-
- private int EmitHeader()
- {
- byte[] commentBytes = (Comment == null) ? null : iso8859dash1.GetBytes(Comment);
- byte[] filenameBytes = (FileName == null) ? null : iso8859dash1.GetBytes(FileName);
-
- int cbLength = (Comment == null) ? 0 : commentBytes.Length + 1;
- int fnLength = (FileName == null) ? 0 : filenameBytes.Length + 1;
-
- int bufferLength = 10 + cbLength + fnLength;
- byte[] header = new byte[bufferLength];
- int i = 0;
- // ID
- header[i++] = 0x1F;
- header[i++] = 0x8B;
-
- // compression method
- header[i++] = 8;
- byte flag = 0;
- if (Comment != null)
- flag ^= 0x10;
- if (FileName != null)
- flag ^= 0x8;
-
- // flag
- header[i++] = flag;
-
- // mtime
- if (!LastModified.HasValue) LastModified = DateTime.Now;
- System.TimeSpan delta = LastModified.Value - _unixEpoch;
- Int32 timet = (Int32)delta.TotalSeconds;
- Array.Copy(BitConverter.GetBytes(timet), 0, header, i, 4);
- i += 4;
-
- // xflg
- header[i++] = 0; // this field is totally useless
- // OS
- header[i++] = 0xFF; // 0xFF == unspecified
-
- // extra field length - only if FEXTRA is set, which it is not.
- //header[i++]= 0;
- //header[i++]= 0;
-
- // filename
- if (fnLength != 0)
- {
- Array.Copy(filenameBytes, 0, header, i, fnLength - 1);
- i += fnLength - 1;
- header[i++] = 0; // terminate
- }
-
- // comment
- if (cbLength != 0)
- {
- Array.Copy(commentBytes, 0, header, i, cbLength - 1);
- i += cbLength - 1;
- header[i++] = 0; // terminate
- }
-
- _baseStream._stream.Write(header, 0, header.Length);
-
- return header.Length; // bytes written
- }
-
-
-
- /// <summary>
- /// Compress a string into a byte array using GZip.
- /// </summary>
- ///
- /// <remarks>
- /// Uncompress it with <see cref="GZipStream.UncompressString(byte[])"/>.
- /// </remarks>
- ///
- /// <seealso cref="GZipStream.UncompressString(byte[])"/>
- /// <seealso cref="GZipStream.CompressBuffer(byte[])"/>
- ///
- /// <param name="s">
- /// A string to compress. The string will first be encoded
- /// using UTF8, then compressed.
- /// </param>
- ///
- /// <returns>The string in compressed form</returns>
- public static byte[] CompressString(String s)
- {
- using (var ms = new MemoryStream())
- {
- System.IO.Stream compressor =
- new GZipStream(ms, CompressionMode.Compress, CompressionLevel.BestCompression);
- ZlibBaseStream.CompressString(s, compressor);
- return ms.ToArray();
- }
- }
-
-
- /// <summary>
- /// Compress a byte array into a new byte array using GZip.
- /// </summary>
- ///
- /// <remarks>
- /// Uncompress it with <see cref="GZipStream.UncompressBuffer(byte[])"/>.
- /// </remarks>
- ///
- /// <seealso cref="GZipStream.CompressString(string)"/>
- /// <seealso cref="GZipStream.UncompressBuffer(byte[])"/>
- ///
- /// <param name="b">
- /// A buffer to compress.
- /// </param>
- ///
- /// <returns>The data in compressed form</returns>
- public static byte[] CompressBuffer(byte[] b)
- {
- using (var ms = new MemoryStream())
- {
- System.IO.Stream compressor =
- new GZipStream( ms, CompressionMode.Compress, CompressionLevel.BestCompression );
-
- ZlibBaseStream.CompressBuffer(b, compressor);
- return ms.ToArray();
- }
- }
-
-
- /// <summary>
- /// Uncompress a GZip'ed byte array into a single string.
- /// </summary>
- ///
- /// <seealso cref="GZipStream.CompressString(String)"/>
- /// <seealso cref="GZipStream.UncompressBuffer(byte[])"/>
- ///
- /// <param name="compressed">
- /// A buffer containing GZIP-compressed data.
- /// </param>
- ///
- /// <returns>The uncompressed string</returns>
- public static String UncompressString(byte[] compressed)
- {
- using (var input = new MemoryStream(compressed))
- {
- Stream decompressor = new GZipStream(input, CompressionMode.Decompress);
- return ZlibBaseStream.UncompressString(compressed, decompressor);
- }
- }
-
-
- /// <summary>
- /// Uncompress a GZip'ed byte array into a byte array.
- /// </summary>
- ///
- /// <seealso cref="GZipStream.CompressBuffer(byte[])"/>
- /// <seealso cref="GZipStream.UncompressString(byte[])"/>
- ///
- /// <param name="compressed">
- /// A buffer containing data that has been compressed with GZip.
- /// </param>
- ///
- /// <returns>The data in uncompressed form</returns>
- public static byte[] UncompressBuffer(byte[] compressed)
- {
- using (var input = new System.IO.MemoryStream(compressed))
- {
- System.IO.Stream decompressor =
- new GZipStream( input, CompressionMode.Decompress );
-
- return ZlibBaseStream.UncompressBuffer(compressed, decompressor);
- }
- }
-
-
- }
-}
diff --git a/EPPlus/Packaging/DotNetZip/Zlib/InfTree.cs b/EPPlus/Packaging/DotNetZip/Zlib/InfTree.cs
deleted file mode 100644
index 431299c..0000000
--- a/EPPlus/Packaging/DotNetZip/Zlib/InfTree.cs
+++ /dev/null
@@ -1,436 +0,0 @@
-// Inftree.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2009-October-28 12:43:54>
-//
-// ------------------------------------------------------------------
-//
-// This module defines classes used in decompression. This code is derived
-// from the jzlib implementation of zlib. In keeping with the license for jzlib,
-// the copyright to that code is below.
-//
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-//
-// 2. 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.
-//
-// 3. The names of the authors may not be used to endorse or promote products
-// derived from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
-// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
-//
-// -----------------------------------------------------------------------
-//
-// This program is based on zlib-1.1.3; credit to authors
-// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
-// and contributors of zlib.
-//
-// -----------------------------------------------------------------------
-
-
-
-using System;
-namespace OfficeOpenXml.Packaging.Ionic.Zlib
-{
-
- sealed class InfTree
- {
-
- private const int MANY = 1440;
-
- private const int Z_OK = 0;
- private const int Z_STREAM_END = 1;
- private const int Z_NEED_DICT = 2;
- private const int Z_ERRNO = - 1;
- private const int Z_STREAM_ERROR = - 2;
- private const int Z_DATA_ERROR = - 3;
- private const int Z_MEM_ERROR = - 4;
- private const int Z_BUF_ERROR = - 5;
- private const int Z_VERSION_ERROR = - 6;
-
- internal const int fixed_bl = 9;
- internal const int fixed_bd = 5;
-
- //UPGRADE_NOTE: Final was removed from the declaration of 'fixed_tl'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
- internal static readonly int[] fixed_tl = new int[]{96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 160, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 208, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 176, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 244, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 236, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 220, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 194, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 154, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186,
- 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 230, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 174, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 222, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 190, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 254, 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 193, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 205, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 173, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 221, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189, 0, 8,
- 14, 0, 8, 142, 0, 8, 78, 0, 9, 253, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 195, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 147, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 243, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 235, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 167, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 159, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 223, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 255};
- //UPGRADE_NOTE: Final was removed from the declaration of 'fixed_td'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
- internal static readonly int[] fixed_td = new int[]{80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33, 92, 5, 8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, 80, 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, 1537, 85, 5, 97, 93, 5, 24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92, 5, 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577};
-
- // Tables for deflate from PKZIP's appnote.txt.
- //UPGRADE_NOTE: Final was removed from the declaration of 'cplens'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
- internal static readonly int[] cplens = new int[]{3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
-
- // see note #13 above about 258
- //UPGRADE_NOTE: Final was removed from the declaration of 'cplext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
- internal static readonly int[] cplext = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112};
-
- //UPGRADE_NOTE: Final was removed from the declaration of 'cpdist'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
- internal static readonly int[] cpdist = new int[]{1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
-
- //UPGRADE_NOTE: Final was removed from the declaration of 'cpdext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
- internal static readonly int[] cpdext = new int[]{0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
-
- // If BMAX needs to be larger than 16, then h and x[] should be uLong.
- internal const int BMAX = 15; // maximum bit length of any code
-
- internal int[] hn = null; // hufts used in space
- internal int[] v = null; // work area for huft_build
- internal int[] c = null; // bit length count table
- internal int[] r = null; // table entry for structure assignment
- internal int[] u = null; // table stack
- internal int[] x = null; // bit offsets, then code stack
-
- private int huft_build(int[] b, int bindex, int n, int s, int[] d, int[] e, int[] t, int[] m, int[] hp, int[] hn, int[] v)
- {
- // Given a list of code lengths and a maximum table size, make a set of
- // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
- // if the given code set is incomplete (the tables are still built in this
- // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
- // lengths), or Z_MEM_ERROR if not enough memory.
-
- int a; // counter for codes of length k
- int f; // i repeats in table every f entries
- int g; // maximum code length
- int h; // table level
- int i; // counter, current code
- int j; // counter
- int k; // number of bits in current code
- int l; // bits per table (returned in m)
- int mask; // (1 << w) - 1, to avoid cc -O bug on HP
- int p; // pointer into c[], b[], or v[]
- int q; // points to current table
- int w; // bits before this table == (l * h)
- int xp; // pointer into x
- int y; // number of dummy codes added
- int z; // number of entries in current table
-
- // Generate counts for each bit length
-
- p = 0; i = n;
- do
- {
- c[b[bindex + p]]++; p++; i--; // assume all entries <= BMAX
- }
- while (i != 0);
-
- if (c[0] == n)
- {
- // null input--all zero length codes
- t[0] = - 1;
- m[0] = 0;
- return Z_OK;
- }
-
- // Find minimum and maximum length, bound *m by those
- l = m[0];
- for (j = 1; j <= BMAX; j++)
- if (c[j] != 0)
- break;
- k = j; // minimum code length
- if (l < j)
- {
- l = j;
- }
- for (i = BMAX; i != 0; i--)
- {
- if (c[i] != 0)
- break;
- }
- g = i; // maximum code length
- if (l > i)
- {
- l = i;
- }
- m[0] = l;
-
- // Adjust last length count to fill out codes, if needed
- for (y = 1 << j; j < i; j++, y <<= 1)
- {
- if ((y -= c[j]) < 0)
- {
- return Z_DATA_ERROR;
- }
- }
- if ((y -= c[i]) < 0)
- {
- return Z_DATA_ERROR;
- }
- c[i] += y;
-
- // Generate starting offsets into the value table for each length
- x[1] = j = 0;
- p = 1; xp = 2;
- while (--i != 0)
- {
- // note that i == g from above
- x[xp] = (j += c[p]);
- xp++;
- p++;
- }
-
- // Make a table of values in order of bit lengths
- i = 0; p = 0;
- do
- {
- if ((j = b[bindex + p]) != 0)
- {
- v[x[j]++] = i;
- }
- p++;
- }
- while (++i < n);
- n = x[g]; // set n to length of v
-
- // Generate the Huffman codes and for each, make the table entries
- x[0] = i = 0; // first Huffman code is zero
- p = 0; // grab values in bit order
- h = - 1; // no tables yet--level -1
- w = - l; // bits decoded == (l * h)
- u[0] = 0; // just to keep compilers happy
- q = 0; // ditto
- z = 0; // ditto
-
- // go through the bit lengths (k already is bits in shortest code)
- for (; k <= g; k++)
- {
- a = c[k];
- while (a-- != 0)
- {
- // here i is the Huffman code of length k bits for value *p
- // make tables up to required level
- while (k > w + l)
- {
- h++;
- w += l; // previous table always l bits
- // compute minimum size table less than or equal to l bits
- z = g - w;
- z = (z > l)?l:z; // table size upper limit
- if ((f = 1 << (j = k - w)) > a + 1)
- {
- // try a k-w bit table
- // too few codes for k-w bit table
- f -= (a + 1); // deduct codes from patterns left
- xp = k;
- if (j < z)
- {
- while (++j < z)
- {
- // try smaller tables up to z bits
- if ((f <<= 1) <= c[++xp])
- break; // enough codes to use up j bits
- f -= c[xp]; // else deduct codes from patterns
- }
- }
- }
- z = 1 << j; // table entries for j-bit table
-
- // allocate new table
- if (hn[0] + z > MANY)
- {
- // (note: doesn't matter for fixed)
- return Z_DATA_ERROR; // overflow of MANY
- }
- u[h] = q = hn[0]; // DEBUG
- hn[0] += z;
-
- // connect to last table, if there is one
- if (h != 0)
- {
- x[h] = i; // save pattern for backing up
- r[0] = (sbyte) j; // bits in this table
- r[1] = (sbyte) l; // bits to dump before this table
- j = SharedUtils.URShift(i, (w - l));
- r[2] = (int) (q - u[h - 1] - j); // offset to this table
- Array.Copy(r, 0, hp, (u[h - 1] + j) * 3, 3); // connect to last table
- }
- else
- {
- t[0] = q; // first table is returned result
- }
- }
-
- // set up table entry in r
- r[1] = (sbyte) (k - w);
- if (p >= n)
- {
- r[0] = 128 + 64; // out of values--invalid code
- }
- else if (v[p] < s)
- {
- r[0] = (sbyte) (v[p] < 256?0:32 + 64); // 256 is end-of-block
- r[2] = v[p++]; // simple code is just the value
- }
- else
- {
- r[0] = (sbyte) (e[v[p] - s] + 16 + 64); // non-simple--look up in lists
- r[2] = d[v[p++] - s];
- }
-
- // fill code-like entries with r
- f = 1 << (k - w);
- for (j = SharedUtils.URShift(i, w); j < z; j += f)
- {
- Array.Copy(r, 0, hp, (q + j) * 3, 3);
- }
-
- // backwards increment the k-bit code i
- for (j = 1 << (k - 1); (i & j) != 0; j = SharedUtils.URShift(j, 1))
- {
- i ^= j;
- }
- i ^= j;
-
- // backup over finished tables
- mask = (1 << w) - 1; // needed on HP, cc -O bug
- while ((i & mask) != x[h])
- {
- h--; // don't need to update q
- w -= l;
- mask = (1 << w) - 1;
- }
- }
- }
- // Return Z_BUF_ERROR if we were given an incomplete table
- return y != 0 && g != 1?Z_BUF_ERROR:Z_OK;
- }
-
- internal int inflate_trees_bits(int[] c, int[] bb, int[] tb, int[] hp, ZlibCodec z)
- {
- int result;
- initWorkArea(19);
- hn[0] = 0;
- result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);
-
- if (result == Z_DATA_ERROR)
- {
- z.Message = "oversubscribed dynamic bit lengths tree";
- }
- else if (result == Z_BUF_ERROR || bb[0] == 0)
- {
- z.Message = "incomplete dynamic bit lengths tree";
- result = Z_DATA_ERROR;
- }
- return result;
- }
-
- internal int inflate_trees_dynamic(int nl, int nd, int[] c, int[] bl, int[] bd, int[] tl, int[] td, int[] hp, ZlibCodec z)
- {
- int result;
-
- // build literal/length tree
- initWorkArea(288);
- hn[0] = 0;
- result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
- if (result != Z_OK || bl[0] == 0)
- {
- if (result == Z_DATA_ERROR)
- {
- z.Message = "oversubscribed literal/length tree";
- }
- else if (result != Z_MEM_ERROR)
- {
- z.Message = "incomplete literal/length tree";
- result = Z_DATA_ERROR;
- }
- return result;
- }
-
- // build distance tree
- initWorkArea(288);
- result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);
-
- if (result != Z_OK || (bd[0] == 0 && nl > 257))
- {
- if (result == Z_DATA_ERROR)
- {
- z.Message = "oversubscribed distance tree";
- }
- else if (result == Z_BUF_ERROR)
- {
- z.Message = "incomplete distance tree";
- result = Z_DATA_ERROR;
- }
- else if (result != Z_MEM_ERROR)
- {
- z.Message = "empty distance tree with lengths";
- result = Z_DATA_ERROR;
- }
- return result;
- }
-
- return Z_OK;
- }
-
- internal static int inflate_trees_fixed(int[] bl, int[] bd, int[][] tl, int[][] td, ZlibCodec z)
- {
- bl[0] = fixed_bl;
- bd[0] = fixed_bd;
- tl[0] = fixed_tl;
- td[0] = fixed_td;
- return Z_OK;
- }
-
- private void initWorkArea(int vsize)
- {
- if (hn == null)
- {
- hn = new int[1];
- v = new int[vsize];
- c = new int[BMAX + 1];
- r = new int[3];
- u = new int[BMAX];
- x = new int[BMAX + 1];
- }
- else
- {
- if (v.Length < vsize)
- {
- v = new int[vsize];
- }
- Array.Clear(v,0,vsize);
- Array.Clear(c,0,BMAX+1);
- r[0]=0; r[1]=0; r[2]=0;
- // for(int i=0; i<BMAX; i++){u[i]=0;}
- //Array.Copy(c, 0, u, 0, BMAX);
- Array.Clear(u,0,BMAX);
- // for(int i=0; i<BMAX+1; i++){x[i]=0;}
- //Array.Copy(c, 0, x, 0, BMAX + 1);
- Array.Clear(x,0,BMAX+1);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/EPPlus/Packaging/DotNetZip/Zlib/Inflate.cs b/EPPlus/Packaging/DotNetZip/Zlib/Inflate.cs
deleted file mode 100644
index 47c8d6e..0000000
--- a/EPPlus/Packaging/DotNetZip/Zlib/Inflate.cs
+++ /dev/null
@@ -1,1796 +0,0 @@
-// Inflate.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2010-January-08 18:32:12>
-//
-// ------------------------------------------------------------------
-//
-// This module defines classes for decompression. This code is derived
-// from the jzlib implementation of zlib, but significantly modified.
-// The object model is not the same, and many of the behaviors are
-// different. Nonetheless, in keeping with the license for jzlib, I am
-// reproducing the copyright to that code here.
-//
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-//
-// 2. 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.
-//
-// 3. The names of the authors may not be used to endorse or promote products
-// derived from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
-// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
-//
-// -----------------------------------------------------------------------
-//
-// This program is based on zlib-1.1.3; credit to authors
-// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
-// and contributors of zlib.
-//
-// -----------------------------------------------------------------------
-
-
-using System;
-namespace OfficeOpenXml.Packaging.Ionic.Zlib
-{
- sealed class InflateBlocks
- {
- private const int MANY = 1440;
-
- // Table for deflate from PKZIP's appnote.txt.
- internal static readonly int[] border = new int[]
- { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
-
- private enum InflateBlockMode
- {
- TYPE = 0, // get type bits (3, including end bit)
- LENS = 1, // get lengths for stored
- STORED = 2, // processing stored block
- TABLE = 3, // get table lengths
- BTREE = 4, // get bit lengths tree for a dynamic block
- DTREE = 5, // get length, distance trees for a dynamic block
- CODES = 6, // processing fixed or dynamic block
- DRY = 7, // output remaining window bytes
- DONE = 8, // finished last block, done
- BAD = 9, // ot a data error--stuck here
- }
-
- private InflateBlockMode mode; // current inflate_block mode
-
- internal int left; // if STORED, bytes left to copy
-
- internal int table; // table lengths (14 bits)
- internal int index; // index into blens (or border)
- internal int[] blens; // bit lengths of codes
- internal int[] bb = new int[1]; // bit length tree depth
- internal int[] tb = new int[1]; // bit length decoding tree
-
- internal InflateCodes codes = new InflateCodes(); // if CODES, current state
-
- internal int last; // true if this block is the last block
-
- internal ZlibCodec _codec; // pointer back to this zlib stream
-
- // mode independent information
- internal int bitk; // bits in bit buffer
- internal int bitb; // bit buffer
- internal int[] hufts; // single malloc for tree space
- internal byte[] window; // sliding window
- internal int end; // one byte after sliding window
- internal int readAt; // window read pointer
- internal int writeAt; // window write pointer
- internal System.Object checkfn; // check function
- internal uint check; // check on output
-
- internal InfTree inftree = new InfTree();
-
- internal InflateBlocks(ZlibCodec codec, System.Object checkfn, int w)
- {
- _codec = codec;
- hufts = new int[MANY * 3];
- window = new byte[w];
- end = w;
- this.checkfn = checkfn;
- mode = InflateBlockMode.TYPE;
- Reset();
- }
-
- internal uint Reset()
- {
- uint oldCheck = check;
- mode = InflateBlockMode.TYPE;
- bitk = 0;
- bitb = 0;
- readAt = writeAt = 0;
-
- if (checkfn != null)
- _codec._Adler32 = check = Adler.Adler32(0, null, 0, 0);
- return oldCheck;
- }
-
-
- internal int Process(int r)
- {
- int t; // temporary storage
- int b; // bit buffer
- int k; // bits in bit buffer
- int p; // input data pointer
- int n; // bytes available there
- int q; // output window write pointer
- int m; // bytes to end of window or read pointer
-
- // copy input/output information to locals (UPDATE macro restores)
-
- p = _codec.NextIn;
- n = _codec.AvailableBytesIn;
- b = bitb;
- k = bitk;
-
- q = writeAt;
- m = (int)(q < readAt ? readAt - q - 1 : end - q);
-
-
- // process input based on current state
- while (true)
- {
- switch (mode)
- {
- case InflateBlockMode.TYPE:
-
- while (k < (3))
- {
- if (n != 0)
- {
- r = ZlibConstants.Z_OK;
- }
- else
- {
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
-
- n--;
- b |= (_codec.InputBuffer[p++] & 0xff) << k;
- k += 8;
- }
- t = (int)(b & 7);
- last = t & 1;
-
- switch ((uint)t >> 1)
- {
- case 0: // stored
- b >>= 3; k -= (3);
- t = k & 7; // go to byte boundary
- b >>= t; k -= t;
- mode = InflateBlockMode.LENS; // get length of stored block
- break;
-
- case 1: // fixed
- int[] bl = new int[1];
- int[] bd = new int[1];
- int[][] tl = new int[1][];
- int[][] td = new int[1][];
- InfTree.inflate_trees_fixed(bl, bd, tl, td, _codec);
- codes.Init(bl[0], bd[0], tl[0], 0, td[0], 0);
- b >>= 3; k -= 3;
- mode = InflateBlockMode.CODES;
- break;
-
- case 2: // dynamic
- b >>= 3; k -= 3;
- mode = InflateBlockMode.TABLE;
- break;
-
- case 3: // illegal
- b >>= 3; k -= 3;
- mode = InflateBlockMode.BAD;
- _codec.Message = "invalid block type";
- r = ZlibConstants.Z_DATA_ERROR;
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
- break;
-
- case InflateBlockMode.LENS:
-
- while (k < (32))
- {
- if (n != 0)
- {
- r = ZlibConstants.Z_OK;
- }
- else
- {
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
- ;
- n--;
- b |= (_codec.InputBuffer[p++] & 0xff) << k;
- k += 8;
- }
-
- if ( ( ((~b)>>16) & 0xffff) != (b & 0xffff))
- {
- mode = InflateBlockMode.BAD;
- _codec.Message = "invalid stored block lengths";
- r = ZlibConstants.Z_DATA_ERROR;
-
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
- left = (b & 0xffff);
- b = k = 0; // dump bits
- mode = left != 0 ? InflateBlockMode.STORED : (last != 0 ? InflateBlockMode.DRY : InflateBlockMode.TYPE);
- break;
-
- case InflateBlockMode.STORED:
- if (n == 0)
- {
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
-
- if (m == 0)
- {
- if (q == end && readAt != 0)
- {
- q = 0; m = (int)(q < readAt ? readAt - q - 1 : end - q);
- }
- if (m == 0)
- {
- writeAt = q;
- r = Flush(r);
- q = writeAt; m = (int)(q < readAt ? readAt - q - 1 : end - q);
- if (q == end && readAt != 0)
- {
- q = 0; m = (int)(q < readAt ? readAt - q - 1 : end - q);
- }
- if (m == 0)
- {
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
- }
- }
- r = ZlibConstants.Z_OK;
-
- t = left;
- if (t > n)
- t = n;
- if (t > m)
- t = m;
- Array.Copy(_codec.InputBuffer, p, window, q, t);
- p += t; n -= t;
- q += t; m -= t;
- if ((left -= t) != 0)
- break;
- mode = last != 0 ? InflateBlockMode.DRY : InflateBlockMode.TYPE;
- break;
-
- case InflateBlockMode.TABLE:
-
- while (k < (14))
- {
- if (n != 0)
- {
- r = ZlibConstants.Z_OK;
- }
- else
- {
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
-
- n--;
- b |= (_codec.InputBuffer[p++] & 0xff) << k;
- k += 8;
- }
-
- table = t = (b & 0x3fff);
- if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
- {
- mode = InflateBlockMode.BAD;
- _codec.Message = "too many length or distance symbols";
- r = ZlibConstants.Z_DATA_ERROR;
-
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
- t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
- if (blens == null || blens.Length < t)
- {
- blens = new int[t];
- }
- else
- {
- Array.Clear(blens, 0, t);
- // for (int i = 0; i < t; i++)
- // {
- // blens[i] = 0;
- // }
- }
-
- b >>= 14;
- k -= 14;
-
-
- index = 0;
- mode = InflateBlockMode.BTREE;
- goto case InflateBlockMode.BTREE;
-
- case InflateBlockMode.BTREE:
- while (index < 4 + (table >> 10))
- {
- while (k < (3))
- {
- if (n != 0)
- {
- r = ZlibConstants.Z_OK;
- }
- else
- {
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
-
- n--;
- b |= (_codec.InputBuffer[p++] & 0xff) << k;
- k += 8;
- }
-
- blens[border[index++]] = b & 7;
-
- b >>= 3; k -= 3;
- }
-
- while (index < 19)
- {
- blens[border[index++]] = 0;
- }
-
- bb[0] = 7;
- t = inftree.inflate_trees_bits(blens, bb, tb, hufts, _codec);
- if (t != ZlibConstants.Z_OK)
- {
- r = t;
- if (r == ZlibConstants.Z_DATA_ERROR)
- {
- blens = null;
- mode = InflateBlockMode.BAD;
- }
-
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
-
- index = 0;
- mode = InflateBlockMode.DTREE;
- goto case InflateBlockMode.DTREE;
-
- case InflateBlockMode.DTREE:
- while (true)
- {
- t = table;
- if (!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)))
- {
- break;
- }
-
- int i, j, c;
-
- t = bb[0];
-
- while (k < t)
- {
- if (n != 0)
- {
- r = ZlibConstants.Z_OK;
- }
- else
- {
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
-
- n--;
- b |= (_codec.InputBuffer[p++] & 0xff) << k;
- k += 8;
- }
-
- t = hufts[(tb[0] + (b & InternalInflateConstants.InflateMask[t])) * 3 + 1];
- c = hufts[(tb[0] + (b & InternalInflateConstants.InflateMask[t])) * 3 + 2];
-
- if (c < 16)
- {
- b >>= t; k -= t;
- blens[index++] = c;
- }
- else
- {
- // c == 16..18
- i = c == 18 ? 7 : c - 14;
- j = c == 18 ? 11 : 3;
-
- while (k < (t + i))
- {
- if (n != 0)
- {
- r = ZlibConstants.Z_OK;
- }
- else
- {
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
-
- n--;
- b |= (_codec.InputBuffer[p++] & 0xff) << k;
- k += 8;
- }
-
- b >>= t; k -= t;
-
- j += (b & InternalInflateConstants.InflateMask[i]);
-
- b >>= i; k -= i;
-
- i = index;
- t = table;
- if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1))
- {
- blens = null;
- mode = InflateBlockMode.BAD;
- _codec.Message = "invalid bit length repeat";
- r = ZlibConstants.Z_DATA_ERROR;
-
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
-
- c = (c == 16) ? blens[i-1] : 0;
- do
- {
- blens[i++] = c;
- }
- while (--j != 0);
- index = i;
- }
- }
-
- tb[0] = -1;
- {
- int[] bl = new int[] { 9 }; // must be <= 9 for lookahead assumptions
- int[] bd = new int[] { 6 }; // must be <= 9 for lookahead assumptions
- int[] tl = new int[1];
- int[] td = new int[1];
-
- t = table;
- t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), blens, bl, bd, tl, td, hufts, _codec);
-
- if (t != ZlibConstants.Z_OK)
- {
- if (t == ZlibConstants.Z_DATA_ERROR)
- {
- blens = null;
- mode = InflateBlockMode.BAD;
- }
- r = t;
-
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
- codes.Init(bl[0], bd[0], hufts, tl[0], hufts, td[0]);
- }
- mode = InflateBlockMode.CODES;
- goto case InflateBlockMode.CODES;
-
- case InflateBlockMode.CODES:
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
-
- r = codes.Process(this, r);
- if (r != ZlibConstants.Z_STREAM_END)
- {
- return Flush(r);
- }
-
- r = ZlibConstants.Z_OK;
- p = _codec.NextIn;
- n = _codec.AvailableBytesIn;
- b = bitb;
- k = bitk;
- q = writeAt;
- m = (int)(q < readAt ? readAt - q - 1 : end - q);
-
- if (last == 0)
- {
- mode = InflateBlockMode.TYPE;
- break;
- }
- mode = InflateBlockMode.DRY;
- goto case InflateBlockMode.DRY;
-
- case InflateBlockMode.DRY:
- writeAt = q;
- r = Flush(r);
- q = writeAt; m = (int)(q < readAt ? readAt - q - 1 : end - q);
- if (readAt != writeAt)
- {
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
- mode = InflateBlockMode.DONE;
- goto case InflateBlockMode.DONE;
-
- case InflateBlockMode.DONE:
- r = ZlibConstants.Z_STREAM_END;
- bitb = b;
- bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
-
- case InflateBlockMode.BAD:
- r = ZlibConstants.Z_DATA_ERROR;
-
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
-
-
- default:
- r = ZlibConstants.Z_STREAM_ERROR;
-
- bitb = b; bitk = k;
- _codec.AvailableBytesIn = n;
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- writeAt = q;
- return Flush(r);
- }
- }
- }
-
-
- internal void Free()
- {
- Reset();
- window = null;
- hufts = null;
- }
-
- internal void SetDictionary(byte[] d, int start, int n)
- {
- Array.Copy(d, start, window, 0, n);
- readAt = writeAt = n;
- }
-
- // Returns true if inflate is currently at the end of a block generated
- // by Z_SYNC_FLUSH or Z_FULL_FLUSH.
- internal int SyncPoint()
- {
- return mode == InflateBlockMode.LENS ? 1 : 0;
- }
-
- // copy as much as possible from the sliding window to the output area
- internal int Flush(int r)
- {
- int nBytes;
-
- for (int pass=0; pass < 2; pass++)
- {
- if (pass==0)
- {
- // compute number of bytes to copy as far as end of window
- nBytes = (int)((readAt <= writeAt ? writeAt : end) - readAt);
- }
- else
- {
- // compute bytes to copy
- nBytes = writeAt - readAt;
- }
-
- // workitem 8870
- if (nBytes == 0)
- {
- if (r == ZlibConstants.Z_BUF_ERROR)
- r = ZlibConstants.Z_OK;
- return r;
- }
-
- if (nBytes > _codec.AvailableBytesOut)
- nBytes = _codec.AvailableBytesOut;
-
- if (nBytes != 0 && r == ZlibConstants.Z_BUF_ERROR)
- r = ZlibConstants.Z_OK;
-
- // update counters
- _codec.AvailableBytesOut -= nBytes;
- _codec.TotalBytesOut += nBytes;
-
- // update check information
- if (checkfn != null)
- _codec._Adler32 = check = Adler.Adler32(check, window, readAt, nBytes);
-
- // copy as far as end of window
- Array.Copy(window, readAt, _codec.OutputBuffer, _codec.NextOut, nBytes);
- _codec.NextOut += nBytes;
- readAt += nBytes;
-
- // see if more to copy at beginning of window
- if (readAt == end && pass == 0)
- {
- // wrap pointers
- readAt = 0;
- if (writeAt == end)
- writeAt = 0;
- }
- else pass++;
- }
-
- // done
- return r;
- }
- }
-
-
- internal static class InternalInflateConstants
- {
- // And'ing with mask[n] masks the lower n bits
- internal static readonly int[] InflateMask = new int[] {
- 0x00000000, 0x00000001, 0x00000003, 0x00000007,
- 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
- 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
- 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff };
- }
-
-
- sealed class InflateCodes
- {
- // waiting for "i:"=input,
- // "o:"=output,
- // "x:"=nothing
- private const int START = 0; // x: set up for LEN
- private const int LEN = 1; // i: get length/literal/eob next
- private const int LENEXT = 2; // i: getting length extra (have base)
- private const int DIST = 3; // i: get distance next
- private const int DISTEXT = 4; // i: getting distance extra
- private const int COPY = 5; // o: copying bytes in window, waiting for space
- private const int LIT = 6; // o: got literal, waiting for output space
- private const int WASH = 7; // o: got eob, possibly still output waiting
- private const int END = 8; // x: got eob and all data flushed
- private const int BADCODE = 9; // x: got error
-
- internal int mode; // current inflate_codes mode
-
- // mode dependent information
- internal int len;
-
- internal int[] tree; // pointer into tree
- internal int tree_index = 0;
- internal int need; // bits needed
-
- internal int lit;
-
- // if EXT or COPY, where and how much
- internal int bitsToGet; // bits to get for extra
- internal int dist; // distance back to copy from
-
- internal byte lbits; // ltree bits decoded per branch
- internal byte dbits; // dtree bits decoder per branch
- internal int[] ltree; // literal/length/eob tree
- internal int ltree_index; // literal/length/eob tree
- internal int[] dtree; // distance tree
- internal int dtree_index; // distance tree
-
- internal InflateCodes()
- {
- }
-
- internal void Init(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index)
- {
- mode = START;
- lbits = (byte)bl;
- dbits = (byte)bd;
- ltree = tl;
- ltree_index = tl_index;
- dtree = td;
- dtree_index = td_index;
- tree = null;
- }
-
- internal int Process(InflateBlocks blocks, int r)
- {
- int j; // temporary storage
- int tindex; // temporary pointer
- int e; // extra bits or operation
- int b = 0; // bit buffer
- int k = 0; // bits in bit buffer
- int p = 0; // input data pointer
- int n; // bytes available there
- int q; // output window write pointer
- int m; // bytes to end of window or read pointer
- int f; // pointer to copy strings from
-
- ZlibCodec z = blocks._codec;
-
- // copy input/output information to locals (UPDATE macro restores)
- p = z.NextIn;
- n = z.AvailableBytesIn;
- b = blocks.bitb;
- k = blocks.bitk;
- q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
-
- // process input and output based on current state
- while (true)
- {
- switch (mode)
- {
- // waiting for "i:"=input, "o:"=output, "x:"=nothing
- case START: // x: set up for LEN
- if (m >= 258 && n >= 10)
- {
- blocks.bitb = b; blocks.bitk = k;
- z.AvailableBytesIn = n;
- z.TotalBytesIn += p - z.NextIn;
- z.NextIn = p;
- blocks.writeAt = q;
- r = InflateFast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, blocks, z);
-
- p = z.NextIn;
- n = z.AvailableBytesIn;
- b = blocks.bitb;
- k = blocks.bitk;
- q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
-
- if (r != ZlibConstants.Z_OK)
- {
- mode = (r == ZlibConstants.Z_STREAM_END) ? WASH : BADCODE;
- break;
- }
- }
- need = lbits;
- tree = ltree;
- tree_index = ltree_index;
-
- mode = LEN;
- goto case LEN;
-
- case LEN: // i: get length/literal/eob next
- j = need;
-
- while (k < j)
- {
- if (n != 0)
- r = ZlibConstants.Z_OK;
- else
- {
- blocks.bitb = b; blocks.bitk = k;
- z.AvailableBytesIn = n;
- z.TotalBytesIn += p - z.NextIn;
- z.NextIn = p;
- blocks.writeAt = q;
- return blocks.Flush(r);
- }
- n--;
- b |= (z.InputBuffer[p++] & 0xff) << k;
- k += 8;
- }
-
- tindex = (tree_index + (b & InternalInflateConstants.InflateMask[j])) * 3;
-
- b >>= (tree[tindex + 1]);
- k -= (tree[tindex + 1]);
-
- e = tree[tindex];
-
- if (e == 0)
- {
- // literal
- lit = tree[tindex + 2];
- mode = LIT;
- break;
- }
- if ((e & 16) != 0)
- {
- // length
- bitsToGet = e & 15;
- len = tree[tindex + 2];
- mode = LENEXT;
- break;
- }
- if ((e & 64) == 0)
- {
- // next table
- need = e;
- tree_index = tindex / 3 + tree[tindex + 2];
- break;
- }
- if ((e & 32) != 0)
- {
- // end of block
- mode = WASH;
- break;
- }
- mode = BADCODE; // invalid code
- z.Message = "invalid literal/length code";
- r = ZlibConstants.Z_DATA_ERROR;
-
- blocks.bitb = b; blocks.bitk = k;
- z.AvailableBytesIn = n;
- z.TotalBytesIn += p - z.NextIn;
- z.NextIn = p;
- blocks.writeAt = q;
- return blocks.Flush(r);
-
-
- case LENEXT: // i: getting length extra (have base)
- j = bitsToGet;
-
- while (k < j)
- {
- if (n != 0)
- r = ZlibConstants.Z_OK;
- else
- {
- blocks.bitb = b; blocks.bitk = k;
- z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
- blocks.writeAt = q;
- return blocks.Flush(r);
- }
- n--; b |= (z.InputBuffer[p++] & 0xff) << k;
- k += 8;
- }
-
- len += (b & InternalInflateConstants.InflateMask[j]);
-
- b >>= j;
- k -= j;
-
- need = dbits;
- tree = dtree;
- tree_index = dtree_index;
- mode = DIST;
- goto case DIST;
-
- case DIST: // i: get distance next
- j = need;
-
- while (k < j)
- {
- if (n != 0)
- r = ZlibConstants.Z_OK;
- else
- {
- blocks.bitb = b; blocks.bitk = k;
- z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
- blocks.writeAt = q;
- return blocks.Flush(r);
- }
- n--; b |= (z.InputBuffer[p++] & 0xff) << k;
- k += 8;
- }
-
- tindex = (tree_index + (b & InternalInflateConstants.InflateMask[j])) * 3;
-
- b >>= tree[tindex + 1];
- k -= tree[tindex + 1];
-
- e = (tree[tindex]);
- if ((e & 0x10) != 0)
- {
- // distance
- bitsToGet = e & 15;
- dist = tree[tindex + 2];
- mode = DISTEXT;
- break;
- }
- if ((e & 64) == 0)
- {
- // next table
- need = e;
- tree_index = tindex / 3 + tree[tindex + 2];
- break;
- }
- mode = BADCODE; // invalid code
- z.Message = "invalid distance code";
- r = ZlibConstants.Z_DATA_ERROR;
-
- blocks.bitb = b; blocks.bitk = k;
- z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
- blocks.writeAt = q;
- return blocks.Flush(r);
-
-
- case DISTEXT: // i: getting distance extra
- j = bitsToGet;
-
- while (k < j)
- {
- if (n != 0)
- r = ZlibConstants.Z_OK;
- else
- {
- blocks.bitb = b; blocks.bitk = k;
- z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
- blocks.writeAt = q;
- return blocks.Flush(r);
- }
- n--; b |= (z.InputBuffer[p++] & 0xff) << k;
- k += 8;
- }
-
- dist += (b & InternalInflateConstants.InflateMask[j]);
-
- b >>= j;
- k -= j;
-
- mode = COPY;
- goto case COPY;
-
- case COPY: // o: copying bytes in window, waiting for space
- f = q - dist;
- while (f < 0)
- {
- // modulo window size-"while" instead
- f += blocks.end; // of "if" handles invalid distances
- }
- while (len != 0)
- {
- if (m == 0)
- {
- if (q == blocks.end && blocks.readAt != 0)
- {
- q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
- }
- if (m == 0)
- {
- blocks.writeAt = q; r = blocks.Flush(r);
- q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
-
- if (q == blocks.end && blocks.readAt != 0)
- {
- q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
- }
-
- if (m == 0)
- {
- blocks.bitb = b; blocks.bitk = k;
- z.AvailableBytesIn = n;
- z.TotalBytesIn += p - z.NextIn;
- z.NextIn = p;
- blocks.writeAt = q;
- return blocks.Flush(r);
- }
- }
- }
-
- blocks.window[q++] = blocks.window[f++]; m--;
-
- if (f == blocks.end)
- f = 0;
- len--;
- }
- mode = START;
- break;
-
- case LIT: // o: got literal, waiting for output space
- if (m == 0)
- {
- if (q == blocks.end && blocks.readAt != 0)
- {
- q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
- }
- if (m == 0)
- {
- blocks.writeAt = q; r = blocks.Flush(r);
- q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
-
- if (q == blocks.end && blocks.readAt != 0)
- {
- q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
- }
- if (m == 0)
- {
- blocks.bitb = b; blocks.bitk = k;
- z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
- blocks.writeAt = q;
- return blocks.Flush(r);
- }
- }
- }
- r = ZlibConstants.Z_OK;
-
- blocks.window[q++] = (byte)lit; m--;
-
- mode = START;
- break;
-
- case WASH: // o: got eob, possibly more output
- if (k > 7)
- {
- // return unused byte, if any
- k -= 8;
- n++;
- p--; // can always return one
- }
-
- blocks.writeAt = q; r = blocks.Flush(r);
- q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q;
-
- if (blocks.readAt != blocks.writeAt)
- {
- blocks.bitb = b; blocks.bitk = k;
- z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
- blocks.writeAt = q;
- return blocks.Flush(r);
- }
- mode = END;
- goto case END;
-
- case END:
- r = ZlibConstants.Z_STREAM_END;
- blocks.bitb = b; blocks.bitk = k;
- z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
- blocks.writeAt = q;
- return blocks.Flush(r);
-
- case BADCODE: // x: got error
-
- r = ZlibConstants.Z_DATA_ERROR;
-
- blocks.bitb = b; blocks.bitk = k;
- z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
- blocks.writeAt = q;
- return blocks.Flush(r);
-
- default:
- r = ZlibConstants.Z_STREAM_ERROR;
-
- blocks.bitb = b; blocks.bitk = k;
- z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
- blocks.writeAt = q;
- return blocks.Flush(r);
- }
- }
- }
-
-
- // Called with number of bytes left to write in window at least 258
- // (the maximum string length) and number of input bytes available
- // at least ten. The ten bytes are six bytes for the longest length/
- // distance pair plus four bytes for overloading the bit buffer.
-
- internal int InflateFast(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, InflateBlocks s, ZlibCodec z)
- {
- int t; // temporary pointer
- int[] tp; // temporary pointer
- int tp_index; // temporary pointer
- int e; // extra bits or operation
- int b; // bit buffer
- int k; // bits in bit buffer
- int p; // input data pointer
- int n; // bytes available there
- int q; // output window write pointer
- int m; // bytes to end of window or read pointer
- int ml; // mask for literal/length tree
- int md; // mask for distance tree
- int c; // bytes to copy
- int d; // distance back to copy from
- int r; // copy source pointer
-
- int tp_index_t_3; // (tp_index+t)*3
-
- // load input, output, bit values
- p = z.NextIn; n = z.AvailableBytesIn; b = s.bitb; k = s.bitk;
- q = s.writeAt; m = q < s.readAt ? s.readAt - q - 1 : s.end - q;
-
- // initialize masks
- ml = InternalInflateConstants.InflateMask[bl];
- md = InternalInflateConstants.InflateMask[bd];
-
- // do until not enough input or output space for fast loop
- do
- {
- // assume called with m >= 258 && n >= 10
- // get literal/length code
- while (k < (20))
- {
- // max bits for literal/length code
- n--;
- b |= (z.InputBuffer[p++] & 0xff) << k; k += 8;
- }
-
- t = b & ml;
- tp = tl;
- tp_index = tl_index;
- tp_index_t_3 = (tp_index + t) * 3;
- if ((e = tp[tp_index_t_3]) == 0)
- {
- b >>= (tp[tp_index_t_3 + 1]); k -= (tp[tp_index_t_3 + 1]);
-
- s.window[q++] = (byte)tp[tp_index_t_3 + 2];
- m--;
- continue;
- }
- do
- {
-
- b >>= (tp[tp_index_t_3 + 1]); k -= (tp[tp_index_t_3 + 1]);
-
- if ((e & 16) != 0)
- {
- e &= 15;
- c = tp[tp_index_t_3 + 2] + ((int)b & InternalInflateConstants.InflateMask[e]);
-
- b >>= e; k -= e;
-
- // decode distance base of block to copy
- while (k < 15)
- {
- // max bits for distance code
- n--;
- b |= (z.InputBuffer[p++] & 0xff) << k; k += 8;
- }
-
- t = b & md;
- tp = td;
- tp_index = td_index;
- tp_index_t_3 = (tp_index + t) * 3;
- e = tp[tp_index_t_3];
-
- do
- {
-
- b >>= (tp[tp_index_t_3 + 1]); k -= (tp[tp_index_t_3 + 1]);
-
- if ((e & 16) != 0)
- {
- // get extra bits to add to distance base
- e &= 15;
- while (k < e)
- {
- // get extra bits (up to 13)
- n--;
- b |= (z.InputBuffer[p++] & 0xff) << k; k += 8;
- }
-
- d = tp[tp_index_t_3 + 2] + (b & InternalInflateConstants.InflateMask[e]);
-
- b >>= e; k -= e;
-
- // do the copy
- m -= c;
- if (q >= d)
- {
- // offset before dest
- // just copy
- r = q - d;
- if (q - r > 0 && 2 > (q - r))
- {
- s.window[q++] = s.window[r++]; // minimum count is three,
- s.window[q++] = s.window[r++]; // so unroll loop a little
- c -= 2;
- }
- else
- {
- Array.Copy(s.window, r, s.window, q, 2);
- q += 2; r += 2; c -= 2;
- }
- }
- else
- {
- // else offset after destination
- r = q - d;
- do
- {
- r += s.end; // force pointer in window
- }
- while (r < 0); // covers invalid distances
- e = s.end - r;
- if (c > e)
- {
- // if source crosses,
- c -= e; // wrapped copy
- if (q - r > 0 && e > (q - r))
- {
- do
- {
- s.window[q++] = s.window[r++];
- }
- while (--e != 0);
- }
- else
- {
- Array.Copy(s.window, r, s.window, q, e);
- q += e; r += e; e = 0;
- }
- r = 0; // copy rest from start of window
- }
- }
-
- // copy all or what's left
- if (q - r > 0 && c > (q - r))
- {
- do
- {
- s.window[q++] = s.window[r++];
- }
- while (--c != 0);
- }
- else
- {
- Array.Copy(s.window, r, s.window, q, c);
- q += c; r += c; c = 0;
- }
- break;
- }
- else if ((e & 64) == 0)
- {
- t += tp[tp_index_t_3 + 2];
- t += (b & InternalInflateConstants.InflateMask[e]);
- tp_index_t_3 = (tp_index + t) * 3;
- e = tp[tp_index_t_3];
- }
- else
- {
- z.Message = "invalid distance code";
-
- c = z.AvailableBytesIn - n; c = (k >> 3) < c ? k >> 3 : c; n += c; p -= c; k -= (c << 3);
-
- s.bitb = b; s.bitk = k;
- z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
- s.writeAt = q;
-
- return ZlibConstants.Z_DATA_ERROR;
- }
- }
- while (true);
- break;
- }
-
- if ((e & 64) == 0)
- {
- t += tp[tp_index_t_3 + 2];
- t += (b & InternalInflateConstants.InflateMask[e]);
- tp_index_t_3 = (tp_index + t) * 3;
- if ((e = tp[tp_index_t_3]) == 0)
- {
- b >>= (tp[tp_index_t_3 + 1]); k -= (tp[tp_index_t_3 + 1]);
- s.window[q++] = (byte)tp[tp_index_t_3 + 2];
- m--;
- break;
- }
- }
- else if ((e & 32) != 0)
- {
- c = z.AvailableBytesIn - n; c = (k >> 3) < c ? k >> 3 : c; n += c; p -= c; k -= (c << 3);
-
- s.bitb = b; s.bitk = k;
- z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
- s.writeAt = q;
-
- return ZlibConstants.Z_STREAM_END;
- }
- else
- {
- z.Message = "invalid literal/length code";
-
- c = z.AvailableBytesIn - n; c = (k >> 3) < c ? k >> 3 : c; n += c; p -= c; k -= (c << 3);
-
- s.bitb = b; s.bitk = k;
- z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
- s.writeAt = q;
-
- return ZlibConstants.Z_DATA_ERROR;
- }
- }
- while (true);
- }
- while (m >= 258 && n >= 10);
-
- // not enough input or output--restore pointers and return
- c = z.AvailableBytesIn - n; c = (k >> 3) < c ? k >> 3 : c; n += c; p -= c; k -= (c << 3);
-
- s.bitb = b; s.bitk = k;
- z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
- s.writeAt = q;
-
- return ZlibConstants.Z_OK;
- }
- }
-
-
- internal sealed class InflateManager
- {
- // preset dictionary flag in zlib header
- private const int PRESET_DICT = 0x20;
-
- private const int Z_DEFLATED = 8;
-
- private enum InflateManagerMode
- {
- METHOD = 0, // waiting for method byte
- FLAG = 1, // waiting for flag byte
- DICT4 = 2, // four dictionary check bytes to go
- DICT3 = 3, // three dictionary check bytes to go
- DICT2 = 4, // two dictionary check bytes to go
- DICT1 = 5, // one dictionary check byte to go
- DICT0 = 6, // waiting for inflateSetDictionary
- BLOCKS = 7, // decompressing blocks
- CHECK4 = 8, // four check bytes to go
- CHECK3 = 9, // three check bytes to go
- CHECK2 = 10, // two check bytes to go
- CHECK1 = 11, // one check byte to go
- DONE = 12, // finished check, done
- BAD = 13, // got an error--stay here
- }
-
- private InflateManagerMode mode; // current inflate mode
- internal ZlibCodec _codec; // pointer back to this zlib stream
-
- // mode dependent information
- internal int method; // if FLAGS, method byte
-
- // if CHECK, check values to compare
- internal uint computedCheck; // computed check value
- internal uint expectedCheck; // stream check value
-
- // if BAD, inflateSync's marker bytes count
- internal int marker;
-
- // mode independent information
- //internal int nowrap; // flag for no wrapper
- private bool _handleRfc1950HeaderBytes = true;
- internal bool HandleRfc1950HeaderBytes
- {
- get { return _handleRfc1950HeaderBytes; }
- set { _handleRfc1950HeaderBytes = value; }
- }
- internal int wbits; // log2(window size) (8..15, defaults to 15)
-
- internal InflateBlocks blocks; // current inflate_blocks state
-
- public InflateManager() { }
-
- public InflateManager(bool expectRfc1950HeaderBytes)
- {
- _handleRfc1950HeaderBytes = expectRfc1950HeaderBytes;
- }
-
- internal int Reset()
- {
- _codec.TotalBytesIn = _codec.TotalBytesOut = 0;
- _codec.Message = null;
- mode = HandleRfc1950HeaderBytes ? InflateManagerMode.METHOD : InflateManagerMode.BLOCKS;
- blocks.Reset();
- return ZlibConstants.Z_OK;
- }
-
- internal int End()
- {
- if (blocks != null)
- blocks.Free();
- blocks = null;
- return ZlibConstants.Z_OK;
- }
-
- internal int Initialize(ZlibCodec codec, int w)
- {
- _codec = codec;
- _codec.Message = null;
- blocks = null;
-
- // handle undocumented nowrap option (no zlib header or check)
- //nowrap = 0;
- //if (w < 0)
- //{
- // w = - w;
- // nowrap = 1;
- //}
-
- // set window size
- if (w < 8 || w > 15)
- {
- End();
- throw new ZlibException("Bad window size.");
-
- //return ZlibConstants.Z_STREAM_ERROR;
- }
- wbits = w;
-
- blocks = new InflateBlocks(codec,
- HandleRfc1950HeaderBytes ? this : null,
- 1 << w);
-
- // reset state
- Reset();
- return ZlibConstants.Z_OK;
- }
-
-
- internal int Inflate(FlushType flush)
- {
- int b;
-
- if (_codec.InputBuffer == null)
- throw new ZlibException("InputBuffer is null. ");
-
-// int f = (flush == FlushType.Finish)
-// ? ZlibConstants.Z_BUF_ERROR
-// : ZlibConstants.Z_OK;
-
- // workitem 8870
- int f = ZlibConstants.Z_OK;
- int r = ZlibConstants.Z_BUF_ERROR;
-
- while (true)
- {
- switch (mode)
- {
- case InflateManagerMode.METHOD:
- if (_codec.AvailableBytesIn == 0) return r;
- r = f;
- _codec.AvailableBytesIn--;
- _codec.TotalBytesIn++;
- if (((method = _codec.InputBuffer[_codec.NextIn++]) & 0xf) != Z_DEFLATED)
- {
- mode = InflateManagerMode.BAD;
- _codec.Message = String.Format("unknown compression method (0x{0:X2})", method);
- marker = 5; // can't try inflateSync
- break;
- }
- if ((method >> 4) + 8 > wbits)
- {
- mode = InflateManagerMode.BAD;
- _codec.Message = String.Format("invalid window size ({0})", (method >> 4) + 8);
- marker = 5; // can't try inflateSync
- break;
- }
- mode = InflateManagerMode.FLAG;
- break;
-
-
- case InflateManagerMode.FLAG:
- if (_codec.AvailableBytesIn == 0) return r;
- r = f;
- _codec.AvailableBytesIn--;
- _codec.TotalBytesIn++;
- b = (_codec.InputBuffer[_codec.NextIn++]) & 0xff;
-
- if ((((method << 8) + b) % 31) != 0)
- {
- mode = InflateManagerMode.BAD;
- _codec.Message = "incorrect header check";
- marker = 5; // can't try inflateSync
- break;
- }
-
- mode = ((b & PRESET_DICT) == 0)
- ? InflateManagerMode.BLOCKS
- : InflateManagerMode.DICT4;
- break;
-
- case InflateManagerMode.DICT4:
- if (_codec.AvailableBytesIn == 0) return r;
- r = f;
- _codec.AvailableBytesIn--;
- _codec.TotalBytesIn++;
- expectedCheck = (uint)((_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000);
- mode = InflateManagerMode.DICT3;
- break;
-
- case InflateManagerMode.DICT3:
- if (_codec.AvailableBytesIn == 0) return r;
- r = f;
- _codec.AvailableBytesIn--;
- _codec.TotalBytesIn++;
- expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000);
- mode = InflateManagerMode.DICT2;
- break;
-
- case InflateManagerMode.DICT2:
-
- if (_codec.AvailableBytesIn == 0) return r;
- r = f;
- _codec.AvailableBytesIn--;
- _codec.TotalBytesIn++;
- expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00);
- mode = InflateManagerMode.DICT1;
- break;
-
-
- case InflateManagerMode.DICT1:
- if (_codec.AvailableBytesIn == 0) return r;
- r = f;
- _codec.AvailableBytesIn--; _codec.TotalBytesIn++;
- expectedCheck += (uint)(_codec.InputBuffer[_codec.NextIn++] & 0x000000ff);
- _codec._Adler32 = expectedCheck;
- mode = InflateManagerMode.DICT0;
- return ZlibConstants.Z_NEED_DICT;
-
-
- case InflateManagerMode.DICT0:
- mode = InflateManagerMode.BAD;
- _codec.Message = "need dictionary";
- marker = 0; // can try inflateSync
- return ZlibConstants.Z_STREAM_ERROR;
-
-
- case InflateManagerMode.BLOCKS:
- r = blocks.Process(r);
- if (r == ZlibConstants.Z_DATA_ERROR)
- {
- mode = InflateManagerMode.BAD;
- marker = 0; // can try inflateSync
- break;
- }
-
- if (r == ZlibConstants.Z_OK) r = f;
-
- if (r != ZlibConstants.Z_STREAM_END)
- return r;
-
- r = f;
- computedCheck = blocks.Reset();
- if (!HandleRfc1950HeaderBytes)
- {
- mode = InflateManagerMode.DONE;
- return ZlibConstants.Z_STREAM_END;
- }
- mode = InflateManagerMode.CHECK4;
- break;
-
- case InflateManagerMode.CHECK4:
- if (_codec.AvailableBytesIn == 0) return r;
- r = f;
- _codec.AvailableBytesIn--;
- _codec.TotalBytesIn++;
- expectedCheck = (uint)((_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000);
- mode = InflateManagerMode.CHECK3;
- break;
-
- case InflateManagerMode.CHECK3:
- if (_codec.AvailableBytesIn == 0) return r;
- r = f;
- _codec.AvailableBytesIn--; _codec.TotalBytesIn++;
- expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000);
- mode = InflateManagerMode.CHECK2;
- break;
-
- case InflateManagerMode.CHECK2:
- if (_codec.AvailableBytesIn == 0) return r;
- r = f;
- _codec.AvailableBytesIn--;
- _codec.TotalBytesIn++;
- expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00);
- mode = InflateManagerMode.CHECK1;
- break;
-
- case InflateManagerMode.CHECK1:
- if (_codec.AvailableBytesIn == 0) return r;
- r = f;
- _codec.AvailableBytesIn--; _codec.TotalBytesIn++;
- expectedCheck += (uint)(_codec.InputBuffer[_codec.NextIn++] & 0x000000ff);
- if (computedCheck != expectedCheck)
- {
- mode = InflateManagerMode.BAD;
- _codec.Message = "incorrect data check";
- marker = 5; // can't try inflateSync
- break;
- }
- mode = InflateManagerMode.DONE;
- return ZlibConstants.Z_STREAM_END;
-
- case InflateManagerMode.DONE:
- return ZlibConstants.Z_STREAM_END;
-
- case InflateManagerMode.BAD:
- throw new ZlibException(String.Format("Bad state ({0})", _codec.Message));
-
- default:
- throw new ZlibException("Stream error.");
-
- }
- }
- }
-
-
-
- internal int SetDictionary(byte[] dictionary)
- {
- int index = 0;
- int length = dictionary.Length;
- if (mode != InflateManagerMode.DICT0)
- throw new ZlibException("Stream error.");
-
- if (Adler.Adler32(1, dictionary, 0, dictionary.Length) != _codec._Adler32)
- {
- return ZlibConstants.Z_DATA_ERROR;
- }
-
- _codec._Adler32 = Adler.Adler32(0, null, 0, 0);
-
- if (length >= (1 << wbits))
- {
- length = (1 << wbits) - 1;
- index = dictionary.Length - length;
- }
- blocks.SetDictionary(dictionary, index, length);
- mode = InflateManagerMode.BLOCKS;
- return ZlibConstants.Z_OK;
- }
-
-
- private static readonly byte[] mark = new byte[] { 0, 0, 0xff, 0xff };
-
- internal int Sync()
- {
- int n; // number of bytes to look at
- int p; // pointer to bytes
- int m; // number of marker bytes found in a row
- long r, w; // temporaries to save total_in and total_out
-
- // set up
- if (mode != InflateManagerMode.BAD)
- {
- mode = InflateManagerMode.BAD;
- marker = 0;
- }
- if ((n = _codec.AvailableBytesIn) == 0)
- return ZlibConstants.Z_BUF_ERROR;
- p = _codec.NextIn;
- m = marker;
-
- // search
- while (n != 0 && m < 4)
- {
- if (_codec.InputBuffer[p] == mark[m])
- {
- m++;
- }
- else if (_codec.InputBuffer[p] != 0)
- {
- m = 0;
- }
- else
- {
- m = 4 - m;
- }
- p++; n--;
- }
-
- // restore
- _codec.TotalBytesIn += p - _codec.NextIn;
- _codec.NextIn = p;
- _codec.AvailableBytesIn = n;
- marker = m;
-
- // return no joy or set up to restart on a new block
- if (m != 4)
- {
- return ZlibConstants.Z_DATA_ERROR;
- }
- r = _codec.TotalBytesIn;
- w = _codec.TotalBytesOut;
- Reset();
- _codec.TotalBytesIn = r;
- _codec.TotalBytesOut = w;
- mode = InflateManagerMode.BLOCKS;
- return ZlibConstants.Z_OK;
- }
-
-
- // Returns true if inflate is currently at the end of a block generated
- // by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
- // implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
- // but removes the length bytes of the resulting empty stored block. When
- // decompressing, PPP checks that at the end of input packet, inflate is
- // waiting for these length bytes.
- internal int SyncPoint(ZlibCodec z)
- {
- return blocks.SyncPoint();
- }
- }
-}
\ No newline at end of file
diff --git a/EPPlus/Packaging/DotNetZip/Zlib/ParallelDeflateOutputStream.cs b/EPPlus/Packaging/DotNetZip/Zlib/ParallelDeflateOutputStream.cs
deleted file mode 100644
index 3fc9685..0000000
--- a/EPPlus/Packaging/DotNetZip/Zlib/ParallelDeflateOutputStream.cs
+++ /dev/null
@@ -1,1386 +0,0 @@
-//#define Trace
-
-// ParallelDeflateOutputStream.cs
-// ------------------------------------------------------------------
-//
-// A DeflateStream that does compression only, it uses a
-// divide-and-conquer approach with multiple threads to exploit multiple
-// CPUs for the DEFLATE computation.
-//
-// last saved: <2011-July-31 14:49:40>
-//
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009-2011 by Dino Chiesa
-// All rights reserved!
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.IO;
-
-
-namespace OfficeOpenXml.Packaging.Ionic.Zlib
-{
- internal class WorkItem
- {
- public byte[] buffer;
- public byte[] compressed;
- public int crc;
- public int index;
- public int ordinal;
- public int inputBytesAvailable;
- public int compressedBytesAvailable;
- public ZlibCodec compressor;
-
- public WorkItem(int size,
- Ionic.Zlib.CompressionLevel compressLevel,
- CompressionStrategy strategy,
- int ix)
- {
- this.buffer= new byte[size];
- // alloc 5 bytes overhead for every block (margin of safety= 2)
- int n = size + ((size / 32768)+1) * 5 * 2;
- this.compressed = new byte[n];
- this.compressor = new ZlibCodec();
- this.compressor.InitializeDeflate(compressLevel, false);
- this.compressor.OutputBuffer = this.compressed;
- this.compressor.InputBuffer = this.buffer;
- this.index = ix;
- }
- }
-
- /// <summary>
- /// A class for compressing streams using the
- /// Deflate algorithm with multiple threads.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This class performs DEFLATE compression through writing. For
- /// more information on the Deflate algorithm, see IETF RFC 1951,
- /// "DEFLATE Compressed Data Format Specification version 1.3."
- /// </para>
- ///
- /// <para>
- /// This class is similar to <see cref="Ionic.Zlib.DeflateStream"/>, except
- /// that this class is for compression only, and this implementation uses an
- /// approach that employs multiple worker threads to perform the DEFLATE. On
- /// a multi-cpu or multi-core computer, the performance of this class can be
- /// significantly higher than the single-threaded DeflateStream, particularly
- /// for larger streams. How large? Anything over 10mb is a good candidate
- /// for parallel compression.
- /// </para>
- ///
- /// <para>
- /// The tradeoff is that this class uses more memory and more CPU than the
- /// vanilla DeflateStream, and also is less efficient as a compressor. For
- /// large files the size of the compressed data stream can be less than 1%
- /// larger than the size of a compressed data stream from the vanialla
- /// DeflateStream. For smaller files the difference can be larger. The
- /// difference will also be larger if you set the BufferSize to be lower than
- /// the default value. Your mileage may vary. Finally, for small files, the
- /// ParallelDeflateOutputStream can be much slower than the vanilla
- /// DeflateStream, because of the overhead associated to using the thread
- /// pool.
- /// </para>
- ///
- /// </remarks>
- /// <seealso cref="Ionic.Zlib.DeflateStream" />
- public class ParallelDeflateOutputStream : System.IO.Stream
- {
-
- private static readonly int IO_BUFFER_SIZE_DEFAULT = 64 * 1024; // 128k
- private static readonly int BufferPairsPerCore = 4;
-
- private System.Collections.Generic.List<WorkItem> _pool;
- private bool _leaveOpen;
- private bool emitting;
- private System.IO.Stream _outStream;
- private int _maxBufferPairs;
- private int _bufferSize = IO_BUFFER_SIZE_DEFAULT;
- private AutoResetEvent _newlyCompressedBlob;
- //private ManualResetEvent _writingDone;
- //private ManualResetEvent _sessionReset;
- private object _outputLock = new object();
- private bool _isClosed;
- private bool _firstWriteDone;
- private int _currentlyFilling;
- private int _lastFilled;
- private int _lastWritten;
- private int _latestCompressed;
- private int _Crc32;
- private Ionic.Crc.CRC32 _runningCrc;
- private object _latestLock = new object();
- private System.Collections.Generic.Queue<int> _toWrite;
- private System.Collections.Generic.Queue<int> _toFill;
- private Int64 _totalBytesProcessed;
- private Ionic.Zlib.CompressionLevel _compressLevel;
- private volatile Exception _pendingException;
- private bool _handlingException;
- private object _eLock = new Object(); // protects _pendingException
-
- // This bitfield is used only when Trace is defined.
- //private TraceBits _DesiredTrace = TraceBits.Write | TraceBits.WriteBegin |
- //TraceBits.WriteDone | TraceBits.Lifecycle | TraceBits.Fill | TraceBits.Flush |
- //TraceBits.Session;
-
- //private TraceBits _DesiredTrace = TraceBits.WriteBegin | TraceBits.WriteDone | TraceBits.Synch | TraceBits.Lifecycle | TraceBits.Session ;
-
- private TraceBits _DesiredTrace =
- TraceBits.Session |
- TraceBits.Compress |
- TraceBits.WriteTake |
- TraceBits.WriteEnter |
- TraceBits.EmitEnter |
- TraceBits.EmitDone |
- TraceBits.EmitLock |
- TraceBits.EmitSkip |
- TraceBits.EmitBegin;
-
- /// <summary>
- /// Create a ParallelDeflateOutputStream.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// This stream compresses data written into it via the DEFLATE
- /// algorithm (see RFC 1951), and writes out the compressed byte stream.
- /// </para>
- ///
- /// <para>
- /// The instance will use the default compression level, the default
- /// buffer sizes and the default number of threads and buffers per
- /// thread.
- /// </para>
- ///
- /// <para>
- /// This class is similar to <see cref="Ionic.Zlib.DeflateStream"/>,
- /// except that this implementation uses an approach that employs
- /// multiple worker threads to perform the DEFLATE. On a multi-cpu or
- /// multi-core computer, the performance of this class can be
- /// significantly higher than the single-threaded DeflateStream,
- /// particularly for larger streams. How large? Anything over 10mb is
- /// a good candidate for parallel compression.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example shows how to use a ParallelDeflateOutputStream to compress
- /// data. It reads a file, compresses it, and writes the compressed data to
- /// a second, output file.
- ///
- /// <code>
- /// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
- /// int n= -1;
- /// String outputFile = fileToCompress + ".compressed";
- /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
- /// {
- /// using (var raw = System.IO.File.Create(outputFile))
- /// {
- /// using (Stream compressor = new ParallelDeflateOutputStream(raw))
- /// {
- /// while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
- /// {
- /// compressor.Write(buffer, 0, n);
- /// }
- /// }
- /// }
- /// }
- /// </code>
- /// <code lang="VB">
- /// Dim buffer As Byte() = New Byte(4096) {}
- /// Dim n As Integer = -1
- /// Dim outputFile As String = (fileToCompress & ".compressed")
- /// Using input As Stream = File.OpenRead(fileToCompress)
- /// Using raw As FileStream = File.Create(outputFile)
- /// Using compressor As Stream = New ParallelDeflateOutputStream(raw)
- /// Do While (n <> 0)
- /// If (n > 0) Then
- /// compressor.Write(buffer, 0, n)
- /// End If
- /// n = input.Read(buffer, 0, buffer.Length)
- /// Loop
- /// End Using
- /// End Using
- /// End Using
- /// </code>
- /// </example>
- /// <param name="stream">The stream to which compressed data will be written.</param>
- public ParallelDeflateOutputStream(System.IO.Stream stream)
- : this(stream, CompressionLevel.Default, CompressionStrategy.Default, false)
- {
- }
-
- /// <summary>
- /// Create a ParallelDeflateOutputStream using the specified CompressionLevel.
- /// </summary>
- /// <remarks>
- /// See the <see cref="ParallelDeflateOutputStream(System.IO.Stream)"/>
- /// constructor for example code.
- /// </remarks>
- /// <param name="stream">The stream to which compressed data will be written.</param>
- /// <param name="level">A tuning knob to trade speed for effectiveness.</param>
- public ParallelDeflateOutputStream(System.IO.Stream stream, CompressionLevel level)
- : this(stream, level, CompressionStrategy.Default, false)
- {
- }
-
- /// <summary>
- /// Create a ParallelDeflateOutputStream and specify whether to leave the captive stream open
- /// when the ParallelDeflateOutputStream is closed.
- /// </summary>
- /// <remarks>
- /// See the <see cref="ParallelDeflateOutputStream(System.IO.Stream)"/>
- /// constructor for example code.
- /// </remarks>
- /// <param name="stream">The stream to which compressed data will be written.</param>
- /// <param name="leaveOpen">
- /// true if the application would like the stream to remain open after inflation/deflation.
- /// </param>
- public ParallelDeflateOutputStream(System.IO.Stream stream, bool leaveOpen)
- : this(stream, CompressionLevel.Default, CompressionStrategy.Default, leaveOpen)
- {
- }
-
- /// <summary>
- /// Create a ParallelDeflateOutputStream and specify whether to leave the captive stream open
- /// when the ParallelDeflateOutputStream is closed.
- /// </summary>
- /// <remarks>
- /// See the <see cref="ParallelDeflateOutputStream(System.IO.Stream)"/>
- /// constructor for example code.
- /// </remarks>
- /// <param name="stream">The stream to which compressed data will be written.</param>
- /// <param name="level">A tuning knob to trade speed for effectiveness.</param>
- /// <param name="leaveOpen">
- /// true if the application would like the stream to remain open after inflation/deflation.
- /// </param>
- public ParallelDeflateOutputStream(System.IO.Stream stream, CompressionLevel level, bool leaveOpen)
- : this(stream, CompressionLevel.Default, CompressionStrategy.Default, leaveOpen)
- {
- }
-
- /// <summary>
- /// Create a ParallelDeflateOutputStream using the specified
- /// CompressionLevel and CompressionStrategy, and specifying whether to
- /// leave the captive stream open when the ParallelDeflateOutputStream is
- /// closed.
- /// </summary>
- /// <remarks>
- /// See the <see cref="ParallelDeflateOutputStream(System.IO.Stream)"/>
- /// constructor for example code.
- /// </remarks>
- /// <param name="stream">The stream to which compressed data will be written.</param>
- /// <param name="level">A tuning knob to trade speed for effectiveness.</param>
- /// <param name="strategy">
- /// By tweaking this parameter, you may be able to optimize the compression for
- /// data with particular characteristics.
- /// </param>
- /// <param name="leaveOpen">
- /// true if the application would like the stream to remain open after inflation/deflation.
- /// </param>
- public ParallelDeflateOutputStream(System.IO.Stream stream,
- CompressionLevel level,
- CompressionStrategy strategy,
- bool leaveOpen)
- {
- TraceOutput(TraceBits.Lifecycle | TraceBits.Session, "-------------------------------------------------------");
- TraceOutput(TraceBits.Lifecycle | TraceBits.Session, "Create {0:X8}", this.GetHashCode());
- _outStream = stream;
- _compressLevel= level;
- Strategy = strategy;
- _leaveOpen = leaveOpen;
- this.MaxBufferPairs = 16; // default
- }
-
-
- /// <summary>
- /// The ZLIB strategy to be used during compression.
- /// </summary>
- ///
- public CompressionStrategy Strategy
- {
- get;
- private set;
- }
-
- /// <summary>
- /// The maximum number of buffer pairs to use.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This property sets an upper limit on the number of memory buffer
- /// pairs to create. The implementation of this stream allocates
- /// multiple buffers to facilitate parallel compression. As each buffer
- /// fills up, this stream uses <see
- /// cref="System.Threading.ThreadPool.QueueUserWorkItem(WaitCallback)">
- /// ThreadPool.QueueUserWorkItem()</see>
- /// to compress those buffers in a background threadpool thread. After a
- /// buffer is compressed, it is re-ordered and written to the output
- /// stream.
- /// </para>
- ///
- /// <para>
- /// A higher number of buffer pairs enables a higher degree of
- /// parallelism, which tends to increase the speed of compression on
- /// multi-cpu computers. On the other hand, a higher number of buffer
- /// pairs also implies a larger memory consumption, more active worker
- /// threads, and a higher cpu utilization for any compression. This
- /// property enables the application to limit its memory consumption and
- /// CPU utilization behavior depending on requirements.
- /// </para>
- ///
- /// <para>
- /// For each compression "task" that occurs in parallel, there are 2
- /// buffers allocated: one for input and one for output. This property
- /// sets a limit for the number of pairs. The total amount of storage
- /// space allocated for buffering will then be (N*S*2), where N is the
- /// number of buffer pairs, S is the size of each buffer (<see
- /// cref="BufferSize"/>). By default, DotNetZip allocates 4 buffer
- /// pairs per CPU core, so if your machine has 4 cores, and you retain
- /// the default buffer size of 128k, then the
- /// ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer
- /// memory in total, or 4mb, in blocks of 128kb. If you then set this
- /// property to 8, then the number will be 8 * 2 * 128kb of buffer
- /// memory, or 2mb.
- /// </para>
- ///
- /// <para>
- /// CPU utilization will also go up with additional buffers, because a
- /// larger number of buffer pairs allows a larger number of background
- /// threads to compress in parallel. If you find that parallel
- /// compression is consuming too much memory or CPU, you can adjust this
- /// value downward.
- /// </para>
- ///
- /// <para>
- /// The default value is 16. Different values may deliver better or
- /// worse results, depending on your priorities and the dynamic
- /// performance characteristics of your storage and compute resources.
- /// </para>
- ///
- /// <para>
- /// This property is not the number of buffer pairs to use; it is an
- /// upper limit. An illustration: Suppose you have an application that
- /// uses the default value of this property (which is 16), and it runs
- /// on a machine with 2 CPU cores. In that case, DotNetZip will allocate
- /// 4 buffer pairs per CPU core, for a total of 8 pairs. The upper
- /// limit specified by this property has no effect.
- /// </para>
- ///
- /// <para>
- /// The application can set this value at any time, but it is effective
- /// only before the first call to Write(), which is when the buffers are
- /// allocated.
- /// </para>
- /// </remarks>
- public int MaxBufferPairs
- {
- get
- {
- return _maxBufferPairs;
- }
- set
- {
- if (value < 4)
- throw new ArgumentException("MaxBufferPairs",
- "Value must be 4 or greater.");
- _maxBufferPairs = value;
- }
- }
-
- /// <summary>
- /// The size of the buffers used by the compressor threads.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// The default buffer size is 128k. The application can set this value
- /// at any time, but it is effective only before the first Write().
- /// </para>
- ///
- /// <para>
- /// Larger buffer sizes implies larger memory consumption but allows
- /// more efficient compression. Using smaller buffer sizes consumes less
- /// memory but may result in less effective compression. For example,
- /// using the default buffer size of 128k, the compression delivered is
- /// within 1% of the compression delivered by the single-threaded <see
- /// cref="Ionic.Zlib.DeflateStream"/>. On the other hand, using a
- /// BufferSize of 8k can result in a compressed data stream that is 5%
- /// larger than that delivered by the single-threaded
- /// <c>DeflateStream</c>. Excessively small buffer sizes can also cause
- /// the speed of the ParallelDeflateOutputStream to drop, because of
- /// larger thread scheduling overhead dealing with many many small
- /// buffers.
- /// </para>
- ///
- /// <para>
- /// The total amount of storage space allocated for buffering will be
- /// (N*S*2), where N is the number of buffer pairs, and S is the size of
- /// each buffer (this property). There are 2 buffers used by the
- /// compressor, one for input and one for output. By default, DotNetZip
- /// allocates 4 buffer pairs per CPU core, so if your machine has 4
- /// cores, then the number of buffer pairs used will be 16. If you
- /// accept the default value of this property, 128k, then the
- /// ParallelDeflateOutputStream will use 16 * 2 * 128kb of buffer memory
- /// in total, or 4mb, in blocks of 128kb. If you set this property to
- /// 64kb, then the number will be 16 * 2 * 64kb of buffer memory, or
- /// 2mb.
- /// </para>
- ///
- /// </remarks>
- public int BufferSize
- {
- get { return _bufferSize;}
- set
- {
- if (value < 1024)
- throw new ArgumentOutOfRangeException("BufferSize",
- "BufferSize must be greater than 1024 bytes");
- _bufferSize = value;
- }
- }
-
- /// <summary>
- /// The CRC32 for the data that was written out, prior to compression.
- /// </summary>
- /// <remarks>
- /// This value is meaningful only after a call to Close().
- /// </remarks>
- public int Crc32 { get { return _Crc32; } }
-
-
- /// <summary>
- /// The total number of uncompressed bytes processed by the ParallelDeflateOutputStream.
- /// </summary>
- /// <remarks>
- /// This value is meaningful only after a call to Close().
- /// </remarks>
- public Int64 BytesProcessed { get { return _totalBytesProcessed; } }
-
-
- private void _InitializePoolOfWorkItems()
- {
- _toWrite = new Queue<int>();
- _toFill = new Queue<int>();
- _pool = new System.Collections.Generic.List<WorkItem>();
- int nTasks = BufferPairsPerCore * Environment.ProcessorCount;
- nTasks = Math.Min(nTasks, _maxBufferPairs);
- for(int i=0; i < nTasks; i++)
- {
- _pool.Add(new WorkItem(_bufferSize, _compressLevel, Strategy, i));
- _toFill.Enqueue(i);
- }
-
- _newlyCompressedBlob = new AutoResetEvent(false);
- _runningCrc = new Ionic.Crc.CRC32();
- _currentlyFilling = -1;
- _lastFilled = -1;
- _lastWritten = -1;
- _latestCompressed = -1;
- }
-
-
-
-
- /// <summary>
- /// Write data to the stream.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// To use the ParallelDeflateOutputStream to compress data, create a
- /// ParallelDeflateOutputStream with CompressionMode.Compress, passing a
- /// writable output stream. Then call Write() on that
- /// ParallelDeflateOutputStream, providing uncompressed data as input. The
- /// data sent to the output stream will be the compressed form of the data
- /// written.
- /// </para>
- ///
- /// <para>
- /// To decompress data, use the <see cref="Ionic.Zlib.DeflateStream"/> class.
- /// </para>
- ///
- /// </remarks>
- /// <param name="buffer">The buffer holding data to write to the stream.</param>
- /// <param name="offset">the offset within that data array to find the first byte to write.</param>
- /// <param name="count">the number of bytes to write.</param>
- public override void Write(byte[] buffer, int offset, int count)
- {
- bool mustWait = false;
-
- // This method does this:
- // 0. handles any pending exceptions
- // 1. write any buffers that are ready to be written,
- // 2. fills a work buffer; when full, flip state to 'Filled',
- // 3. if more data to be written, goto step 1
-
- if (_isClosed)
- throw new InvalidOperationException();
-
- // dispense any exceptions that occurred on the BG threads
- if (_pendingException != null)
- {
- _handlingException = true;
- var pe = _pendingException;
- _pendingException = null;
- throw pe;
- }
-
- if (count == 0) return;
-
- if (!_firstWriteDone)
- {
- // Want to do this on first Write, first session, and not in the
- // constructor. We want to allow MaxBufferPairs to
- // change after construction, but before first Write.
- _InitializePoolOfWorkItems();
- _firstWriteDone = true;
- }
-
-
- do
- {
- // may need to make buffers available
- EmitPendingBuffers(false, mustWait);
-
- mustWait = false;
- // use current buffer, or get a new buffer to fill
- int ix = -1;
- if (_currentlyFilling >= 0)
- {
- ix = _currentlyFilling;
- TraceOutput(TraceBits.WriteTake,
- "Write notake wi({0}) lf({1})",
- ix,
- _lastFilled);
- }
- else
- {
- TraceOutput(TraceBits.WriteTake, "Write take?");
- if (_toFill.Count == 0)
- {
- // no available buffers, so... need to emit
- // compressed buffers.
- mustWait = true;
- continue;
- }
-
- ix = _toFill.Dequeue();
- TraceOutput(TraceBits.WriteTake,
- "Write take wi({0}) lf({1})",
- ix,
- _lastFilled);
- ++_lastFilled; // TODO: consider rollover?
- }
-
- WorkItem workitem = _pool[ix];
-
- int limit = ((workitem.buffer.Length - workitem.inputBytesAvailable) > count)
- ? count
- : (workitem.buffer.Length - workitem.inputBytesAvailable);
-
- workitem.ordinal = _lastFilled;
-
- TraceOutput(TraceBits.Write,
- "Write lock wi({0}) ord({1}) iba({2})",
- workitem.index,
- workitem.ordinal,
- workitem.inputBytesAvailable
- );
-
- // copy from the provided buffer to our workitem, starting at
- // the tail end of whatever data we might have in there currently.
- Buffer.BlockCopy(buffer,
- offset,
- workitem.buffer,
- workitem.inputBytesAvailable,
- limit);
-
- count -= limit;
- offset += limit;
- workitem.inputBytesAvailable += limit;
- if (workitem.inputBytesAvailable == workitem.buffer.Length)
- {
- // No need for interlocked.increment: the Write()
- // method is documented as not multi-thread safe, so
- // we can assume Write() calls come in from only one
- // thread.
- TraceOutput(TraceBits.Write,
- "Write QUWI wi({0}) ord({1}) iba({2}) nf({3})",
- workitem.index,
- workitem.ordinal,
- workitem.inputBytesAvailable );
-
- if (!ThreadPool.QueueUserWorkItem( _DeflateOne, workitem ))
- throw new Exception("Cannot enqueue workitem");
-
- _currentlyFilling = -1; // will get a new buffer next time
- }
- else
- _currentlyFilling = ix;
-
- if (count > 0)
- TraceOutput(TraceBits.WriteEnter, "Write more");
- }
- while (count > 0); // until no more to write
-
- TraceOutput(TraceBits.WriteEnter, "Write exit");
- return;
- }
-
-
-
- private void _FlushFinish()
- {
- // After writing a series of compressed buffers, each one closed
- // with Flush.Sync, we now write the final one as Flush.Finish,
- // and then stop.
- byte[] buffer = new byte[128];
- var compressor = new ZlibCodec();
- int rc = compressor.InitializeDeflate(_compressLevel, false);
- compressor.InputBuffer = null;
- compressor.NextIn = 0;
- compressor.AvailableBytesIn = 0;
- compressor.OutputBuffer = buffer;
- compressor.NextOut = 0;
- compressor.AvailableBytesOut = buffer.Length;
- rc = compressor.Deflate(FlushType.Finish);
-
- if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK)
- throw new Exception("deflating: " + compressor.Message);
-
- if (buffer.Length - compressor.AvailableBytesOut > 0)
- {
- TraceOutput(TraceBits.EmitBegin,
- "Emit begin flush bytes({0})",
- buffer.Length - compressor.AvailableBytesOut);
-
- _outStream.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut);
-
- TraceOutput(TraceBits.EmitDone,
- "Emit done flush");
- }
-
- compressor.EndDeflate();
-
- _Crc32 = _runningCrc.Crc32Result;
- }
-
-
- private void _Flush(bool lastInput)
- {
- if (_isClosed)
- throw new InvalidOperationException();
-
- if (emitting) return;
-
- // compress any partial buffer
- if (_currentlyFilling >= 0)
- {
- WorkItem workitem = _pool[_currentlyFilling];
- _DeflateOne(workitem);
- _currentlyFilling = -1; // get a new buffer next Write()
- }
-
- if (lastInput)
- {
- EmitPendingBuffers(true, false);
- _FlushFinish();
- }
- else
- {
- EmitPendingBuffers(false, false);
- }
- }
-
-
-
- /// <summary>
- /// Flush the stream.
- /// </summary>
- public override void Flush()
- {
- if (_pendingException != null)
- {
- _handlingException = true;
- var pe = _pendingException;
- _pendingException = null;
- throw pe;
- }
- if (_handlingException)
- return;
-
- _Flush(false);
- }
-
-
- /// <summary>
- /// Close the stream.
- /// </summary>
- /// <remarks>
- /// You must call Close on the stream to guarantee that all of the data written in has
- /// been compressed, and the compressed data has been written out.
- /// </remarks>
- public override void Close()
- {
- TraceOutput(TraceBits.Session, "Close {0:X8}", this.GetHashCode());
-
- if (_pendingException != null)
- {
- _handlingException = true;
- var pe = _pendingException;
- _pendingException = null;
- throw pe;
- }
-
- if (_handlingException)
- return;
-
- if (_isClosed) return;
-
- _Flush(true);
-
- if (!_leaveOpen)
- _outStream.Close();
-
- _isClosed= true;
- }
-
-
-
- // workitem 10030 - implement a new Dispose method
-
- /// <summary>Dispose the object</summary>
- /// <remarks>
- /// <para>
- /// Because ParallelDeflateOutputStream is IDisposable, the
- /// application must call this method when finished using the instance.
- /// </para>
- /// <para>
- /// This method is generally called implicitly upon exit from
- /// a <c>using</c> scope in C# (<c>Using</c> in VB).
- /// </para>
- /// </remarks>
- new public void Dispose()
- {
- TraceOutput(TraceBits.Lifecycle, "Dispose {0:X8}", this.GetHashCode());
- Close();
- _pool = null;
- Dispose(true);
- }
-
-
-
- /// <summary>The Dispose method</summary>
- /// <param name="disposing">
- /// indicates whether the Dispose method was invoked by user code.
- /// </param>
- protected override void Dispose(bool disposing)
- {
- base.Dispose(disposing);
- }
-
-
- /// <summary>
- /// Resets the stream for use with another stream.
- /// </summary>
- /// <remarks>
- /// Because the ParallelDeflateOutputStream is expensive to create, it
- /// has been designed so that it can be recycled and re-used. You have
- /// to call Close() on the stream first, then you can call Reset() on
- /// it, to use it again on another stream.
- /// </remarks>
- ///
- /// <param name="stream">
- /// The new output stream for this era.
- /// </param>
- ///
- /// <example>
- /// <code>
- /// ParallelDeflateOutputStream deflater = null;
- /// foreach (var inputFile in listOfFiles)
- /// {
- /// string outputFile = inputFile + ".compressed";
- /// using (System.IO.Stream input = System.IO.File.OpenRead(inputFile))
- /// {
- /// using (var outStream = System.IO.File.Create(outputFile))
- /// {
- /// if (deflater == null)
- /// deflater = new ParallelDeflateOutputStream(outStream,
- /// CompressionLevel.Best,
- /// CompressionStrategy.Default,
- /// true);
- /// deflater.Reset(outStream);
- ///
- /// while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
- /// {
- /// deflater.Write(buffer, 0, n);
- /// }
- /// }
- /// }
- /// }
- /// </code>
- /// </example>
- public void Reset(Stream stream)
- {
- TraceOutput(TraceBits.Session, "-------------------------------------------------------");
- TraceOutput(TraceBits.Session, "Reset {0:X8} firstDone({1})", this.GetHashCode(), _firstWriteDone);
-
- if (!_firstWriteDone) return;
-
- // reset all status
- _toWrite.Clear();
- _toFill.Clear();
- foreach (var workitem in _pool)
- {
- _toFill.Enqueue(workitem.index);
- workitem.ordinal = -1;
- }
-
- _firstWriteDone = false;
- _totalBytesProcessed = 0L;
- _runningCrc = new Ionic.Crc.CRC32();
- _isClosed= false;
- _currentlyFilling = -1;
- _lastFilled = -1;
- _lastWritten = -1;
- _latestCompressed = -1;
- _outStream = stream;
- }
-
-
-
-
- private void EmitPendingBuffers(bool doAll, bool mustWait)
- {
- // When combining parallel deflation with a ZipSegmentedStream, it's
- // possible for the ZSS to throw from within this method. In that
- // case, Close/Dispose will be called on this stream, if this stream
- // is employed within a using or try/finally pair as required. But
- // this stream is unaware of the pending exception, so the Close()
- // method invokes this method AGAIN. This can lead to a deadlock.
- // Therefore, failfast if re-entering.
-
- if (emitting) return;
- emitting = true;
- if (doAll || mustWait)
- _newlyCompressedBlob.WaitOne();
-
- do
- {
- int firstSkip = -1;
- int millisecondsToWait = doAll ? 200 : (mustWait ? -1 : 0);
- int nextToWrite = -1;
-
- do
- {
- if (Monitor.TryEnter(_toWrite, millisecondsToWait))
- {
- nextToWrite = -1;
- try
- {
- if (_toWrite.Count > 0)
- nextToWrite = _toWrite.Dequeue();
- }
- finally
- {
- Monitor.Exit(_toWrite);
- }
-
- if (nextToWrite >= 0)
- {
- WorkItem workitem = _pool[nextToWrite];
- if (workitem.ordinal != _lastWritten + 1)
- {
- // out of order. requeue and try again.
- TraceOutput(TraceBits.EmitSkip,
- "Emit skip wi({0}) ord({1}) lw({2}) fs({3})",
- workitem.index,
- workitem.ordinal,
- _lastWritten,
- firstSkip);
-
- lock(_toWrite)
- {
- _toWrite.Enqueue(nextToWrite);
- }
-
- if (firstSkip == nextToWrite)
- {
- // We went around the list once.
- // None of the items in the list is the one we want.
- // Now wait for a compressor to signal again.
- _newlyCompressedBlob.WaitOne();
- firstSkip = -1;
- }
- else if (firstSkip == -1)
- firstSkip = nextToWrite;
-
- continue;
- }
-
- firstSkip = -1;
-
- TraceOutput(TraceBits.EmitBegin,
- "Emit begin wi({0}) ord({1}) cba({2})",
- workitem.index,
- workitem.ordinal,
- workitem.compressedBytesAvailable);
-
- _outStream.Write(workitem.compressed, 0, workitem.compressedBytesAvailable);
- _runningCrc.Combine(workitem.crc, workitem.inputBytesAvailable);
- _totalBytesProcessed += workitem.inputBytesAvailable;
- workitem.inputBytesAvailable = 0;
-
- TraceOutput(TraceBits.EmitDone,
- "Emit done wi({0}) ord({1}) cba({2}) mtw({3})",
- workitem.index,
- workitem.ordinal,
- workitem.compressedBytesAvailable,
- millisecondsToWait);
-
- _lastWritten = workitem.ordinal;
- _toFill.Enqueue(workitem.index);
-
- // don't wait next time through
- if (millisecondsToWait == -1) millisecondsToWait = 0;
- }
- }
- else
- nextToWrite = -1;
-
- } while (nextToWrite >= 0);
-
- //} while (doAll && (_lastWritten != _latestCompressed));
- } while (doAll && (_lastWritten != _latestCompressed || _lastWritten != _lastFilled));
-
- emitting = false;
- }
-
-
-
-#if OLD
- private void _PerpetualWriterMethod(object state)
- {
- TraceOutput(TraceBits.WriterThread, "_PerpetualWriterMethod START");
-
- try
- {
- do
- {
- // wait for the next session
- TraceOutput(TraceBits.Synch | TraceBits.WriterThread, "Synch _sessionReset.WaitOne(begin) PWM");
- _sessionReset.WaitOne();
- TraceOutput(TraceBits.Synch | TraceBits.WriterThread, "Synch _sessionReset.WaitOne(done) PWM");
-
- if (_isDisposed) break;
-
- TraceOutput(TraceBits.Synch | TraceBits.WriterThread, "Synch _sessionReset.Reset() PWM");
- _sessionReset.Reset();
-
- // repeatedly write buffers as they become ready
- WorkItem workitem = null;
- Ionic.Zlib.CRC32 c= new Ionic.Zlib.CRC32();
- do
- {
- workitem = _pool[_nextToWrite % _pc];
- lock(workitem)
- {
- if (_noMoreInputForThisSegment)
- TraceOutput(TraceBits.Write,
- "Write drain wi({0}) stat({1}) canuse({2}) cba({3})",
- workitem.index,
- workitem.status,
- (workitem.status == (int)WorkItem.Status.Compressed),
- workitem.compressedBytesAvailable);
-
- do
- {
- if (workitem.status == (int)WorkItem.Status.Compressed)
- {
- TraceOutput(TraceBits.WriteBegin,
- "Write begin wi({0}) stat({1}) cba({2})",
- workitem.index,
- workitem.status,
- workitem.compressedBytesAvailable);
-
- workitem.status = (int)WorkItem.Status.Writing;
- _outStream.Write(workitem.compressed, 0, workitem.compressedBytesAvailable);
- c.Combine(workitem.crc, workitem.inputBytesAvailable);
- _totalBytesProcessed += workitem.inputBytesAvailable;
- _nextToWrite++;
- workitem.inputBytesAvailable= 0;
- workitem.status = (int)WorkItem.Status.Done;
-
- TraceOutput(TraceBits.WriteDone,
- "Write done wi({0}) stat({1}) cba({2})",
- workitem.index,
- workitem.status,
- workitem.compressedBytesAvailable);
-
-
- Monitor.Pulse(workitem);
- break;
- }
- else
- {
- int wcycles = 0;
- // I've locked a workitem I cannot use.
- // Therefore, wake someone else up, and then release the lock.
- while (workitem.status != (int)WorkItem.Status.Compressed)
- {
- TraceOutput(TraceBits.WriteWait,
- "Write waiting wi({0}) stat({1}) nw({2}) nf({3}) nomore({4})",
- workitem.index,
- workitem.status,
- _nextToWrite, _nextToFill,
- _noMoreInputForThisSegment );
-
- if (_noMoreInputForThisSegment && _nextToWrite == _nextToFill)
- break;
-
- wcycles++;
-
- // wake up someone else
- Monitor.Pulse(workitem);
- // release and wait
- Monitor.Wait(workitem);
-
- if (workitem.status == (int)WorkItem.Status.Compressed)
- TraceOutput(TraceBits.WriteWait,
- "Write A-OK wi({0}) stat({1}) iba({2}) cba({3}) cyc({4})",
- workitem.index,
- workitem.status,
- workitem.inputBytesAvailable,
- workitem.compressedBytesAvailable,
- wcycles);
- }
-
- if (_noMoreInputForThisSegment && _nextToWrite == _nextToFill)
- break;
-
- }
- }
- while (true);
- }
-
- if (_noMoreInputForThisSegment)
- TraceOutput(TraceBits.Write,
- "Write nomore nw({0}) nf({1}) break({2})",
- _nextToWrite, _nextToFill, (_nextToWrite == _nextToFill));
-
- if (_noMoreInputForThisSegment && _nextToWrite == _nextToFill)
- break;
-
- } while (true);
-
-
- // Finish:
- // After writing a series of buffers, closing each one with
- // Flush.Sync, we now write the final one as Flush.Finish, and
- // then stop.
- byte[] buffer = new byte[128];
- ZlibCodec compressor = new ZlibCodec();
- int rc = compressor.InitializeDeflate(_compressLevel, false);
- compressor.InputBuffer = null;
- compressor.NextIn = 0;
- compressor.AvailableBytesIn = 0;
- compressor.OutputBuffer = buffer;
- compressor.NextOut = 0;
- compressor.AvailableBytesOut = buffer.Length;
- rc = compressor.Deflate(FlushType.Finish);
-
- if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK)
- throw new Exception("deflating: " + compressor.Message);
-
- if (buffer.Length - compressor.AvailableBytesOut > 0)
- {
- TraceOutput(TraceBits.WriteBegin,
- "Write begin flush bytes({0})",
- buffer.Length - compressor.AvailableBytesOut);
-
- _outStream.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut);
-
- TraceOutput(TraceBits.WriteBegin,
- "Write done flush");
- }
-
- compressor.EndDeflate();
-
- _Crc32 = c.Crc32Result;
-
- // signal that writing is complete:
- TraceOutput(TraceBits.Synch, "Synch _writingDone.Set() PWM");
- _writingDone.Set();
- }
- while (true);
- }
- catch (System.Exception exc1)
- {
- lock(_eLock)
- {
- // expose the exception to the main thread
- if (_pendingException!=null)
- _pendingException = exc1;
- }
- }
-
- TraceOutput(TraceBits.WriterThread, "_PerpetualWriterMethod FINIS");
- }
-#endif
-
-
-
-
- private void _DeflateOne(Object wi)
- {
- // compress one buffer
- WorkItem workitem = (WorkItem) wi;
- try
- {
- int myItem = workitem.index;
- Ionic.Crc.CRC32 crc = new Ionic.Crc.CRC32();
-
- // calc CRC on the buffer
- crc.SlurpBlock(workitem.buffer, 0, workitem.inputBytesAvailable);
-
- // deflate it
- DeflateOneSegment(workitem);
-
- // update status
- workitem.crc = crc.Crc32Result;
- TraceOutput(TraceBits.Compress,
- "Compress wi({0}) ord({1}) len({2})",
- workitem.index,
- workitem.ordinal,
- workitem.compressedBytesAvailable
- );
-
- lock(_latestLock)
- {
- if (workitem.ordinal > _latestCompressed)
- _latestCompressed = workitem.ordinal;
- }
- lock (_toWrite)
- {
- _toWrite.Enqueue(workitem.index);
- }
- _newlyCompressedBlob.Set();
- }
- catch (System.Exception exc1)
- {
- lock(_eLock)
- {
- // expose the exception to the main thread
- if (_pendingException!=null)
- _pendingException = exc1;
- }
- }
- }
-
-
-
-
- private bool DeflateOneSegment(WorkItem workitem)
- {
- ZlibCodec compressor = workitem.compressor;
- int rc= 0;
- compressor.ResetDeflate();
- compressor.NextIn = 0;
-
- compressor.AvailableBytesIn = workitem.inputBytesAvailable;
-
- // step 1: deflate the buffer
- compressor.NextOut = 0;
- compressor.AvailableBytesOut = workitem.compressed.Length;
- do
- {
- compressor.Deflate(FlushType.None);
- }
- while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0);
-
- // step 2: flush (sync)
- rc = compressor.Deflate(FlushType.Sync);
-
- workitem.compressedBytesAvailable= (int) compressor.TotalBytesOut;
- return true;
- }
-
-
- [System.Diagnostics.ConditionalAttribute("Trace")]
- private void TraceOutput(TraceBits bits, string format, params object[] varParams)
- {
- if ((bits & _DesiredTrace) != 0)
- {
- lock(_outputLock)
- {
- int tid = Thread.CurrentThread.GetHashCode();
-#if !SILVERLIGHT
- Console.ForegroundColor = (ConsoleColor) (tid % 8 + 8);
-#endif
- Console.Write("{0:000} PDOS ", tid);
- Console.WriteLine(format, varParams);
-#if !SILVERLIGHT
- Console.ResetColor();
-#endif
- }
- }
- }
-
-
- // used only when Trace is defined
- [Flags]
- enum TraceBits : uint
- {
- None = 0,
- NotUsed1 = 1,
- EmitLock = 2,
- EmitEnter = 4, // enter _EmitPending
- EmitBegin = 8, // begin to write out
- EmitDone = 16, // done writing out
- EmitSkip = 32, // writer skipping a workitem
- EmitAll = 58, // All Emit flags
- Flush = 64,
- Lifecycle = 128, // constructor/disposer
- Session = 256, // Close/Reset
- Synch = 512, // thread synchronization
- Instance = 1024, // instance settings
- Compress = 2048, // compress task
- Write = 4096, // filling buffers, when caller invokes Write()
- WriteEnter = 8192, // upon entry to Write()
- WriteTake = 16384, // on _toFill.Take()
- All = 0xffffffff,
- }
-
-
-
- /// <summary>
- /// Indicates whether the stream supports Seek operations.
- /// </summary>
- /// <remarks>
- /// Always returns false.
- /// </remarks>
- public override bool CanSeek
- {
- get { return false; }
- }
-
-
- /// <summary>
- /// Indicates whether the stream supports Read operations.
- /// </summary>
- /// <remarks>
- /// Always returns false.
- /// </remarks>
- public override bool CanRead
- {
- get {return false;}
- }
-
- /// <summary>
- /// Indicates whether the stream supports Write operations.
- /// </summary>
- /// <remarks>
- /// Returns true if the provided stream is writable.
- /// </remarks>
- public override bool CanWrite
- {
- get { return _outStream.CanWrite; }
- }
-
- /// <summary>
- /// Reading this property always throws a NotSupportedException.
- /// </summary>
- public override long Length
- {
- get { throw new NotSupportedException(); }
- }
-
- /// <summary>
- /// Returns the current position of the output stream.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Because the output gets written by a background thread,
- /// the value may change asynchronously. Setting this
- /// property always throws a NotSupportedException.
- /// </para>
- /// </remarks>
- public override long Position
- {
- get { return _outStream.Position; }
- set { throw new NotSupportedException(); }
- }
-
- /// <summary>
- /// This method always throws a NotSupportedException.
- /// </summary>
- /// <param name="buffer">
- /// The buffer into which data would be read, IF THIS METHOD
- /// ACTUALLY DID ANYTHING.
- /// </param>
- /// <param name="offset">
- /// The offset within that data array at which to insert the
- /// data that is read, IF THIS METHOD ACTUALLY DID
- /// ANYTHING.
- /// </param>
- /// <param name="count">
- /// The number of bytes to write, IF THIS METHOD ACTUALLY DID
- /// ANYTHING.
- /// </param>
- /// <returns>nothing.</returns>
- public override int Read(byte[] buffer, int offset, int count)
- {
- throw new NotSupportedException();
- }
-
- /// <summary>
- /// This method always throws a NotSupportedException.
- /// </summary>
- /// <param name="offset">
- /// The offset to seek to....
- /// IF THIS METHOD ACTUALLY DID ANYTHING.
- /// </param>
- /// <param name="origin">
- /// The reference specifying how to apply the offset.... IF
- /// THIS METHOD ACTUALLY DID ANYTHING.
- /// </param>
- /// <returns>nothing. It always throws.</returns>
- public override long Seek(long offset, System.IO.SeekOrigin origin)
- {
- throw new NotSupportedException();
- }
-
- /// <summary>
- /// This method always throws a NotSupportedException.
- /// </summary>
- /// <param name="value">
- /// The new value for the stream length.... IF
- /// THIS METHOD ACTUALLY DID ANYTHING.
- /// </param>
- public override void SetLength(long value)
- {
- throw new NotSupportedException();
- }
-
- }
-
-}
-
-
diff --git a/EPPlus/Packaging/DotNetZip/Zlib/Tree.cs b/EPPlus/Packaging/DotNetZip/Zlib/Tree.cs
deleted file mode 100644
index c411d08..0000000
--- a/EPPlus/Packaging/DotNetZip/Zlib/Tree.cs
+++ /dev/null
@@ -1,423 +0,0 @@
-// Tree.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2009-October-28 13:29:50>
-//
-// ------------------------------------------------------------------
-//
-// This module defines classes for zlib compression and
-// decompression. This code is derived from the jzlib implementation of
-// zlib. In keeping with the license for jzlib, the copyright to that
-// code is below.
-//
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-//
-// 2. 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.
-//
-// 3. The names of the authors may not be used to endorse or promote products
-// derived from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
-// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
-//
-// -----------------------------------------------------------------------
-//
-// This program is based on zlib-1.1.3; credit to authors
-// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
-// and contributors of zlib.
-//
-// -----------------------------------------------------------------------
-
-
-using System;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zlib
-{
- sealed class Tree
- {
- private static readonly int HEAP_SIZE = (2 * InternalConstants.L_CODES + 1);
-
- // extra bits for each length code
- internal static readonly int[] ExtraLengthBits = new int[]
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
- 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
- };
-
- // extra bits for each distance code
- internal static readonly int[] ExtraDistanceBits = new int[]
- {
- 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
- 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13
- };
-
- // extra bits for each bit length code
- internal static readonly int[] extra_blbits = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7};
-
- internal static readonly sbyte[] bl_order = new sbyte[]{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-
-
- // The lengths of the bit length codes are sent in order of decreasing
- // probability, to avoid transmitting the lengths for unused bit
- // length codes.
-
- internal const int Buf_size = 8 * 2;
-
- // see definition of array dist_code below
- //internal const int DIST_CODE_LEN = 512;
-
- private static readonly sbyte[] _dist_code = new sbyte[]
- {
- 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
- 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21,
- 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
- 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
- 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
- 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
- 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
- };
-
- internal static readonly sbyte[] LengthCode = new sbyte[]
- {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11,
- 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
- 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17,
- 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19,
- 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
- 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
- };
-
-
- internal static readonly int[] LengthBase = new int[]
- {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28,
- 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0
- };
-
-
- internal static readonly int[] DistanceBase = new int[]
- {
- 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
- 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
- };
-
-
- /// <summary>
- /// Map from a distance to a distance code.
- /// </summary>
- /// <remarks>
- /// No side effects. _dist_code[256] and _dist_code[257] are never used.
- /// </remarks>
- internal static int DistanceCode(int dist)
- {
- return (dist < 256)
- ? _dist_code[dist]
- : _dist_code[256 + SharedUtils.URShift(dist, 7)];
- }
-
- internal short[] dyn_tree; // the dynamic tree
- internal int max_code; // largest code with non zero frequency
- internal StaticTree staticTree; // the corresponding static tree
-
- // Compute the optimal bit lengths for a tree and update the total bit length
- // for the current block.
- // IN assertion: the fields freq and dad are set, heap[heap_max] and
- // above are the tree nodes sorted by increasing frequency.
- // OUT assertions: the field len is set to the optimal bit length, the
- // array bl_count contains the frequencies for each bit length.
- // The length opt_len is updated; static_len is also updated if stree is
- // not null.
- internal void gen_bitlen(DeflateManager s)
- {
- short[] tree = dyn_tree;
- short[] stree = staticTree.treeCodes;
- int[] extra = staticTree.extraBits;
- int base_Renamed = staticTree.extraBase;
- int max_length = staticTree.maxLength;
- int h; // heap index
- int n, m; // iterate over the tree elements
- int bits; // bit length
- int xbits; // extra bits
- short f; // frequency
- int overflow = 0; // number of elements with bit length too large
-
- for (bits = 0; bits <= InternalConstants.MAX_BITS; bits++)
- s.bl_count[bits] = 0;
-
- // In a first pass, compute the optimal bit lengths (which may
- // overflow in the case of the bit length tree).
- tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap
-
- for (h = s.heap_max + 1; h < HEAP_SIZE; h++)
- {
- n = s.heap[h];
- bits = tree[tree[n * 2 + 1] * 2 + 1] + 1;
- if (bits > max_length)
- {
- bits = max_length; overflow++;
- }
- tree[n * 2 + 1] = (short) bits;
- // We overwrite tree[n*2+1] which is no longer needed
-
- if (n > max_code)
- continue; // not a leaf node
-
- s.bl_count[bits]++;
- xbits = 0;
- if (n >= base_Renamed)
- xbits = extra[n - base_Renamed];
- f = tree[n * 2];
- s.opt_len += f * (bits + xbits);
- if (stree != null)
- s.static_len += f * (stree[n * 2 + 1] + xbits);
- }
- if (overflow == 0)
- return ;
-
- // This happens for example on obj2 and pic of the Calgary corpus
- // Find the first bit length which could increase:
- do
- {
- bits = max_length - 1;
- while (s.bl_count[bits] == 0)
- bits--;
- s.bl_count[bits]--; // move one leaf down the tree
- s.bl_count[bits + 1] = (short) (s.bl_count[bits + 1] + 2); // move one overflow item as its brother
- s.bl_count[max_length]--;
- // The brother of the overflow item also moves one step up,
- // but this does not affect bl_count[max_length]
- overflow -= 2;
- }
- while (overflow > 0);
-
- for (bits = max_length; bits != 0; bits--)
- {
- n = s.bl_count[bits];
- while (n != 0)
- {
- m = s.heap[--h];
- if (m > max_code)
- continue;
- if (tree[m * 2 + 1] != bits)
- {
- s.opt_len = (int) (s.opt_len + ((long) bits - (long) tree[m * 2 + 1]) * (long) tree[m * 2]);
- tree[m * 2 + 1] = (short) bits;
- }
- n--;
- }
- }
- }
-
- // Construct one Huffman tree and assigns the code bit strings and lengths.
- // Update the total bit length for the current block.
- // IN assertion: the field freq is set for all tree elements.
- // OUT assertions: the fields len and code are set to the optimal bit length
- // and corresponding code. The length opt_len is updated; static_len is
- // also updated if stree is not null. The field max_code is set.
- internal void build_tree(DeflateManager s)
- {
- short[] tree = dyn_tree;
- short[] stree = staticTree.treeCodes;
- int elems = staticTree.elems;
- int n, m; // iterate over heap elements
- int max_code = -1; // largest code with non zero frequency
- int node; // new node being created
-
- // Construct the initial heap, with least frequent element in
- // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
- // heap[0] is not used.
- s.heap_len = 0;
- s.heap_max = HEAP_SIZE;
-
- for (n = 0; n < elems; n++)
- {
- if (tree[n * 2] != 0)
- {
- s.heap[++s.heap_len] = max_code = n;
- s.depth[n] = 0;
- }
- else
- {
- tree[n * 2 + 1] = 0;
- }
- }
-
- // The pkzip format requires that at least one distance code exists,
- // and that at least one bit should be sent even if there is only one
- // possible code. So to avoid special checks later on we force at least
- // two codes of non zero frequency.
- while (s.heap_len < 2)
- {
- node = s.heap[++s.heap_len] = (max_code < 2?++max_code:0);
- tree[node * 2] = 1;
- s.depth[node] = 0;
- s.opt_len--;
- if (stree != null)
- s.static_len -= stree[node * 2 + 1];
- // node is 0 or 1 so it does not have extra bits
- }
- this.max_code = max_code;
-
- // The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
- // establish sub-heaps of increasing lengths:
-
- for (n = s.heap_len / 2; n >= 1; n--)
- s.pqdownheap(tree, n);
-
- // Construct the Huffman tree by repeatedly combining the least two
- // frequent nodes.
-
- node = elems; // next internal node of the tree
- do
- {
- // n = node of least frequency
- n = s.heap[1];
- s.heap[1] = s.heap[s.heap_len--];
- s.pqdownheap(tree, 1);
- m = s.heap[1]; // m = node of next least frequency
-
- s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
- s.heap[--s.heap_max] = m;
-
- // Create a new node father of n and m
- tree[node * 2] = unchecked((short) (tree[n * 2] + tree[m * 2]));
- s.depth[node] = (sbyte) (System.Math.Max((byte) s.depth[n], (byte) s.depth[m]) + 1);
- tree[n * 2 + 1] = tree[m * 2 + 1] = (short) node;
-
- // and insert the new node in the heap
- s.heap[1] = node++;
- s.pqdownheap(tree, 1);
- }
- while (s.heap_len >= 2);
-
- s.heap[--s.heap_max] = s.heap[1];
-
- // At this point, the fields freq and dad are set. We can now
- // generate the bit lengths.
-
- gen_bitlen(s);
-
- // The field len is now set, we can generate the bit codes
- gen_codes(tree, max_code, s.bl_count);
- }
-
- // Generate the codes for a given tree and bit counts (which need not be
- // optimal).
- // IN assertion: the array bl_count contains the bit length statistics for
- // the given tree and the field len is set for all tree elements.
- // OUT assertion: the field code is set for all tree elements of non
- // zero code length.
- internal static void gen_codes(short[] tree, int max_code, short[] bl_count)
- {
- short[] next_code = new short[InternalConstants.MAX_BITS + 1]; // next code value for each bit length
- short code = 0; // running code value
- int bits; // bit index
- int n; // code index
-
- // The distribution counts are first used to generate the code values
- // without bit reversal.
- for (bits = 1; bits <= InternalConstants.MAX_BITS; bits++)
- unchecked {
- next_code[bits] = code = (short) ((code + bl_count[bits - 1]) << 1);
- }
-
- // Check that the bit counts in bl_count are consistent. The last code
- // must be all ones.
- //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
- // "inconsistent bit counts");
- //Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
-
- for (n = 0; n <= max_code; n++)
- {
- int len = tree[n * 2 + 1];
- if (len == 0)
- continue;
- // Now reverse the bits
- tree[n * 2] = unchecked((short) (bi_reverse(next_code[len]++, len)));
- }
- }
-
- // Reverse the first len bits of a code, using straightforward code (a faster
- // method would use a table)
- // IN assertion: 1 <= len <= 15
- internal static int bi_reverse(int code, int len)
- {
- int res = 0;
- do
- {
- res |= code & 1;
- code >>= 1; //SharedUtils.URShift(code, 1);
- res <<= 1;
- }
- while (--len > 0);
- return res >> 1;
- }
- }
-}
\ No newline at end of file
diff --git a/EPPlus/Packaging/DotNetZip/Zlib/Zlib.cs b/EPPlus/Packaging/DotNetZip/Zlib/Zlib.cs
deleted file mode 100644
index 06d8e7d..0000000
--- a/EPPlus/Packaging/DotNetZip/Zlib/Zlib.cs
+++ /dev/null
@@ -1,546 +0,0 @@
-// Zlib.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009-2011 Dino Chiesa and Microsoft Corporation.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// Last Saved: <2011-August-03 19:52:28>
-//
-// ------------------------------------------------------------------
-//
-// This module defines classes for ZLIB compression and
-// decompression. This code is derived from the jzlib implementation of
-// zlib, but significantly modified. The object model is not the same,
-// and many of the behaviors are new or different. Nonetheless, in
-// keeping with the license for jzlib, the copyright to that code is
-// included below.
-//
-// ------------------------------------------------------------------
-//
-// The following notice applies to jzlib:
-//
-// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-//
-// 2. 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.
-//
-// 3. The names of the authors may not be used to endorse or promote products
-// derived from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
-// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
-//
-// -----------------------------------------------------------------------
-//
-// jzlib is based on zlib-1.1.3.
-//
-// The following notice applies to zlib:
-//
-// -----------------------------------------------------------------------
-//
-// Copyright (C) 1995-2004 Jean-loup Gailly and Mark Adler
-//
-// The ZLIB software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
-//
-// Jean-loup Gailly jloup@gzip.org
-// Mark Adler madler@alumni.caltech.edu
-//
-// -----------------------------------------------------------------------
-
-
-
-using System;
-using Interop=System.Runtime.InteropServices;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zlib
-{
-
- /// <summary>
- /// Describes how to flush the current deflate operation.
- /// </summary>
- /// <remarks>
- /// The different FlushType values are useful when using a Deflate in a streaming application.
- /// </remarks>
- public enum FlushType
- {
- /// <summary>No flush at all.</summary>
- None = 0,
-
- /// <summary>Closes the current block, but doesn't flush it to
- /// the output. Used internally only in hypothetical
- /// scenarios. This was supposed to be removed by Zlib, but it is
- /// still in use in some edge cases.
- /// </summary>
- Partial,
-
- /// <summary>
- /// Use this during compression to specify that all pending output should be
- /// flushed to the output buffer and the output should be aligned on a byte
- /// boundary. You might use this in a streaming communication scenario, so that
- /// the decompressor can get all input data available so far. When using this
- /// with a ZlibCodec, <c>AvailableBytesIn</c> will be zero after the call if
- /// enough output space has been provided before the call. Flushing will
- /// degrade compression and so it should be used only when necessary.
- /// </summary>
- Sync,
-
- /// <summary>
- /// Use this during compression to specify that all output should be flushed, as
- /// with <c>FlushType.Sync</c>, but also, the compression state should be reset
- /// so that decompression can restart from this point if previous compressed
- /// data has been damaged or if random access is desired. Using
- /// <c>FlushType.Full</c> too often can significantly degrade the compression.
- /// </summary>
- Full,
-
- /// <summary>Signals the end of the compression/decompression stream.</summary>
- Finish,
- }
-
-
- /// <summary>
- /// The compression level to be used when using a DeflateStream or ZlibStream with CompressionMode.Compress.
- /// </summary>
- public enum CompressionLevel
- {
- /// <summary>
- /// None means that the data will be simply stored, with no change at all.
- /// If you are producing ZIPs for use on Mac OSX, be aware that archives produced with CompressionLevel.None
- /// cannot be opened with the default zip reader. Use a different CompressionLevel.
- /// </summary>
- None= 0,
- /// <summary>
- /// Same as None.
- /// </summary>
- Level0 = 0,
-
- /// <summary>
- /// The fastest but least effective compression.
- /// </summary>
- BestSpeed = 1,
-
- /// <summary>
- /// A synonym for BestSpeed.
- /// </summary>
- Level1 = 1,
-
- /// <summary>
- /// A little slower, but better, than level 1.
- /// </summary>
- Level2 = 2,
-
- /// <summary>
- /// A little slower, but better, than level 2.
- /// </summary>
- Level3 = 3,
-
- /// <summary>
- /// A little slower, but better, than level 3.
- /// </summary>
- Level4 = 4,
-
- /// <summary>
- /// A little slower than level 4, but with better compression.
- /// </summary>
- Level5 = 5,
-
- /// <summary>
- /// The default compression level, with a good balance of speed and compression efficiency.
- /// </summary>
- Default = 6,
- /// <summary>
- /// A synonym for Default.
- /// </summary>
- Level6 = 6,
-
- /// <summary>
- /// Pretty good compression!
- /// </summary>
- Level7 = 7,
-
- /// <summary>
- /// Better compression than Level7!
- /// </summary>
- Level8 = 8,
-
- /// <summary>
- /// The "best" compression, where best means greatest reduction in size of the input data stream.
- /// This is also the slowest compression.
- /// </summary>
- BestCompression = 9,
-
- /// <summary>
- /// A synonym for BestCompression.
- /// </summary>
- Level9 = 9,
- }
-
- /// <summary>
- /// Describes options for how the compression algorithm is executed. Different strategies
- /// work better on different sorts of data. The strategy parameter can affect the compression
- /// ratio and the speed of compression but not the correctness of the compresssion.
- /// </summary>
- public enum CompressionStrategy
- {
- /// <summary>
- /// The default strategy is probably the best for normal data.
- /// </summary>
- Default = 0,
-
- /// <summary>
- /// The <c>Filtered</c> strategy is intended to be used most effectively with data produced by a
- /// filter or predictor. By this definition, filtered data consists mostly of small
- /// values with a somewhat random distribution. In this case, the compression algorithm
- /// is tuned to compress them better. The effect of <c>Filtered</c> is to force more Huffman
- /// coding and less string matching; it is a half-step between <c>Default</c> and <c>HuffmanOnly</c>.
- /// </summary>
- Filtered = 1,
-
- /// <summary>
- /// Using <c>HuffmanOnly</c> will force the compressor to do Huffman encoding only, with no
- /// string matching.
- /// </summary>
- HuffmanOnly = 2,
- }
-
-
- /// <summary>
- /// An enum to specify the direction of transcoding - whether to compress or decompress.
- /// </summary>
- public enum CompressionMode
- {
- /// <summary>
- /// Used to specify that the stream should compress the data.
- /// </summary>
- Compress= 0,
- /// <summary>
- /// Used to specify that the stream should decompress the data.
- /// </summary>
- Decompress = 1,
- }
-
-
- /// <summary>
- /// A general purpose exception class for exceptions in the Zlib library.
- /// </summary>
- [Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000E")]
- public class ZlibException : System.Exception
- {
- /// <summary>
- /// The ZlibException class captures exception information generated
- /// by the Zlib library.
- /// </summary>
- public ZlibException()
- : base()
- {
- }
-
- /// <summary>
- /// This ctor collects a message attached to the exception.
- /// </summary>
- /// <param name="s">the message for the exception.</param>
- public ZlibException(System.String s)
- : base(s)
- {
- }
- }
-
-
- internal class SharedUtils
- {
- /// <summary>
- /// Performs an unsigned bitwise right shift with the specified number
- /// </summary>
- /// <param name="number">Number to operate on</param>
- /// <param name="bits">Ammount of bits to shift</param>
- /// <returns>The resulting number from the shift operation</returns>
- public static int URShift(int number, int bits)
- {
- return (int)((uint)number >> bits);
- }
-
-#if NOT
- /// <summary>
- /// Performs an unsigned bitwise right shift with the specified number
- /// </summary>
- /// <param name="number">Number to operate on</param>
- /// <param name="bits">Ammount of bits to shift</param>
- /// <returns>The resulting number from the shift operation</returns>
- public static long URShift(long number, int bits)
- {
- return (long) ((UInt64)number >> bits);
- }
-#endif
-
- /// <summary>
- /// Reads a number of characters from the current source TextReader and writes
- /// the data to the target array at the specified index.
- /// </summary>
- ///
- /// <param name="sourceTextReader">The source TextReader to read from</param>
- /// <param name="target">Contains the array of characteres read from the source TextReader.</param>
- /// <param name="start">The starting index of the target array.</param>
- /// <param name="count">The maximum number of characters to read from the source TextReader.</param>
- ///
- /// <returns>
- /// The number of characters read. The number will be less than or equal to
- /// count depending on the data available in the source TextReader. Returns -1
- /// if the end of the stream is reached.
- /// </returns>
- public static System.Int32 ReadInput(System.IO.TextReader sourceTextReader, byte[] target, int start, int count)
- {
- // Returns 0 bytes if not enough space in target
- if (target.Length == 0) return 0;
-
- char[] charArray = new char[target.Length];
- int bytesRead = sourceTextReader.Read(charArray, start, count);
-
- // Returns -1 if EOF
- if (bytesRead == 0) return -1;
-
- for (int index = start; index < start + bytesRead; index++)
- target[index] = (byte)charArray[index];
-
- return bytesRead;
- }
-
-
- internal static byte[] ToByteArray(System.String sourceString)
- {
- return System.Text.UTF8Encoding.UTF8.GetBytes(sourceString);
- }
-
-
- internal static char[] ToCharArray(byte[] byteArray)
- {
- return System.Text.UTF8Encoding.UTF8.GetChars(byteArray);
- }
- }
-
- internal static class InternalConstants
- {
- internal static readonly int MAX_BITS = 15;
- internal static readonly int BL_CODES = 19;
- internal static readonly int D_CODES = 30;
- internal static readonly int LITERALS = 256;
- internal static readonly int LENGTH_CODES = 29;
- internal static readonly int L_CODES = (LITERALS + 1 + LENGTH_CODES);
-
- // Bit length codes must not exceed MAX_BL_BITS bits
- internal static readonly int MAX_BL_BITS = 7;
-
- // repeat previous bit length 3-6 times (2 bits of repeat count)
- internal static readonly int REP_3_6 = 16;
-
- // repeat a zero length 3-10 times (3 bits of repeat count)
- internal static readonly int REPZ_3_10 = 17;
-
- // repeat a zero length 11-138 times (7 bits of repeat count)
- internal static readonly int REPZ_11_138 = 18;
-
- }
-
- internal sealed class StaticTree
- {
- internal static readonly short[] lengthAndLiteralsTreeCodes = new short[] {
- 12, 8, 140, 8, 76, 8, 204, 8, 44, 8, 172, 8, 108, 8, 236, 8,
- 28, 8, 156, 8, 92, 8, 220, 8, 60, 8, 188, 8, 124, 8, 252, 8,
- 2, 8, 130, 8, 66, 8, 194, 8, 34, 8, 162, 8, 98, 8, 226, 8,
- 18, 8, 146, 8, 82, 8, 210, 8, 50, 8, 178, 8, 114, 8, 242, 8,
- 10, 8, 138, 8, 74, 8, 202, 8, 42, 8, 170, 8, 106, 8, 234, 8,
- 26, 8, 154, 8, 90, 8, 218, 8, 58, 8, 186, 8, 122, 8, 250, 8,
- 6, 8, 134, 8, 70, 8, 198, 8, 38, 8, 166, 8, 102, 8, 230, 8,
- 22, 8, 150, 8, 86, 8, 214, 8, 54, 8, 182, 8, 118, 8, 246, 8,
- 14, 8, 142, 8, 78, 8, 206, 8, 46, 8, 174, 8, 110, 8, 238, 8,
- 30, 8, 158, 8, 94, 8, 222, 8, 62, 8, 190, 8, 126, 8, 254, 8,
- 1, 8, 129, 8, 65, 8, 193, 8, 33, 8, 161, 8, 97, 8, 225, 8,
- 17, 8, 145, 8, 81, 8, 209, 8, 49, 8, 177, 8, 113, 8, 241, 8,
- 9, 8, 137, 8, 73, 8, 201, 8, 41, 8, 169, 8, 105, 8, 233, 8,
- 25, 8, 153, 8, 89, 8, 217, 8, 57, 8, 185, 8, 121, 8, 249, 8,
- 5, 8, 133, 8, 69, 8, 197, 8, 37, 8, 165, 8, 101, 8, 229, 8,
- 21, 8, 149, 8, 85, 8, 213, 8, 53, 8, 181, 8, 117, 8, 245, 8,
- 13, 8, 141, 8, 77, 8, 205, 8, 45, 8, 173, 8, 109, 8, 237, 8,
- 29, 8, 157, 8, 93, 8, 221, 8, 61, 8, 189, 8, 125, 8, 253, 8,
- 19, 9, 275, 9, 147, 9, 403, 9, 83, 9, 339, 9, 211, 9, 467, 9,
- 51, 9, 307, 9, 179, 9, 435, 9, 115, 9, 371, 9, 243, 9, 499, 9,
- 11, 9, 267, 9, 139, 9, 395, 9, 75, 9, 331, 9, 203, 9, 459, 9,
- 43, 9, 299, 9, 171, 9, 427, 9, 107, 9, 363, 9, 235, 9, 491, 9,
- 27, 9, 283, 9, 155, 9, 411, 9, 91, 9, 347, 9, 219, 9, 475, 9,
- 59, 9, 315, 9, 187, 9, 443, 9, 123, 9, 379, 9, 251, 9, 507, 9,
- 7, 9, 263, 9, 135, 9, 391, 9, 71, 9, 327, 9, 199, 9, 455, 9,
- 39, 9, 295, 9, 167, 9, 423, 9, 103, 9, 359, 9, 231, 9, 487, 9,
- 23, 9, 279, 9, 151, 9, 407, 9, 87, 9, 343, 9, 215, 9, 471, 9,
- 55, 9, 311, 9, 183, 9, 439, 9, 119, 9, 375, 9, 247, 9, 503, 9,
- 15, 9, 271, 9, 143, 9, 399, 9, 79, 9, 335, 9, 207, 9, 463, 9,
- 47, 9, 303, 9, 175, 9, 431, 9, 111, 9, 367, 9, 239, 9, 495, 9,
- 31, 9, 287, 9, 159, 9, 415, 9, 95, 9, 351, 9, 223, 9, 479, 9,
- 63, 9, 319, 9, 191, 9, 447, 9, 127, 9, 383, 9, 255, 9, 511, 9,
- 0, 7, 64, 7, 32, 7, 96, 7, 16, 7, 80, 7, 48, 7, 112, 7,
- 8, 7, 72, 7, 40, 7, 104, 7, 24, 7, 88, 7, 56, 7, 120, 7,
- 4, 7, 68, 7, 36, 7, 100, 7, 20, 7, 84, 7, 52, 7, 116, 7,
- 3, 8, 131, 8, 67, 8, 195, 8, 35, 8, 163, 8, 99, 8, 227, 8
- };
-
- internal static readonly short[] distTreeCodes = new short[] {
- 0, 5, 16, 5, 8, 5, 24, 5, 4, 5, 20, 5, 12, 5, 28, 5,
- 2, 5, 18, 5, 10, 5, 26, 5, 6, 5, 22, 5, 14, 5, 30, 5,
- 1, 5, 17, 5, 9, 5, 25, 5, 5, 5, 21, 5, 13, 5, 29, 5,
- 3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 };
-
- internal static readonly StaticTree Literals;
- internal static readonly StaticTree Distances;
- internal static readonly StaticTree BitLengths;
-
- internal short[] treeCodes; // static tree or null
- internal int[] extraBits; // extra bits for each code or null
- internal int extraBase; // base index for extra_bits
- internal int elems; // max number of elements in the tree
- internal int maxLength; // max bit length for the codes
-
- private StaticTree(short[] treeCodes, int[] extraBits, int extraBase, int elems, int maxLength)
- {
- this.treeCodes = treeCodes;
- this.extraBits = extraBits;
- this.extraBase = extraBase;
- this.elems = elems;
- this.maxLength = maxLength;
- }
- static StaticTree()
- {
- Literals = new StaticTree(lengthAndLiteralsTreeCodes, Tree.ExtraLengthBits, InternalConstants.LITERALS + 1, InternalConstants.L_CODES, InternalConstants.MAX_BITS);
- Distances = new StaticTree(distTreeCodes, Tree.ExtraDistanceBits, 0, InternalConstants.D_CODES, InternalConstants.MAX_BITS);
- BitLengths = new StaticTree(null, Tree.extra_blbits, 0, InternalConstants.BL_CODES, InternalConstants.MAX_BL_BITS);
- }
- }
-
-
-
- /// <summary>
- /// Computes an Adler-32 checksum.
- /// </summary>
- /// <remarks>
- /// The Adler checksum is similar to a CRC checksum, but faster to compute, though less
- /// reliable. It is used in producing RFC1950 compressed streams. The Adler checksum
- /// is a required part of the "ZLIB" standard. Applications will almost never need to
- /// use this class directly.
- /// </remarks>
- ///
- /// <exclude/>
- public sealed class Adler
- {
- // largest prime smaller than 65536
- private static readonly uint BASE = 65521;
- // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
- private static readonly int NMAX = 5552;
-
-
-#pragma warning disable 3001
-#pragma warning disable 3002
-
- /// <summary>
- /// Calculates the Adler32 checksum.
- /// </summary>
- /// <remarks>
- /// <para>
- /// This is used within ZLIB. You probably don't need to use this directly.
- /// </para>
- /// </remarks>
- /// <example>
- /// To compute an Adler32 checksum on a byte array:
- /// <code>
- /// var adler = Adler.Adler32(0, null, 0, 0);
- /// adler = Adler.Adler32(adler, buffer, index, length);
- /// </code>
- /// </example>
- public static uint Adler32(uint adler, byte[] buf, int index, int len)
- {
- if (buf == null)
- return 1;
-
- uint s1 = (uint) (adler & 0xffff);
- uint s2 = (uint) ((adler >> 16) & 0xffff);
-
- while (len > 0)
- {
- int k = len < NMAX ? len : NMAX;
- len -= k;
- while (k >= 16)
- {
- //s1 += (buf[index++] & 0xff); s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- s1 += buf[index++]; s2 += s1;
- k -= 16;
- }
- if (k != 0)
- {
- do
- {
- s1 += buf[index++];
- s2 += s1;
- }
- while (--k != 0);
- }
- s1 %= BASE;
- s2 %= BASE;
- }
- return (uint)((s2 << 16) | s1);
- }
-#pragma warning restore 3001
-#pragma warning restore 3002
-
- }
-
-}
\ No newline at end of file
diff --git a/EPPlus/Packaging/DotNetZip/Zlib/ZlibBaseStream.cs b/EPPlus/Packaging/DotNetZip/Zlib/ZlibBaseStream.cs
deleted file mode 100644
index 3215e3a..0000000
--- a/EPPlus/Packaging/DotNetZip/Zlib/ZlibBaseStream.cs
+++ /dev/null
@@ -1,628 +0,0 @@
-// ZlibBaseStream.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-August-06 21:22:38>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the ZlibBaseStream class, which is an intnernal
-// base class for DeflateStream, ZlibStream and GZipStream.
-//
-// ------------------------------------------------------------------
-
-using OfficeOpenXml.Packaging.Ionic.Crc;
-using System;
-using System.IO;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zlib
-{
-
- internal enum ZlibStreamFlavor { ZLIB = 1950, DEFLATE = 1951, GZIP = 1952 }
-
- internal class ZlibBaseStream : System.IO.Stream
- {
- protected internal ZlibCodec _z = null; // deferred init... new ZlibCodec();
-
- protected internal StreamMode _streamMode = StreamMode.Undefined;
- protected internal FlushType _flushMode;
- protected internal ZlibStreamFlavor _flavor;
- protected internal CompressionMode _compressionMode;
- protected internal CompressionLevel _level;
- protected internal bool _leaveOpen;
- protected internal byte[] _workingBuffer;
- protected internal int _bufferSize = ZlibConstants.WorkingBufferSizeDefault;
- protected internal byte[] _buf1 = new byte[1];
-
- protected internal System.IO.Stream _stream;
- protected internal CompressionStrategy Strategy = CompressionStrategy.Default;
-
- // workitem 7159
- CRC32 crc;
- protected internal string _GzipFileName;
- protected internal string _GzipComment;
- protected internal DateTime _GzipMtime;
- protected internal int _gzipHeaderByteCount;
-
- internal int Crc32 { get { if (crc == null) return 0; return crc.Crc32Result; } }
-
- public ZlibBaseStream(System.IO.Stream stream,
- CompressionMode compressionMode,
- CompressionLevel level,
- ZlibStreamFlavor flavor,
- bool leaveOpen)
- : base()
- {
- this._flushMode = FlushType.None;
- //this._workingBuffer = new byte[WORKING_BUFFER_SIZE_DEFAULT];
- this._stream = stream;
- this._leaveOpen = leaveOpen;
- this._compressionMode = compressionMode;
- this._flavor = flavor;
- this._level = level;
- // workitem 7159
- if (flavor == ZlibStreamFlavor.GZIP)
- {
- this.crc = new Ionic.Crc.CRC32();
- }
- }
-
-
- protected internal bool _wantCompress
- {
- get
- {
- return (this._compressionMode == CompressionMode.Compress);
- }
- }
-
- private ZlibCodec z
- {
- get
- {
- if (_z == null)
- {
- bool wantRfc1950Header = (this._flavor == ZlibStreamFlavor.ZLIB);
- _z = new ZlibCodec();
- if (this._compressionMode == CompressionMode.Decompress)
- {
- _z.InitializeInflate(wantRfc1950Header);
- }
- else
- {
- _z.Strategy = Strategy;
- _z.InitializeDeflate(this._level, wantRfc1950Header);
- }
- }
- return _z;
- }
- }
-
-
-
- private byte[] workingBuffer
- {
- get
- {
- if (_workingBuffer == null)
- _workingBuffer = new byte[_bufferSize];
- return _workingBuffer;
- }
- }
-
-
-
- public override void Write(System.Byte[] buffer, int offset, int count)
- {
- // workitem 7159
- // calculate the CRC on the unccompressed data (before writing)
- if (crc != null)
- crc.SlurpBlock(buffer, offset, count);
-
- if (_streamMode == StreamMode.Undefined)
- _streamMode = StreamMode.Writer;
- else if (_streamMode != StreamMode.Writer)
- throw new ZlibException("Cannot Write after Reading.");
-
- if (count == 0)
- return;
-
- // first reference of z property will initialize the private var _z
- z.InputBuffer = buffer;
- _z.NextIn = offset;
- _z.AvailableBytesIn = count;
- bool done = false;
- do
- {
- _z.OutputBuffer = workingBuffer;
- _z.NextOut = 0;
- _z.AvailableBytesOut = _workingBuffer.Length;
- int rc = (_wantCompress)
- ? _z.Deflate(_flushMode)
- : _z.Inflate(_flushMode);
- if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
- throw new ZlibException((_wantCompress ? "de" : "in") + "flating: " + _z.Message);
-
- //if (_workingBuffer.Length - _z.AvailableBytesOut > 0)
- _stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut);
-
- done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0;
-
- // If GZIP and de-compress, we're done when 8 bytes remain.
- if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress)
- done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0);
-
- }
- while (!done);
- }
-
-
-
- private void finish()
- {
- if (_z == null) return;
-
- if (_streamMode == StreamMode.Writer)
- {
- bool done = false;
- do
- {
- _z.OutputBuffer = workingBuffer;
- _z.NextOut = 0;
- _z.AvailableBytesOut = _workingBuffer.Length;
- int rc = (_wantCompress)
- ? _z.Deflate(FlushType.Finish)
- : _z.Inflate(FlushType.Finish);
-
- if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK)
- {
- string verb = (_wantCompress ? "de" : "in") + "flating";
- if (_z.Message == null)
- throw new ZlibException(String.Format("{0}: (rc = {1})", verb, rc));
- else
- throw new ZlibException(verb + ": " + _z.Message);
- }
-
- if (_workingBuffer.Length - _z.AvailableBytesOut > 0)
- {
- _stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut);
- }
-
- done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0;
- // If GZIP and de-compress, we're done when 8 bytes remain.
- if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress)
- done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0);
-
- }
- while (!done);
-
- Flush();
-
- // workitem 7159
- if (_flavor == ZlibStreamFlavor.GZIP)
- {
- if (_wantCompress)
- {
- // Emit the GZIP trailer: CRC32 and size mod 2^32
- int c1 = crc.Crc32Result;
- _stream.Write(BitConverter.GetBytes(c1), 0, 4);
- int c2 = (Int32)(crc.TotalBytesRead & 0x00000000FFFFFFFF);
- _stream.Write(BitConverter.GetBytes(c2), 0, 4);
- }
- else
- {
- throw new ZlibException("Writing with decompression is not supported.");
- }
- }
- }
- // workitem 7159
- else if (_streamMode == StreamMode.Reader)
- {
- if (_flavor == ZlibStreamFlavor.GZIP)
- {
- if (!_wantCompress)
- {
- // workitem 8501: handle edge case (decompress empty stream)
- if (_z.TotalBytesOut == 0L)
- return;
-
- // Read and potentially verify the GZIP trailer:
- // CRC32 and size mod 2^32
- byte[] trailer = new byte[8];
-
- // workitems 8679 & 12554
- if (_z.AvailableBytesIn < 8)
- {
- // Make sure we have read to the end of the stream
- Array.Copy(_z.InputBuffer, _z.NextIn, trailer, 0, _z.AvailableBytesIn);
- int bytesNeeded = 8 - _z.AvailableBytesIn;
- int bytesRead = _stream.Read(trailer,
- _z.AvailableBytesIn,
- bytesNeeded);
- if (bytesNeeded != bytesRead)
- {
- throw new ZlibException(String.Format("Missing or incomplete GZIP trailer. Expected 8 bytes, got {0}.",
- _z.AvailableBytesIn + bytesRead));
- }
- }
- else
- {
- Array.Copy(_z.InputBuffer, _z.NextIn, trailer, 0, trailer.Length);
- }
-
- Int32 crc32_expected = BitConverter.ToInt32(trailer, 0);
- Int32 crc32_actual = crc.Crc32Result;
- Int32 isize_expected = BitConverter.ToInt32(trailer, 4);
- Int32 isize_actual = (Int32)(_z.TotalBytesOut & 0x00000000FFFFFFFF);
-
- if (crc32_actual != crc32_expected)
- throw new ZlibException(String.Format("Bad CRC32 in GZIP trailer. (actual({0:X8})!=expected({1:X8}))", crc32_actual, crc32_expected));
-
- if (isize_actual != isize_expected)
- throw new ZlibException(String.Format("Bad size in GZIP trailer. (actual({0})!=expected({1}))", isize_actual, isize_expected));
-
- }
- else
- {
- throw new ZlibException("Reading with compression is not supported.");
- }
- }
- }
- }
-
-
- private void end()
- {
- if (z == null)
- return;
- if (_wantCompress)
- {
- _z.EndDeflate();
- }
- else
- {
- _z.EndInflate();
- }
- _z = null;
- }
-
-
- public override void Close()
- {
- if (_stream == null) return;
- try
- {
- finish();
- }
- finally
- {
- end();
- if (!_leaveOpen) _stream.Close();
- _stream = null;
- }
- }
-
- public override void Flush()
- {
- _stream.Flush();
- }
-
- public override System.Int64 Seek(System.Int64 offset, System.IO.SeekOrigin origin)
- {
- throw new NotImplementedException();
- //_outStream.Seek(offset, origin);
- }
- public override void SetLength(System.Int64 value)
- {
- _stream.SetLength(value);
- }
-
-
-#if NOT
- public int Read()
- {
- if (Read(_buf1, 0, 1) == 0)
- return 0;
- // calculate CRC after reading
- if (crc!=null)
- crc.SlurpBlock(_buf1,0,1);
- return (_buf1[0] & 0xFF);
- }
-#endif
-
- private bool nomoreinput = false;
-
-
-
- private string ReadZeroTerminatedString()
- {
- var list = new System.Collections.Generic.List<byte>();
- bool done = false;
- do
- {
- // workitem 7740
- int n = _stream.Read(_buf1, 0, 1);
- if (n != 1)
- throw new ZlibException("Unexpected EOF reading GZIP header.");
- else
- {
- if (_buf1[0] == 0)
- done = true;
- else
- list.Add(_buf1[0]);
- }
- } while (!done);
- byte[] a = list.ToArray();
- return GZipStream.iso8859dash1.GetString(a, 0, a.Length);
- }
-
-
- private int _ReadAndValidateGzipHeader()
- {
- int totalBytesRead = 0;
- // read the header on the first read
- byte[] header = new byte[10];
- int n = _stream.Read(header, 0, header.Length);
-
- // workitem 8501: handle edge case (decompress empty stream)
- if (n == 0)
- return 0;
-
- if (n != 10)
- throw new ZlibException("Not a valid GZIP stream.");
-
- if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8)
- throw new ZlibException("Bad GZIP header.");
-
- Int32 timet = BitConverter.ToInt32(header, 4);
- _GzipMtime = GZipStream._unixEpoch.AddSeconds(timet);
- totalBytesRead += n;
- if ((header[3] & 0x04) == 0x04)
- {
- // read and discard extra field
- n = _stream.Read(header, 0, 2); // 2-byte length field
- totalBytesRead += n;
-
- Int16 extraLength = (Int16)(header[0] + header[1] * 256);
- byte[] extra = new byte[extraLength];
- n = _stream.Read(extra, 0, extra.Length);
- if (n != extraLength)
- throw new ZlibException("Unexpected end-of-file reading GZIP header.");
- totalBytesRead += n;
- }
- if ((header[3] & 0x08) == 0x08)
- _GzipFileName = ReadZeroTerminatedString();
- if ((header[3] & 0x10) == 0x010)
- _GzipComment = ReadZeroTerminatedString();
- if ((header[3] & 0x02) == 0x02)
- Read(_buf1, 0, 1); // CRC16, ignore
-
- return totalBytesRead;
- }
-
-
-
- public override System.Int32 Read(System.Byte[] buffer, System.Int32 offset, System.Int32 count)
- {
- // According to MS documentation, any implementation of the IO.Stream.Read function must:
- // (a) throw an exception if offset & count reference an invalid part of the buffer,
- // or if count < 0, or if buffer is null
- // (b) return 0 only upon EOF, or if count = 0
- // (c) if not EOF, then return at least 1 byte, up to <count> bytes
-
- if (_streamMode == StreamMode.Undefined)
- {
- if (!this._stream.CanRead) throw new ZlibException("The stream is not readable.");
- // for the first read, set up some controls.
- _streamMode = StreamMode.Reader;
- // (The first reference to _z goes through the private accessor which
- // may initialize it.)
- z.AvailableBytesIn = 0;
- if (_flavor == ZlibStreamFlavor.GZIP)
- {
- _gzipHeaderByteCount = _ReadAndValidateGzipHeader();
- // workitem 8501: handle edge case (decompress empty stream)
- if (_gzipHeaderByteCount == 0)
- return 0;
- }
- }
-
- if (_streamMode != StreamMode.Reader)
- throw new ZlibException("Cannot Read after Writing.");
-
- if (count == 0) return 0;
- if (nomoreinput && _wantCompress) return 0; // workitem 8557
- if (buffer == null) throw new ArgumentNullException("buffer");
- if (count < 0) throw new ArgumentOutOfRangeException("count");
- if (offset < buffer.GetLowerBound(0)) throw new ArgumentOutOfRangeException("offset");
- if ((offset + count) > buffer.GetLength(0)) throw new ArgumentOutOfRangeException("count");
-
- int rc = 0;
-
- // set up the output of the deflate/inflate codec:
- _z.OutputBuffer = buffer;
- _z.NextOut = offset;
- _z.AvailableBytesOut = count;
-
- // This is necessary in case _workingBuffer has been resized. (new byte[])
- // (The first reference to _workingBuffer goes through the private accessor which
- // may initialize it.)
- _z.InputBuffer = workingBuffer;
-
- do
- {
- // need data in _workingBuffer in order to deflate/inflate. Here, we check if we have any.
- if ((_z.AvailableBytesIn == 0) && (!nomoreinput))
- {
- // No data available, so try to Read data from the captive stream.
- _z.NextIn = 0;
- _z.AvailableBytesIn = _stream.Read(_workingBuffer, 0, _workingBuffer.Length);
- if (_z.AvailableBytesIn == 0)
- nomoreinput = true;
-
- }
- // we have data in InputBuffer; now compress or decompress as appropriate
- rc = (_wantCompress)
- ? _z.Deflate(_flushMode)
- : _z.Inflate(_flushMode);
-
- if (nomoreinput && (rc == ZlibConstants.Z_BUF_ERROR))
- return 0;
-
- if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
- throw new ZlibException(String.Format("{0}flating: rc={1} msg={2}", (_wantCompress ? "de" : "in"), rc, _z.Message));
-
- if ((nomoreinput || rc == ZlibConstants.Z_STREAM_END) && (_z.AvailableBytesOut == count))
- break; // nothing more to read
- }
- //while (_z.AvailableBytesOut == count && rc == ZlibConstants.Z_OK);
- while (_z.AvailableBytesOut > 0 && !nomoreinput && rc == ZlibConstants.Z_OK);
-
-
- // workitem 8557
- // is there more room in output?
- if (_z.AvailableBytesOut > 0)
- {
- if (rc == ZlibConstants.Z_OK && _z.AvailableBytesIn == 0)
- {
- // deferred
- }
-
- // are we completely done reading?
- if (nomoreinput)
- {
- // and in compression?
- if (_wantCompress)
- {
- // no more input data available; therefore we flush to
- // try to complete the read
- rc = _z.Deflate(FlushType.Finish);
-
- if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
- throw new ZlibException(String.Format("Deflating: rc={0} msg={1}", rc, _z.Message));
- }
- }
- }
-
-
- rc = (count - _z.AvailableBytesOut);
-
- // calculate CRC after reading
- if (crc != null)
- crc.SlurpBlock(buffer, offset, rc);
-
- return rc;
- }
-
-
-
- public override System.Boolean CanRead
- {
- get { return this._stream.CanRead; }
- }
-
- public override System.Boolean CanSeek
- {
- get { return this._stream.CanSeek; }
- }
-
- public override System.Boolean CanWrite
- {
- get { return this._stream.CanWrite; }
- }
-
- public override System.Int64 Length
- {
- get { return _stream.Length; }
- }
-
- public override long Position
- {
- get { throw new NotImplementedException(); }
- set { throw new NotImplementedException(); }
- }
-
- internal enum StreamMode
- {
- Writer,
- Reader,
- Undefined,
- }
-
-
- public static void CompressString(String s, Stream compressor)
- {
- byte[] uncompressed = System.Text.Encoding.UTF8.GetBytes(s);
- using (compressor)
- {
- compressor.Write(uncompressed, 0, uncompressed.Length);
- }
- }
-
- public static void CompressBuffer(byte[] b, Stream compressor)
- {
- // workitem 8460
- using (compressor)
- {
- compressor.Write(b, 0, b.Length);
- }
- }
-
- public static String UncompressString(byte[] compressed, Stream decompressor)
- {
- // workitem 8460
- byte[] working = new byte[1024];
- var encoding = System.Text.Encoding.UTF8;
- using (var output = new MemoryStream())
- {
- using (decompressor)
- {
- int n;
- while ((n = decompressor.Read(working, 0, working.Length)) != 0)
- {
- output.Write(working, 0, n);
- }
- }
-
- // reset to allow read from start
- output.Seek(0, SeekOrigin.Begin);
- var sr = new StreamReader(output, encoding);
- return sr.ReadToEnd();
- }
- }
-
- public static byte[] UncompressBuffer(byte[] compressed, Stream decompressor)
- {
- // workitem 8460
- byte[] working = new byte[1024];
- using (var output = new MemoryStream())
- {
- using (decompressor)
- {
- int n;
- while ((n = decompressor.Read(working, 0, working.Length)) != 0)
- {
- output.Write(working, 0, n);
- }
- }
- return output.ToArray();
- }
- }
-
- }
-
-
-}
diff --git a/EPPlus/Packaging/DotNetZip/Zlib/ZlibCodec.cs b/EPPlus/Packaging/DotNetZip/Zlib/ZlibCodec.cs
deleted file mode 100644
index 8cd6ce4..0000000
--- a/EPPlus/Packaging/DotNetZip/Zlib/ZlibCodec.cs
+++ /dev/null
@@ -1,717 +0,0 @@
-// ZlibCodec.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2009-November-03 15:40:51>
-//
-// ------------------------------------------------------------------
-//
-// This module defines a Codec for ZLIB compression and
-// decompression. This code extends code that was based the jzlib
-// implementation of zlib, but this code is completely novel. The codec
-// class is new, and encapsulates some behaviors that are new, and some
-// that were present in other classes in the jzlib code base. In
-// keeping with the license for jzlib, the copyright to the jzlib code
-// is included below.
-//
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-//
-// 2. 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.
-//
-// 3. The names of the authors may not be used to endorse or promote products
-// derived from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
-// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
-//
-// -----------------------------------------------------------------------
-//
-// This program is based on zlib-1.1.3; credit to authors
-// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
-// and contributors of zlib.
-//
-// -----------------------------------------------------------------------
-
-
-using System;
-using Interop=System.Runtime.InteropServices;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zlib
-{
- /// <summary>
- /// Encoder and Decoder for ZLIB and DEFLATE (IETF RFC1950 and RFC1951).
- /// </summary>
- ///
- /// <remarks>
- /// This class compresses and decompresses data according to the Deflate algorithm
- /// and optionally, the ZLIB format, as documented in <see
- /// href="http://www.ietf.org/rfc/rfc1950.txt">RFC 1950 - ZLIB</see> and <see
- /// href="http://www.ietf.org/rfc/rfc1951.txt">RFC 1951 - DEFLATE</see>.
- /// </remarks>
- [Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000D")]
- [Interop.ComVisible(true)]
-#if !NETCF
- [Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)]
-#endif
- sealed public class ZlibCodec
- {
- /// <summary>
- /// The buffer from which data is taken.
- /// </summary>
- public byte[] InputBuffer;
-
- /// <summary>
- /// An index into the InputBuffer array, indicating where to start reading.
- /// </summary>
- public int NextIn;
-
- /// <summary>
- /// The number of bytes available in the InputBuffer, starting at NextIn.
- /// </summary>
- /// <remarks>
- /// Generally you should set this to InputBuffer.Length before the first Inflate() or Deflate() call.
- /// The class will update this number as calls to Inflate/Deflate are made.
- /// </remarks>
- public int AvailableBytesIn;
-
- /// <summary>
- /// Total number of bytes read so far, through all calls to Inflate()/Deflate().
- /// </summary>
- public long TotalBytesIn;
-
- /// <summary>
- /// Buffer to store output data.
- /// </summary>
- public byte[] OutputBuffer;
-
- /// <summary>
- /// An index into the OutputBuffer array, indicating where to start writing.
- /// </summary>
- public int NextOut;
-
- /// <summary>
- /// The number of bytes available in the OutputBuffer, starting at NextOut.
- /// </summary>
- /// <remarks>
- /// Generally you should set this to OutputBuffer.Length before the first Inflate() or Deflate() call.
- /// The class will update this number as calls to Inflate/Deflate are made.
- /// </remarks>
- public int AvailableBytesOut;
-
- /// <summary>
- /// Total number of bytes written to the output so far, through all calls to Inflate()/Deflate().
- /// </summary>
- public long TotalBytesOut;
-
- /// <summary>
- /// used for diagnostics, when something goes wrong!
- /// </summary>
- public System.String Message;
-
- internal DeflateManager dstate;
- internal InflateManager istate;
-
- internal uint _Adler32;
-
- /// <summary>
- /// The compression level to use in this codec. Useful only in compression mode.
- /// </summary>
- public CompressionLevel CompressLevel = CompressionLevel.Default;
-
- /// <summary>
- /// The number of Window Bits to use.
- /// </summary>
- /// <remarks>
- /// This gauges the size of the sliding window, and hence the
- /// compression effectiveness as well as memory consumption. It's best to just leave this
- /// setting alone if you don't know what it is. The maximum value is 15 bits, which implies
- /// a 32k window.
- /// </remarks>
- public int WindowBits = ZlibConstants.WindowBitsDefault;
-
- /// <summary>
- /// The compression strategy to use.
- /// </summary>
- /// <remarks>
- /// This is only effective in compression. The theory offered by ZLIB is that different
- /// strategies could potentially produce significant differences in compression behavior
- /// for different data sets. Unfortunately I don't have any good recommendations for how
- /// to set it differently. When I tested changing the strategy I got minimally different
- /// compression performance. It's best to leave this property alone if you don't have a
- /// good feel for it. Or, you may want to produce a test harness that runs through the
- /// different strategy options and evaluates them on different file types. If you do that,
- /// let me know your results.
- /// </remarks>
- public CompressionStrategy Strategy = CompressionStrategy.Default;
-
-
- /// <summary>
- /// The Adler32 checksum on the data transferred through the codec so far. You probably don't need to look at this.
- /// </summary>
- public int Adler32 { get { return (int)_Adler32; } }
-
-
- /// <summary>
- /// Create a ZlibCodec.
- /// </summary>
- /// <remarks>
- /// If you use this default constructor, you will later have to explicitly call
- /// InitializeInflate() or InitializeDeflate() before using the ZlibCodec to compress
- /// or decompress.
- /// </remarks>
- public ZlibCodec() { }
-
- /// <summary>
- /// Create a ZlibCodec that either compresses or decompresses.
- /// </summary>
- /// <param name="mode">
- /// Indicates whether the codec should compress (deflate) or decompress (inflate).
- /// </param>
- public ZlibCodec(CompressionMode mode)
- {
- if (mode == CompressionMode.Compress)
- {
- int rc = InitializeDeflate();
- if (rc != ZlibConstants.Z_OK) throw new ZlibException("Cannot initialize for deflate.");
- }
- else if (mode == CompressionMode.Decompress)
- {
- int rc = InitializeInflate();
- if (rc != ZlibConstants.Z_OK) throw new ZlibException("Cannot initialize for inflate.");
- }
- else throw new ZlibException("Invalid ZlibStreamFlavor.");
- }
-
- /// <summary>
- /// Initialize the inflation state.
- /// </summary>
- /// <remarks>
- /// It is not necessary to call this before using the ZlibCodec to inflate data;
- /// It is implicitly called when you call the constructor.
- /// </remarks>
- /// <returns>Z_OK if everything goes well.</returns>
- public int InitializeInflate()
- {
- return InitializeInflate(this.WindowBits);
- }
-
- /// <summary>
- /// Initialize the inflation state with an explicit flag to
- /// govern the handling of RFC1950 header bytes.
- /// </summary>
- ///
- /// <remarks>
- /// By default, the ZLIB header defined in <see
- /// href="http://www.ietf.org/rfc/rfc1950.txt">RFC 1950</see> is expected. If
- /// you want to read a zlib stream you should specify true for
- /// expectRfc1950Header. If you have a deflate stream, you will want to specify
- /// false. It is only necessary to invoke this initializer explicitly if you
- /// want to specify false.
- /// </remarks>
- ///
- /// <param name="expectRfc1950Header">whether to expect an RFC1950 header byte
- /// pair when reading the stream of data to be inflated.</param>
- ///
- /// <returns>Z_OK if everything goes well.</returns>
- public int InitializeInflate(bool expectRfc1950Header)
- {
- return InitializeInflate(this.WindowBits, expectRfc1950Header);
- }
-
- /// <summary>
- /// Initialize the ZlibCodec for inflation, with the specified number of window bits.
- /// </summary>
- /// <param name="windowBits">The number of window bits to use. If you need to ask what that is,
- /// then you shouldn't be calling this initializer.</param>
- /// <returns>Z_OK if all goes well.</returns>
- public int InitializeInflate(int windowBits)
- {
- this.WindowBits = windowBits;
- return InitializeInflate(windowBits, true);
- }
-
- /// <summary>
- /// Initialize the inflation state with an explicit flag to govern the handling of
- /// RFC1950 header bytes.
- /// </summary>
- ///
- /// <remarks>
- /// If you want to read a zlib stream you should specify true for
- /// expectRfc1950Header. In this case, the library will expect to find a ZLIB
- /// header, as defined in <see href="http://www.ietf.org/rfc/rfc1950.txt">RFC
- /// 1950</see>, in the compressed stream. If you will be reading a DEFLATE or
- /// GZIP stream, which does not have such a header, you will want to specify
- /// false.
- /// </remarks>
- ///
- /// <param name="expectRfc1950Header">whether to expect an RFC1950 header byte pair when reading
- /// the stream of data to be inflated.</param>
- /// <param name="windowBits">The number of window bits to use. If you need to ask what that is,
- /// then you shouldn't be calling this initializer.</param>
- /// <returns>Z_OK if everything goes well.</returns>
- public int InitializeInflate(int windowBits, bool expectRfc1950Header)
- {
- this.WindowBits = windowBits;
- if (dstate != null) throw new ZlibException("You may not call InitializeInflate() after calling InitializeDeflate().");
- istate = new InflateManager(expectRfc1950Header);
- return istate.Initialize(this, windowBits);
- }
-
- /// <summary>
- /// Inflate the data in the InputBuffer, placing the result in the OutputBuffer.
- /// </summary>
- /// <remarks>
- /// You must have set InputBuffer and OutputBuffer, NextIn and NextOut, and AvailableBytesIn and
- /// AvailableBytesOut before calling this method.
- /// </remarks>
- /// <example>
- /// <code>
- /// private void InflateBuffer()
- /// {
- /// int bufferSize = 1024;
- /// byte[] buffer = new byte[bufferSize];
- /// ZlibCodec decompressor = new ZlibCodec();
- ///
- /// Console.WriteLine("\n============================================");
- /// Console.WriteLine("Size of Buffer to Inflate: {0} bytes.", CompressedBytes.Length);
- /// MemoryStream ms = new MemoryStream(DecompressedBytes);
- ///
- /// int rc = decompressor.InitializeInflate();
- ///
- /// decompressor.InputBuffer = CompressedBytes;
- /// decompressor.NextIn = 0;
- /// decompressor.AvailableBytesIn = CompressedBytes.Length;
- ///
- /// decompressor.OutputBuffer = buffer;
- ///
- /// // pass 1: inflate
- /// do
- /// {
- /// decompressor.NextOut = 0;
- /// decompressor.AvailableBytesOut = buffer.Length;
- /// rc = decompressor.Inflate(FlushType.None);
- ///
- /// if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
- /// throw new Exception("inflating: " + decompressor.Message);
- ///
- /// ms.Write(decompressor.OutputBuffer, 0, buffer.Length - decompressor.AvailableBytesOut);
- /// }
- /// while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0);
- ///
- /// // pass 2: finish and flush
- /// do
- /// {
- /// decompressor.NextOut = 0;
- /// decompressor.AvailableBytesOut = buffer.Length;
- /// rc = decompressor.Inflate(FlushType.Finish);
- ///
- /// if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK)
- /// throw new Exception("inflating: " + decompressor.Message);
- ///
- /// if (buffer.Length - decompressor.AvailableBytesOut > 0)
- /// ms.Write(buffer, 0, buffer.Length - decompressor.AvailableBytesOut);
- /// }
- /// while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0);
- ///
- /// decompressor.EndInflate();
- /// }
- ///
- /// </code>
- /// </example>
- /// <param name="flush">The flush to use when inflating.</param>
- /// <returns>Z_OK if everything goes well.</returns>
- public int Inflate(FlushType flush)
- {
- if (istate == null)
- throw new ZlibException("No Inflate State!");
- return istate.Inflate(flush);
- }
-
-
- /// <summary>
- /// Ends an inflation session.
- /// </summary>
- /// <remarks>
- /// Call this after successively calling Inflate(). This will cause all buffers to be flushed.
- /// After calling this you cannot call Inflate() without a intervening call to one of the
- /// InitializeInflate() overloads.
- /// </remarks>
- /// <returns>Z_OK if everything goes well.</returns>
- public int EndInflate()
- {
- if (istate == null)
- throw new ZlibException("No Inflate State!");
- int ret = istate.End();
- istate = null;
- return ret;
- }
-
- /// <summary>
- /// I don't know what this does!
- /// </summary>
- /// <returns>Z_OK if everything goes well.</returns>
- public int SyncInflate()
- {
- if (istate == null)
- throw new ZlibException("No Inflate State!");
- return istate.Sync();
- }
-
- /// <summary>
- /// Initialize the ZlibCodec for deflation operation.
- /// </summary>
- /// <remarks>
- /// The codec will use the MAX window bits and the default level of compression.
- /// </remarks>
- /// <example>
- /// <code>
- /// int bufferSize = 40000;
- /// byte[] CompressedBytes = new byte[bufferSize];
- /// byte[] DecompressedBytes = new byte[bufferSize];
- ///
- /// ZlibCodec compressor = new ZlibCodec();
- ///
- /// compressor.InitializeDeflate(CompressionLevel.Default);
- ///
- /// compressor.InputBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(TextToCompress);
- /// compressor.NextIn = 0;
- /// compressor.AvailableBytesIn = compressor.InputBuffer.Length;
- ///
- /// compressor.OutputBuffer = CompressedBytes;
- /// compressor.NextOut = 0;
- /// compressor.AvailableBytesOut = CompressedBytes.Length;
- ///
- /// while (compressor.TotalBytesIn != TextToCompress.Length && compressor.TotalBytesOut < bufferSize)
- /// {
- /// compressor.Deflate(FlushType.None);
- /// }
- ///
- /// while (true)
- /// {
- /// int rc= compressor.Deflate(FlushType.Finish);
- /// if (rc == ZlibConstants.Z_STREAM_END) break;
- /// }
- ///
- /// compressor.EndDeflate();
- ///
- /// </code>
- /// </example>
- /// <returns>Z_OK if all goes well. You generally don't need to check the return code.</returns>
- public int InitializeDeflate()
- {
- return _InternalInitializeDeflate(true);
- }
-
- /// <summary>
- /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel.
- /// </summary>
- /// <remarks>
- /// The codec will use the maximum window bits (15) and the specified
- /// CompressionLevel. It will emit a ZLIB stream as it compresses.
- /// </remarks>
- /// <param name="level">The compression level for the codec.</param>
- /// <returns>Z_OK if all goes well.</returns>
- public int InitializeDeflate(CompressionLevel level)
- {
- this.CompressLevel = level;
- return _InternalInitializeDeflate(true);
- }
-
-
- /// <summary>
- /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel,
- /// and the explicit flag governing whether to emit an RFC1950 header byte pair.
- /// </summary>
- /// <remarks>
- /// The codec will use the maximum window bits (15) and the specified CompressionLevel.
- /// If you want to generate a zlib stream, you should specify true for
- /// wantRfc1950Header. In this case, the library will emit a ZLIB
- /// header, as defined in <see href="http://www.ietf.org/rfc/rfc1950.txt">RFC
- /// 1950</see>, in the compressed stream.
- /// </remarks>
- /// <param name="level">The compression level for the codec.</param>
- /// <param name="wantRfc1950Header">whether to emit an initial RFC1950 byte pair in the compressed stream.</param>
- /// <returns>Z_OK if all goes well.</returns>
- public int InitializeDeflate(CompressionLevel level, bool wantRfc1950Header)
- {
- this.CompressLevel = level;
- return _InternalInitializeDeflate(wantRfc1950Header);
- }
-
-
- /// <summary>
- /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel,
- /// and the specified number of window bits.
- /// </summary>
- /// <remarks>
- /// The codec will use the specified number of window bits and the specified CompressionLevel.
- /// </remarks>
- /// <param name="level">The compression level for the codec.</param>
- /// <param name="bits">the number of window bits to use. If you don't know what this means, don't use this method.</param>
- /// <returns>Z_OK if all goes well.</returns>
- public int InitializeDeflate(CompressionLevel level, int bits)
- {
- this.CompressLevel = level;
- this.WindowBits = bits;
- return _InternalInitializeDeflate(true);
- }
-
- /// <summary>
- /// Initialize the ZlibCodec for deflation operation, using the specified
- /// CompressionLevel, the specified number of window bits, and the explicit flag
- /// governing whether to emit an RFC1950 header byte pair.
- /// </summary>
- ///
- /// <param name="level">The compression level for the codec.</param>
- /// <param name="wantRfc1950Header">whether to emit an initial RFC1950 byte pair in the compressed stream.</param>
- /// <param name="bits">the number of window bits to use. If you don't know what this means, don't use this method.</param>
- /// <returns>Z_OK if all goes well.</returns>
- public int InitializeDeflate(CompressionLevel level, int bits, bool wantRfc1950Header)
- {
- this.CompressLevel = level;
- this.WindowBits = bits;
- return _InternalInitializeDeflate(wantRfc1950Header);
- }
-
- private int _InternalInitializeDeflate(bool wantRfc1950Header)
- {
- if (istate != null) throw new ZlibException("You may not call InitializeDeflate() after calling InitializeInflate().");
- dstate = new DeflateManager();
- dstate.WantRfc1950HeaderBytes = wantRfc1950Header;
-
- return dstate.Initialize(this, this.CompressLevel, this.WindowBits, this.Strategy);
- }
-
- /// <summary>
- /// Deflate one batch of data.
- /// </summary>
- /// <remarks>
- /// You must have set InputBuffer and OutputBuffer before calling this method.
- /// </remarks>
- /// <example>
- /// <code>
- /// private void DeflateBuffer(CompressionLevel level)
- /// {
- /// int bufferSize = 1024;
- /// byte[] buffer = new byte[bufferSize];
- /// ZlibCodec compressor = new ZlibCodec();
- ///
- /// Console.WriteLine("\n============================================");
- /// Console.WriteLine("Size of Buffer to Deflate: {0} bytes.", UncompressedBytes.Length);
- /// MemoryStream ms = new MemoryStream();
- ///
- /// int rc = compressor.InitializeDeflate(level);
- ///
- /// compressor.InputBuffer = UncompressedBytes;
- /// compressor.NextIn = 0;
- /// compressor.AvailableBytesIn = UncompressedBytes.Length;
- ///
- /// compressor.OutputBuffer = buffer;
- ///
- /// // pass 1: deflate
- /// do
- /// {
- /// compressor.NextOut = 0;
- /// compressor.AvailableBytesOut = buffer.Length;
- /// rc = compressor.Deflate(FlushType.None);
- ///
- /// if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
- /// throw new Exception("deflating: " + compressor.Message);
- ///
- /// ms.Write(compressor.OutputBuffer, 0, buffer.Length - compressor.AvailableBytesOut);
- /// }
- /// while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0);
- ///
- /// // pass 2: finish and flush
- /// do
- /// {
- /// compressor.NextOut = 0;
- /// compressor.AvailableBytesOut = buffer.Length;
- /// rc = compressor.Deflate(FlushType.Finish);
- ///
- /// if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK)
- /// throw new Exception("deflating: " + compressor.Message);
- ///
- /// if (buffer.Length - compressor.AvailableBytesOut > 0)
- /// ms.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut);
- /// }
- /// while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0);
- ///
- /// compressor.EndDeflate();
- ///
- /// ms.Seek(0, SeekOrigin.Begin);
- /// CompressedBytes = new byte[compressor.TotalBytesOut];
- /// ms.Read(CompressedBytes, 0, CompressedBytes.Length);
- /// }
- /// </code>
- /// </example>
- /// <param name="flush">whether to flush all data as you deflate. Generally you will want to
- /// use Z_NO_FLUSH here, in a series of calls to Deflate(), and then call EndDeflate() to
- /// flush everything.
- /// </param>
- /// <returns>Z_OK if all goes well.</returns>
- public int Deflate(FlushType flush)
- {
- if (dstate == null)
- throw new ZlibException("No Deflate State!");
- return dstate.Deflate(flush);
- }
-
- /// <summary>
- /// End a deflation session.
- /// </summary>
- /// <remarks>
- /// Call this after making a series of one or more calls to Deflate(). All buffers are flushed.
- /// </remarks>
- /// <returns>Z_OK if all goes well.</returns>
- public int EndDeflate()
- {
- if (dstate == null)
- throw new ZlibException("No Deflate State!");
- // TODO: dinoch Tue, 03 Nov 2009 15:39 (test this)
- //int ret = dstate.End();
- dstate = null;
- return ZlibConstants.Z_OK; //ret;
- }
-
- /// <summary>
- /// Reset a codec for another deflation session.
- /// </summary>
- /// <remarks>
- /// Call this to reset the deflation state. For example if a thread is deflating
- /// non-consecutive blocks, you can call Reset() after the Deflate(Sync) of the first
- /// block and before the next Deflate(None) of the second block.
- /// </remarks>
- /// <returns>Z_OK if all goes well.</returns>
- public void ResetDeflate()
- {
- if (dstate == null)
- throw new ZlibException("No Deflate State!");
- dstate.Reset();
- }
-
-
- /// <summary>
- /// Set the CompressionStrategy and CompressionLevel for a deflation session.
- /// </summary>
- /// <param name="level">the level of compression to use.</param>
- /// <param name="strategy">the strategy to use for compression.</param>
- /// <returns>Z_OK if all goes well.</returns>
- public int SetDeflateParams(CompressionLevel level, CompressionStrategy strategy)
- {
- if (dstate == null)
- throw new ZlibException("No Deflate State!");
- return dstate.SetParams(level, strategy);
- }
-
-
- /// <summary>
- /// Set the dictionary to be used for either Inflation or Deflation.
- /// </summary>
- /// <param name="dictionary">The dictionary bytes to use.</param>
- /// <returns>Z_OK if all goes well.</returns>
- public int SetDictionary(byte[] dictionary)
- {
- if (istate != null)
- return istate.SetDictionary(dictionary);
-
- if (dstate != null)
- return dstate.SetDictionary(dictionary);
-
- throw new ZlibException("No Inflate or Deflate state!");
- }
-
- // Flush as much pending output as possible. All deflate() output goes
- // through this function so some applications may wish to modify it
- // to avoid allocating a large strm->next_out buffer and copying into it.
- // (See also read_buf()).
- internal void flush_pending()
- {
- int len = dstate.pendingCount;
-
- if (len > AvailableBytesOut)
- len = AvailableBytesOut;
- if (len == 0)
- return;
-
- if (dstate.pending.Length <= dstate.nextPending ||
- OutputBuffer.Length <= NextOut ||
- dstate.pending.Length < (dstate.nextPending + len) ||
- OutputBuffer.Length < (NextOut + len))
- {
- throw new ZlibException(String.Format("Invalid State. (pending.Length={0}, pendingCount={1})",
- dstate.pending.Length, dstate.pendingCount));
- }
-
- Array.Copy(dstate.pending, dstate.nextPending, OutputBuffer, NextOut, len);
-
- NextOut += len;
- dstate.nextPending += len;
- TotalBytesOut += len;
- AvailableBytesOut -= len;
- dstate.pendingCount -= len;
- if (dstate.pendingCount == 0)
- {
- dstate.nextPending = 0;
- }
- }
-
- // Read a new buffer from the current input stream, update the adler32
- // and total number of bytes read. All deflate() input goes through
- // this function so some applications may wish to modify it to avoid
- // allocating a large strm->next_in buffer and copying from it.
- // (See also flush_pending()).
- internal int read_buf(byte[] buf, int start, int size)
- {
- int len = AvailableBytesIn;
-
- if (len > size)
- len = size;
- if (len == 0)
- return 0;
-
- AvailableBytesIn -= len;
-
- if (dstate.WantRfc1950HeaderBytes)
- {
- _Adler32 = Adler.Adler32(_Adler32, InputBuffer, NextIn, len);
- }
- Array.Copy(InputBuffer, NextIn, buf, start, len);
- NextIn += len;
- TotalBytesIn += len;
- return len;
- }
-
- }
-}
\ No newline at end of file
diff --git a/EPPlus/Packaging/DotNetZip/Zlib/ZlibConstants.cs b/EPPlus/Packaging/DotNetZip/Zlib/ZlibConstants.cs
deleted file mode 100644
index 951f42a..0000000
--- a/EPPlus/Packaging/DotNetZip/Zlib/ZlibConstants.cs
+++ /dev/null
@@ -1,128 +0,0 @@
-// ZlibConstants.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2009-November-03 18:50:19>
-//
-// ------------------------------------------------------------------
-//
-// This module defines constants used by the zlib class library. This
-// code is derived from the jzlib implementation of zlib, but
-// significantly modified. In keeping with the license for jzlib, the
-// copyright to that code is included here.
-//
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-//
-// 2. 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.
-//
-// 3. The names of the authors may not be used to endorse or promote products
-// derived from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
-// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
-//
-// -----------------------------------------------------------------------
-//
-// This program is based on zlib-1.1.3; credit to authors
-// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
-// and contributors of zlib.
-//
-// -----------------------------------------------------------------------
-
-
-using System;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zlib
-{
- /// <summary>
- /// A bunch of constants used in the Zlib interface.
- /// </summary>
- public static class ZlibConstants
- {
- /// <summary>
- /// The maximum number of window bits for the Deflate algorithm.
- /// </summary>
- public const int WindowBitsMax = 15; // 32K LZ77 window
-
- /// <summary>
- /// The default number of window bits for the Deflate algorithm.
- /// </summary>
- public const int WindowBitsDefault = WindowBitsMax;
-
- /// <summary>
- /// indicates everything is A-OK
- /// </summary>
- public const int Z_OK = 0;
-
- /// <summary>
- /// Indicates that the last operation reached the end of the stream.
- /// </summary>
- public const int Z_STREAM_END = 1;
-
- /// <summary>
- /// The operation ended in need of a dictionary.
- /// </summary>
- public const int Z_NEED_DICT = 2;
-
- /// <summary>
- /// There was an error with the stream - not enough data, not open and readable, etc.
- /// </summary>
- public const int Z_STREAM_ERROR = -2;
-
- /// <summary>
- /// There was an error with the data - not enough data, bad data, etc.
- /// </summary>
- public const int Z_DATA_ERROR = -3;
-
- /// <summary>
- /// There was an error with the working buffer.
- /// </summary>
- public const int Z_BUF_ERROR = -5;
-
- /// <summary>
- /// The size of the working buffer used in the ZlibCodec class. Defaults to 8192 bytes.
- /// </summary>
-#if NETCF
- public const int WorkingBufferSizeDefault = 8192;
-#else
- public const int WorkingBufferSizeDefault = 16384;
-#endif
- /// <summary>
- /// The minimum size of the working buffer used in the ZlibCodec class. Currently it is 128 bytes.
- /// </summary>
- public const int WorkingBufferSizeMin = 1024;
- }
-
-}
-
diff --git a/EPPlus/Packaging/DotNetZip/Zlib/ZlibStream.cs b/EPPlus/Packaging/DotNetZip/Zlib/ZlibStream.cs
deleted file mode 100644
index 460aee7..0000000
--- a/EPPlus/Packaging/DotNetZip/Zlib/ZlibStream.cs
+++ /dev/null
@@ -1,725 +0,0 @@
-// ZlibStream.cs
-// ------------------------------------------------------------------
-//
-// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
-// All rights reserved.
-//
-// This code module is part of DotNetZip, a zipfile class library.
-//
-// ------------------------------------------------------------------
-//
-// This code is licensed under the Microsoft Public License.
-// See the file License.txt for the license details.
-// More info on: http://dotnetzip.codeplex.com
-//
-// ------------------------------------------------------------------
-//
-// last saved (in emacs):
-// Time-stamp: <2011-July-31 14:53:33>
-//
-// ------------------------------------------------------------------
-//
-// This module defines the ZlibStream class, which is similar in idea to
-// the System.IO.Compression.DeflateStream and
-// System.IO.Compression.GZipStream classes in the .NET BCL.
-//
-// ------------------------------------------------------------------
-
-using System;
-using System.IO;
-
-namespace OfficeOpenXml.Packaging.Ionic.Zlib
-{
-
- /// <summary>
- /// Represents a Zlib stream for compression or decompression.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// The ZlibStream is a <see
- /// href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator</see> on a <see
- /// cref="System.IO.Stream"/>. It adds ZLIB compression or decompression to any
- /// stream.
- /// </para>
- ///
- /// <para> Using this stream, applications can compress or decompress data via
- /// stream <c>Read()</c> and <c>Write()</c> operations. Either compresssion or
- /// decompression can occur through either reading or writing. The compression
- /// format used is ZLIB, which is documented in <see
- /// href="http://www.ietf.org/rfc/rfc1950.txt">IETF RFC 1950</see>, "ZLIB Compressed
- /// Data Format Specification version 3.3". This implementation of ZLIB always uses
- /// DEFLATE as the compression method. (see <see
- /// href="http://www.ietf.org/rfc/rfc1951.txt">IETF RFC 1951</see>, "DEFLATE
- /// Compressed Data Format Specification version 1.3.") </para>
- ///
- /// <para>
- /// The ZLIB format allows for varying compression methods, window sizes, and dictionaries.
- /// This implementation always uses the DEFLATE compression method, a preset dictionary,
- /// and 15 window bits by default.
- /// </para>
- ///
- /// <para>
- /// This class is similar to <see cref="DeflateStream"/>, except that it adds the
- /// RFC1950 header and trailer bytes to a compressed stream when compressing, or expects
- /// the RFC1950 header and trailer bytes when decompressing. It is also similar to the
- /// <see cref="GZipStream"/>.
- /// </para>
- /// </remarks>
- /// <seealso cref="DeflateStream" />
- /// <seealso cref="GZipStream" />
- public class ZlibStream : System.IO.Stream
- {
- internal ZlibBaseStream _baseStream;
- bool _disposed;
-
- /// <summary>
- /// Create a <c>ZlibStream</c> using the specified <c>CompressionMode</c>.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// When mode is <c>CompressionMode.Compress</c>, the <c>ZlibStream</c>
- /// will use the default compression level. The "captive" stream will be
- /// closed when the <c>ZlibStream</c> is closed.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// This example uses a <c>ZlibStream</c> to compress a file, and writes the
- /// compressed data to another file.
- /// <code>
- /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
- /// {
- /// using (var raw = System.IO.File.Create(fileToCompress + ".zlib"))
- /// {
- /// using (Stream compressor = new ZlibStream(raw, CompressionMode.Compress))
- /// {
- /// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
- /// int n;
- /// while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
- /// {
- /// compressor.Write(buffer, 0, n);
- /// }
- /// }
- /// }
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using input As Stream = File.OpenRead(fileToCompress)
- /// Using raw As FileStream = File.Create(fileToCompress & ".zlib")
- /// Using compressor As Stream = New ZlibStream(raw, CompressionMode.Compress)
- /// Dim buffer As Byte() = New Byte(4096) {}
- /// Dim n As Integer = -1
- /// Do While (n <> 0)
- /// If (n > 0) Then
- /// compressor.Write(buffer, 0, n)
- /// End If
- /// n = input.Read(buffer, 0, buffer.Length)
- /// Loop
- /// End Using
- /// End Using
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="stream">The stream which will be read or written.</param>
- /// <param name="mode">Indicates whether the ZlibStream will compress or decompress.</param>
- public ZlibStream(System.IO.Stream stream, CompressionMode mode)
- : this(stream, mode, CompressionLevel.Default, false)
- {
- }
-
- /// <summary>
- /// Create a <c>ZlibStream</c> using the specified <c>CompressionMode</c> and
- /// the specified <c>CompressionLevel</c>.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// When mode is <c>CompressionMode.Decompress</c>, the level parameter is ignored.
- /// The "captive" stream will be closed when the <c>ZlibStream</c> is closed.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- /// This example uses a <c>ZlibStream</c> to compress data from a file, and writes the
- /// compressed data to another file.
- ///
- /// <code>
- /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
- /// {
- /// using (var raw = System.IO.File.Create(fileToCompress + ".zlib"))
- /// {
- /// using (Stream compressor = new ZlibStream(raw,
- /// CompressionMode.Compress,
- /// CompressionLevel.BestCompression))
- /// {
- /// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
- /// int n;
- /// while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
- /// {
- /// compressor.Write(buffer, 0, n);
- /// }
- /// }
- /// }
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Using input As Stream = File.OpenRead(fileToCompress)
- /// Using raw As FileStream = File.Create(fileToCompress & ".zlib")
- /// Using compressor As Stream = New ZlibStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression)
- /// Dim buffer As Byte() = New Byte(4096) {}
- /// Dim n As Integer = -1
- /// Do While (n <> 0)
- /// If (n > 0) Then
- /// compressor.Write(buffer, 0, n)
- /// End If
- /// n = input.Read(buffer, 0, buffer.Length)
- /// Loop
- /// End Using
- /// End Using
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="stream">The stream to be read or written while deflating or inflating.</param>
- /// <param name="mode">Indicates whether the ZlibStream will compress or decompress.</param>
- /// <param name="level">A tuning knob to trade speed for effectiveness.</param>
- public ZlibStream(System.IO.Stream stream, CompressionMode mode, CompressionLevel level)
- : this(stream, mode, level, false)
- {
- }
-
- /// <summary>
- /// Create a <c>ZlibStream</c> using the specified <c>CompressionMode</c>, and
- /// explicitly specify whether the captive stream should be left open after
- /// Deflation or Inflation.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// When mode is <c>CompressionMode.Compress</c>, the <c>ZlibStream</c> will use
- /// the default compression level.
- /// </para>
- ///
- /// <para>
- /// This constructor allows the application to request that the captive stream
- /// remain open after the deflation or inflation occurs. By default, after
- /// <c>Close()</c> is called on the stream, the captive stream is also
- /// closed. In some cases this is not desired, for example if the stream is a
- /// <see cref="System.IO.MemoryStream"/> that will be re-read after
- /// compression. Specify true for the <paramref name="leaveOpen"/> parameter to leave the stream
- /// open.
- /// </para>
- ///
- /// <para>
- /// See the other overloads of this constructor for example code.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="stream">The stream which will be read or written. This is called the
- /// "captive" stream in other places in this documentation.</param>
- /// <param name="mode">Indicates whether the ZlibStream will compress or decompress.</param>
- /// <param name="leaveOpen">true if the application would like the stream to remain
- /// open after inflation/deflation.</param>
- public ZlibStream(System.IO.Stream stream, CompressionMode mode, bool leaveOpen)
- : this(stream, mode, CompressionLevel.Default, leaveOpen)
- {
- }
-
- /// <summary>
- /// Create a <c>ZlibStream</c> using the specified <c>CompressionMode</c>
- /// and the specified <c>CompressionLevel</c>, and explicitly specify
- /// whether the stream should be left open after Deflation or Inflation.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This constructor allows the application to request that the captive
- /// stream remain open after the deflation or inflation occurs. By
- /// default, after <c>Close()</c> is called on the stream, the captive
- /// stream is also closed. In some cases this is not desired, for example
- /// if the stream is a <see cref="System.IO.MemoryStream"/> that will be
- /// re-read after compression. Specify true for the <paramref
- /// name="leaveOpen"/> parameter to leave the stream open.
- /// </para>
- ///
- /// <para>
- /// When mode is <c>CompressionMode.Decompress</c>, the level parameter is
- /// ignored.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <example>
- ///
- /// This example shows how to use a ZlibStream to compress the data from a file,
- /// and store the result into another file. The filestream remains open to allow
- /// additional data to be written to it.
- ///
- /// <code>
- /// using (var output = System.IO.File.Create(fileToCompress + ".zlib"))
- /// {
- /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
- /// {
- /// using (Stream compressor = new ZlibStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, true))
- /// {
- /// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
- /// int n;
- /// while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
- /// {
- /// compressor.Write(buffer, 0, n);
- /// }
- /// }
- /// }
- /// // can write additional data to the output stream here
- /// }
- /// </code>
- /// <code lang="VB">
- /// Using output As FileStream = File.Create(fileToCompress & ".zlib")
- /// Using input As Stream = File.OpenRead(fileToCompress)
- /// Using compressor As Stream = New ZlibStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, True)
- /// Dim buffer As Byte() = New Byte(4096) {}
- /// Dim n As Integer = -1
- /// Do While (n <> 0)
- /// If (n > 0) Then
- /// compressor.Write(buffer, 0, n)
- /// End If
- /// n = input.Read(buffer, 0, buffer.Length)
- /// Loop
- /// End Using
- /// End Using
- /// ' can write additional data to the output stream here.
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="stream">The stream which will be read or written.</param>
- ///
- /// <param name="mode">Indicates whether the ZlibStream will compress or decompress.</param>
- ///
- /// <param name="leaveOpen">
- /// true if the application would like the stream to remain open after
- /// inflation/deflation.
- /// </param>
- ///
- /// <param name="level">
- /// A tuning knob to trade speed for effectiveness. This parameter is
- /// effective only when mode is <c>CompressionMode.Compress</c>.
- /// </param>
- public ZlibStream(System.IO.Stream stream, CompressionMode mode, CompressionLevel level, bool leaveOpen)
- {
- _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.ZLIB, leaveOpen);
- }
-
- #region Zlib properties
-
- /// <summary>
- /// This property sets the flush behavior on the stream.
- /// Sorry, though, not sure exactly how to describe all the various settings.
- /// </summary>
- virtual public FlushType FlushMode
- {
- get { return (this._baseStream._flushMode); }
- set
- {
- if (_disposed) throw new ObjectDisposedException("ZlibStream");
- this._baseStream._flushMode = value;
- }
- }
-
- /// <summary>
- /// The size of the working buffer for the compression codec.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// The working buffer is used for all stream operations. The default size is
- /// 1024 bytes. The minimum size is 128 bytes. You may get better performance
- /// with a larger buffer. Then again, you might not. You would have to test
- /// it.
- /// </para>
- ///
- /// <para>
- /// Set this before the first call to <c>Read()</c> or <c>Write()</c> on the
- /// stream. If you try to set it afterwards, it will throw.
- /// </para>
- /// </remarks>
- public int BufferSize
- {
- get
- {
- return this._baseStream._bufferSize;
- }
- set
- {
- if (_disposed) throw new ObjectDisposedException("ZlibStream");
- if (this._baseStream._workingBuffer != null)
- throw new ZlibException("The working buffer is already set.");
- if (value < ZlibConstants.WorkingBufferSizeMin)
- throw new ZlibException(String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, ZlibConstants.WorkingBufferSizeMin));
- this._baseStream._bufferSize = value;
- }
- }
-
- /// <summary> Returns the total number of bytes input so far.</summary>
- virtual public long TotalIn
- {
- get { return this._baseStream._z.TotalBytesIn; }
- }
-
- /// <summary> Returns the total number of bytes output so far.</summary>
- virtual public long TotalOut
- {
- get { return this._baseStream._z.TotalBytesOut; }
- }
-
- #endregion
-
- #region System.IO.Stream methods
-
- /// <summary>
- /// Dispose the stream.
- /// </summary>
- /// <remarks>
- /// <para>
- /// This may or may not result in a <c>Close()</c> call on the captive
- /// stream. See the constructors that have a <c>leaveOpen</c> parameter
- /// for more information.
- /// </para>
- /// <para>
- /// This method may be invoked in two distinct scenarios. If disposing
- /// == true, the method has been called directly or indirectly by a
- /// user's code, for example via the public Dispose() method. In this
- /// case, both managed and unmanaged resources can be referenced and
- /// disposed. If disposing == false, the method has been called by the
- /// runtime from inside the object finalizer and this method should not
- /// reference other objects; in that case only unmanaged resources must
- /// be referenced or disposed.
- /// </para>
- /// </remarks>
- /// <param name="disposing">
- /// indicates whether the Dispose method was invoked by user code.
- /// </param>
- protected override void Dispose(bool disposing)
- {
- try
- {
- if (!_disposed)
- {
- if (disposing && (this._baseStream != null))
- this._baseStream.Close();
- _disposed = true;
- }
- }
- finally
- {
- base.Dispose(disposing);
- }
- }
-
-
- /// <summary>
- /// Indicates whether the stream can be read.
- /// </summary>
- /// <remarks>
- /// The return value depends on whether the captive stream supports reading.
- /// </remarks>
- public override bool CanRead
- {
- get
- {
- if (_disposed) throw new ObjectDisposedException("ZlibStream");
- return _baseStream._stream.CanRead;
- }
- }
-
- /// <summary>
- /// Indicates whether the stream supports Seek operations.
- /// </summary>
- /// <remarks>
- /// Always returns false.
- /// </remarks>
- public override bool CanSeek
- {
- get { return false; }
- }
-
- /// <summary>
- /// Indicates whether the stream can be written.
- /// </summary>
- /// <remarks>
- /// The return value depends on whether the captive stream supports writing.
- /// </remarks>
- public override bool CanWrite
- {
- get
- {
- if (_disposed) throw new ObjectDisposedException("ZlibStream");
- return _baseStream._stream.CanWrite;
- }
- }
-
- /// <summary>
- /// Flush the stream.
- /// </summary>
- public override void Flush()
- {
- if (_disposed) throw new ObjectDisposedException("ZlibStream");
- _baseStream.Flush();
- }
-
- /// <summary>
- /// Reading this property always throws a <see cref="NotSupportedException"/>.
- /// </summary>
- public override long Length
- {
- get { throw new NotSupportedException(); }
- }
-
- /// <summary>
- /// The position of the stream pointer.
- /// </summary>
- ///
- /// <remarks>
- /// Setting this property always throws a <see
- /// cref="NotSupportedException"/>. Reading will return the total bytes
- /// written out, if used in writing, or the total bytes read in, if used in
- /// reading. The count may refer to compressed bytes or uncompressed bytes,
- /// depending on how you've used the stream.
- /// </remarks>
- public override long Position
- {
- get
- {
- if (this._baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Writer)
- return this._baseStream._z.TotalBytesOut;
- if (this._baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Reader)
- return this._baseStream._z.TotalBytesIn;
- return 0;
- }
-
- set { throw new NotSupportedException(); }
- }
-
- /// <summary>
- /// Read data from the stream.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// If you wish to use the <c>ZlibStream</c> to compress data while reading,
- /// you can create a <c>ZlibStream</c> with <c>CompressionMode.Compress</c>,
- /// providing an uncompressed data stream. Then call <c>Read()</c> on that
- /// <c>ZlibStream</c>, and the data read will be compressed. If you wish to
- /// use the <c>ZlibStream</c> to decompress data while reading, you can create
- /// a <c>ZlibStream</c> with <c>CompressionMode.Decompress</c>, providing a
- /// readable compressed data stream. Then call <c>Read()</c> on that
- /// <c>ZlibStream</c>, and the data will be decompressed as it is read.
- /// </para>
- ///
- /// <para>
- /// A <c>ZlibStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but
- /// not both.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <param name="buffer">
- /// The buffer into which the read data should be placed.</param>
- ///
- /// <param name="offset">
- /// the offset within that data array to put the first byte read.</param>
- ///
- /// <param name="count">the number of bytes to read.</param>
- ///
- /// <returns>the number of bytes read</returns>
- public override int Read(byte[] buffer, int offset, int count)
- {
- if (_disposed) throw new ObjectDisposedException("ZlibStream");
- return _baseStream.Read(buffer, offset, count);
- }
-
- /// <summary>
- /// Calling this method always throws a <see cref="NotSupportedException"/>.
- /// </summary>
- /// <param name="offset">
- /// The offset to seek to....
- /// IF THIS METHOD ACTUALLY DID ANYTHING.
- /// </param>
- /// <param name="origin">
- /// The reference specifying how to apply the offset.... IF
- /// THIS METHOD ACTUALLY DID ANYTHING.
- /// </param>
- ///
- /// <returns>nothing. This method always throws.</returns>
- public override long Seek(long offset, System.IO.SeekOrigin origin)
- {
- throw new NotSupportedException();
- }
-
- /// <summary>
- /// Calling this method always throws a <see cref="NotSupportedException"/>.
- /// </summary>
- /// <param name="value">
- /// The new value for the stream length.... IF
- /// THIS METHOD ACTUALLY DID ANYTHING.
- /// </param>
- public override void SetLength(long value)
- {
- throw new NotSupportedException();
- }
-
- /// <summary>
- /// Write data to the stream.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// If you wish to use the <c>ZlibStream</c> to compress data while writing,
- /// you can create a <c>ZlibStream</c> with <c>CompressionMode.Compress</c>,
- /// and a writable output stream. Then call <c>Write()</c> on that
- /// <c>ZlibStream</c>, providing uncompressed data as input. The data sent to
- /// the output stream will be the compressed form of the data written. If you
- /// wish to use the <c>ZlibStream</c> to decompress data while writing, you
- /// can create a <c>ZlibStream</c> with <c>CompressionMode.Decompress</c>, and a
- /// writable output stream. Then call <c>Write()</c> on that stream,
- /// providing previously compressed data. The data sent to the output stream
- /// will be the decompressed form of the data written.
- /// </para>
- ///
- /// <para>
- /// A <c>ZlibStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but not both.
- /// </para>
- /// </remarks>
- /// <param name="buffer">The buffer holding data to write to the stream.</param>
- /// <param name="offset">the offset within that data array to find the first byte to write.</param>
- /// <param name="count">the number of bytes to write.</param>
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (_disposed) throw new ObjectDisposedException("ZlibStream");
- _baseStream.Write(buffer, offset, count);
- }
- #endregion
-
-
- /// <summary>
- /// Compress a string into a byte array using ZLIB.
- /// </summary>
- ///
- /// <remarks>
- /// Uncompress it with <see cref="ZlibStream.UncompressString(byte[])"/>.
- /// </remarks>
- ///
- /// <seealso cref="ZlibStream.UncompressString(byte[])"/>
- /// <seealso cref="ZlibStream.CompressBuffer(byte[])"/>
- /// <seealso cref="GZipStream.CompressString(string)"/>
- ///
- /// <param name="s">
- /// A string to compress. The string will first be encoded
- /// using UTF8, then compressed.
- /// </param>
- ///
- /// <returns>The string in compressed form</returns>
- public static byte[] CompressString(String s)
- {
- using (var ms = new MemoryStream())
- {
- Stream compressor =
- new ZlibStream(ms, CompressionMode.Compress, CompressionLevel.BestCompression);
- ZlibBaseStream.CompressString(s, compressor);
- return ms.ToArray();
- }
- }
-
-
- /// <summary>
- /// Compress a byte array into a new byte array using ZLIB.
- /// </summary>
- ///
- /// <remarks>
- /// Uncompress it with <see cref="ZlibStream.UncompressBuffer(byte[])"/>.
- /// </remarks>
- ///
- /// <seealso cref="ZlibStream.CompressString(string)"/>
- /// <seealso cref="ZlibStream.UncompressBuffer(byte[])"/>
- ///
- /// <param name="b">
- /// A buffer to compress.
- /// </param>
- ///
- /// <returns>The data in compressed form</returns>
- public static byte[] CompressBuffer(byte[] b)
- {
- using (var ms = new MemoryStream())
- {
- Stream compressor =
- new ZlibStream( ms, CompressionMode.Compress, CompressionLevel.BestCompression );
-
- ZlibBaseStream.CompressBuffer(b, compressor);
- return ms.ToArray();
- }
- }
-
-
- /// <summary>
- /// Uncompress a ZLIB-compressed byte array into a single string.
- /// </summary>
- ///
- /// <seealso cref="ZlibStream.CompressString(String)"/>
- /// <seealso cref="ZlibStream.UncompressBuffer(byte[])"/>
- ///
- /// <param name="compressed">
- /// A buffer containing ZLIB-compressed data.
- /// </param>
- ///
- /// <returns>The uncompressed string</returns>
- public static String UncompressString(byte[] compressed)
- {
- using (var input = new MemoryStream(compressed))
- {
- Stream decompressor =
- new ZlibStream(input, CompressionMode.Decompress);
-
- return ZlibBaseStream.UncompressString(compressed, decompressor);
- }
- }
-
-
- /// <summary>
- /// Uncompress a ZLIB-compressed byte array into a byte array.
- /// </summary>
- ///
- /// <seealso cref="ZlibStream.CompressBuffer(byte[])"/>
- /// <seealso cref="ZlibStream.UncompressString(byte[])"/>
- ///
- /// <param name="compressed">
- /// A buffer containing ZLIB-compressed data.
- /// </param>
- ///
- /// <returns>The data in uncompressed form</returns>
- public static byte[] UncompressBuffer(byte[] compressed)
- {
- using (var input = new MemoryStream(compressed))
- {
- Stream decompressor =
- new ZlibStream( input, CompressionMode.Decompress );
-
- return ZlibBaseStream.UncompressBuffer(compressed, decompressor);
- }
- }
-
- }
-
-
-}
\ No newline at end of file
diff --git a/EPPlus/Packaging/ZipPackage.cs b/EPPlus/Packaging/ZipPackage.cs
index 9c6c8b4..c47d5ea 100644
--- a/EPPlus/Packaging/ZipPackage.cs
+++ b/EPPlus/Packaging/ZipPackage.cs
@@ -34,10 +34,9 @@
using System.Linq;
using System.Text;
using System.IO;
+using System.IO.Compression;
using System.Xml;
using OfficeOpenXml.Utils;
-using OfficeOpenXml.Packaging.Ionic.Zip;
-using Ionic.Zip;
namespace OfficeOpenXml.Packaging
{
/// <summary>
@@ -93,82 +92,75 @@
}
else
{
- var rels = new Dictionary<string, string>();
- stream.Seek(0, SeekOrigin.Begin);
- using (ZipInputStream zip = new ZipInputStream(stream))
+ var rels = new Dictionary<string, ZipArchiveEntry>();
+ stream.Seek(0, SeekOrigin.Begin);
+ using var zip = new ZipArchive(stream);
+ foreach (var e in zip.Entries)
{
- var e = zip.GetNextEntry();
- while (e != null)
+ if (e.Length > 0)
{
- if (e.UncompressedSize > 0)
+ if (e.FullName .Equals("[content_types].xml", StringComparison.InvariantCultureIgnoreCase))
{
- var b = new byte[e.UncompressedSize];
- var size = zip.Read(b, 0, (int)e.UncompressedSize);
- if (e.FileName.Equals("[content_types].xml", StringComparison.InvariantCultureIgnoreCase))
- {
- AddContentTypes(Encoding.UTF8.GetString(b));
- hasContentTypeXml = true;
- }
- else if (e.FileName.Equals("_rels/.rels", StringComparison.InvariantCultureIgnoreCase))
- {
- ReadRelation(Encoding.UTF8.GetString(b), "");
- }
- else
- {
- if (e.FileName.EndsWith(".rels", StringComparison.InvariantCultureIgnoreCase))
- {
- rels.Add(GetUriKey(e.FileName), Encoding.UTF8.GetString(b));
- }
- else
- {
- var part = new ZipPackagePart(this, e);
- part.Stream = new MemoryStream();
- part.Stream.Write(b, 0, b.Length);
- Parts.Add(GetUriKey(e.FileName), part);
- }
- }
+ using var inputStream = e.Open();
+ AddContentTypes(inputStream);
+ hasContentTypeXml = true;
+ }
+ else if (e.FullName .Equals("_rels/.rels", StringComparison.InvariantCultureIgnoreCase))
+ {
+ using var inputStream = e.Open();
+ ReadRelation(inputStream, "");
}
else
{
+ if (e.FullName.EndsWith(".rels", StringComparison.InvariantCultureIgnoreCase))
+ {
+ rels.Add(GetUriKey(e.FullName), e);
+ }
+ else
+ {
+ using var inputStream = e.Open();
+ var part = new ZipPackagePart(this, e);
+ part.Stream = new MemoryStream();
+ inputStream.CopyTo(part.Stream);
+ Parts.Add(GetUriKey(e.FullName), part);
+ }
}
- e = zip.GetNextEntry();
}
-
- foreach (var p in Parts)
+ }
+ foreach (var p in Parts)
+ {
+ string name = Path.GetFileName(p.Key);
+ string extension = Path.GetExtension(p.Key);
+ string relFile = string.Format("{0}_rels/{1}.rels", p.Key.Substring(0, p.Key.Length - name.Length), name);
+ if (rels.TryGetValue(relFile, out var zipArchiveEntry))
{
- string name = Path.GetFileName(p.Key);
- string extension = Path.GetExtension(p.Key);
- string relFile = string.Format("{0}_rels/{1}.rels", p.Key.Substring(0, p.Key.Length - name.Length), name);
- if (rels.ContainsKey(relFile))
- {
- p.Value.ReadRelation(rels[relFile], p.Value.Uri.OriginalString);
- }
- if (_contentTypes.ContainsKey(p.Key))
- {
- p.Value.ContentType = _contentTypes[p.Key].Name;
- }
- else if (extension.Length > 1 && _contentTypes.ContainsKey(extension.Substring(1)))
- {
- p.Value.ContentType = _contentTypes[extension.Substring(1)].Name;
- }
+ using var inputStream = zipArchiveEntry.Open();
+ p.Value.ReadRelation(inputStream, p.Value.Uri.OriginalString);
}
- if (!hasContentTypeXml)
+ if (_contentTypes.TryGetValue(p.Key, out var type))
{
- throw (new InvalidDataException("The file is not an valid Package file. If the file is encrypted, please supply the password in the constructor."));
+ p.Value.ContentType = type.Name;
}
- if (!hasContentTypeXml)
+ else if (extension.Length > 1 && _contentTypes.ContainsKey(extension.Substring(1)))
{
- throw (new InvalidDataException("The file is not an valid Package file. If the file is encrypted, please supply the password in the constructor."));
+ p.Value.ContentType = _contentTypes[extension.Substring(1)].Name;
}
- zip.Close();
+ }
+ if (!hasContentTypeXml)
+ {
+ throw (new InvalidDataException("The file is not an valid Package file. If the file is encrypted, please supply the password in the constructor."));
+ }
+ if (!hasContentTypeXml)
+ {
+ throw (new InvalidDataException("The file is not an valid Package file. If the file is encrypted, please supply the password in the constructor."));
}
}
}
- private void AddContentTypes(string xml)
+ private void AddContentTypes(Stream inputStream)
{
var doc = new XmlDocument();
- XmlHelper.LoadXmlSafe(doc, xml, Encoding.UTF8);
+ XmlHelper.LoadXmlSafe(doc, inputStream);
foreach (XmlElement c in doc.DocumentElement.ChildNodes)
{
@@ -260,21 +252,21 @@
}
internal void Save(Stream stream)
{
- var enc = Encoding.UTF8;
- ZipOutputStream os = new ZipOutputStream(stream, true);
- os.CompressionLevel = (OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel)_compression;
+ using var zipArchive = new ZipArchive(stream, ZipArchiveMode.Create);
/**** ContentType****/
- var entry = os.PutNextEntry("[Content_Types].xml");
- byte[] b = enc.GetBytes(GetContentTypeXml());
- os.Write(b, 0, b.Length);
+ var contentTypesEntry = zipArchive.CreateEntry("[Content_Types].xml");
+ using (var contentTypesWriter = new StreamWriter(contentTypesEntry.Open()))
+ {
+ contentTypesWriter.Write(GetContentTypeXml());
+ }
/**** Top Rels ****/
- _rels.WriteZip(os, "_rels\\.rels");
+ _rels.WriteZip(zipArchive, "_rels\\.rels");
ZipPackagePart ssPart=null;
foreach(var part in Parts.Values)
{
if (part.ContentType != ExcelPackage.contentTypeSharedString)
{
- part.WriteZip(os);
+ part.WriteZip(zipArchive);
}
else
{
@@ -284,12 +276,8 @@
//Shared strings must be saved after all worksheets. The ss dictionary is populated when that workheets are saved (to get the best performance).
if (ssPart != null)
{
- ssPart.WriteZip(os);
+ ssPart.WriteZip(zipArchive);
}
- os.Flush();
- os.Close();
- os.Dispose();
-
//return ms;
}
diff --git a/EPPlus/Packaging/ZipPackagePart.cs b/EPPlus/Packaging/ZipPackagePart.cs
index 5d45c35..06ca810 100644
--- a/EPPlus/Packaging/ZipPackagePart.cs
+++ b/EPPlus/Packaging/ZipPackagePart.cs
@@ -29,24 +29,20 @@
* Jan Källman Added 25-Oct-2012
*******************************************************************************/
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using System.IO;
-using OfficeOpenXml.Packaging.Ionic.Zip;
+using System.IO.Compression;
namespace OfficeOpenXml.Packaging
{
internal class ZipPackagePart : ZipPackageRelationshipBase, IDisposable
{
- internal delegate void SaveHandlerDelegate(ZipOutputStream stream, CompressionLevel compressionLevel, string fileName);
+ internal delegate void SaveHandlerDelegate(StreamWriter streamWriter);
- internal ZipPackagePart(ZipPackage package, ZipEntry entry)
+ internal ZipPackagePart(ZipPackage package, ZipArchiveEntry entry)
{
Package = package;
- Entry = entry;
SaveHandler = null;
- Uri = new Uri(package.GetUriKey(entry.FileName), UriKind.Relative);
+ Uri = new Uri(package.GetUriKey(entry.FullName), UriKind.Relative);
}
internal ZipPackagePart(ZipPackage package, Uri partUri, string contentType, CompressionLevel compressionLevel)
{
@@ -58,7 +54,6 @@
CompressionLevel = compressionLevel;
}
internal ZipPackage Package { get; set; }
- internal ZipEntry Entry { get; set; }
internal CompressionLevel CompressionLevel;
MemoryStream _stream = null;
internal MemoryStream Stream
@@ -121,18 +116,12 @@
}
}
public Uri Uri { get; private set; }
- public Stream GetZipStream()
- {
- MemoryStream ms = new MemoryStream();
- ZipOutputStream os = new ZipOutputStream(ms);
- return os;
- }
internal SaveHandlerDelegate SaveHandler
{
get;
set;
}
- internal void WriteZip(ZipOutputStream os)
+ internal void WriteZip(ZipArchive zipArchive)
{
byte[] b;
if (SaveHandler == null)
@@ -142,20 +131,22 @@
{
return;
}
- os.CompressionLevel = (OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel)CompressionLevel;
- os.PutNextEntry(Uri.OriginalString);
- os.Write(b, 0, b.Length);
+ var zipEntry = zipArchive.CreateEntry(Uri.OriginalString);
+ using var os = zipEntry.Open();
+ os.Write(b);
}
else
{
- SaveHandler(os, (CompressionLevel)CompressionLevel, Uri.OriginalString);
+ var zipEntry = zipArchive.CreateEntry(Uri.OriginalString);
+ using var streamWriter = new StreamWriter(zipEntry.Open());
+ SaveHandler(streamWriter);
}
if (_rels.Count > 0)
{
string f = Uri.OriginalString;
var name = Path.GetFileName(f);
- _rels.WriteZip(os, (string.Format("{0}_rels/{1}.rels", f.Substring(0, f.Length - name.Length), name)));
+ _rels.WriteZip(zipArchive, $"{f.Substring(0, f.Length - name.Length)}_rels/{name}.rels");
}
b = null;
}
diff --git a/EPPlus/Packaging/ZipPackageRelationship.cs b/EPPlus/Packaging/ZipPackageRelationship.cs
index 2c04a28..7bb7a50 100644
--- a/EPPlus/Packaging/ZipPackageRelationship.cs
+++ b/EPPlus/Packaging/ZipPackageRelationship.cs
@@ -29,9 +29,6 @@
* Jan Källman Added 25-Oct-2012
*******************************************************************************/
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
namespace OfficeOpenXml.Packaging
{
diff --git a/EPPlus/Packaging/ZipPackageRelationshipBase.cs b/EPPlus/Packaging/ZipPackageRelationshipBase.cs
index 60b6948..b0bd124 100644
--- a/EPPlus/Packaging/ZipPackageRelationshipBase.cs
+++ b/EPPlus/Packaging/ZipPackageRelationshipBase.cs
@@ -29,21 +29,15 @@
* Jan Källman Added 25-Oct-2012
*******************************************************************************/
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Ionic.Zip;
using System.IO;
using System.Xml;
-using OfficeOpenXml.Packaging.Ionic.Zlib;
-using System.Web;
+
namespace OfficeOpenXml.Packaging
{
public abstract class ZipPackageRelationshipBase
{
protected ZipPackageRelationshipCollection _rels = new ZipPackageRelationshipCollection();
- protected internal
- int maxRId = 1;
+ protected internal int maxRId = 1;
internal void DeleteRelationship(string id)
{
_rels.Remove(id);
@@ -89,10 +83,10 @@
{
return _rels[id];
}
- internal void ReadRelation(string xml, string source)
+ internal void ReadRelation(Stream inputStream, string source)
{
var doc = new XmlDocument();
- XmlHelper.LoadXmlSafe(doc, xml, Encoding.UTF8);
+ XmlHelper.LoadXmlSafe(doc, inputStream);
foreach (XmlElement c in doc.DocumentElement.ChildNodes)
{
diff --git a/EPPlus/Packaging/ZipPackageRelationshipCollection.cs b/EPPlus/Packaging/ZipPackageRelationshipCollection.cs
index df1ce86..0820322 100644
--- a/EPPlus/Packaging/ZipPackageRelationshipCollection.cs
+++ b/EPPlus/Packaging/ZipPackageRelationshipCollection.cs
@@ -30,12 +30,9 @@
*******************************************************************************/
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Ionic.Zip;
using System.IO;
+using System.IO.Compression;
using System.Security;
-using OfficeOpenXml.Packaging.Ionic.Zip;
namespace OfficeOpenXml.Packaging
{
@@ -84,18 +81,17 @@
return ret;
}
- internal void WriteZip(ZipOutputStream os, string fileName)
+ internal void WriteZip(ZipArchive zipArchive, string filename)
{
- StringBuilder xml = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">");
+ var entry = zipArchive.CreateEntry(filename);
+ using var writer = new StreamWriter(entry.Open());
+
+ writer.Write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">");
foreach (var rel in _rels.Values)
{
- xml.AppendFormat("<Relationship Id=\"{0}\" Type=\"{1}\" Target=\"{2}\"{3}/>", SecurityElement.Escape(rel.Id), rel.RelationshipType, SecurityElement.Escape(rel.TargetUri.OriginalString), rel.TargetMode == TargetMode.External ? " TargetMode=\"External\"" : "");
+ writer.Write("<Relationship Id=\"{0}\" Type=\"{1}\" Target=\"{2}\"{3}/>", SecurityElement.Escape(rel.Id), rel.RelationshipType, SecurityElement.Escape(rel.TargetUri.OriginalString), rel.TargetMode == TargetMode.External ? " TargetMode=\"External\"" : "");
}
- xml.Append("</Relationships>");
-
- os.PutNextEntry(fileName);
- byte[] b = Encoding.UTF8.GetBytes(xml.ToString());
- os.Write(b, 0, b.Length);
+ writer.Write("</Relationships>");
}
public int Count