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