This commit is contained in:
commit
64687d4db9
|
@ -0,0 +1,34 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2012
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RPFTool", "RPFTool\RPFTool.csproj", "{E2C27E34-2FCA-4DB0-AE38-35BEBDFC54A2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SubversionScc) = preSolution
|
||||
Svn-Managed = True
|
||||
Manager = AnkhSVN - Subversion Support for Visual Studio
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|Mixed Platforms = Release|Mixed Platforms
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E2C27E34-2FCA-4DB0-AE38-35BEBDFC54A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E2C27E34-2FCA-4DB0-AE38-35BEBDFC54A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E2C27E34-2FCA-4DB0-AE38-35BEBDFC54A2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{E2C27E34-2FCA-4DB0-AE38-35BEBDFC54A2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{E2C27E34-2FCA-4DB0-AE38-35BEBDFC54A2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E2C27E34-2FCA-4DB0-AE38-35BEBDFC54A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E2C27E34-2FCA-4DB0-AE38-35BEBDFC54A2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E2C27E34-2FCA-4DB0-AE38-35BEBDFC54A2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{E2C27E34-2FCA-4DB0-AE38-35BEBDFC54A2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{E2C27E34-2FCA-4DB0-AE38-35BEBDFC54A2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
Binary file not shown.
|
@ -0,0 +1,105 @@
|
|||
// BZip2.cs
|
||||
//
|
||||
// Copyright (C) 2010 David Pierson
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
// Suppress this in CF and 1.1, not needed. Static classes introduced in C# version 2.0
|
||||
#if !NETCF_2_0 && !NET_1_1
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.BZip2 {
|
||||
|
||||
/// <summary>
|
||||
/// An example class to demonstrate compression and decompression of BZip2 streams.
|
||||
/// </summary>
|
||||
public static class BZip2
|
||||
{
|
||||
/// <summary>
|
||||
/// Decompress the <paramref name="inStream">input</paramref> writing
|
||||
/// uncompressed data to the <paramref name="outStream">output stream</paramref>
|
||||
/// </summary>
|
||||
/// <param name="inStream">The readable stream containing data to decompress.</param>
|
||||
/// <param name="outStream">The output stream to receive the decompressed data.</param>
|
||||
/// <param name="isStreamOwner">Both streams are closed on completion if true.</param>
|
||||
public static void Decompress(Stream inStream, Stream outStream, bool isStreamOwner)
|
||||
{
|
||||
if (inStream == null || outStream == null) {
|
||||
throw new Exception("Null Stream");
|
||||
}
|
||||
|
||||
try {
|
||||
using (BZip2InputStream bzipInput = new BZip2InputStream(inStream)) {
|
||||
bzipInput.IsStreamOwner = isStreamOwner;
|
||||
Core.StreamUtils.Copy(bzipInput, outStream, new byte[4096]);
|
||||
}
|
||||
} finally {
|
||||
if (isStreamOwner) {
|
||||
// inStream is closed by the BZip2InputStream if stream owner
|
||||
outStream.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compress the <paramref name="inStream">input stream</paramref> sending
|
||||
/// result data to <paramref name="outStream">output stream</paramref>
|
||||
/// </summary>
|
||||
/// <param name="inStream">The readable stream to compress.</param>
|
||||
/// <param name="outStream">The output stream to receive the compressed data.</param>
|
||||
/// <param name="isStreamOwner">Both streams are closed on completion if true.</param>
|
||||
/// <param name="level">Block size acts as compression level (1 to 9) with 1 giving
|
||||
/// the lowest compression and 9 the highest.</param>
|
||||
public static void Compress(Stream inStream, Stream outStream, bool isStreamOwner, int level)
|
||||
{
|
||||
if (inStream == null || outStream == null) {
|
||||
throw new Exception("Null Stream");
|
||||
}
|
||||
|
||||
try {
|
||||
using (BZip2OutputStream bzipOutput = new BZip2OutputStream(outStream, level)) {
|
||||
bzipOutput.IsStreamOwner = isStreamOwner;
|
||||
Core.StreamUtils.Copy(inStream, bzipOutput, new byte[4096]);
|
||||
}
|
||||
} finally {
|
||||
if (isStreamOwner) {
|
||||
// outStream is closed by the BZip2OutputStream if stream owner
|
||||
inStream.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,197 @@
|
|||
// BZip2Constants.cs
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.BZip2
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Defines internal values for both compression and decompression
|
||||
/// </summary>
|
||||
internal sealed class BZip2Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Random numbers used to randomise repetitive blocks
|
||||
/// </summary>
|
||||
public readonly static int[] RandomNumbers = {
|
||||
619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
|
||||
985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
|
||||
733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
|
||||
419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
|
||||
878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
|
||||
862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
|
||||
150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
|
||||
170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
|
||||
73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
|
||||
909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
|
||||
641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
|
||||
161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
|
||||
382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
|
||||
98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
|
||||
227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
|
||||
469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
|
||||
184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
|
||||
715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
|
||||
951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
|
||||
652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
|
||||
645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
|
||||
609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
|
||||
653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
|
||||
411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
|
||||
170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
|
||||
857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
|
||||
669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
|
||||
944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
|
||||
344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
|
||||
897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
|
||||
433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
|
||||
686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
|
||||
946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
|
||||
978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
|
||||
680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
|
||||
707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
|
||||
297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
|
||||
134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
|
||||
343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
|
||||
140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
|
||||
170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
|
||||
369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
|
||||
804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
|
||||
896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
|
||||
661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
|
||||
768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
|
||||
61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
|
||||
372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
|
||||
780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
|
||||
920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
|
||||
645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
|
||||
936, 638
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// When multiplied by compression parameter (1-9) gives the block size for compression
|
||||
/// 9 gives the best compression but uses the most memory.
|
||||
/// </summary>
|
||||
public const int BaseBlockSize = 100000;
|
||||
|
||||
/// <summary>
|
||||
/// Backend constant
|
||||
/// </summary>
|
||||
public const int MaximumAlphaSize = 258;
|
||||
|
||||
/// <summary>
|
||||
/// Backend constant
|
||||
/// </summary>
|
||||
public const int MaximumCodeLength = 23;
|
||||
|
||||
/// <summary>
|
||||
/// Backend constant
|
||||
/// </summary>
|
||||
public const int RunA = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Backend constant
|
||||
/// </summary>
|
||||
public const int RunB = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Backend constant
|
||||
/// </summary>
|
||||
public const int GroupCount = 6;
|
||||
|
||||
/// <summary>
|
||||
/// Backend constant
|
||||
/// </summary>
|
||||
public const int GroupSize = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Backend constant
|
||||
/// </summary>
|
||||
public const int NumberOfIterations = 4;
|
||||
|
||||
/// <summary>
|
||||
/// Backend constant
|
||||
/// </summary>
|
||||
public const int MaximumSelectors = (2 + (900000 / GroupSize));
|
||||
|
||||
/// <summary>
|
||||
/// Backend constant
|
||||
/// </summary>
|
||||
public const int OvershootBytes = 20;
|
||||
|
||||
private BZip2Constants()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This file was derived from a file containing this license:
|
||||
*
|
||||
* This file is a part of bzip2 and/or libbzip2, a program and
|
||||
* library for lossless, block-sorting data compression.
|
||||
*
|
||||
* Copyright (C) 1996-1998 Julian R Seward. 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. 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.
|
||||
*
|
||||
* 3. Altered source versions must be plainly marked as such, and must
|
||||
* not be misrepresented as being the original software.
|
||||
*
|
||||
* 4. The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
|
||||
*
|
||||
* Java version ported by Keiron Liddle, Aftex Software <keiron@aftexsw.com> 1999-2001
|
||||
*/
|
|
@ -0,0 +1,90 @@
|
|||
// BZip2.cs
|
||||
//
|
||||
// Copyright 2004 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
using System.Runtime.Serialization;
|
||||
#endif
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.BZip2
|
||||
{
|
||||
/// <summary>
|
||||
/// BZip2Exception represents exceptions specific to Bzip2 algorithm
|
||||
/// </summary>
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
[Serializable]
|
||||
#endif
|
||||
public class BZip2Exception : SharpZipBaseException
|
||||
{
|
||||
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
/// <summary>
|
||||
/// Deserialization constructor
|
||||
/// </summary>
|
||||
/// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>
|
||||
/// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
|
||||
protected BZip2Exception(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
|
||||
{
|
||||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Initialise a new instance of BZip2Exception.
|
||||
/// </summary>
|
||||
public BZip2Exception()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of BZip2Exception with its message set to message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message describing the error.</param>
|
||||
public BZip2Exception(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise an instance of BZip2Exception
|
||||
/// </summary>
|
||||
/// <param name="message">A message describing the error.</param>
|
||||
/// <param name="exception">The exception that is the cause of the current exception.</param>
|
||||
public BZip2Exception(string message, Exception exception)
|
||||
: base(message, exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,237 @@
|
|||
// Adler32.cs - Computes Adler32 data checksum of a data stream
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Checksums
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Computes Adler32 checksum for a stream of data. An Adler32
|
||||
/// checksum is not as reliable as a CRC32 checksum, but a lot faster to
|
||||
/// compute.
|
||||
///
|
||||
/// The specification for Adler32 may be found in RFC 1950.
|
||||
/// ZLIB Compressed Data Format Specification version 3.3)
|
||||
///
|
||||
///
|
||||
/// From that document:
|
||||
///
|
||||
/// "ADLER32 (Adler-32 checksum)
|
||||
/// This contains a checksum value of the uncompressed data
|
||||
/// (excluding any dictionary data) computed according to Adler-32
|
||||
/// algorithm. This algorithm is a 32-bit extension and improvement
|
||||
/// of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073
|
||||
/// standard.
|
||||
///
|
||||
/// Adler-32 is composed of two sums accumulated per byte: s1 is
|
||||
/// the sum of all bytes, s2 is the sum of all s1 values. Both sums
|
||||
/// are done modulo 65521. s1 is initialized to 1, s2 to zero. The
|
||||
/// Adler-32 checksum is stored as s2*65536 + s1 in most-
|
||||
/// significant-byte first (network) order."
|
||||
///
|
||||
/// "8.2. The Adler-32 algorithm
|
||||
///
|
||||
/// The Adler-32 algorithm is much faster than the CRC32 algorithm yet
|
||||
/// still provides an extremely low probability of undetected errors.
|
||||
///
|
||||
/// The modulo on unsigned long accumulators can be delayed for 5552
|
||||
/// bytes, so the modulo operation time is negligible. If the bytes
|
||||
/// are a, b, c, the second sum is 3a + 2b + c + 3, and so is position
|
||||
/// and order sensitive, unlike the first sum, which is just a
|
||||
/// checksum. That 65521 is prime is important to avoid a possible
|
||||
/// large class of two-byte errors that leave the check unchanged.
|
||||
/// (The Fletcher checksum uses 255, which is not prime and which also
|
||||
/// makes the Fletcher check insensitive to single byte changes 0 -
|
||||
/// 255.)
|
||||
///
|
||||
/// The sum s1 is initialized to 1 instead of zero to make the length
|
||||
/// of the sequence part of s2, so that the length does not have to be
|
||||
/// checked separately. (Any sequence of zeroes has a Fletcher
|
||||
/// checksum of zero.)"
|
||||
/// </summary>
|
||||
/// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream"/>
|
||||
/// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream"/>
|
||||
public sealed class Adler32 : IChecksum
|
||||
{
|
||||
/// <summary>
|
||||
/// largest prime smaller than 65536
|
||||
/// </summary>
|
||||
const uint BASE = 65521;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Adler32 data checksum computed so far.
|
||||
/// </summary>
|
||||
public long Value {
|
||||
get {
|
||||
return checksum;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the Adler32 class.
|
||||
/// The checksum starts off with a value of 1.
|
||||
/// </summary>
|
||||
public Adler32()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the Adler32 checksum to the initial value.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
checksum = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the checksum with a byte value.
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// The data value to add. The high byte of the int is ignored.
|
||||
/// </param>
|
||||
public void Update(int value)
|
||||
{
|
||||
// We could make a length 1 byte array and call update again, but I
|
||||
// would rather not have that overhead
|
||||
uint s1 = checksum & 0xFFFF;
|
||||
uint s2 = checksum >> 16;
|
||||
|
||||
s1 = (s1 + ((uint)value & 0xFF)) % BASE;
|
||||
s2 = (s1 + s2) % BASE;
|
||||
|
||||
checksum = (s2 << 16) + s1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the checksum with an array of bytes.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// The source of the data to update with.
|
||||
/// </param>
|
||||
public void Update(byte[] buffer)
|
||||
{
|
||||
if ( buffer == null ) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
Update(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the checksum with the bytes taken from the array.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// an array of bytes
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// the start of the data used for this update
|
||||
/// </param>
|
||||
/// <param name="count">
|
||||
/// the number of bytes to use for this update
|
||||
/// </param>
|
||||
public void Update(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (buffer == null) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
if (offset < 0) {
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("offset", "cannot be negative");
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( count < 0 )
|
||||
{
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("count", "cannot be negative");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (offset >= buffer.Length)
|
||||
{
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("offset", "not a valid index into buffer");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (offset + count > buffer.Length)
|
||||
{
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("count", "exceeds buffer size");
|
||||
#endif
|
||||
}
|
||||
|
||||
//(By Per Bothner)
|
||||
uint s1 = checksum & 0xFFFF;
|
||||
uint s2 = checksum >> 16;
|
||||
|
||||
while (count > 0) {
|
||||
// We can defer the modulo operation:
|
||||
// s1 maximally grows from 65521 to 65521 + 255 * 3800
|
||||
// s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31
|
||||
int n = 3800;
|
||||
if (n > count) {
|
||||
n = count;
|
||||
}
|
||||
count -= n;
|
||||
while (--n >= 0) {
|
||||
s1 = s1 + (uint)(buffer[offset++] & 0xff);
|
||||
s2 = s2 + s1;
|
||||
}
|
||||
s1 %= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
|
||||
checksum = (s2 << 16) | s1;
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
uint checksum;
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
// CRC32.cs - Computes CRC32 data checksum of a data stream
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Checksums
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
|
||||
/// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
|
||||
///
|
||||
/// Polynomials over GF(2) are represented in binary, one bit per coefficient,
|
||||
/// with the lowest powers in the most significant bit. Then adding polynomials
|
||||
/// is just exclusive-or, and multiplying a polynomial by x is a right shift by
|
||||
/// one. If we call the above polynomial p, and represent a byte as the
|
||||
/// polynomial q, also with the lowest power in the most significant bit (so the
|
||||
/// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
|
||||
/// where a mod b means the remainder after dividing a by b.
|
||||
///
|
||||
/// This calculation is done using the shift-register method of multiplying and
|
||||
/// taking the remainder. The register is initialized to zero, and for each
|
||||
/// incoming bit, x^32 is added mod p to the register if the bit is a one (where
|
||||
/// x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
|
||||
/// x (which is shifting right by one and adding x^32 mod p if the bit shifted
|
||||
/// out is a one). We start with the highest power (least significant bit) of
|
||||
/// q and repeat for all eight bits of q.
|
||||
///
|
||||
/// The table is simply the CRC of all possible eight bit values. This is all
|
||||
/// the information needed to generate CRC's on data a byte at a time for all
|
||||
/// combinations of CRC register values and incoming bytes.
|
||||
/// </summary>
|
||||
public sealed class Crc32 : IChecksum
|
||||
{
|
||||
const uint CrcSeed = 0xFFFFFFFF;
|
||||
|
||||
readonly static uint[] CrcTable = new uint[] {
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,
|
||||
0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
|
||||
0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
|
||||
0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
|
||||
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,
|
||||
0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
|
||||
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
|
||||
0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
|
||||
0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,
|
||||
0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
|
||||
0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
||||
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,
|
||||
0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
|
||||
0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
|
||||
0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
|
||||
0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
|
||||
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
|
||||
0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
||||
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
|
||||
0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
|
||||
0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,
|
||||
0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,
|
||||
0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
|
||||
0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
|
||||
0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
|
||||
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
|
||||
0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
|
||||
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,
|
||||
0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
|
||||
0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
|
||||
0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
|
||||
0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,
|
||||
0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
|
||||
0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
|
||||
0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
|
||||
0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
|
||||
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,
|
||||
0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
|
||||
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
|
||||
0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
|
||||
0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
|
||||
0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
|
||||
0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
|
||||
0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
|
||||
0x2D02EF8D
|
||||
};
|
||||
|
||||
internal static uint ComputeCrc32(uint oldCrc, byte value)
|
||||
{
|
||||
return (uint)(Crc32.CrcTable[(oldCrc ^ value) & 0xFF] ^ (oldCrc >> 8));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The crc data checksum so far.
|
||||
/// </summary>
|
||||
uint crc;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the CRC32 data checksum computed so far.
|
||||
/// </summary>
|
||||
public long Value {
|
||||
get {
|
||||
return (long)crc;
|
||||
}
|
||||
set {
|
||||
crc = (uint)value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the CRC32 data checksum as if no update was ever called.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
crc = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the checksum with the int bval.
|
||||
/// </summary>
|
||||
/// <param name = "value">
|
||||
/// the byte is taken as the lower 8 bits of value
|
||||
/// </param>
|
||||
public void Update(int value)
|
||||
{
|
||||
crc ^= CrcSeed;
|
||||
crc = CrcTable[(crc ^ value) & 0xFF] ^ (crc >> 8);
|
||||
crc ^= CrcSeed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the checksum with the bytes taken from the array.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// buffer an array of bytes
|
||||
/// </param>
|
||||
public void Update(byte[] buffer)
|
||||
{
|
||||
if (buffer == null) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
Update(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the byte array to the data checksum.
|
||||
/// </summary>
|
||||
/// <param name = "buffer">
|
||||
/// The buffer which contains the data
|
||||
/// </param>
|
||||
/// <param name = "offset">
|
||||
/// The offset in the buffer where the data starts
|
||||
/// </param>
|
||||
/// <param name = "count">
|
||||
/// The number of data bytes to update the CRC with.
|
||||
/// </param>
|
||||
public void Update(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (buffer == null) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
if ( count < 0 ) {
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("count", "Count cannot be less than zero");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (offset < 0 || offset + count > buffer.Length) {
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
}
|
||||
|
||||
crc ^= CrcSeed;
|
||||
|
||||
while (--count >= 0) {
|
||||
crc = CrcTable[(crc ^ buffer[offset++]) & 0xFF] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
crc ^= CrcSeed;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
// IChecksum.cs - Interface to compute a data checksum
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Checksums
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Interface to compute a data checksum used by checked input/output streams.
|
||||
/// A data checksum can be updated by one byte or with a byte array. After each
|
||||
/// update the value of the current checksum can be returned by calling
|
||||
/// <code>getValue</code>. The complete checksum object can also be reset
|
||||
/// so it can be used again with new data.
|
||||
/// </summary>
|
||||
public interface IChecksum
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the data checksum computed so far.
|
||||
/// </summary>
|
||||
long Value
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the data checksum as if no update was ever called.
|
||||
/// </summary>
|
||||
void Reset();
|
||||
|
||||
/// <summary>
|
||||
/// Adds one byte to the data checksum.
|
||||
/// </summary>
|
||||
/// <param name = "value">
|
||||
/// the data value to add. The high byte of the int is ignored.
|
||||
/// </param>
|
||||
void Update(int value);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the data checksum with the bytes taken from the array.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// buffer an array of bytes
|
||||
/// </param>
|
||||
void Update(byte[] buffer);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the byte array to the data checksum.
|
||||
/// </summary>
|
||||
/// <param name = "buffer">
|
||||
/// The buffer which contains the data
|
||||
/// </param>
|
||||
/// <param name = "offset">
|
||||
/// The offset in the buffer where the data starts
|
||||
/// </param>
|
||||
/// <param name = "count">
|
||||
/// the number of data bytes to add.
|
||||
/// </param>
|
||||
void Update(byte[] buffer, int offset, int count);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
// StrangeCRC.cs - computes a crc used in the bziplib
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Checksums
|
||||
{
|
||||
/// <summary>
|
||||
/// Bzip2 checksum algorithm
|
||||
/// </summary>
|
||||
public class StrangeCRC : IChecksum
|
||||
{
|
||||
readonly static uint[] crc32Table = {
|
||||
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
|
||||
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
|
||||
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
|
||||
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
|
||||
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
|
||||
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
|
||||
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
|
||||
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
|
||||
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
|
||||
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
|
||||
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
|
||||
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
|
||||
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
|
||||
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
|
||||
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
|
||||
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
|
||||
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
|
||||
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
|
||||
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
|
||||
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
|
||||
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
|
||||
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
|
||||
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
|
||||
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
|
||||
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
|
||||
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
|
||||
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
|
||||
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
|
||||
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
|
||||
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
|
||||
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
|
||||
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
|
||||
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
|
||||
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
|
||||
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
|
||||
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
|
||||
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
|
||||
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
|
||||
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
|
||||
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
|
||||
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
|
||||
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
|
||||
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
|
||||
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
|
||||
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
|
||||
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
|
||||
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
|
||||
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
|
||||
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
|
||||
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
|
||||
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
|
||||
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
|
||||
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
|
||||
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
|
||||
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
|
||||
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
|
||||
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
|
||||
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
|
||||
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
|
||||
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
|
||||
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
|
||||
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
|
||||
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
|
||||
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
|
||||
};
|
||||
|
||||
int globalCrc;
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a default instance of <see cref="StrangeCRC"></see>
|
||||
/// </summary>
|
||||
public StrangeCRC()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the state of Crc.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
globalCrc = -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current Crc value.
|
||||
/// </summary>
|
||||
public long Value {
|
||||
get {
|
||||
return ~globalCrc;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the Crc value.
|
||||
/// </summary>
|
||||
/// <param name="value">data update is based on</param>
|
||||
public void Update(int value)
|
||||
{
|
||||
int temp = (globalCrc >> 24) ^ value;
|
||||
if (temp < 0) {
|
||||
temp = 256 + temp;
|
||||
}
|
||||
globalCrc = unchecked((int)((globalCrc << 8) ^ crc32Table[temp]));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update Crc based on a block of data
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer containing data to update the crc with.</param>
|
||||
public void Update(byte[] buffer)
|
||||
{
|
||||
if (buffer == null) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
Update(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update Crc based on a portion of a block of data
|
||||
/// </summary>
|
||||
/// <param name="buffer">block of data</param>
|
||||
/// <param name="offset">index of first byte to use</param>
|
||||
/// <param name="count">number of bytes to use</param>
|
||||
public void Update(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (buffer == null) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
if ( offset < 0 )
|
||||
{
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("offset", "cannot be less than zero");
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( count < 0 )
|
||||
{
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("count", "cannot be less than zero");
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( offset + count > buffer.Length )
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
Update(buffer[offset++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,533 @@
|
|||
// FileSystemScanner.cs
|
||||
//
|
||||
// Copyright 2005 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
|
||||
using System;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Core
|
||||
{
|
||||
#region EventArgs
|
||||
/// <summary>
|
||||
/// Event arguments for scanning.
|
||||
/// </summary>
|
||||
public class ScanEventArgs : EventArgs
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="ScanEventArgs"/>
|
||||
/// </summary>
|
||||
/// <param name="name">The file or directory name.</param>
|
||||
public ScanEventArgs(string name)
|
||||
{
|
||||
name_ = name;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The file or directory name for this event.
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return name_; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get set a value indicating if scanning should continue or not.
|
||||
/// </summary>
|
||||
public bool ContinueRunning
|
||||
{
|
||||
get { return continueRunning_; }
|
||||
set { continueRunning_ = value; }
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
string name_;
|
||||
bool continueRunning_ = true;
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event arguments during processing of a single file or directory.
|
||||
/// </summary>
|
||||
public class ProgressEventArgs : EventArgs
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="ScanEventArgs"/>
|
||||
/// </summary>
|
||||
/// <param name="name">The file or directory name if known.</param>
|
||||
/// <param name="processed">The number of bytes processed so far</param>
|
||||
/// <param name="target">The total number of bytes to process, 0 if not known</param>
|
||||
public ProgressEventArgs(string name, long processed, long target)
|
||||
{
|
||||
name_ = name;
|
||||
processed_ = processed;
|
||||
target_ = target;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The name for this event if known.
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return name_; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get set a value indicating wether scanning should continue or not.
|
||||
/// </summary>
|
||||
public bool ContinueRunning
|
||||
{
|
||||
get { return continueRunning_; }
|
||||
set { continueRunning_ = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a percentage representing how much of the <see cref="Target"></see> has been processed
|
||||
/// </summary>
|
||||
/// <value>0.0 to 100.0 percent; 0 if target is not known.</value>
|
||||
public float PercentComplete
|
||||
{
|
||||
get
|
||||
{
|
||||
float result;
|
||||
if (target_ <= 0)
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ((float)processed_ / (float)target_) * 100.0f;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes processed so far
|
||||
/// </summary>
|
||||
public long Processed
|
||||
{
|
||||
get { return processed_; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes to process.
|
||||
/// </summary>
|
||||
/// <remarks>Target may be 0 or negative if the value isnt known.</remarks>
|
||||
public long Target
|
||||
{
|
||||
get { return target_; }
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
string name_;
|
||||
long processed_;
|
||||
long target_;
|
||||
bool continueRunning_ = true;
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event arguments for directories.
|
||||
/// </summary>
|
||||
public class DirectoryEventArgs : ScanEventArgs
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialize an instance of <see cref="DirectoryEventArgs"></see>.
|
||||
/// </summary>
|
||||
/// <param name="name">The name for this directory.</param>
|
||||
/// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</param>
|
||||
public DirectoryEventArgs(string name, bool hasMatchingFiles)
|
||||
: base (name)
|
||||
{
|
||||
hasMatchingFiles_ = hasMatchingFiles;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Get a value indicating if the directory contains any matching files or not.
|
||||
/// </summary>
|
||||
public bool HasMatchingFiles
|
||||
{
|
||||
get { return hasMatchingFiles_; }
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
bool hasMatchingFiles_;
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arguments passed when scan failures are detected.
|
||||
/// </summary>
|
||||
public class ScanFailureEventArgs : EventArgs
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="ScanFailureEventArgs"></see>
|
||||
/// </summary>
|
||||
/// <param name="name">The name to apply.</param>
|
||||
/// <param name="e">The exception to use.</param>
|
||||
public ScanFailureEventArgs(string name, Exception e)
|
||||
{
|
||||
name_ = name;
|
||||
exception_ = e;
|
||||
continueRunning_ = true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The applicable name.
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return name_; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The applicable exception.
|
||||
/// </summary>
|
||||
public Exception Exception
|
||||
{
|
||||
get { return exception_; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get / set a value indicating wether scanning should continue.
|
||||
/// </summary>
|
||||
public bool ContinueRunning
|
||||
{
|
||||
get { return continueRunning_; }
|
||||
set { continueRunning_ = value; }
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
string name_;
|
||||
Exception exception_;
|
||||
bool continueRunning_;
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Delegates
|
||||
/// <summary>
|
||||
/// Delegate invoked before starting to process a directory.
|
||||
/// </summary>
|
||||
public delegate void ProcessDirectoryHandler(object sender, DirectoryEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Delegate invoked before starting to process a file.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event</param>
|
||||
/// <param name="e">The event arguments.</param>
|
||||
public delegate void ProcessFileHandler(object sender, ScanEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Delegate invoked during processing of a file or directory
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event</param>
|
||||
/// <param name="e">The event arguments.</param>
|
||||
public delegate void ProgressHandler(object sender, ProgressEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Delegate invoked when a file has been completely processed.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event</param>
|
||||
/// <param name="e">The event arguments.</param>
|
||||
public delegate void CompletedFileHandler(object sender, ScanEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Delegate invoked when a directory failure is detected.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event</param>
|
||||
/// <param name="e">The event arguments.</param>
|
||||
public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Delegate invoked when a file failure is detected.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event</param>
|
||||
/// <param name="e">The event arguments.</param>
|
||||
public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e);
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// FileSystemScanner provides facilities scanning of files and directories.
|
||||
/// </summary>
|
||||
public class FileSystemScanner
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="FileSystemScanner"></see>
|
||||
/// </summary>
|
||||
/// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param>
|
||||
public FileSystemScanner(string filter)
|
||||
{
|
||||
fileFilter_ = new PathFilter(filter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="FileSystemScanner"></see>
|
||||
/// </summary>
|
||||
/// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
|
||||
/// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param>
|
||||
public FileSystemScanner(string fileFilter, string directoryFilter)
|
||||
{
|
||||
fileFilter_ = new PathFilter(fileFilter);
|
||||
directoryFilter_ = new PathFilter(directoryFilter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="FileSystemScanner"></see>
|
||||
/// </summary>
|
||||
/// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param>
|
||||
public FileSystemScanner(IScanFilter fileFilter)
|
||||
{
|
||||
fileFilter_ = fileFilter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="FileSystemScanner"></see>
|
||||
/// </summary>
|
||||
/// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param>
|
||||
/// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see> to apply.</param>
|
||||
public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter)
|
||||
{
|
||||
fileFilter_ = fileFilter;
|
||||
directoryFilter_ = directoryFilter;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Delegates
|
||||
/// <summary>
|
||||
/// Delegate to invoke when a directory is processed.
|
||||
/// </summary>
|
||||
public ProcessDirectoryHandler ProcessDirectory;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate to invoke when a file is processed.
|
||||
/// </summary>
|
||||
public ProcessFileHandler ProcessFile;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate to invoke when processing for a file has finished.
|
||||
/// </summary>
|
||||
public CompletedFileHandler CompletedFile;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate to invoke when a directory failure is detected.
|
||||
/// </summary>
|
||||
public DirectoryFailureHandler DirectoryFailure;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate to invoke when a file failure is detected.
|
||||
/// </summary>
|
||||
public FileFailureHandler FileFailure;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Raise the DirectoryFailure event.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory name.</param>
|
||||
/// <param name="e">The exception detected.</param>
|
||||
bool OnDirectoryFailure(string directory, Exception e)
|
||||
{
|
||||
DirectoryFailureHandler handler = DirectoryFailure;
|
||||
bool result = (handler != null);
|
||||
if ( result ) {
|
||||
ScanFailureEventArgs args = new ScanFailureEventArgs(directory, e);
|
||||
handler(this, args);
|
||||
alive_ = args.ContinueRunning;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raise the FileFailure event.
|
||||
/// </summary>
|
||||
/// <param name="file">The file name.</param>
|
||||
/// <param name="e">The exception detected.</param>
|
||||
bool OnFileFailure(string file, Exception e)
|
||||
{
|
||||
FileFailureHandler handler = FileFailure;
|
||||
|
||||
bool result = (handler != null);
|
||||
|
||||
if ( result ){
|
||||
ScanFailureEventArgs args = new ScanFailureEventArgs(file, e);
|
||||
FileFailure(this, args);
|
||||
alive_ = args.ContinueRunning;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raise the ProcessFile event.
|
||||
/// </summary>
|
||||
/// <param name="file">The file name.</param>
|
||||
void OnProcessFile(string file)
|
||||
{
|
||||
ProcessFileHandler handler = ProcessFile;
|
||||
|
||||
if ( handler!= null ) {
|
||||
ScanEventArgs args = new ScanEventArgs(file);
|
||||
handler(this, args);
|
||||
alive_ = args.ContinueRunning;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raise the complete file event
|
||||
/// </summary>
|
||||
/// <param name="file">The file name</param>
|
||||
void OnCompleteFile(string file)
|
||||
{
|
||||
CompletedFileHandler handler = CompletedFile;
|
||||
|
||||
if (handler != null)
|
||||
{
|
||||
ScanEventArgs args = new ScanEventArgs(file);
|
||||
handler(this, args);
|
||||
alive_ = args.ContinueRunning;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raise the ProcessDirectory event.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory name.</param>
|
||||
/// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param>
|
||||
void OnProcessDirectory(string directory, bool hasMatchingFiles)
|
||||
{
|
||||
ProcessDirectoryHandler handler = ProcessDirectory;
|
||||
|
||||
if ( handler != null ) {
|
||||
DirectoryEventArgs args = new DirectoryEventArgs(directory, hasMatchingFiles);
|
||||
handler(this, args);
|
||||
alive_ = args.ContinueRunning;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scan a directory.
|
||||
/// </summary>
|
||||
/// <param name="directory">The base directory to scan.</param>
|
||||
/// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param>
|
||||
public void Scan(string directory, bool recurse)
|
||||
{
|
||||
alive_ = true;
|
||||
ScanDir(directory, recurse);
|
||||
}
|
||||
|
||||
void ScanDir(string directory, bool recurse)
|
||||
{
|
||||
|
||||
try {
|
||||
string[] names = System.IO.Directory.GetFiles(directory);
|
||||
bool hasMatch = false;
|
||||
for (int fileIndex = 0; fileIndex < names.Length; ++fileIndex) {
|
||||
if ( !fileFilter_.IsMatch(names[fileIndex]) ) {
|
||||
names[fileIndex] = null;
|
||||
} else {
|
||||
hasMatch = true;
|
||||
}
|
||||
}
|
||||
|
||||
OnProcessDirectory(directory, hasMatch);
|
||||
|
||||
if ( alive_ && hasMatch ) {
|
||||
foreach (string fileName in names) {
|
||||
try {
|
||||
if ( fileName != null ) {
|
||||
OnProcessFile(fileName);
|
||||
if ( !alive_ ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (!OnFileFailure(fileName, e)) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (!OnDirectoryFailure(directory, e)) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if ( alive_ && recurse ) {
|
||||
try {
|
||||
string[] names = System.IO.Directory.GetDirectories(directory);
|
||||
foreach (string fulldir in names) {
|
||||
if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir))) {
|
||||
ScanDir(fulldir, true);
|
||||
if ( !alive_ ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (!OnDirectoryFailure(directory, e)) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// The file filter currently in use.
|
||||
/// </summary>
|
||||
IScanFilter fileFilter_;
|
||||
/// <summary>
|
||||
/// The directory filter currently in use.
|
||||
/// </summary>
|
||||
IScanFilter directoryFilter_;
|
||||
/// <summary>
|
||||
/// Flag indicating if scanning should continue running.
|
||||
/// </summary>
|
||||
bool alive_;
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
// INameTransform.cs
|
||||
//
|
||||
// Copyright 2005 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// INameTransform defines how file system names are transformed for use with archives, or vice versa.
|
||||
/// </summary>
|
||||
public interface INameTransform
|
||||
{
|
||||
/// <summary>
|
||||
/// Given a file name determine the transformed value.
|
||||
/// </summary>
|
||||
/// <param name="name">The name to transform.</param>
|
||||
/// <returns>The transformed file name.</returns>
|
||||
string TransformFile(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Given a directory name determine the transformed value.
|
||||
/// </summary>
|
||||
/// <param name="name">The name to transform.</param>
|
||||
/// <returns>The transformed directory name</returns>
|
||||
string TransformDirectory(string name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// IScanFilter.cs
|
||||
//
|
||||
// Copyright 2006 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Scanning filters support filtering of names.
|
||||
/// </summary>
|
||||
public interface IScanFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Test a name to see if it 'matches' the filter.
|
||||
/// </summary>
|
||||
/// <param name="name">The name to test.</param>
|
||||
/// <returns>Returns true if the name matches the filter, false if it does not match.</returns>
|
||||
bool IsMatch(string name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,290 @@
|
|||
// NameFilter.cs
|
||||
//
|
||||
// Copyright 2005 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
// HISTORY
|
||||
// 2010-03-03 Z-1654 Fixed bug where escape characters were excluded in SplitQuoted()
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// NameFilter is a string matching class which allows for both positive and negative
|
||||
/// matching.
|
||||
/// A filter is a sequence of independant <see cref="Regex">regular expressions</see> separated by semi-colons ';'.
|
||||
/// To include a semi-colon it may be quoted as in \;. Each expression can be prefixed by a plus '+' sign or
|
||||
/// a minus '-' sign to denote the expression is intended to include or exclude names.
|
||||
/// If neither a plus or minus sign is found include is the default.
|
||||
/// A given name is tested for inclusion before checking exclusions. Only names matching an include spec
|
||||
/// and not matching an exclude spec are deemed to match the filter.
|
||||
/// An empty filter matches any name.
|
||||
/// </summary>
|
||||
/// <example>The following expression includes all name ending in '.dat' with the exception of 'dummy.dat'
|
||||
/// "+\.dat$;-^dummy\.dat$"
|
||||
/// </example>
|
||||
public class NameFilter : IScanFilter
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Construct an instance based on the filter expression passed
|
||||
/// </summary>
|
||||
/// <param name="filter">The filter expression.</param>
|
||||
public NameFilter(string filter)
|
||||
{
|
||||
filter_ = filter;
|
||||
inclusions_ = new ArrayList();
|
||||
exclusions_ = new ArrayList();
|
||||
Compile();
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Test a string to see if it is a valid regular expression.
|
||||
/// </summary>
|
||||
/// <param name="expression">The expression to test.</param>
|
||||
/// <returns>True if expression is a valid <see cref="System.Text.RegularExpressions.Regex"/> false otherwise.</returns>
|
||||
public static bool IsValidExpression(string expression)
|
||||
{
|
||||
bool result = true;
|
||||
try {
|
||||
Regex exp = new Regex(expression, RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
}
|
||||
catch (ArgumentException) {
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test an expression to see if it is valid as a filter.
|
||||
/// </summary>
|
||||
/// <param name="toTest">The filter expression to test.</param>
|
||||
/// <returns>True if the expression is valid, false otherwise.</returns>
|
||||
public static bool IsValidFilterExpression(string toTest)
|
||||
{
|
||||
if ( toTest == null ) {
|
||||
throw new ArgumentNullException("toTest");
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
|
||||
try {
|
||||
string[] items = SplitQuoted(toTest);
|
||||
for (int i = 0; i < items.Length; ++i) {
|
||||
if ((items[i] != null) && (items[i].Length > 0)) {
|
||||
string toCompile;
|
||||
|
||||
if (items[i][0] == '+') {
|
||||
toCompile = items[i].Substring(1, items[i].Length - 1);
|
||||
}
|
||||
else if (items[i][0] == '-') {
|
||||
toCompile = items[i].Substring(1, items[i].Length - 1);
|
||||
}
|
||||
else {
|
||||
toCompile = items[i];
|
||||
}
|
||||
|
||||
Regex testRegex = new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ArgumentException) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Split a string into its component pieces
|
||||
/// </summary>
|
||||
/// <param name="original">The original string</param>
|
||||
/// <returns>Returns an array of <see cref="T:System.String"/> values containing the individual filter elements.</returns>
|
||||
public static string[] SplitQuoted(string original)
|
||||
{
|
||||
char escape = '\\';
|
||||
char[] separators = { ';' };
|
||||
|
||||
ArrayList result = new ArrayList();
|
||||
|
||||
if ((original != null) && (original.Length > 0)) {
|
||||
int endIndex = -1;
|
||||
StringBuilder b = new StringBuilder();
|
||||
|
||||
while (endIndex < original.Length) {
|
||||
endIndex += 1;
|
||||
if (endIndex >= original.Length) {
|
||||
result.Add(b.ToString());
|
||||
}
|
||||
else if (original[endIndex] == escape) {
|
||||
endIndex += 1;
|
||||
if (endIndex >= original.Length) {
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentException("Missing terminating escape character");
|
||||
#else
|
||||
throw new ArgumentException("Missing terminating escape character", "original");
|
||||
#endif
|
||||
}
|
||||
// include escape if this is not an escaped separator
|
||||
if (Array.IndexOf(separators, original[endIndex]) < 0)
|
||||
b.Append(escape);
|
||||
|
||||
b.Append(original[endIndex]);
|
||||
}
|
||||
else {
|
||||
if (Array.IndexOf(separators, original[endIndex]) >= 0) {
|
||||
result.Add(b.ToString());
|
||||
b.Length = 0;
|
||||
}
|
||||
else {
|
||||
b.Append(original[endIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (string[])result.ToArray(typeof(string));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert this filter to its string equivalent.
|
||||
/// </summary>
|
||||
/// <returns>The string equivalent for this filter.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return filter_;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test a value to see if it is included by the filter.
|
||||
/// </summary>
|
||||
/// <param name="name">The value to test.</param>
|
||||
/// <returns>True if the value is included, false otherwise.</returns>
|
||||
public bool IsIncluded(string name)
|
||||
{
|
||||
bool result = false;
|
||||
if ( inclusions_.Count == 0 ) {
|
||||
result = true;
|
||||
}
|
||||
else {
|
||||
foreach ( Regex r in inclusions_ ) {
|
||||
if ( r.IsMatch(name) ) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test a value to see if it is excluded by the filter.
|
||||
/// </summary>
|
||||
/// <param name="name">The value to test.</param>
|
||||
/// <returns>True if the value is excluded, false otherwise.</returns>
|
||||
public bool IsExcluded(string name)
|
||||
{
|
||||
bool result = false;
|
||||
foreach ( Regex r in exclusions_ ) {
|
||||
if ( r.IsMatch(name) ) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#region IScanFilter Members
|
||||
/// <summary>
|
||||
/// Test a value to see if it matches the filter.
|
||||
/// </summary>
|
||||
/// <param name="name">The value to test.</param>
|
||||
/// <returns>True if the value matches, false otherwise.</returns>
|
||||
public bool IsMatch(string name)
|
||||
{
|
||||
return (IsIncluded(name) && !IsExcluded(name));
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Compile this filter.
|
||||
/// </summary>
|
||||
void Compile()
|
||||
{
|
||||
// TODO: Check to see if combining RE's makes it faster/smaller.
|
||||
// simple scheme would be to have one RE for inclusion and one for exclusion.
|
||||
if ( filter_ == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
string[] items = SplitQuoted(filter_);
|
||||
for ( int i = 0; i < items.Length; ++i ) {
|
||||
if ( (items[i] != null) && (items[i].Length > 0) ) {
|
||||
bool include = (items[i][0] != '-');
|
||||
string toCompile;
|
||||
|
||||
if ( items[i][0] == '+' ) {
|
||||
toCompile = items[i].Substring(1, items[i].Length - 1);
|
||||
}
|
||||
else if ( items[i][0] == '-' ) {
|
||||
toCompile = items[i].Substring(1, items[i].Length - 1);
|
||||
}
|
||||
else {
|
||||
toCompile = items[i];
|
||||
}
|
||||
|
||||
// NOTE: Regular expressions can fail to compile here for a number of reasons that cause an exception
|
||||
// these are left unhandled here as the caller is responsible for ensuring all is valid.
|
||||
// several functions IsValidFilterExpression and IsValidExpression are provided for such checking
|
||||
if ( include ) {
|
||||
inclusions_.Add(new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline));
|
||||
}
|
||||
else {
|
||||
exclusions_.Add(new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
string filter_;
|
||||
ArrayList inclusions_;
|
||||
ArrayList exclusions_;
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,334 @@
|
|||
// PathFilter.cs
|
||||
//
|
||||
// Copyright 2005 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// PathFilter filters directories and files using a form of <see cref="System.Text.RegularExpressions.Regex">regular expressions</see>
|
||||
/// by full path name.
|
||||
/// See <see cref="NameFilter">NameFilter</see> for more detail on filtering.
|
||||
/// </summary>
|
||||
public class PathFilter : IScanFilter
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="PathFilter"></see>.
|
||||
/// </summary>
|
||||
/// <param name="filter">The <see cref="NameFilter">filter</see> expression to apply.</param>
|
||||
public PathFilter(string filter)
|
||||
{
|
||||
nameFilter_ = new NameFilter(filter);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IScanFilter Members
|
||||
/// <summary>
|
||||
/// Test a name to see if it matches the filter.
|
||||
/// </summary>
|
||||
/// <param name="name">The name to test.</param>
|
||||
/// <returns>True if the name matches, false otherwise.</returns>
|
||||
/// <remarks><see cref="Path.GetFullPath(string)"/> is used to get the full path before matching.</remarks>
|
||||
public virtual bool IsMatch(string name)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if ( name != null ) {
|
||||
string cooked = (name.Length > 0) ? Path.GetFullPath(name) : "";
|
||||
result = nameFilter_.IsMatch(cooked);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Instance Fields
|
||||
NameFilter nameFilter_;
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ExtendedPathFilter filters based on name, file size, and the last write time of the file.
|
||||
/// </summary>
|
||||
/// <remarks>Provides an example of how to customise filtering.</remarks>
|
||||
public class ExtendedPathFilter : PathFilter
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialise a new instance of ExtendedPathFilter.
|
||||
/// </summary>
|
||||
/// <param name="filter">The filter to apply.</param>
|
||||
/// <param name="minSize">The minimum file size to include.</param>
|
||||
/// <param name="maxSize">The maximum file size to include.</param>
|
||||
public ExtendedPathFilter(string filter,
|
||||
long minSize, long maxSize)
|
||||
: base(filter)
|
||||
{
|
||||
MinSize = minSize;
|
||||
MaxSize = maxSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of ExtendedPathFilter.
|
||||
/// </summary>
|
||||
/// <param name="filter">The filter to apply.</param>
|
||||
/// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>
|
||||
/// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>
|
||||
public ExtendedPathFilter(string filter,
|
||||
DateTime minDate, DateTime maxDate)
|
||||
: base(filter)
|
||||
{
|
||||
MinDate = minDate;
|
||||
MaxDate = maxDate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of ExtendedPathFilter.
|
||||
/// </summary>
|
||||
/// <param name="filter">The filter to apply.</param>
|
||||
/// <param name="minSize">The minimum file size to include.</param>
|
||||
/// <param name="maxSize">The maximum file size to include.</param>
|
||||
/// <param name="minDate">The minimum <see cref="DateTime"/> to include.</param>
|
||||
/// <param name="maxDate">The maximum <see cref="DateTime"/> to include.</param>
|
||||
public ExtendedPathFilter(string filter,
|
||||
long minSize, long maxSize,
|
||||
DateTime minDate, DateTime maxDate)
|
||||
: base(filter)
|
||||
{
|
||||
MinSize = minSize;
|
||||
MaxSize = maxSize;
|
||||
MinDate = minDate;
|
||||
MaxDate = maxDate;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IScanFilter Members
|
||||
/// <summary>
|
||||
/// Test a filename to see if it matches the filter.
|
||||
/// </summary>
|
||||
/// <param name="name">The filename to test.</param>
|
||||
/// <returns>True if the filter matches, false otherwise.</returns>
|
||||
/// <exception cref="System.IO.FileNotFoundException">The <see paramref="fileName"/> doesnt exist</exception>
|
||||
public override bool IsMatch(string name)
|
||||
{
|
||||
bool result = base.IsMatch(name);
|
||||
|
||||
if ( result ) {
|
||||
FileInfo fileInfo = new FileInfo(name);
|
||||
result =
|
||||
(MinSize <= fileInfo.Length) &&
|
||||
(MaxSize >= fileInfo.Length) &&
|
||||
(MinDate <= fileInfo.LastWriteTime) &&
|
||||
(MaxDate >= fileInfo.LastWriteTime)
|
||||
;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Get/set the minimum size/length for a file that will match this filter.
|
||||
/// </summary>
|
||||
/// <remarks>The default value is zero.</remarks>
|
||||
/// <exception cref="ArgumentOutOfRangeException">value is less than zero; greater than <see cref="MaxSize"/></exception>
|
||||
public long MinSize
|
||||
{
|
||||
get { return minSize_; }
|
||||
set
|
||||
{
|
||||
if ( (value < 0) || (maxSize_ < value) ) {
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
minSize_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the maximum size/length for a file that will match this filter.
|
||||
/// </summary>
|
||||
/// <remarks>The default value is <see cref="System.Int64.MaxValue"/></remarks>
|
||||
/// <exception cref="ArgumentOutOfRangeException">value is less than zero or less than <see cref="MinSize"/></exception>
|
||||
public long MaxSize
|
||||
{
|
||||
get { return maxSize_; }
|
||||
set
|
||||
{
|
||||
if ( (value < 0) || (minSize_ > value) ) {
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
maxSize_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the minimum <see cref="DateTime"/> value that will match for this filter.
|
||||
/// </summary>
|
||||
/// <remarks>Files with a LastWrite time less than this value are excluded by the filter.</remarks>
|
||||
public DateTime MinDate
|
||||
{
|
||||
get
|
||||
{
|
||||
return minDate_;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if ( value > maxDate_ ) {
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("value", "Exceeds MaxDate");
|
||||
#endif
|
||||
}
|
||||
|
||||
minDate_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the maximum <see cref="DateTime"/> value that will match for this filter.
|
||||
/// </summary>
|
||||
/// <remarks>Files with a LastWrite time greater than this value are excluded by the filter.</remarks>
|
||||
public DateTime MaxDate
|
||||
{
|
||||
get
|
||||
{
|
||||
return maxDate_;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if ( minDate_ > value ) {
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("value", "Exceeds MinDate");
|
||||
#endif
|
||||
}
|
||||
|
||||
maxDate_ = value;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Instance Fields
|
||||
long minSize_;
|
||||
long maxSize_ = long.MaxValue;
|
||||
DateTime minDate_ = DateTime.MinValue;
|
||||
DateTime maxDate_ = DateTime.MaxValue;
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NameAndSizeFilter filters based on name and file size.
|
||||
/// </summary>
|
||||
/// <remarks>A sample showing how filters might be extended.</remarks>
|
||||
[Obsolete("Use ExtendedPathFilter instead")]
|
||||
public class NameAndSizeFilter : PathFilter
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of NameAndSizeFilter.
|
||||
/// </summary>
|
||||
/// <param name="filter">The filter to apply.</param>
|
||||
/// <param name="minSize">The minimum file size to include.</param>
|
||||
/// <param name="maxSize">The maximum file size to include.</param>
|
||||
public NameAndSizeFilter(string filter, long minSize, long maxSize)
|
||||
: base(filter)
|
||||
{
|
||||
MinSize = minSize;
|
||||
MaxSize = maxSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test a filename to see if it matches the filter.
|
||||
/// </summary>
|
||||
/// <param name="name">The filename to test.</param>
|
||||
/// <returns>True if the filter matches, false otherwise.</returns>
|
||||
public override bool IsMatch(string name)
|
||||
{
|
||||
bool result = base.IsMatch(name);
|
||||
|
||||
if ( result ) {
|
||||
FileInfo fileInfo = new FileInfo(name);
|
||||
long length = fileInfo.Length;
|
||||
result =
|
||||
(MinSize <= length) &&
|
||||
(MaxSize >= length);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the minimum size for a file that will match this filter.
|
||||
/// </summary>
|
||||
public long MinSize
|
||||
{
|
||||
get { return minSize_; }
|
||||
set {
|
||||
if ( (value < 0) || (maxSize_ < value) ) {
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
minSize_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the maximum size for a file that will match this filter.
|
||||
/// </summary>
|
||||
public long MaxSize
|
||||
{
|
||||
get { return maxSize_; }
|
||||
set
|
||||
{
|
||||
if ( (value < 0) || (minSize_ > value) ) {
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
maxSize_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
long minSize_;
|
||||
long maxSize_ = long.MaxValue;
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
// StreamUtils.cs
|
||||
//
|
||||
// Copyright 2005 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides simple <see cref="Stream"/>" utilities.
|
||||
/// </summary>
|
||||
public sealed class StreamUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Read from a <see cref="Stream"/> ensuring all the required data is read.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to read.</param>
|
||||
/// <param name="buffer">The buffer to fill.</param>
|
||||
/// <seealso cref="ReadFully(Stream,byte[],int,int)"/>
|
||||
static public void ReadFully(Stream stream, byte[] buffer)
|
||||
{
|
||||
ReadFully(stream, buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a <see cref="Stream"/>" ensuring all the required data is read.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to read data from.</param>
|
||||
/// <param name="buffer">The buffer to store data in.</param>
|
||||
/// <param name="offset">The offset at which to begin storing data.</param>
|
||||
/// <param name="count">The number of bytes of data to store.</param>
|
||||
/// <exception cref="ArgumentNullException">Required parameter is null</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="offset"/> and or <paramref name="count"/> are invalid.</exception>
|
||||
/// <exception cref="EndOfStreamException">End of stream is encountered before all the data has been read.</exception>
|
||||
static public void ReadFully(Stream stream, byte[] buffer, int offset, int count)
|
||||
{
|
||||
if ( stream == null ) {
|
||||
throw new ArgumentNullException("stream");
|
||||
}
|
||||
|
||||
if ( buffer == null ) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
// Offset can equal length when buffer and count are 0.
|
||||
if ( (offset < 0) || (offset > buffer.Length) ) {
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
}
|
||||
|
||||
if ( (count < 0) || (offset + count > buffer.Length) ) {
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
}
|
||||
|
||||
while ( count > 0 ) {
|
||||
int readCount = stream.Read(buffer, offset, count);
|
||||
if ( readCount <= 0 ) {
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
offset += readCount;
|
||||
count -= readCount;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the contents of one <see cref="Stream"/> to another.
|
||||
/// </summary>
|
||||
/// <param name="source">The stream to source data from.</param>
|
||||
/// <param name="destination">The stream to write data to.</param>
|
||||
/// <param name="buffer">The buffer to use during copying.</param>
|
||||
static public void Copy(Stream source, Stream destination, byte[] buffer)
|
||||
{
|
||||
if (source == null) {
|
||||
throw new ArgumentNullException("source");
|
||||
}
|
||||
|
||||
if (destination == null) {
|
||||
throw new ArgumentNullException("destination");
|
||||
}
|
||||
|
||||
if (buffer == null) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
// Ensure a reasonable size of buffer is used without being prohibitive.
|
||||
if (buffer.Length < 128) {
|
||||
throw new ArgumentException("Buffer is too small", "buffer");
|
||||
}
|
||||
|
||||
bool copying = true;
|
||||
|
||||
while (copying) {
|
||||
int bytesRead = source.Read(buffer, 0, buffer.Length);
|
||||
if (bytesRead > 0) {
|
||||
destination.Write(buffer, 0, bytesRead);
|
||||
}
|
||||
else {
|
||||
destination.Flush();
|
||||
copying = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the contents of one <see cref="Stream"/> to another.
|
||||
/// </summary>
|
||||
/// <param name="source">The stream to source data from.</param>
|
||||
/// <param name="destination">The stream to write data to.</param>
|
||||
/// <param name="buffer">The buffer to use during copying.</param>
|
||||
/// <param name="progressHandler">The <see cref="ProgressHandler">progress handler delegate</see> to use.</param>
|
||||
/// <param name="updateInterval">The minimum <see cref="TimeSpan"/> between progress updates.</param>
|
||||
/// <param name="sender">The source for this event.</param>
|
||||
/// <param name="name">The name to use with the event.</param>
|
||||
/// <remarks>This form is specialised for use within #Zip to support events during archive operations.</remarks>
|
||||
static public void Copy(Stream source, Stream destination,
|
||||
byte[] buffer, ProgressHandler progressHandler, TimeSpan updateInterval, object sender, string name)
|
||||
{
|
||||
Copy(source, destination, buffer, progressHandler, updateInterval, sender, name, -1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the contents of one <see cref="Stream"/> to another.
|
||||
/// </summary>
|
||||
/// <param name="source">The stream to source data from.</param>
|
||||
/// <param name="destination">The stream to write data to.</param>
|
||||
/// <param name="buffer">The buffer to use during copying.</param>
|
||||
/// <param name="progressHandler">The <see cref="ProgressHandler">progress handler delegate</see> to use.</param>
|
||||
/// <param name="updateInterval">The minimum <see cref="TimeSpan"/> between progress updates.</param>
|
||||
/// <param name="sender">The source for this event.</param>
|
||||
/// <param name="name">The name to use with the event.</param>
|
||||
/// <param name="fixedTarget">A predetermined fixed target value to use with progress updates.
|
||||
/// If the value is negative the target is calculated by looking at the stream.</param>
|
||||
/// <remarks>This form is specialised for use within #Zip to support events during archive operations.</remarks>
|
||||
static public void Copy(Stream source, Stream destination,
|
||||
byte[] buffer,
|
||||
ProgressHandler progressHandler, TimeSpan updateInterval,
|
||||
object sender, string name, long fixedTarget)
|
||||
{
|
||||
if (source == null) {
|
||||
throw new ArgumentNullException("source");
|
||||
}
|
||||
|
||||
if (destination == null) {
|
||||
throw new ArgumentNullException("destination");
|
||||
}
|
||||
|
||||
if (buffer == null) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
// Ensure a reasonable size of buffer is used without being prohibitive.
|
||||
if (buffer.Length < 128) {
|
||||
throw new ArgumentException("Buffer is too small", "buffer");
|
||||
}
|
||||
|
||||
if (progressHandler == null) {
|
||||
throw new ArgumentNullException("progressHandler");
|
||||
}
|
||||
|
||||
bool copying = true;
|
||||
|
||||
DateTime marker = DateTime.Now;
|
||||
long processed = 0;
|
||||
long target = 0;
|
||||
|
||||
if (fixedTarget >= 0) {
|
||||
target = fixedTarget;
|
||||
}
|
||||
else if (source.CanSeek) {
|
||||
target = source.Length - source.Position;
|
||||
}
|
||||
|
||||
// Always fire 0% progress..
|
||||
ProgressEventArgs args = new ProgressEventArgs(name, processed, target);
|
||||
progressHandler(sender, args);
|
||||
|
||||
bool progressFired = true;
|
||||
|
||||
while (copying) {
|
||||
int bytesRead = source.Read(buffer, 0, buffer.Length);
|
||||
if (bytesRead > 0) {
|
||||
processed += bytesRead;
|
||||
progressFired = false;
|
||||
destination.Write(buffer, 0, bytesRead);
|
||||
}
|
||||
else {
|
||||
destination.Flush();
|
||||
copying = false;
|
||||
}
|
||||
|
||||
if (DateTime.Now - marker > updateInterval) {
|
||||
progressFired = true;
|
||||
marker = DateTime.Now;
|
||||
args = new ProgressEventArgs(name, processed, target);
|
||||
progressHandler(sender, args);
|
||||
|
||||
copying = args.ContinueRunning;
|
||||
}
|
||||
}
|
||||
|
||||
if (!progressFired) {
|
||||
args = new ProgressEventArgs(name, processed, target);
|
||||
progressHandler(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise an instance of <see cref="StreamUtils"></see>
|
||||
/// </summary>
|
||||
private StreamUtils()
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
// WindowsPathUtils.cs
|
||||
//
|
||||
// Copyright 2007 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// WindowsPathUtils provides simple utilities for handling windows paths.
|
||||
/// </summary>
|
||||
public abstract class WindowsPathUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WindowsPathUtils"/> class.
|
||||
/// </summary>
|
||||
internal WindowsPathUtils()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove any path root present in the path
|
||||
/// </summary>
|
||||
/// <param name="path">A <see cref="string"/> containing path information.</param>
|
||||
/// <returns>The path with the root removed if it was present; path otherwise.</returns>
|
||||
/// <remarks>Unlike the <see cref="System.IO.Path"/> class the path isnt otherwise checked for validity.</remarks>
|
||||
public static string DropPathRoot(string path)
|
||||
{
|
||||
string result = path;
|
||||
|
||||
if ( (path != null) && (path.Length > 0) ) {
|
||||
if ((path[0] == '\\') || (path[0] == '/')) {
|
||||
// UNC name ?
|
||||
if ((path.Length > 1) && ((path[1] == '\\') || (path[1] == '/'))) {
|
||||
int index = 2;
|
||||
int elements = 2;
|
||||
|
||||
// Scan for two separate elements \\machine\share\restofpath
|
||||
while ((index <= path.Length) &&
|
||||
(((path[index] != '\\') && (path[index] != '/')) || (--elements > 0))) {
|
||||
index++;
|
||||
}
|
||||
|
||||
index++;
|
||||
|
||||
if (index < path.Length) {
|
||||
result = path.Substring(index);
|
||||
}
|
||||
else {
|
||||
result = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((path.Length > 1) && (path[1] == ':')) {
|
||||
int dropCount = 2;
|
||||
if ((path.Length > 2) && ((path[2] == '\\') || (path[2] == '/'))) {
|
||||
dropCount = 3;
|
||||
}
|
||||
result = result.Remove(0, dropCount);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,498 @@
|
|||
//
|
||||
// PkzipClassic encryption
|
||||
//
|
||||
// Copyright 2004 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
//
|
||||
|
||||
|
||||
#if !NETCF_1_0
|
||||
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using ICSharpCode.SharpZipLib.Checksums;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Encryption
|
||||
{
|
||||
/// <summary>
|
||||
/// PkzipClassic embodies the classic or original encryption facilities used in Pkzip archives.
|
||||
/// While it has been superceded by more recent and more powerful algorithms, its still in use and
|
||||
/// is viable for preventing casual snooping
|
||||
/// </summary>
|
||||
public abstract class PkzipClassic : SymmetricAlgorithm
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates new encryption keys based on given seed
|
||||
/// </summary>
|
||||
/// <param name="seed">The seed value to initialise keys with.</param>
|
||||
/// <returns>A new key value.</returns>
|
||||
static public byte[] GenerateKeys(byte[] seed)
|
||||
{
|
||||
if ( seed == null ) {
|
||||
throw new ArgumentNullException("seed");
|
||||
}
|
||||
|
||||
if ( seed.Length == 0 ) {
|
||||
throw new ArgumentException("Length is zero", "seed");
|
||||
}
|
||||
|
||||
uint[] newKeys = new uint[] {
|
||||
0x12345678,
|
||||
0x23456789,
|
||||
0x34567890
|
||||
};
|
||||
|
||||
for (int i = 0; i < seed.Length; ++i) {
|
||||
newKeys[0] = Crc32.ComputeCrc32(newKeys[0], seed[i]);
|
||||
newKeys[1] = newKeys[1] + (byte)newKeys[0];
|
||||
newKeys[1] = newKeys[1] * 134775813 + 1;
|
||||
newKeys[2] = Crc32.ComputeCrc32(newKeys[2], (byte)(newKeys[1] >> 24));
|
||||
}
|
||||
|
||||
byte[] result = new byte[12];
|
||||
result[0] = (byte)(newKeys[0] & 0xff);
|
||||
result[1] = (byte)((newKeys[0] >> 8) & 0xff);
|
||||
result[2] = (byte)((newKeys[0] >> 16) & 0xff);
|
||||
result[3] = (byte)((newKeys[0] >> 24) & 0xff);
|
||||
result[4] = (byte)(newKeys[1] & 0xff);
|
||||
result[5] = (byte)((newKeys[1] >> 8) & 0xff);
|
||||
result[6] = (byte)((newKeys[1] >> 16) & 0xff);
|
||||
result[7] = (byte)((newKeys[1] >> 24) & 0xff);
|
||||
result[8] = (byte)(newKeys[2] & 0xff);
|
||||
result[9] = (byte)((newKeys[2] >> 8) & 0xff);
|
||||
result[10] = (byte)((newKeys[2] >> 16) & 0xff);
|
||||
result[11] = (byte)((newKeys[2] >> 24) & 0xff);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PkzipClassicCryptoBase provides the low level facilities for encryption
|
||||
/// and decryption using the PkzipClassic algorithm.
|
||||
/// </summary>
|
||||
class PkzipClassicCryptoBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Transform a single byte
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The transformed value
|
||||
/// </returns>
|
||||
protected byte TransformByte()
|
||||
{
|
||||
uint temp = ((keys[2] & 0xFFFF) | 2);
|
||||
return (byte)((temp * (temp ^ 1)) >> 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the key schedule for encryption/decryption.
|
||||
/// </summary>
|
||||
/// <param name="keyData">The data use to set the keys from.</param>
|
||||
protected void SetKeys(byte[] keyData)
|
||||
{
|
||||
if ( keyData == null ) {
|
||||
throw new ArgumentNullException("keyData");
|
||||
}
|
||||
|
||||
if ( keyData.Length != 12 ) {
|
||||
throw new InvalidOperationException("Key length is not valid");
|
||||
}
|
||||
|
||||
keys = new uint[3];
|
||||
keys[0] = (uint)((keyData[3] << 24) | (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]);
|
||||
keys[1] = (uint)((keyData[7] << 24) | (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]);
|
||||
keys[2] = (uint)((keyData[11] << 24) | (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update encryption keys
|
||||
/// </summary>
|
||||
protected void UpdateKeys(byte ch)
|
||||
{
|
||||
keys[0] = Crc32.ComputeCrc32(keys[0], ch);
|
||||
keys[1] = keys[1] + (byte)keys[0];
|
||||
keys[1] = keys[1] * 134775813 + 1;
|
||||
keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the internal state.
|
||||
/// </summary>
|
||||
protected void Reset()
|
||||
{
|
||||
keys[0] = 0;
|
||||
keys[1] = 0;
|
||||
keys[2] = 0;
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
uint[] keys;
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PkzipClassic CryptoTransform for encryption.
|
||||
/// </summary>
|
||||
class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="PkzipClassicEncryptCryptoTransform"></see>
|
||||
/// </summary>
|
||||
/// <param name="keyBlock">The key block to use.</param>
|
||||
internal PkzipClassicEncryptCryptoTransform(byte[] keyBlock)
|
||||
{
|
||||
SetKeys(keyBlock);
|
||||
}
|
||||
|
||||
#region ICryptoTransform Members
|
||||
|
||||
/// <summary>
|
||||
/// Transforms the specified region of the specified byte array.
|
||||
/// </summary>
|
||||
/// <param name="inputBuffer">The input for which to compute the transform.</param>
|
||||
/// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
|
||||
/// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
|
||||
/// <returns>The computed transform.</returns>
|
||||
public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
|
||||
{
|
||||
byte[] result = new byte[inputCount];
|
||||
TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms the specified region of the input byte array and copies
|
||||
/// the resulting transform to the specified region of the output byte array.
|
||||
/// </summary>
|
||||
/// <param name="inputBuffer">The input for which to compute the transform.</param>
|
||||
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
|
||||
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
|
||||
/// <param name="outputBuffer">The output to which to write the transform.</param>
|
||||
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
|
||||
/// <returns>The number of bytes written.</returns>
|
||||
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
|
||||
{
|
||||
for (int i = inputOffset; i < inputOffset + inputCount; ++i) {
|
||||
byte oldbyte = inputBuffer[i];
|
||||
outputBuffer[outputOffset++] = (byte)(inputBuffer[i] ^ TransformByte());
|
||||
UpdateKeys(oldbyte);
|
||||
}
|
||||
return inputCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current transform can be reused.
|
||||
/// </summary>
|
||||
public bool CanReuseTransform
|
||||
{
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the input data blocks in bytes.
|
||||
/// </summary>
|
||||
public int InputBlockSize
|
||||
{
|
||||
get {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the output data blocks in bytes.
|
||||
/// </summary>
|
||||
public int OutputBlockSize
|
||||
{
|
||||
get {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether multiple blocks can be transformed.
|
||||
/// </summary>
|
||||
public bool CanTransformMultipleBlocks
|
||||
{
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup internal state.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PkzipClassic CryptoTransform for decryption.
|
||||
/// </summary>
|
||||
class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="PkzipClassicDecryptCryptoTransform"></see>.
|
||||
/// </summary>
|
||||
/// <param name="keyBlock">The key block to decrypt with.</param>
|
||||
internal PkzipClassicDecryptCryptoTransform(byte[] keyBlock)
|
||||
{
|
||||
SetKeys(keyBlock);
|
||||
}
|
||||
|
||||
#region ICryptoTransform Members
|
||||
|
||||
/// <summary>
|
||||
/// Transforms the specified region of the specified byte array.
|
||||
/// </summary>
|
||||
/// <param name="inputBuffer">The input for which to compute the transform.</param>
|
||||
/// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
|
||||
/// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
|
||||
/// <returns>The computed transform.</returns>
|
||||
public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
|
||||
{
|
||||
byte[] result = new byte[inputCount];
|
||||
TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms the specified region of the input byte array and copies
|
||||
/// the resulting transform to the specified region of the output byte array.
|
||||
/// </summary>
|
||||
/// <param name="inputBuffer">The input for which to compute the transform.</param>
|
||||
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
|
||||
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
|
||||
/// <param name="outputBuffer">The output to which to write the transform.</param>
|
||||
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
|
||||
/// <returns>The number of bytes written.</returns>
|
||||
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
|
||||
{
|
||||
for (int i = inputOffset; i < inputOffset + inputCount; ++i) {
|
||||
byte newByte = (byte)(inputBuffer[i] ^ TransformByte());
|
||||
outputBuffer[outputOffset++] = newByte;
|
||||
UpdateKeys(newByte);
|
||||
}
|
||||
return inputCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current transform can be reused.
|
||||
/// </summary>
|
||||
public bool CanReuseTransform
|
||||
{
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the input data blocks in bytes.
|
||||
/// </summary>
|
||||
public int InputBlockSize
|
||||
{
|
||||
get {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the output data blocks in bytes.
|
||||
/// </summary>
|
||||
public int OutputBlockSize
|
||||
{
|
||||
get {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether multiple blocks can be transformed.
|
||||
/// </summary>
|
||||
public bool CanTransformMultipleBlocks
|
||||
{
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup internal state.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines a wrapper object to access the Pkzip algorithm.
|
||||
/// This class cannot be inherited.
|
||||
/// </summary>
|
||||
public sealed class PkzipClassicManaged : PkzipClassic
|
||||
{
|
||||
/// <summary>
|
||||
/// Get / set the applicable block size in bits.
|
||||
/// </summary>
|
||||
/// <remarks>The only valid block size is 8.</remarks>
|
||||
public override int BlockSize
|
||||
{
|
||||
get {
|
||||
return 8;
|
||||
}
|
||||
|
||||
set {
|
||||
if (value != 8) {
|
||||
throw new CryptographicException("Block size is invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an array of legal <see cref="KeySizes">key sizes.</see>
|
||||
/// </summary>
|
||||
public override KeySizes[] LegalKeySizes
|
||||
{
|
||||
get {
|
||||
KeySizes[] keySizes = new KeySizes[1];
|
||||
keySizes[0] = new KeySizes(12 * 8, 12 * 8, 0);
|
||||
return keySizes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate an initial vector.
|
||||
/// </summary>
|
||||
public override void GenerateIV()
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an array of legal <see cref="KeySizes">block sizes</see>.
|
||||
/// </summary>
|
||||
public override KeySizes[] LegalBlockSizes
|
||||
{
|
||||
get {
|
||||
KeySizes[] keySizes = new KeySizes[1];
|
||||
keySizes[0] = new KeySizes(1 * 8, 1 * 8, 0);
|
||||
return keySizes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get / set the key value applicable.
|
||||
/// </summary>
|
||||
public override byte[] Key
|
||||
{
|
||||
get {
|
||||
if ( key_ == null ) {
|
||||
GenerateKey();
|
||||
}
|
||||
|
||||
return (byte[]) key_.Clone();
|
||||
}
|
||||
|
||||
set {
|
||||
if ( value == null ) {
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
if ( value.Length != 12 ) {
|
||||
throw new CryptographicException("Key size is illegal");
|
||||
}
|
||||
|
||||
key_ = (byte[]) value.Clone();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a new random key.
|
||||
/// </summary>
|
||||
public override void GenerateKey()
|
||||
{
|
||||
key_ = new byte[12];
|
||||
Random rnd = new Random();
|
||||
rnd.NextBytes(key_);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an encryptor.
|
||||
/// </summary>
|
||||
/// <param name="rgbKey">The key to use for this encryptor.</param>
|
||||
/// <param name="rgbIV">Initialisation vector for the new encryptor.</param>
|
||||
/// <returns>Returns a new PkzipClassic encryptor</returns>
|
||||
public override ICryptoTransform CreateEncryptor(
|
||||
byte[] rgbKey,
|
||||
byte[] rgbIV)
|
||||
{
|
||||
key_ = rgbKey;
|
||||
return new PkzipClassicEncryptCryptoTransform(Key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a decryptor.
|
||||
/// </summary>
|
||||
/// <param name="rgbKey">Keys to use for this new decryptor.</param>
|
||||
/// <param name="rgbIV">Initialisation vector for the new decryptor.</param>
|
||||
/// <returns>Returns a new decryptor.</returns>
|
||||
public override ICryptoTransform CreateDecryptor(
|
||||
byte[] rgbKey,
|
||||
byte[] rgbIV)
|
||||
{
|
||||
key_ = rgbKey;
|
||||
return new PkzipClassicDecryptCryptoTransform(Key);
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
byte[] key_;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,170 @@
|
|||
//
|
||||
// ZipAESStream.cs
|
||||
//
|
||||
// Copyright 2009 David Pierson
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
//
|
||||
|
||||
#if !NET_1_1 && !NETCF_2_0
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Encryption {
|
||||
|
||||
// Based on information from http://www.winzip.com/aes_info.htm
|
||||
// and http://www.gladman.me.uk/cryptography_technology/fileencrypt/
|
||||
|
||||
/// <summary>
|
||||
/// Encrypts and decrypts AES ZIP
|
||||
/// </summary>
|
||||
internal class ZipAESStream : CryptoStream {
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream on which to perform the cryptographic transformation.</param>
|
||||
/// <param name="transform">Instance of ZipAESTransform</param>
|
||||
/// <param name="mode">Read or Write</param>
|
||||
public ZipAESStream(Stream stream, ZipAESTransform transform, CryptoStreamMode mode)
|
||||
: base(stream, transform, mode) {
|
||||
|
||||
_stream = stream;
|
||||
_transform = transform;
|
||||
_slideBuffer = new byte[1024];
|
||||
|
||||
_blockAndAuth = CRYPTO_BLOCK_SIZE + AUTH_CODE_LENGTH;
|
||||
|
||||
// mode:
|
||||
// CryptoStreamMode.Read means we read from "stream" and pass decrypted to our Read() method.
|
||||
// Write bypasses this stream and uses the Transform directly.
|
||||
if (mode != CryptoStreamMode.Read) {
|
||||
throw new Exception("ZipAESStream only for read");
|
||||
}
|
||||
}
|
||||
|
||||
// The final n bytes of the AES stream contain the Auth Code.
|
||||
private const int AUTH_CODE_LENGTH = 10;
|
||||
|
||||
private Stream _stream;
|
||||
private ZipAESTransform _transform;
|
||||
private byte[] _slideBuffer;
|
||||
private int _slideBufStartPos;
|
||||
private int _slideBufFreePos;
|
||||
// Blocksize is always 16 here, even for AES-256 which has transform.InputBlockSize of 32.
|
||||
private const int CRYPTO_BLOCK_SIZE = 16;
|
||||
private int _blockAndAuth;
|
||||
|
||||
/// <summary>
|
||||
/// Reads a sequence of bytes from the current CryptoStream into buffer,
|
||||
/// and advances the position within the stream by the number of bytes read.
|
||||
/// </summary>
|
||||
public override int Read(byte[] outBuffer, int offset, int count) {
|
||||
int nBytes = 0;
|
||||
while (nBytes < count) {
|
||||
// Calculate buffer quantities vs read-ahead size, and check for sufficient free space
|
||||
int byteCount = _slideBufFreePos - _slideBufStartPos;
|
||||
|
||||
// Need to handle final block and Auth Code specially, but don't know total data length.
|
||||
// Maintain a read-ahead equal to the length of (crypto block + Auth Code).
|
||||
// When that runs out we can detect these final sections.
|
||||
int lengthToRead = _blockAndAuth - byteCount;
|
||||
if (_slideBuffer.Length - _slideBufFreePos < lengthToRead) {
|
||||
// Shift the data to the beginning of the buffer
|
||||
int iTo = 0;
|
||||
for (int iFrom = _slideBufStartPos; iFrom < _slideBufFreePos; iFrom++, iTo++) {
|
||||
_slideBuffer[iTo] = _slideBuffer[iFrom];
|
||||
}
|
||||
_slideBufFreePos -= _slideBufStartPos; // Note the -=
|
||||
_slideBufStartPos = 0;
|
||||
}
|
||||
int obtained = _stream.Read(_slideBuffer, _slideBufFreePos, lengthToRead);
|
||||
_slideBufFreePos += obtained;
|
||||
|
||||
// Recalculate how much data we now have
|
||||
byteCount = _slideBufFreePos - _slideBufStartPos;
|
||||
if (byteCount >= _blockAndAuth) {
|
||||
// At least a 16 byte block and an auth code remains.
|
||||
_transform.TransformBlock(_slideBuffer,
|
||||
_slideBufStartPos,
|
||||
CRYPTO_BLOCK_SIZE,
|
||||
outBuffer,
|
||||
offset);
|
||||
nBytes += CRYPTO_BLOCK_SIZE;
|
||||
offset += CRYPTO_BLOCK_SIZE;
|
||||
_slideBufStartPos += CRYPTO_BLOCK_SIZE;
|
||||
} else {
|
||||
// Last round.
|
||||
if (byteCount > AUTH_CODE_LENGTH) {
|
||||
// At least one byte of data plus auth code
|
||||
int finalBlock = byteCount - AUTH_CODE_LENGTH;
|
||||
_transform.TransformBlock(_slideBuffer,
|
||||
_slideBufStartPos,
|
||||
finalBlock,
|
||||
outBuffer,
|
||||
offset);
|
||||
|
||||
nBytes += finalBlock;
|
||||
_slideBufStartPos += finalBlock;
|
||||
}
|
||||
else if (byteCount < AUTH_CODE_LENGTH)
|
||||
throw new Exception("Internal error missed auth code"); // Coding bug
|
||||
// Final block done. Check Auth code.
|
||||
byte[] calcAuthCode = _transform.GetAuthCode();
|
||||
for (int i = 0; i < AUTH_CODE_LENGTH; i++) {
|
||||
if (calcAuthCode[i] != _slideBuffer[_slideBufStartPos + i]) {
|
||||
throw new Exception("AES Authentication Code does not match. This is a super-CRC check on the data in the file after compression and encryption. \r\n"
|
||||
+ "The file may be damaged.");
|
||||
}
|
||||
}
|
||||
|
||||
break; // Reached the auth code
|
||||
}
|
||||
}
|
||||
return nBytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
|
||||
/// </summary>
|
||||
/// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream. </param>
|
||||
/// <param name="offset">The byte offset in buffer at which to begin copying bytes to the current stream. </param>
|
||||
/// <param name="count">The number of bytes to be written to the current stream. </param>
|
||||
public override void Write(byte[] buffer, int offset, int count) {
|
||||
// ZipAESStream is used for reading but not for writing. Writing uses the ZipAESTransform directly.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,219 @@
|
|||
//
|
||||
// ZipAESTransform.cs
|
||||
//
|
||||
// Copyright 2009 David Pierson
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
//
|
||||
|
||||
#if !NET_1_1 && !NETCF_2_0
|
||||
// Framework version 2.0 required for Rfc2898DeriveBytes
|
||||
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Encryption {
|
||||
|
||||
/// <summary>
|
||||
/// Transforms stream using AES in CTR mode
|
||||
/// </summary>
|
||||
internal class ZipAESTransform : ICryptoTransform {
|
||||
|
||||
private const int PWD_VER_LENGTH = 2;
|
||||
|
||||
// WinZip use iteration count of 1000 for PBKDF2 key generation
|
||||
private const int KEY_ROUNDS = 1000;
|
||||
|
||||
// For 128-bit AES (16 bytes) the encryption is implemented as expected.
|
||||
// For 256-bit AES (32 bytes) WinZip do full 256 bit AES of the nonce to create the encryption
|
||||
// block but use only the first 16 bytes of it, and discard the second half.
|
||||
private const int ENCRYPT_BLOCK = 16;
|
||||
|
||||
private int _blockSize;
|
||||
private ICryptoTransform _encryptor;
|
||||
private readonly byte[] _counterNonce;
|
||||
private byte[] _encryptBuffer;
|
||||
private int _encrPos;
|
||||
private byte[] _pwdVerifier;
|
||||
private HMACSHA1 _hmacsha1;
|
||||
private bool _finalised;
|
||||
|
||||
private bool _writeMode;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="key">Password string</param>
|
||||
/// <param name="saltBytes">Random bytes, length depends on encryption strength.
|
||||
/// 128 bits = 8 bytes, 192 bits = 12 bytes, 256 bits = 16 bytes.</param>
|
||||
/// <param name="blockSize">The encryption strength, in bytes eg 16 for 128 bits.</param>
|
||||
/// <param name="writeMode">True when creating a zip, false when reading. For the AuthCode.</param>
|
||||
///
|
||||
public ZipAESTransform(string key, byte[] saltBytes, int blockSize, bool writeMode) {
|
||||
|
||||
if (blockSize != 16 && blockSize != 32) // 24 valid for AES but not supported by Winzip
|
||||
throw new Exception("Invalid blocksize " + blockSize + ". Must be 16 or 32.");
|
||||
if (saltBytes.Length != blockSize / 2)
|
||||
throw new Exception("Invalid salt len. Must be " + blockSize / 2 + " for blocksize " + blockSize);
|
||||
// initialise the encryption buffer and buffer pos
|
||||
_blockSize = blockSize;
|
||||
_encryptBuffer = new byte[_blockSize];
|
||||
_encrPos = ENCRYPT_BLOCK;
|
||||
|
||||
// Performs the equivalent of derive_key in Dr Brian Gladman's pwd2key.c
|
||||
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(key, saltBytes, KEY_ROUNDS);
|
||||
RijndaelManaged rm = new RijndaelManaged();
|
||||
rm.Mode = CipherMode.ECB; // No feedback from cipher for CTR mode
|
||||
_counterNonce = new byte[_blockSize];
|
||||
byte[] byteKey1 = pdb.GetBytes(_blockSize);
|
||||
byte[] byteKey2 = pdb.GetBytes(_blockSize);
|
||||
_encryptor = rm.CreateEncryptor(byteKey1, byteKey2);
|
||||
_pwdVerifier = pdb.GetBytes(PWD_VER_LENGTH);
|
||||
//
|
||||
_hmacsha1 = new HMACSHA1(byteKey2);
|
||||
_writeMode = writeMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement the ICryptoTransform method.
|
||||
/// </summary>
|
||||
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) {
|
||||
|
||||
// Pass the data stream to the hash algorithm for generating the Auth Code.
|
||||
// This does not change the inputBuffer. Do this before decryption for read mode.
|
||||
if (!_writeMode) {
|
||||
_hmacsha1.TransformBlock(inputBuffer, inputOffset, inputCount, inputBuffer, inputOffset);
|
||||
}
|
||||
// Encrypt with AES in CTR mode. Regards to Dr Brian Gladman for this.
|
||||
int ix = 0;
|
||||
while (ix < inputCount) {
|
||||
if (_encrPos == ENCRYPT_BLOCK) {
|
||||
/* increment encryption nonce */
|
||||
int j = 0;
|
||||
while (++_counterNonce[j] == 0) {
|
||||
++j;
|
||||
}
|
||||
/* encrypt the nonce to form next xor buffer */
|
||||
_encryptor.TransformBlock(_counterNonce, 0, _blockSize, _encryptBuffer, 0);
|
||||
_encrPos = 0;
|
||||
}
|
||||
outputBuffer[ix + outputOffset] = (byte)(inputBuffer[ix + inputOffset] ^ _encryptBuffer[_encrPos++]);
|
||||
//
|
||||
ix++;
|
||||
}
|
||||
if (_writeMode) {
|
||||
// This does not change the buffer.
|
||||
_hmacsha1.TransformBlock(outputBuffer, outputOffset, inputCount, outputBuffer, outputOffset);
|
||||
}
|
||||
return inputCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the 2 byte password verifier
|
||||
/// </summary>
|
||||
public byte[] PwdVerifier {
|
||||
get {
|
||||
return _pwdVerifier;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the 10 byte AUTH CODE to be checked or appended immediately following the AES data stream.
|
||||
/// </summary>
|
||||
public byte[] GetAuthCode() {
|
||||
// We usually don't get advance notice of final block. Hash requres a TransformFinal.
|
||||
if (!_finalised) {
|
||||
byte[] dummy = new byte[0];
|
||||
_hmacsha1.TransformFinalBlock(dummy, 0, 0);
|
||||
_finalised = true;
|
||||
}
|
||||
return _hmacsha1.Hash;
|
||||
}
|
||||
|
||||
#region ICryptoTransform Members
|
||||
|
||||
/// <summary>
|
||||
/// Not implemented.
|
||||
/// </summary>
|
||||
public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) {
|
||||
|
||||
throw new NotImplementedException("ZipAESTransform.TransformFinalBlock");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the input data blocks in bytes.
|
||||
/// </summary>
|
||||
public int InputBlockSize {
|
||||
get {
|
||||
return _blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the output data blocks in bytes.
|
||||
/// </summary>
|
||||
public int OutputBlockSize {
|
||||
get {
|
||||
return _blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether multiple blocks can be transformed.
|
||||
/// </summary>
|
||||
public bool CanTransformMultipleBlocks {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current transform can be reused.
|
||||
/// </summary>
|
||||
public bool CanReuseTransform {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup internal state.
|
||||
/// </summary>
|
||||
public void Dispose() {
|
||||
_encryptor.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,97 @@
|
|||
// GZipConstants.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.GZip
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This class contains constants used for gzip.
|
||||
/// </summary>
|
||||
sealed public class GZipConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// Magic number found at start of GZIP header
|
||||
/// </summary>
|
||||
public const int GZIP_MAGIC = 0x1F8B;
|
||||
|
||||
/* The flag byte is divided into individual bits as follows:
|
||||
|
||||
bit 0 FTEXT
|
||||
bit 1 FHCRC
|
||||
bit 2 FEXTRA
|
||||
bit 3 FNAME
|
||||
bit 4 FCOMMENT
|
||||
bit 5 reserved
|
||||
bit 6 reserved
|
||||
bit 7 reserved
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Flag bit mask for text
|
||||
/// </summary>
|
||||
public const int FTEXT = 0x1;
|
||||
|
||||
/// <summary>
|
||||
/// Flag bitmask for Crc
|
||||
/// </summary>
|
||||
public const int FHCRC = 0x2;
|
||||
|
||||
/// <summary>
|
||||
/// Flag bit mask for extra
|
||||
/// </summary>
|
||||
public const int FEXTRA = 0x4;
|
||||
|
||||
/// <summary>
|
||||
/// flag bitmask for name
|
||||
/// </summary>
|
||||
public const int FNAME = 0x8;
|
||||
|
||||
/// <summary>
|
||||
/// flag bit mask indicating comment is present
|
||||
/// </summary>
|
||||
public const int FCOMMENT = 0x10;
|
||||
|
||||
/// <summary>
|
||||
/// Initialise default instance.
|
||||
/// </summary>
|
||||
/// <remarks>Constructor is private to prevent instances being created.</remarks>
|
||||
GZipConstants()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
// GZipException.cs
|
||||
//
|
||||
// Copyright 2004 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
using System.Runtime.Serialization;
|
||||
#endif
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.GZip
|
||||
{
|
||||
/// <summary>
|
||||
/// GZipException represents a Gzip specific exception
|
||||
/// </summary>
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
[Serializable]
|
||||
#endif
|
||||
public class GZipException : SharpZipBaseException
|
||||
{
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
/// <summary>
|
||||
/// Deserialization constructor
|
||||
/// </summary>
|
||||
/// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>
|
||||
/// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
|
||||
protected GZipException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of GZipException
|
||||
/// </summary>
|
||||
public GZipException()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of GZipException with its message string.
|
||||
/// </summary>
|
||||
/// <param name="message">A <see cref="string"/> that describes the error.</param>
|
||||
public GZipException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="GZipException"></see>.
|
||||
/// </summary>
|
||||
/// <param name="message">A <see cref="string"/> that describes the error.</param>
|
||||
/// <param name="innerException">The <see cref="Exception"/> that caused this exception.</param>
|
||||
public GZipException(string message, Exception innerException)
|
||||
: base (message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,384 @@
|
|||
// GzipInputStream.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
// HISTORY
|
||||
// 11-08-2009 GeoffHart T9121 Added Multi-member gzip support
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using ICSharpCode.SharpZipLib.Checksums;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.GZip
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This filter stream is used to decompress a "GZIP" format stream.
|
||||
/// The "GZIP" format is described baseInputStream RFC 1952.
|
||||
///
|
||||
/// author of the original java version : John Leuner
|
||||
/// </summary>
|
||||
/// <example> This sample shows how to unzip a gzipped file
|
||||
/// <code>
|
||||
/// using System;
|
||||
/// using System.IO;
|
||||
///
|
||||
/// using ICSharpCode.SharpZipLib.Core;
|
||||
/// using ICSharpCode.SharpZipLib.GZip;
|
||||
///
|
||||
/// class MainClass
|
||||
/// {
|
||||
/// public static void Main(string[] args)
|
||||
/// {
|
||||
/// using (Stream inStream = new GZipInputStream(File.OpenRead(args[0])))
|
||||
/// using (FileStream outStream = File.Create(Path.GetFileNameWithoutExtension(args[0]))) {
|
||||
/// byte[] buffer = new byte[4096];
|
||||
/// StreamUtils.Copy(inStream, outStream, buffer);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class GZipInputStream : InflaterInputStream
|
||||
{
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// CRC-32 value for uncompressed data
|
||||
/// </summary>
|
||||
protected Crc32 crc;
|
||||
|
||||
/// <summary>
|
||||
/// Flag to indicate if we've read the GZIP header yet for the current member (block of compressed data).
|
||||
/// This is tracked per-block as the file is parsed.
|
||||
/// </summary>
|
||||
bool readGZIPHeader;
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Creates a GZipInputStream with the default buffer size
|
||||
/// </summary>
|
||||
/// <param name="baseInputStream">
|
||||
/// The stream to read compressed data from (baseInputStream GZIP format)
|
||||
/// </param>
|
||||
public GZipInputStream(Stream baseInputStream)
|
||||
: this(baseInputStream, 4096)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a GZIPInputStream with the specified buffer size
|
||||
/// </summary>
|
||||
/// <param name="baseInputStream">
|
||||
/// The stream to read compressed data from (baseInputStream GZIP format)
|
||||
/// </param>
|
||||
/// <param name="size">
|
||||
/// Size of the buffer to use
|
||||
/// </param>
|
||||
public GZipInputStream(Stream baseInputStream, int size)
|
||||
: base(baseInputStream, new Inflater(true), size)
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Stream overrides
|
||||
/// <summary>
|
||||
/// Reads uncompressed data into an array of bytes
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// The buffer to read uncompressed data into
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// The offset indicating where the data should be placed
|
||||
/// </param>
|
||||
/// <param name="count">
|
||||
/// The number of uncompressed bytes to be read
|
||||
/// </param>
|
||||
/// <returns>Returns the number of bytes actually read.</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
// A GZIP file can contain multiple blocks of compressed data, although this is quite rare.
|
||||
// A compressed block could potentially be empty, so we need to loop until we reach EOF or
|
||||
// we find data.
|
||||
while (true) {
|
||||
|
||||
// If we haven't read the header for this block, read it
|
||||
if (! readGZIPHeader) {
|
||||
|
||||
// Try to read header. If there is no header (0 bytes available), this is EOF. If there is
|
||||
// an incomplete header, this will throw an exception.
|
||||
if (! ReadHeader()) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to read compressed data
|
||||
int bytesRead = base.Read(buffer, offset, count);
|
||||
if (bytesRead > 0) {
|
||||
crc.Update(buffer, offset, bytesRead);
|
||||
}
|
||||
|
||||
// If this is the end of stream, read the footer
|
||||
if (inf.IsFinished) {
|
||||
ReadFooter();
|
||||
}
|
||||
|
||||
if (bytesRead > 0) {
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Support routines
|
||||
bool ReadHeader()
|
||||
{
|
||||
// Initialize CRC for this block
|
||||
crc = new Crc32();
|
||||
|
||||
// Make sure there is data in file. We can't rely on ReadLeByte() to fill the buffer, as this could be EOF,
|
||||
// which is fine, but ReadLeByte() throws an exception if it doesn't find data, so we do this part ourselves.
|
||||
if (inputBuffer.Available <= 0) {
|
||||
inputBuffer.Fill();
|
||||
if (inputBuffer.Available <= 0) {
|
||||
// No header, EOF.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Check the two magic bytes
|
||||
Crc32 headCRC = new Crc32();
|
||||
int magic = inputBuffer.ReadLeByte();
|
||||
|
||||
if (magic < 0) {
|
||||
throw new EndOfStreamException("EOS reading GZIP header");
|
||||
}
|
||||
|
||||
headCRC.Update(magic);
|
||||
if (magic != (GZipConstants.GZIP_MAGIC >> 8)) {
|
||||
throw new GZipException("Error GZIP header, first magic byte doesn't match");
|
||||
}
|
||||
|
||||
//magic = baseInputStream.ReadByte();
|
||||
magic = inputBuffer.ReadLeByte();
|
||||
|
||||
if (magic < 0) {
|
||||
throw new EndOfStreamException("EOS reading GZIP header");
|
||||
}
|
||||
|
||||
if (magic != (GZipConstants.GZIP_MAGIC & 0xFF)) {
|
||||
throw new GZipException("Error GZIP header, second magic byte doesn't match");
|
||||
}
|
||||
|
||||
headCRC.Update(magic);
|
||||
|
||||
// 2. Check the compression type (must be 8)
|
||||
int compressionType = inputBuffer.ReadLeByte();
|
||||
|
||||
if ( compressionType < 0 ) {
|
||||
throw new EndOfStreamException("EOS reading GZIP header");
|
||||
}
|
||||
|
||||
if ( compressionType != 8 ) {
|
||||
throw new GZipException("Error GZIP header, data not in deflate format");
|
||||
}
|
||||
headCRC.Update(compressionType);
|
||||
|
||||
// 3. Check the flags
|
||||
int flags = inputBuffer.ReadLeByte();
|
||||
if (flags < 0) {
|
||||
throw new EndOfStreamException("EOS reading GZIP header");
|
||||
}
|
||||
headCRC.Update(flags);
|
||||
|
||||
/* This flag byte is divided into individual bits as follows:
|
||||
|
||||
bit 0 FTEXT
|
||||
bit 1 FHCRC
|
||||
bit 2 FEXTRA
|
||||
bit 3 FNAME
|
||||
bit 4 FCOMMENT
|
||||
bit 5 reserved
|
||||
bit 6 reserved
|
||||
bit 7 reserved
|
||||
*/
|
||||
|
||||
// 3.1 Check the reserved bits are zero
|
||||
|
||||
if ((flags & 0xE0) != 0) {
|
||||
throw new GZipException("Reserved flag bits in GZIP header != 0");
|
||||
}
|
||||
|
||||
// 4.-6. Skip the modification time, extra flags, and OS type
|
||||
for (int i=0; i< 6; i++) {
|
||||
int readByte = inputBuffer.ReadLeByte();
|
||||
if (readByte < 0) {
|
||||
throw new EndOfStreamException("EOS reading GZIP header");
|
||||
}
|
||||
headCRC.Update(readByte);
|
||||
}
|
||||
|
||||
// 7. Read extra field
|
||||
if ((flags & GZipConstants.FEXTRA) != 0) {
|
||||
// Skip subfield id
|
||||
for (int i=0; i< 2; i++) {
|
||||
int readByte = inputBuffer.ReadLeByte();
|
||||
if (readByte < 0) {
|
||||
throw new EndOfStreamException("EOS reading GZIP header");
|
||||
}
|
||||
headCRC.Update(readByte);
|
||||
}
|
||||
|
||||
if (inputBuffer.ReadLeByte() < 0 || inputBuffer.ReadLeByte() < 0) {
|
||||
throw new EndOfStreamException("EOS reading GZIP header");
|
||||
}
|
||||
|
||||
int len1, len2;
|
||||
len1 = inputBuffer.ReadLeByte();
|
||||
len2 = inputBuffer.ReadLeByte();
|
||||
if ((len1 < 0) || (len2 < 0)) {
|
||||
throw new EndOfStreamException("EOS reading GZIP header");
|
||||
}
|
||||
headCRC.Update(len1);
|
||||
headCRC.Update(len2);
|
||||
|
||||
int extraLen = (len1 << 8) | len2;
|
||||
for (int i = 0; i < extraLen;i++) {
|
||||
int readByte = inputBuffer.ReadLeByte();
|
||||
if (readByte < 0)
|
||||
{
|
||||
throw new EndOfStreamException("EOS reading GZIP header");
|
||||
}
|
||||
headCRC.Update(readByte);
|
||||
}
|
||||
}
|
||||
|
||||
// 8. Read file name
|
||||
if ((flags & GZipConstants.FNAME) != 0) {
|
||||
int readByte;
|
||||
while ( (readByte = inputBuffer.ReadLeByte()) > 0) {
|
||||
headCRC.Update(readByte);
|
||||
}
|
||||
|
||||
if (readByte < 0) {
|
||||
throw new EndOfStreamException("EOS reading GZIP header");
|
||||
}
|
||||
headCRC.Update(readByte);
|
||||
}
|
||||
|
||||
// 9. Read comment
|
||||
if ((flags & GZipConstants.FCOMMENT) != 0) {
|
||||
int readByte;
|
||||
while ( (readByte = inputBuffer.ReadLeByte()) > 0) {
|
||||
headCRC.Update(readByte);
|
||||
}
|
||||
|
||||
if (readByte < 0) {
|
||||
throw new EndOfStreamException("EOS reading GZIP header");
|
||||
}
|
||||
|
||||
headCRC.Update(readByte);
|
||||
}
|
||||
|
||||
// 10. Read header CRC
|
||||
if ((flags & GZipConstants.FHCRC) != 0) {
|
||||
int tempByte;
|
||||
int crcval = inputBuffer.ReadLeByte();
|
||||
if (crcval < 0) {
|
||||
throw new EndOfStreamException("EOS reading GZIP header");
|
||||
}
|
||||
|
||||
tempByte = inputBuffer.ReadLeByte();
|
||||
if (tempByte < 0) {
|
||||
throw new EndOfStreamException("EOS reading GZIP header");
|
||||
}
|
||||
|
||||
crcval = (crcval << 8) | tempByte;
|
||||
if (crcval != ((int) headCRC.Value & 0xffff)) {
|
||||
throw new GZipException("Header CRC value mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
readGZIPHeader = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReadFooter()
|
||||
{
|
||||
byte[] footer = new byte[8];
|
||||
|
||||
// End of stream; reclaim all bytes from inf, read the final byte count, and reset the inflator
|
||||
long bytesRead = inf.TotalOut & 0xffffffff;
|
||||
inputBuffer.Available += inf.RemainingInput;
|
||||
inf.Reset();
|
||||
|
||||
// Read footer from inputBuffer
|
||||
int needed = 8;
|
||||
while (needed > 0) {
|
||||
int count = inputBuffer.ReadClearTextBuffer(footer, 8 - needed, needed);
|
||||
if (count <= 0) {
|
||||
throw new EndOfStreamException("EOS reading GZIP footer");
|
||||
}
|
||||
needed -= count; // Jewel Jan 16
|
||||
}
|
||||
|
||||
// Calculate CRC
|
||||
int crcval = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8) | ((footer[2] & 0xff) << 16) | (footer[3] << 24);
|
||||
if (crcval != (int) crc.Value) {
|
||||
throw new GZipException("GZIP crc sum mismatch, theirs \"" + crcval + "\" and ours \"" + (int) crc.Value);
|
||||
}
|
||||
|
||||
// NOTE The total here is the original total modulo 2 ^ 32.
|
||||
uint total =
|
||||
(uint)((uint)footer[4] & 0xff) |
|
||||
(uint)(((uint)footer[5] & 0xff) << 8) |
|
||||
(uint)(((uint)footer[6] & 0xff) << 16) |
|
||||
(uint)((uint)footer[7] << 24);
|
||||
|
||||
if (bytesRead != total) {
|
||||
throw new GZipException("Number of bytes mismatch in footer");
|
||||
}
|
||||
|
||||
// Mark header read as false so if another header exists, we'll continue reading through the file
|
||||
readGZIPHeader = false;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
// GZipOutputStream.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using ICSharpCode.SharpZipLib.Checksums;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.GZip
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This filter stream is used to compress a stream into a "GZIP" stream.
|
||||
/// The "GZIP" format is described in RFC 1952.
|
||||
///
|
||||
/// author of the original java version : John Leuner
|
||||
/// </summary>
|
||||
/// <example> This sample shows how to gzip a file
|
||||
/// <code>
|
||||
/// using System;
|
||||
/// using System.IO;
|
||||
///
|
||||
/// using ICSharpCode.SharpZipLib.GZip;
|
||||
/// using ICSharpCode.SharpZipLib.Core;
|
||||
///
|
||||
/// class MainClass
|
||||
/// {
|
||||
/// public static void Main(string[] args)
|
||||
/// {
|
||||
/// using (Stream s = new GZipOutputStream(File.Create(args[0] + ".gz")))
|
||||
/// using (FileStream fs = File.OpenRead(args[0])) {
|
||||
/// byte[] writeData = new byte[4096];
|
||||
/// Streamutils.Copy(s, fs, writeData);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class GZipOutputStream : DeflaterOutputStream
|
||||
{
|
||||
enum OutputState
|
||||
{
|
||||
Header,
|
||||
Footer,
|
||||
Finished,
|
||||
Closed,
|
||||
};
|
||||
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// CRC-32 value for uncompressed data
|
||||
/// </summary>
|
||||
protected Crc32 crc = new Crc32();
|
||||
OutputState state_ = OutputState.Header;
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Creates a GzipOutputStream with the default buffer size
|
||||
/// </summary>
|
||||
/// <param name="baseOutputStream">
|
||||
/// The stream to read data (to be compressed) from
|
||||
/// </param>
|
||||
public GZipOutputStream(Stream baseOutputStream)
|
||||
: this(baseOutputStream, 4096)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a GZipOutputStream with the specified buffer size
|
||||
/// </summary>
|
||||
/// <param name="baseOutputStream">
|
||||
/// The stream to read data (to be compressed) from
|
||||
/// </param>
|
||||
/// <param name="size">
|
||||
/// Size of the buffer to use
|
||||
/// </param>
|
||||
public GZipOutputStream(Stream baseOutputStream, int size) : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true), size)
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public API
|
||||
/// <summary>
|
||||
/// Sets the active compression level (1-9). The new level will be activated
|
||||
/// immediately.
|
||||
/// </summary>
|
||||
/// <param name="level">The compression level to set.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Level specified is not supported.
|
||||
/// </exception>
|
||||
/// <see cref="Deflater"/>
|
||||
public void SetLevel(int level)
|
||||
{
|
||||
if (level < Deflater.BEST_SPEED) {
|
||||
throw new ArgumentOutOfRangeException("level");
|
||||
}
|
||||
deflater_.SetLevel(level);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current compression level.
|
||||
/// </summary>
|
||||
/// <returns>The current compression level.</returns>
|
||||
public int GetLevel()
|
||||
{
|
||||
return deflater_.GetLevel();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Stream overrides
|
||||
/// <summary>
|
||||
/// Write given buffer to output updating crc
|
||||
/// </summary>
|
||||
/// <param name="buffer">Buffer to write</param>
|
||||
/// <param name="offset">Offset of first byte in buf to write</param>
|
||||
/// <param name="count">Number of bytes to write</param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if ( state_ == OutputState.Header ) {
|
||||
WriteHeader();
|
||||
}
|
||||
|
||||
if( state_!=OutputState.Footer )
|
||||
{
|
||||
throw new InvalidOperationException("Write not permitted in current state");
|
||||
}
|
||||
|
||||
crc.Update(buffer, offset, count);
|
||||
base.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes remaining compressed output data to the output stream
|
||||
/// and closes it.
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
try {
|
||||
Finish();
|
||||
}
|
||||
finally {
|
||||
if ( state_ != OutputState.Closed ) {
|
||||
state_ = OutputState.Closed;
|
||||
if( IsStreamOwner ) {
|
||||
baseOutputStream_.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region DeflaterOutputStream overrides
|
||||
/// <summary>
|
||||
/// Finish compression and write any footer information required to stream
|
||||
/// </summary>
|
||||
public override void Finish()
|
||||
{
|
||||
// If no data has been written a header should be added.
|
||||
if ( state_ == OutputState.Header ) {
|
||||
WriteHeader();
|
||||
}
|
||||
|
||||
if( state_ == OutputState.Footer)
|
||||
{
|
||||
state_=OutputState.Finished;
|
||||
base.Finish();
|
||||
|
||||
uint totalin=(uint)(deflater_.TotalIn&0xffffffff);
|
||||
uint crcval=(uint)(crc.Value&0xffffffff);
|
||||
|
||||
byte[] gzipFooter;
|
||||
|
||||
unchecked
|
||||
{
|
||||
gzipFooter=new byte[] {
|
||||
(byte) crcval, (byte) (crcval >> 8),
|
||||
(byte) (crcval >> 16), (byte) (crcval >> 24),
|
||||
|
||||
(byte) totalin, (byte) (totalin >> 8),
|
||||
(byte) (totalin >> 16), (byte) (totalin >> 24)
|
||||
};
|
||||
}
|
||||
|
||||
baseOutputStream_.Write(gzipFooter, 0, gzipFooter.Length);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Support Routines
|
||||
void WriteHeader()
|
||||
{
|
||||
if ( state_ == OutputState.Header )
|
||||
{
|
||||
state_=OutputState.Footer;
|
||||
|
||||
int mod_time = (int)((DateTime.Now.Ticks - new DateTime(1970, 1, 1).Ticks) / 10000000L); // Ticks give back 100ns intervals
|
||||
byte[] gzipHeader = {
|
||||
// The two magic bytes
|
||||
(byte) (GZipConstants.GZIP_MAGIC >> 8), (byte) (GZipConstants.GZIP_MAGIC & 0xff),
|
||||
|
||||
// The compression type
|
||||
(byte) Deflater.DEFLATED,
|
||||
|
||||
// The flags (not set)
|
||||
0,
|
||||
|
||||
// The modification time
|
||||
(byte) mod_time, (byte) (mod_time >> 8),
|
||||
(byte) (mod_time >> 16), (byte) (mod_time >> 24),
|
||||
|
||||
// The extra flags
|
||||
0,
|
||||
|
||||
// The OS type (unknown)
|
||||
(byte) 255
|
||||
};
|
||||
baseOutputStream_.Write(gzipHeader, 0, gzipHeader.Length);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
// LzwConstants.cs
|
||||
//
|
||||
// Copyright (C) 2009 Gabriel Burca
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.LZW {
|
||||
|
||||
/// <summary>
|
||||
/// This class contains constants used for LZW
|
||||
/// </summary>
|
||||
sealed public class LzwConstants {
|
||||
/// <summary>
|
||||
/// Magic number found at start of LZW header: 0x1f 0x9d
|
||||
/// </summary>
|
||||
public const int MAGIC = 0x1f9d;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of bits per code
|
||||
/// </summary>
|
||||
public const int MAX_BITS = 16;
|
||||
|
||||
/* 3rd header byte:
|
||||
* bit 0..4 Number of compression bits
|
||||
* bit 5 Extended header
|
||||
* bit 6 Free
|
||||
* bit 7 Block mode
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Mask for 'number of compression bits'
|
||||
/// </summary>
|
||||
public const int BIT_MASK = 0x1f;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the presence of a fourth header byte
|
||||
/// </summary>
|
||||
public const int EXTENDED_MASK = 0x20;
|
||||
//public const int FREE_MASK = 0x40;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved bits
|
||||
/// </summary>
|
||||
public const int RESERVED_MASK = 0x60;
|
||||
|
||||
/// <summary>
|
||||
/// Block compression: if table is full and compression rate is dropping,
|
||||
/// clear the dictionary.
|
||||
/// </summary>
|
||||
public const int BLOCK_MODE_MASK = 0x80;
|
||||
|
||||
/// <summary>
|
||||
/// LZW file header size (in bytes)
|
||||
/// </summary>
|
||||
public const int HDR_SIZE = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Initial number of bits per code
|
||||
/// </summary>
|
||||
public const int INIT_BITS = 9;
|
||||
|
||||
LzwConstants() {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
// LzwException.cs
|
||||
//
|
||||
// Copyright (C) 2009 Gabriel Burca
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
using System.Runtime.Serialization;
|
||||
#endif
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.LZW
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// LzwException represents a LZW specific exception
|
||||
/// </summary>
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
[Serializable]
|
||||
#endif
|
||||
public class LzwException : SharpZipBaseException
|
||||
{
|
||||
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
/// <summary>
|
||||
/// Deserialization constructor
|
||||
/// </summary>
|
||||
/// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>
|
||||
/// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
|
||||
protected LzwException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of LzwException
|
||||
/// </summary>
|
||||
public LzwException() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of LzwException with its message string.
|
||||
/// </summary>
|
||||
/// <param name="message">A <see cref="string"/> that describes the error.</param>
|
||||
public LzwException(string message)
|
||||
: base(message) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="LzwException"></see>.
|
||||
/// </summary>
|
||||
/// <param name="message">A <see cref="string"/> that describes the error.</param>
|
||||
/// <param name="innerException">The <see cref="Exception"/> that caused this exception.</param>
|
||||
public LzwException(string message, Exception innerException)
|
||||
: base(message, innerException) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,598 @@
|
|||
// LzwInputStream.cs
|
||||
//
|
||||
// Copyright (C) 2009 Gabriel Burca
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.LZW
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This filter stream is used to decompress a LZW format stream.
|
||||
/// Specifically, a stream that uses the LZC compression method.
|
||||
/// This file format is usually associated with the .Z file extension.
|
||||
///
|
||||
/// See http://en.wikipedia.org/wiki/Compress
|
||||
/// See http://wiki.wxwidgets.org/Development:_Z_File_Format
|
||||
///
|
||||
/// The file header consists of 3 (or optionally 4) bytes. The first two bytes
|
||||
/// contain the magic marker "0x1f 0x9d", followed by a byte of flags.
|
||||
///
|
||||
/// Based on Java code by Ronald Tschalar, which in turn was based on the unlzw.c
|
||||
/// code in the gzip package.
|
||||
/// </summary>
|
||||
/// <example> This sample shows how to unzip a compressed file
|
||||
/// <code>
|
||||
/// using System;
|
||||
/// using System.IO;
|
||||
///
|
||||
/// using ICSharpCode.SharpZipLib.Core;
|
||||
/// using ICSharpCode.SharpZipLib.LZW;
|
||||
///
|
||||
/// class MainClass
|
||||
/// {
|
||||
/// public static void Main(string[] args)
|
||||
/// {
|
||||
/// using (Stream inStream = new LzwInputStream(File.OpenRead(args[0])))
|
||||
/// using (FileStream outStream = File.Create(Path.GetFileNameWithoutExtension(args[0]))) {
|
||||
/// byte[] buffer = new byte[4096];
|
||||
/// StreamUtils.Copy(inStream, outStream, buffer);
|
||||
/// // OR
|
||||
/// inStream.Read(buffer, 0, buffer.Length);
|
||||
/// // now do something with the buffer
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class LzwInputStream : Stream
|
||||
{
|
||||
/// <summary>
|
||||
/// Get/set flag indicating ownership of underlying stream.
|
||||
/// When the flag is true <see cref="Close"/> will close the underlying stream also.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is true.
|
||||
/// </remarks>
|
||||
public bool IsStreamOwner
|
||||
{
|
||||
get { return isStreamOwner; }
|
||||
set { isStreamOwner = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a LzwInputStream
|
||||
/// </summary>
|
||||
/// <param name="baseInputStream">
|
||||
/// The stream to read compressed data from (baseInputStream LZW format)
|
||||
/// </param>
|
||||
public LzwInputStream(Stream baseInputStream) {
|
||||
this.baseInputStream = baseInputStream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See <see cref="System.IO.Stream.ReadByte"/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int ReadByte() {
|
||||
int b = Read(one, 0, 1);
|
||||
if (b == 1)
|
||||
return (one[0] & 0xff);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads decompressed data into the provided buffer byte array
|
||||
/// </summary>
|
||||
/// <param name ="buffer">
|
||||
/// The array to read and decompress data into
|
||||
/// </param>
|
||||
/// <param name ="offset">
|
||||
/// The offset indicating where the data should be placed
|
||||
/// </param>
|
||||
/// <param name ="count">
|
||||
/// The number of bytes to decompress
|
||||
/// </param>
|
||||
/// <returns>The number of bytes read. Zero signals the end of stream</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count) {
|
||||
if (!headerParsed) ParseHeader();
|
||||
|
||||
if (eof) return -1;
|
||||
int start = offset;
|
||||
|
||||
/* Using local copies of various variables speeds things up by as
|
||||
* much as 30% in Java! Performance not tested in C#.
|
||||
*/
|
||||
int[] lTabPrefix = tabPrefix;
|
||||
byte[] lTabSuffix = tabSuffix;
|
||||
byte[] lStack = stack;
|
||||
int lNBits = nBits;
|
||||
int lMaxCode = maxCode;
|
||||
int lMaxMaxCode = maxMaxCode;
|
||||
int lBitMask = bitMask;
|
||||
int lOldCode = oldCode;
|
||||
byte lFinChar = finChar;
|
||||
int lStackP = stackP;
|
||||
int lFreeEnt = freeEnt;
|
||||
byte[] lData = data;
|
||||
int lBitPos = bitPos;
|
||||
|
||||
|
||||
// empty stack if stuff still left
|
||||
int sSize = lStack.Length - lStackP;
|
||||
if (sSize > 0) {
|
||||
int num = (sSize >= count) ? count : sSize;
|
||||
Array.Copy(lStack, lStackP, buffer, offset, num);
|
||||
offset += num;
|
||||
count -= num;
|
||||
lStackP += num;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
stackP = lStackP;
|
||||
return offset - start;
|
||||
}
|
||||
|
||||
|
||||
// loop, filling local buffer until enough data has been decompressed
|
||||
MainLoop: do {
|
||||
if (end < EXTRA) {
|
||||
Fill();
|
||||
}
|
||||
|
||||
int bitIn = (got > 0) ? (end - end % lNBits) << 3 :
|
||||
(end << 3) - (lNBits - 1);
|
||||
|
||||
while (lBitPos < bitIn) {
|
||||
#region A
|
||||
// handle 1-byte reads correctly
|
||||
if (count == 0) {
|
||||
nBits = lNBits;
|
||||
maxCode = lMaxCode;
|
||||
maxMaxCode = lMaxMaxCode;
|
||||
bitMask = lBitMask;
|
||||
oldCode = lOldCode;
|
||||
finChar = lFinChar;
|
||||
stackP = lStackP;
|
||||
freeEnt = lFreeEnt;
|
||||
bitPos = lBitPos;
|
||||
|
||||
return offset - start;
|
||||
}
|
||||
|
||||
// check for code-width expansion
|
||||
if (lFreeEnt > lMaxCode) {
|
||||
int nBytes = lNBits << 3;
|
||||
lBitPos = (lBitPos - 1) +
|
||||
nBytes - (lBitPos - 1 + nBytes) % nBytes;
|
||||
|
||||
lNBits++;
|
||||
lMaxCode = (lNBits == maxBits) ? lMaxMaxCode :
|
||||
(1 << lNBits) - 1;
|
||||
|
||||
lBitMask = (1 << lNBits) - 1;
|
||||
lBitPos = ResetBuf(lBitPos);
|
||||
goto MainLoop;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region B
|
||||
// read next code
|
||||
int pos = lBitPos >> 3;
|
||||
int code = (((lData[pos] & 0xFF) |
|
||||
((lData[pos + 1] & 0xFF) << 8) |
|
||||
((lData[pos + 2] & 0xFF) << 16)) >>
|
||||
(lBitPos & 0x7)) & lBitMask;
|
||||
|
||||
lBitPos += lNBits;
|
||||
|
||||
// handle first iteration
|
||||
if (lOldCode == -1) {
|
||||
if (code >= 256) throw new LzwException("corrupt input: " + code + " > 255");
|
||||
|
||||
lFinChar = (byte) (lOldCode = code);
|
||||
buffer[offset++] = lFinChar;
|
||||
count--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// handle CLEAR code
|
||||
if (code == TBL_CLEAR && blockMode) {
|
||||
Array.Copy(zeros, 0, lTabPrefix, 0, zeros.Length);
|
||||
lFreeEnt = TBL_FIRST - 1;
|
||||
|
||||
int nBytes = lNBits << 3;
|
||||
lBitPos = (lBitPos - 1) + nBytes - (lBitPos - 1 + nBytes) % nBytes;
|
||||
lNBits = LzwConstants.INIT_BITS;
|
||||
lMaxCode = (1 << lNBits) - 1;
|
||||
lBitMask = lMaxCode;
|
||||
|
||||
// Code tables reset
|
||||
|
||||
lBitPos = ResetBuf(lBitPos);
|
||||
goto MainLoop;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region C
|
||||
// setup
|
||||
int inCode = code;
|
||||
lStackP = lStack.Length;
|
||||
|
||||
// Handle KwK case
|
||||
if (code >= lFreeEnt) {
|
||||
if (code > lFreeEnt) {
|
||||
throw new LzwException("corrupt input: code=" + code +
|
||||
", freeEnt=" + lFreeEnt);
|
||||
}
|
||||
|
||||
lStack[--lStackP] = lFinChar;
|
||||
code = lOldCode;
|
||||
}
|
||||
|
||||
// Generate output characters in reverse order
|
||||
while (code >= 256) {
|
||||
lStack[--lStackP] = lTabSuffix[code];
|
||||
code = lTabPrefix[code];
|
||||
}
|
||||
|
||||
lFinChar = lTabSuffix[code];
|
||||
buffer[offset++] = lFinChar;
|
||||
count--;
|
||||
|
||||
// And put them out in forward order
|
||||
sSize = lStack.Length - lStackP;
|
||||
int num = (sSize >= count) ? count : sSize;
|
||||
Array.Copy(lStack, lStackP, buffer, offset, num);
|
||||
offset += num;
|
||||
count -= num;
|
||||
lStackP += num;
|
||||
#endregion
|
||||
|
||||
#region D
|
||||
// generate new entry in table
|
||||
if (lFreeEnt < lMaxMaxCode) {
|
||||
lTabPrefix[lFreeEnt] = lOldCode;
|
||||
lTabSuffix[lFreeEnt] = lFinChar;
|
||||
lFreeEnt++;
|
||||
}
|
||||
|
||||
// Remember previous code
|
||||
lOldCode = inCode;
|
||||
|
||||
// if output buffer full, then return
|
||||
if (count == 0) {
|
||||
nBits = lNBits;
|
||||
maxCode = lMaxCode;
|
||||
bitMask = lBitMask;
|
||||
oldCode = lOldCode;
|
||||
finChar = lFinChar;
|
||||
stackP = lStackP;
|
||||
freeEnt = lFreeEnt;
|
||||
bitPos = lBitPos;
|
||||
|
||||
return offset - start;
|
||||
}
|
||||
#endregion
|
||||
} // while
|
||||
|
||||
lBitPos = ResetBuf(lBitPos);
|
||||
|
||||
} while (got > 0); // do..while
|
||||
|
||||
nBits = lNBits;
|
||||
maxCode = lMaxCode;
|
||||
bitMask = lBitMask;
|
||||
oldCode = lOldCode;
|
||||
finChar = lFinChar;
|
||||
stackP = lStackP;
|
||||
freeEnt = lFreeEnt;
|
||||
bitPos = lBitPos;
|
||||
|
||||
eof = true;
|
||||
return offset - start;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the unread data in the buffer to the beginning and resets
|
||||
/// the pointers.
|
||||
/// </summary>
|
||||
/// <param name="bitPosition"></param>
|
||||
/// <returns></returns>
|
||||
private int ResetBuf(int bitPosition) {
|
||||
int pos = bitPosition >> 3;
|
||||
Array.Copy(data, pos, data, 0, end - pos);
|
||||
end -= pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
private void Fill() {
|
||||
got = baseInputStream.Read(data, end, data.Length - 1 - end);
|
||||
if (got > 0) {
|
||||
end += got;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ParseHeader() {
|
||||
headerParsed = true;
|
||||
|
||||
byte[] hdr = new byte[LzwConstants.HDR_SIZE];
|
||||
|
||||
int result = baseInputStream.Read(hdr, 0, hdr.Length);
|
||||
|
||||
// Check the magic marker
|
||||
if (result < 0)
|
||||
throw new LzwException("Failed to read LZW header");
|
||||
|
||||
if (hdr[0] != (LzwConstants.MAGIC >> 8) || hdr[1] != (LzwConstants.MAGIC & 0xff)) {
|
||||
throw new LzwException(String.Format(
|
||||
"Wrong LZW header. Magic bytes don't match. 0x{0:x2} 0x{1:x2}",
|
||||
hdr[0], hdr[1]));
|
||||
}
|
||||
|
||||
// Check the 3rd header byte
|
||||
blockMode = (hdr[2] & LzwConstants.BLOCK_MODE_MASK) > 0;
|
||||
maxBits = hdr[2] & LzwConstants.BIT_MASK;
|
||||
|
||||
if (maxBits > LzwConstants.MAX_BITS) {
|
||||
throw new LzwException("Stream compressed with " + maxBits +
|
||||
" bits, but decompression can only handle " +
|
||||
LzwConstants.MAX_BITS + " bits.");
|
||||
}
|
||||
|
||||
if ((hdr[2] & LzwConstants.RESERVED_MASK) > 0) {
|
||||
throw new LzwException("Unsupported bits set in the header.");
|
||||
}
|
||||
|
||||
// Initialize variables
|
||||
maxMaxCode = 1 << maxBits;
|
||||
nBits = LzwConstants.INIT_BITS;
|
||||
maxCode = (1 << nBits) - 1;
|
||||
bitMask = maxCode;
|
||||
oldCode = -1;
|
||||
finChar = 0;
|
||||
freeEnt = blockMode ? TBL_FIRST : 256;
|
||||
|
||||
tabPrefix = new int[1 << maxBits];
|
||||
tabSuffix = new byte[1 << maxBits];
|
||||
stack = new byte[1 << maxBits];
|
||||
stackP = stack.Length;
|
||||
|
||||
for (int idx = 255; idx >= 0; idx--)
|
||||
tabSuffix[idx] = (byte)idx;
|
||||
}
|
||||
|
||||
#region Stream Overrides
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current stream supports reading
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseInputStream.CanRead;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value of false indicating seeking is not supported for this stream.
|
||||
/// </summary>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value of false indicating that this stream is not writeable.
|
||||
/// </summary>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A value representing the length of the stream in bytes.
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return got;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The current position within the stream.
|
||||
/// Throws a NotSupportedException when attempting to set the position
|
||||
/// </summary>
|
||||
/// <exception cref="NotSupportedException">Attempting to set the position</exception>
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseInputStream.Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotSupportedException("InflaterInputStream Position not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the baseInputStream
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
baseInputStream.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the position within the current stream
|
||||
/// Always throws a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="offset">The relative offset to seek to.</param>
|
||||
/// <param name="origin">The <see cref="SeekOrigin"/> defining where to seek from.</param>
|
||||
/// <returns>The new position in the stream.</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException("Seek not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the length of the current stream
|
||||
/// Always throws a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="value">The new length value for the stream.</param>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException("InflaterInputStream SetLength not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a sequence of bytes to stream and advances the current position
|
||||
/// This method always throws a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="buffer">Thew buffer containing data to write.</param>
|
||||
/// <param name="offset">The offset of the first byte to write.</param>
|
||||
/// <param name="count">The number of bytes to write.</param>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException("InflaterInputStream Write not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes one byte to the current stream and advances the current position
|
||||
/// Always throws a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="value">The byte to write.</param>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
throw new NotSupportedException("InflaterInputStream WriteByte not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Entry point to begin an asynchronous write. Always throws a NotSupportedException.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to write data from</param>
|
||||
/// <param name="offset">Offset of first byte to write</param>
|
||||
/// <param name="count">The maximum number of bytes to write</param>
|
||||
/// <param name="callback">The method to be called when the asynchronous write operation is completed</param>
|
||||
/// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from other requests</param>
|
||||
/// <returns>An <see cref="System.IAsyncResult">IAsyncResult</see> that references the asynchronous write</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
{
|
||||
throw new NotSupportedException("InflaterInputStream BeginWrite not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the input stream. When <see cref="IsStreamOwner"></see>
|
||||
/// is true the underlying stream is also closed.
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
if (!isClosed)
|
||||
{
|
||||
isClosed = true;
|
||||
if (isStreamOwner)
|
||||
{
|
||||
baseInputStream.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Instance Fields
|
||||
|
||||
Stream baseInputStream;
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating wether this instance is designated the stream owner.
|
||||
/// When closing if this flag is true the underlying stream is closed.
|
||||
/// </summary>
|
||||
bool isStreamOwner = true;
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating wether this instance has been closed or not.
|
||||
/// </summary>
|
||||
bool isClosed;
|
||||
|
||||
readonly byte[] one = new byte[1];
|
||||
bool headerParsed;
|
||||
|
||||
// string table stuff
|
||||
private const int TBL_CLEAR = 0x100;
|
||||
private const int TBL_FIRST = TBL_CLEAR + 1;
|
||||
|
||||
private int[] tabPrefix;
|
||||
private byte[] tabSuffix;
|
||||
private readonly int[] zeros = new int[256];
|
||||
private byte[] stack;
|
||||
|
||||
// various state
|
||||
private bool blockMode;
|
||||
private int nBits;
|
||||
private int maxBits;
|
||||
private int maxMaxCode;
|
||||
private int maxCode;
|
||||
private int bitMask;
|
||||
private int oldCode;
|
||||
private byte finChar;
|
||||
private int stackP;
|
||||
private int freeEnt;
|
||||
|
||||
// input buffer
|
||||
private readonly byte[] data = new byte[1024 * 8];
|
||||
private int bitPos;
|
||||
private int end;
|
||||
int got;
|
||||
private bool eof;
|
||||
private const int EXTRA = 64;
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
// SharpZipBaseException.cs
|
||||
//
|
||||
// Copyright 2004 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
using System.Runtime.Serialization;
|
||||
#endif
|
||||
|
||||
namespace ICSharpCode.SharpZipLib
|
||||
{
|
||||
/// <summary>
|
||||
/// SharpZipBaseException is the base exception class for the SharpZipLibrary.
|
||||
/// All library exceptions are derived from this.
|
||||
/// </summary>
|
||||
/// <remarks>NOTE: Not all exceptions thrown will be derived from this class.
|
||||
/// A variety of other exceptions are possible for example <see cref="ArgumentNullException"></see></remarks>
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
[Serializable]
|
||||
#endif
|
||||
public class SharpZipBaseException : ApplicationException
|
||||
{
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
/// <summary>
|
||||
/// Deserialization constructor
|
||||
/// </summary>
|
||||
/// <param name="info"><see cref="System.Runtime.Serialization.SerializationInfo"/> for this constructor</param>
|
||||
/// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
|
||||
protected SharpZipBaseException(SerializationInfo info, StreamingContext context )
|
||||
: base( info, context )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SharpZipBaseException class.
|
||||
/// </summary>
|
||||
public SharpZipBaseException()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SharpZipBaseException class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">A message describing the exception.</param>
|
||||
public SharpZipBaseException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SharpZipBaseException class with a specified
|
||||
/// error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">A message describing the exception.</param>
|
||||
/// <param name="innerException">The inner exception</param>
|
||||
public SharpZipBaseException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
// InvalidHeaderException.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
using System.Runtime.Serialization;
|
||||
#endif
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Tar {
|
||||
|
||||
/// <summary>
|
||||
/// This exception is used to indicate that there is a problem
|
||||
/// with a TAR archive header.
|
||||
/// </summary>
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
[Serializable]
|
||||
#endif
|
||||
public class InvalidHeaderException : TarException
|
||||
{
|
||||
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
/// <summary>
|
||||
/// Deserialization constructor
|
||||
/// </summary>
|
||||
/// <param name="information"><see cref="SerializationInfo"/> for this constructor</param>
|
||||
/// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
|
||||
protected InvalidHeaderException(SerializationInfo information, StreamingContext context)
|
||||
: base(information, context)
|
||||
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of the InvalidHeaderException class.
|
||||
/// </summary>
|
||||
public InvalidHeaderException()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialises a new instance of the InvalidHeaderException class with a specified message.
|
||||
/// </summary>
|
||||
/// <param name="message">Message describing the exception cause.</param>
|
||||
public InvalidHeaderException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of InvalidHeaderException
|
||||
/// </summary>
|
||||
/// <param name="message">Message describing the problem.</param>
|
||||
/// <param name="exception">The exception that is the cause of the current exception.</param>
|
||||
public InvalidHeaderException(string message, Exception exception)
|
||||
: base(message, exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The original Java file had this header:
|
||||
** Authored by Timothy Gerard Endres
|
||||
** <mailto:time@gjt.org> <http://www.trustice.com>
|
||||
**
|
||||
** This work has been placed into the public domain.
|
||||
** You may use this work in any way and for any purpose you wish.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
|
||||
** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
|
||||
** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
|
||||
** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
|
||||
** REDISTRIBUTION OF THIS SOFTWARE.
|
||||
**
|
||||
*/
|
||||
|
|
@ -0,0 +1,894 @@
|
|||
// TarArchive.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
// HISTORY
|
||||
// 28-01-2010 DavidPierson Added IsStreamOwner
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Tar
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to advise clients of 'events' while processing archives
|
||||
/// </summary>
|
||||
public delegate void ProgressMessageHandler(TarArchive archive, TarEntry entry, string message);
|
||||
|
||||
/// <summary>
|
||||
/// The TarArchive class implements the concept of a
|
||||
/// 'Tape Archive'. A tar archive is a series of entries, each of
|
||||
/// which represents a file system object. Each entry in
|
||||
/// the archive consists of a header block followed by 0 or more data blocks.
|
||||
/// Directory entries consist only of the header block, and are followed by entries
|
||||
/// for the directory's contents. File entries consist of a
|
||||
/// header followed by the number of blocks needed to
|
||||
/// contain the file's contents. All entries are written on
|
||||
/// block boundaries. Blocks are 512 bytes long.
|
||||
///
|
||||
/// TarArchives are instantiated in either read or write mode,
|
||||
/// based upon whether they are instantiated with an InputStream
|
||||
/// or an OutputStream. Once instantiated TarArchives read/write
|
||||
/// mode can not be changed.
|
||||
///
|
||||
/// There is currently no support for random access to tar archives.
|
||||
/// However, it seems that subclassing TarArchive, and using the
|
||||
/// TarBuffer.CurrentRecord and TarBuffer.CurrentBlock
|
||||
/// properties, this would be rather trivial.
|
||||
/// </summary>
|
||||
public class TarArchive : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Client hook allowing detailed information to be reported during processing
|
||||
/// </summary>
|
||||
public event ProgressMessageHandler ProgressMessageEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the ProgressMessage event
|
||||
/// </summary>
|
||||
/// <param name="entry">The <see cref="TarEntry">TarEntry</see> for this event</param>
|
||||
/// <param name="message">message for this event. Null is no message</param>
|
||||
protected virtual void OnProgressMessageEvent(TarEntry entry, string message)
|
||||
{
|
||||
ProgressMessageHandler handler = ProgressMessageEvent;
|
||||
if (handler != null) {
|
||||
handler(this, entry, message);
|
||||
}
|
||||
}
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for a default <see cref="TarArchive"/>.
|
||||
/// </summary>
|
||||
protected TarArchive()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initalise a TarArchive for input.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="TarInputStream"/> to use for input.</param>
|
||||
protected TarArchive(TarInputStream stream)
|
||||
{
|
||||
if ( stream == null ) {
|
||||
throw new ArgumentNullException("stream");
|
||||
}
|
||||
|
||||
tarIn = stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a TarArchive for output.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="TarOutputStream"/> to use for output.</param>
|
||||
protected TarArchive(TarOutputStream stream)
|
||||
{
|
||||
if ( stream == null ) {
|
||||
throw new ArgumentNullException("stream");
|
||||
}
|
||||
|
||||
tarOut = stream;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Static factory methods
|
||||
/// <summary>
|
||||
/// The InputStream based constructors create a TarArchive for the
|
||||
/// purposes of extracting or listing a tar archive. Thus, use
|
||||
/// these constructors when you wish to extract files from or list
|
||||
/// the contents of an existing tar archive.
|
||||
/// </summary>
|
||||
/// <param name="inputStream">The stream to retrieve archive data from.</param>
|
||||
/// <returns>Returns a new <see cref="TarArchive"/> suitable for reading from.</returns>
|
||||
public static TarArchive CreateInputTarArchive(Stream inputStream)
|
||||
{
|
||||
if ( inputStream == null ) {
|
||||
throw new ArgumentNullException("inputStream");
|
||||
}
|
||||
|
||||
TarInputStream tarStream = inputStream as TarInputStream;
|
||||
|
||||
TarArchive result;
|
||||
if ( tarStream != null ) {
|
||||
result = new TarArchive(tarStream);
|
||||
}
|
||||
else {
|
||||
result = CreateInputTarArchive(inputStream, TarBuffer.DefaultBlockFactor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create TarArchive for reading setting block factor
|
||||
/// </summary>
|
||||
/// <param name="inputStream">A stream containing the tar archive contents</param>
|
||||
/// <param name="blockFactor">The blocking factor to apply</param>
|
||||
/// <returns>Returns a <see cref="TarArchive"/> suitable for reading.</returns>
|
||||
public static TarArchive CreateInputTarArchive(Stream inputStream, int blockFactor)
|
||||
{
|
||||
if ( inputStream == null ) {
|
||||
throw new ArgumentNullException("inputStream");
|
||||
}
|
||||
|
||||
if ( inputStream is TarInputStream ) {
|
||||
throw new ArgumentException("TarInputStream not valid");
|
||||
}
|
||||
|
||||
return new TarArchive(new TarInputStream(inputStream, blockFactor));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a TarArchive for writing to, using the default blocking factor
|
||||
/// </summary>
|
||||
/// <param name="outputStream">The <see cref="Stream"/> to write to</param>
|
||||
/// <returns>Returns a <see cref="TarArchive"/> suitable for writing.</returns>
|
||||
public static TarArchive CreateOutputTarArchive(Stream outputStream)
|
||||
{
|
||||
if ( outputStream == null ) {
|
||||
throw new ArgumentNullException("outputStream");
|
||||
}
|
||||
|
||||
TarOutputStream tarStream = outputStream as TarOutputStream;
|
||||
|
||||
TarArchive result;
|
||||
if ( tarStream != null ) {
|
||||
result = new TarArchive(tarStream);
|
||||
}
|
||||
else {
|
||||
result = CreateOutputTarArchive(outputStream, TarBuffer.DefaultBlockFactor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="TarArchive">tar archive</see> for writing.
|
||||
/// </summary>
|
||||
/// <param name="outputStream">The stream to write to</param>
|
||||
/// <param name="blockFactor">The blocking factor to use for buffering.</param>
|
||||
/// <returns>Returns a <see cref="TarArchive"/> suitable for writing.</returns>
|
||||
public static TarArchive CreateOutputTarArchive(Stream outputStream, int blockFactor)
|
||||
{
|
||||
if ( outputStream == null ) {
|
||||
throw new ArgumentNullException("outputStream");
|
||||
}
|
||||
|
||||
if ( outputStream is TarOutputStream ) {
|
||||
throw new ArgumentException("TarOutputStream is not valid");
|
||||
}
|
||||
|
||||
return new TarArchive(new TarOutputStream(outputStream, blockFactor));
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Set the flag that determines whether existing files are
|
||||
/// kept, or overwritten during extraction.
|
||||
/// </summary>
|
||||
/// <param name="keepExistingFiles">
|
||||
/// If true, do not overwrite existing files.
|
||||
/// </param>
|
||||
public void SetKeepOldFiles(bool keepExistingFiles)
|
||||
{
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
keepOldFiles = keepExistingFiles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the ascii file translation flag. If ascii file translation
|
||||
/// is true, then the file is checked to see if it a binary file or not.
|
||||
/// If the flag is true and the test indicates it is ascii text
|
||||
/// file, it will be translated. The translation converts the local
|
||||
/// operating system's concept of line ends into the UNIX line end,
|
||||
/// '\n', which is the defacto standard for a TAR archive. This makes
|
||||
/// text files compatible with UNIX.
|
||||
/// </summary>
|
||||
public bool AsciiTranslate
|
||||
{
|
||||
get {
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
return asciiTranslate;
|
||||
}
|
||||
|
||||
set {
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
asciiTranslate = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the ascii file translation flag.
|
||||
/// </summary>
|
||||
/// <param name= "translateAsciiFiles">
|
||||
/// If true, translate ascii text files.
|
||||
/// </param>
|
||||
[Obsolete("Use the AsciiTranslate property")]
|
||||
public void SetAsciiTranslation(bool translateAsciiFiles)
|
||||
{
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
asciiTranslate = translateAsciiFiles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PathPrefix is added to entry names as they are written if the value is not null.
|
||||
/// A slash character is appended after PathPrefix
|
||||
/// </summary>
|
||||
public string PathPrefix
|
||||
{
|
||||
get {
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
return pathPrefix;
|
||||
}
|
||||
|
||||
set {
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
pathPrefix = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RootPath is removed from entry names if it is found at the
|
||||
/// beginning of the name.
|
||||
/// </summary>
|
||||
public string RootPath
|
||||
{
|
||||
get {
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
return rootPath;
|
||||
}
|
||||
|
||||
set {
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
rootPath = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set user and group information that will be used to fill in the
|
||||
/// tar archive's entry headers. This information is based on that available
|
||||
/// for the linux operating system, which is not always available on other
|
||||
/// operating systems. TarArchive allows the programmer to specify values
|
||||
/// to be used in their place.
|
||||
/// <see cref="ApplyUserInfoOverrides"/> is set to true by this call.
|
||||
/// </summary>
|
||||
/// <param name="userId">
|
||||
/// The user id to use in the headers.
|
||||
/// </param>
|
||||
/// <param name="userName">
|
||||
/// The user name to use in the headers.
|
||||
/// </param>
|
||||
/// <param name="groupId">
|
||||
/// The group id to use in the headers.
|
||||
/// </param>
|
||||
/// <param name="groupName">
|
||||
/// The group name to use in the headers.
|
||||
/// </param>
|
||||
public void SetUserInfo(int userId, string userName, int groupId, string groupName)
|
||||
{
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
this.userId = userId;
|
||||
this.userName = userName;
|
||||
this.groupId = groupId;
|
||||
this.groupName = groupName;
|
||||
applyUserInfoOverrides = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or set a value indicating if overrides defined by <see cref="SetUserInfo">SetUserInfo</see> should be applied.
|
||||
/// </summary>
|
||||
/// <remarks>If overrides are not applied then the values as set in each header will be used.</remarks>
|
||||
public bool ApplyUserInfoOverrides
|
||||
{
|
||||
get {
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
return applyUserInfoOverrides;
|
||||
}
|
||||
|
||||
set {
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
applyUserInfoOverrides = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the archive user id.
|
||||
/// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
|
||||
/// on how to allow setting values on a per entry basis.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The current user id.
|
||||
/// </returns>
|
||||
public int UserId {
|
||||
get {
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
return userId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the archive user name.
|
||||
/// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
|
||||
/// on how to allow setting values on a per entry basis.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The current user name.
|
||||
/// </returns>
|
||||
public string UserName {
|
||||
get {
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
return userName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the archive group id.
|
||||
/// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
|
||||
/// on how to allow setting values on a per entry basis.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The current group id.
|
||||
/// </returns>
|
||||
public int GroupId {
|
||||
get {
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
return groupId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the archive group name.
|
||||
/// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
|
||||
/// on how to allow setting values on a per entry basis.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The current group name.
|
||||
/// </returns>
|
||||
public string GroupName {
|
||||
get {
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
return groupName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the archive's record size. Tar archives are composed of
|
||||
/// a series of RECORDS each containing a number of BLOCKS.
|
||||
/// This allowed tar archives to match the IO characteristics of
|
||||
/// the physical device being used. Archives are expected
|
||||
/// to be properly "blocked".
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The record size this archive is using.
|
||||
/// </returns>
|
||||
public int RecordSize {
|
||||
get {
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
if (tarIn != null) {
|
||||
return tarIn.RecordSize;
|
||||
} else if (tarOut != null) {
|
||||
return tarOut.RecordSize;
|
||||
}
|
||||
return TarBuffer.DefaultRecordSize;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the IsStreamOwner property on the underlying stream.
|
||||
/// Set this to false to prevent the Close of the TarArchive from closing the stream.
|
||||
/// </summary>
|
||||
public bool IsStreamOwner {
|
||||
set {
|
||||
if (tarIn != null) {
|
||||
tarIn.IsStreamOwner = value;
|
||||
} else {
|
||||
tarOut.IsStreamOwner = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the archive.
|
||||
/// </summary>
|
||||
[Obsolete("Use Close instead")]
|
||||
public void CloseArchive()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform the "list" command for the archive contents.
|
||||
///
|
||||
/// NOTE That this method uses the <see cref="ProgressMessageEvent"> progress event</see> to actually list
|
||||
/// the contents. If the progress display event is not set, nothing will be listed!
|
||||
/// </summary>
|
||||
public void ListContents()
|
||||
{
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
while (true) {
|
||||
TarEntry entry = tarIn.GetNextEntry();
|
||||
|
||||
if (entry == null) {
|
||||
break;
|
||||
}
|
||||
OnProgressMessageEvent(entry, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform the "extract" command and extract the contents of the archive.
|
||||
/// </summary>
|
||||
/// <param name="destinationDirectory">
|
||||
/// The destination directory into which to extract.
|
||||
/// </param>
|
||||
public void ExtractContents(string destinationDirectory)
|
||||
{
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
while (true) {
|
||||
TarEntry entry = tarIn.GetNextEntry();
|
||||
|
||||
if (entry == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
ExtractEntry(destinationDirectory, entry);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract an entry from the archive. This method assumes that the
|
||||
/// tarIn stream has been properly set with a call to GetNextEntry().
|
||||
/// </summary>
|
||||
/// <param name="destDir">
|
||||
/// The destination directory into which to extract.
|
||||
/// </param>
|
||||
/// <param name="entry">
|
||||
/// The TarEntry returned by tarIn.GetNextEntry().
|
||||
/// </param>
|
||||
void ExtractEntry(string destDir, TarEntry entry)
|
||||
{
|
||||
OnProgressMessageEvent(entry, null);
|
||||
|
||||
string name = entry.Name;
|
||||
|
||||
if (Path.IsPathRooted(name)) {
|
||||
// NOTE:
|
||||
// for UNC names... \\machine\share\zoom\beet.txt gives \zoom\beet.txt
|
||||
name = name.Substring(Path.GetPathRoot(name).Length);
|
||||
}
|
||||
|
||||
name = name.Replace('/', Path.DirectorySeparatorChar);
|
||||
|
||||
string destFile = Path.Combine(destDir, name);
|
||||
|
||||
if (entry.IsDirectory) {
|
||||
EnsureDirectoryExists(destFile);
|
||||
} else {
|
||||
string parentDirectory = Path.GetDirectoryName(destFile);
|
||||
EnsureDirectoryExists(parentDirectory);
|
||||
|
||||
bool process = true;
|
||||
FileInfo fileInfo = new FileInfo(destFile);
|
||||
if (fileInfo.Exists) {
|
||||
if (keepOldFiles) {
|
||||
OnProgressMessageEvent(entry, "Destination file already exists");
|
||||
process = false;
|
||||
} else if ((fileInfo.Attributes & FileAttributes.ReadOnly) != 0) {
|
||||
OnProgressMessageEvent(entry, "Destination file already exists, and is read-only");
|
||||
process = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (process) {
|
||||
bool asciiTrans = false;
|
||||
|
||||
Stream outputStream = File.Create(destFile);
|
||||
if (this.asciiTranslate) {
|
||||
asciiTrans = !IsBinary(destFile);
|
||||
}
|
||||
|
||||
StreamWriter outw = null;
|
||||
if (asciiTrans) {
|
||||
outw = new StreamWriter(outputStream);
|
||||
}
|
||||
|
||||
byte[] rdbuf = new byte[32 * 1024];
|
||||
|
||||
while (true) {
|
||||
int numRead = tarIn.Read(rdbuf, 0, rdbuf.Length);
|
||||
|
||||
if (numRead <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (asciiTrans) {
|
||||
for (int off = 0, b = 0; b < numRead; ++b) {
|
||||
if (rdbuf[b] == 10) {
|
||||
string s = Encoding.ASCII.GetString(rdbuf, off, (b - off));
|
||||
outw.WriteLine(s);
|
||||
off = b + 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
outputStream.Write(rdbuf, 0, numRead);
|
||||
}
|
||||
}
|
||||
|
||||
if (asciiTrans) {
|
||||
outw.Close();
|
||||
} else {
|
||||
outputStream.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an entry to the archive. This method will call the putNextEntry
|
||||
/// and then write the contents of the entry, and finally call closeEntry()
|
||||
/// for entries that are files. For directories, it will call putNextEntry(),
|
||||
/// and then, if the recurse flag is true, process each entry that is a
|
||||
/// child of the directory.
|
||||
/// </summary>
|
||||
/// <param name="sourceEntry">
|
||||
/// The TarEntry representing the entry to write to the archive.
|
||||
/// </param>
|
||||
/// <param name="recurse">
|
||||
/// If true, process the children of directory entries.
|
||||
/// </param>
|
||||
public void WriteEntry(TarEntry sourceEntry, bool recurse)
|
||||
{
|
||||
if ( sourceEntry == null ) {
|
||||
throw new ArgumentNullException("sourceEntry");
|
||||
}
|
||||
|
||||
if ( isDisposed ) {
|
||||
throw new ObjectDisposedException("TarArchive");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if ( recurse ) {
|
||||
TarHeader.SetValueDefaults(sourceEntry.UserId, sourceEntry.UserName,
|
||||
sourceEntry.GroupId, sourceEntry.GroupName);
|
||||
}
|
||||
WriteEntryCore(sourceEntry, recurse);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ( recurse ) {
|
||||
TarHeader.RestoreSetValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an entry to the archive. This method will call the putNextEntry
|
||||
/// and then write the contents of the entry, and finally call closeEntry()
|
||||
/// for entries that are files. For directories, it will call putNextEntry(),
|
||||
/// and then, if the recurse flag is true, process each entry that is a
|
||||
/// child of the directory.
|
||||
/// </summary>
|
||||
/// <param name="sourceEntry">
|
||||
/// The TarEntry representing the entry to write to the archive.
|
||||
/// </param>
|
||||
/// <param name="recurse">
|
||||
/// If true, process the children of directory entries.
|
||||
/// </param>
|
||||
void WriteEntryCore(TarEntry sourceEntry, bool recurse)
|
||||
{
|
||||
string tempFileName = null;
|
||||
string entryFilename = sourceEntry.File;
|
||||
|
||||
TarEntry entry = (TarEntry)sourceEntry.Clone();
|
||||
|
||||
if ( applyUserInfoOverrides ) {
|
||||
entry.GroupId = groupId;
|
||||
entry.GroupName = groupName;
|
||||
entry.UserId = userId;
|
||||
entry.UserName = userName;
|
||||
}
|
||||
|
||||
OnProgressMessageEvent(entry, null);
|
||||
|
||||
if (asciiTranslate && !entry.IsDirectory) {
|
||||
|
||||
if (!IsBinary(entryFilename)) {
|
||||
tempFileName = Path.GetTempFileName();
|
||||
|
||||
using (StreamReader inStream = File.OpenText(entryFilename)) {
|
||||
using (Stream outStream = File.Create(tempFileName)) {
|
||||
|
||||
while (true) {
|
||||
string line = inStream.ReadLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
byte[] data = Encoding.ASCII.GetBytes(line);
|
||||
outStream.Write(data, 0, data.Length);
|
||||
outStream.WriteByte((byte)'\n');
|
||||
}
|
||||
|
||||
outStream.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
entry.Size = new FileInfo(tempFileName).Length;
|
||||
entryFilename = tempFileName;
|
||||
}
|
||||
}
|
||||
|
||||
string newName = null;
|
||||
|
||||
if (rootPath != null) {
|
||||
if (entry.Name.StartsWith(rootPath)) {
|
||||
newName = entry.Name.Substring(rootPath.Length + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
if (pathPrefix != null) {
|
||||
newName = (newName == null) ? pathPrefix + "/" + entry.Name : pathPrefix + "/" + newName;
|
||||
}
|
||||
|
||||
if (newName != null) {
|
||||
entry.Name = newName;
|
||||
}
|
||||
|
||||
tarOut.PutNextEntry(entry);
|
||||
|
||||
if (entry.IsDirectory) {
|
||||
if (recurse) {
|
||||
TarEntry[] list = entry.GetDirectoryEntries();
|
||||
for (int i = 0; i < list.Length; ++i) {
|
||||
WriteEntryCore(list[i], recurse);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
using (Stream inputStream = File.OpenRead(entryFilename)) {
|
||||
byte[] localBuffer = new byte[32 * 1024];
|
||||
while (true) {
|
||||
int numRead = inputStream.Read(localBuffer, 0, localBuffer.Length);
|
||||
|
||||
if (numRead <=0) {
|
||||
break;
|
||||
}
|
||||
|
||||
tarOut.Write(localBuffer, 0, numRead);
|
||||
}
|
||||
}
|
||||
|
||||
if ( (tempFileName != null) && (tempFileName.Length > 0) ) {
|
||||
File.Delete(tempFileName);
|
||||
}
|
||||
|
||||
tarOut.CloseEntry();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases the unmanaged resources used by the FileStream and optionally releases the managed resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true to release both managed and unmanaged resources;
|
||||
/// false to release only unmanaged resources.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if ( !isDisposed ) {
|
||||
isDisposed = true;
|
||||
if ( disposing ) {
|
||||
if ( tarOut != null ) {
|
||||
tarOut.Flush();
|
||||
tarOut.Close();
|
||||
}
|
||||
|
||||
if ( tarIn != null ) {
|
||||
tarIn.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the archive and releases any associated resources.
|
||||
/// </summary>
|
||||
public virtual void Close()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that resources are freed and other cleanup operations are performed
|
||||
/// when the garbage collector reclaims the <see cref="TarArchive"/>.
|
||||
/// </summary>
|
||||
~TarArchive()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
static void EnsureDirectoryExists(string directoryName)
|
||||
{
|
||||
if (!Directory.Exists(directoryName)) {
|
||||
try {
|
||||
Directory.CreateDirectory(directoryName);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TarException("Exception creating directory '" + directoryName + "', " + e.Message, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: TarArchive - Is there a better way to test for a text file?
|
||||
// It no longer reads entire files into memory but is still a weak test!
|
||||
// This assumes that byte values 0-7, 14-31 or 255 are binary
|
||||
// and that all non text files contain one of these values
|
||||
static bool IsBinary(string filename)
|
||||
{
|
||||
using (FileStream fs = File.OpenRead(filename))
|
||||
{
|
||||
int sampleSize = Math.Min(4096, (int)fs.Length);
|
||||
byte[] content = new byte[sampleSize];
|
||||
|
||||
int bytesRead = fs.Read(content, 0, sampleSize);
|
||||
|
||||
for (int i = 0; i < bytesRead; ++i) {
|
||||
byte b = content[i];
|
||||
if ( (b < 8) || ((b > 13) && (b < 32)) || (b == 255) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
bool keepOldFiles;
|
||||
bool asciiTranslate;
|
||||
|
||||
int userId;
|
||||
string userName = string.Empty;
|
||||
int groupId;
|
||||
string groupName = string.Empty;
|
||||
|
||||
string rootPath;
|
||||
string pathPrefix;
|
||||
|
||||
bool applyUserInfoOverrides;
|
||||
|
||||
TarInputStream tarIn;
|
||||
TarOutputStream tarOut;
|
||||
bool isDisposed;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* The original Java file had this header:
|
||||
** Authored by Timothy Gerard Endres
|
||||
** <mailto:time@gjt.org> <http://www.trustice.com>
|
||||
**
|
||||
** This work has been placed into the public domain.
|
||||
** You may use this work in any way and for any purpose you wish.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
|
||||
** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
|
||||
** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
|
||||
** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
|
||||
** REDISTRIBUTION OF THIS SOFTWARE.
|
||||
**
|
||||
*/
|
||||
|
|
@ -0,0 +1,624 @@
|
|||
// TarBuffer.cs
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Tar
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The TarBuffer class implements the tar archive concept
|
||||
/// of a buffered input stream. This concept goes back to the
|
||||
/// days of blocked tape drives and special io devices. In the
|
||||
/// C# universe, the only real function that this class
|
||||
/// performs is to ensure that files have the correct "record"
|
||||
/// size, or other tars will complain.
|
||||
/// <p>
|
||||
/// You should never have a need to access this class directly.
|
||||
/// TarBuffers are created by Tar IO Streams.
|
||||
/// </p>
|
||||
/// </summary>
|
||||
public class TarBuffer
|
||||
{
|
||||
|
||||
/* A quote from GNU tar man file on blocking and records
|
||||
A `tar' archive file contains a series of blocks. Each block
|
||||
contains `BLOCKSIZE' bytes. Although this format may be thought of as
|
||||
being on magnetic tape, other media are often used.
|
||||
|
||||
Each file archived is represented by a header block which describes
|
||||
the file, followed by zero or more blocks which give the contents of
|
||||
the file. At the end of the archive file there may be a block filled
|
||||
with binary zeros as an end-of-file marker. A reasonable system should
|
||||
write a block of zeros at the end, but must not assume that such a
|
||||
block exists when reading an archive.
|
||||
|
||||
The blocks may be "blocked" for physical I/O operations. Each
|
||||
record of N blocks is written with a single 'write ()'
|
||||
operation. On magnetic tapes, the result of such a write is a single
|
||||
record. When writing an archive, the last record of blocks should be
|
||||
written at the full size, with blocks after the zero block containing
|
||||
all zeros. When reading an archive, a reasonable system should
|
||||
properly handle an archive whose last record is shorter than the rest,
|
||||
or which contains garbage records after a zero block.
|
||||
*/
|
||||
|
||||
#region Constants
|
||||
/// <summary>
|
||||
/// The size of a block in a tar archive in bytes.
|
||||
/// </summary>
|
||||
/// <remarks>This is 512 bytes.</remarks>
|
||||
public const int BlockSize = 512;
|
||||
|
||||
/// <summary>
|
||||
/// The number of blocks in a default record.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is 20 blocks per record.
|
||||
/// </remarks>
|
||||
public const int DefaultBlockFactor = 20;
|
||||
|
||||
/// <summary>
|
||||
/// The size in bytes of a default record.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default size is 10KB.
|
||||
/// </remarks>
|
||||
public const int DefaultRecordSize = BlockSize * DefaultBlockFactor;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Get the record size for this buffer
|
||||
/// </summary>
|
||||
/// <value>The record size in bytes.
|
||||
/// This is equal to the <see cref="BlockFactor"/> multiplied by the <see cref="BlockSize"/></value>
|
||||
public int RecordSize
|
||||
{
|
||||
get {
|
||||
return recordSize;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the TAR Buffer's record size.
|
||||
/// </summary>
|
||||
/// <returns>The record size in bytes.
|
||||
/// This is equal to the <see cref="BlockFactor"/> multiplied by the <see cref="BlockSize"/></returns>
|
||||
[Obsolete("Use RecordSize property instead")]
|
||||
public int GetRecordSize()
|
||||
{
|
||||
return recordSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Blocking factor for the buffer
|
||||
/// </summary>
|
||||
/// <value>This is the number of blocks in each record.</value>
|
||||
public int BlockFactor {
|
||||
get {
|
||||
return blockFactor;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the TAR Buffer's block factor
|
||||
/// </summary>
|
||||
/// <returns>The block factor; the number of blocks per record.</returns>
|
||||
[Obsolete("Use BlockFactor property instead")]
|
||||
public int GetBlockFactor()
|
||||
{
|
||||
return blockFactor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a default TarBuffer
|
||||
/// </summary>
|
||||
protected TarBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create TarBuffer for reading with default BlockFactor
|
||||
/// </summary>
|
||||
/// <param name="inputStream">Stream to buffer</param>
|
||||
/// <returns>A new <see cref="TarBuffer"/> suitable for input.</returns>
|
||||
public static TarBuffer CreateInputTarBuffer(Stream inputStream)
|
||||
{
|
||||
if ( inputStream == null )
|
||||
{
|
||||
throw new ArgumentNullException("inputStream");
|
||||
}
|
||||
|
||||
return CreateInputTarBuffer(inputStream, DefaultBlockFactor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct TarBuffer for reading inputStream setting BlockFactor
|
||||
/// </summary>
|
||||
/// <param name="inputStream">Stream to buffer</param>
|
||||
/// <param name="blockFactor">Blocking factor to apply</param>
|
||||
/// <returns>A new <see cref="TarBuffer"/> suitable for input.</returns>
|
||||
public static TarBuffer CreateInputTarBuffer(Stream inputStream, int blockFactor)
|
||||
{
|
||||
if ( inputStream == null )
|
||||
{
|
||||
throw new ArgumentNullException("inputStream");
|
||||
}
|
||||
|
||||
if ( blockFactor <= 0 )
|
||||
{
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("blockFactor");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("blockFactor", "Factor cannot be negative");
|
||||
#endif
|
||||
}
|
||||
|
||||
TarBuffer tarBuffer = new TarBuffer();
|
||||
tarBuffer.inputStream = inputStream;
|
||||
tarBuffer.outputStream = null;
|
||||
tarBuffer.Initialize(blockFactor);
|
||||
|
||||
return tarBuffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct TarBuffer for writing with default BlockFactor
|
||||
/// </summary>
|
||||
/// <param name="outputStream">output stream for buffer</param>
|
||||
/// <returns>A new <see cref="TarBuffer"/> suitable for output.</returns>
|
||||
public static TarBuffer CreateOutputTarBuffer(Stream outputStream)
|
||||
{
|
||||
if ( outputStream == null )
|
||||
{
|
||||
throw new ArgumentNullException("outputStream");
|
||||
}
|
||||
|
||||
return CreateOutputTarBuffer(outputStream, DefaultBlockFactor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct TarBuffer for writing Tar output to streams.
|
||||
/// </summary>
|
||||
/// <param name="outputStream">Output stream to write to.</param>
|
||||
/// <param name="blockFactor">Blocking factor to apply</param>
|
||||
/// <returns>A new <see cref="TarBuffer"/> suitable for output.</returns>
|
||||
public static TarBuffer CreateOutputTarBuffer(Stream outputStream, int blockFactor)
|
||||
{
|
||||
if ( outputStream == null )
|
||||
{
|
||||
throw new ArgumentNullException("outputStream");
|
||||
}
|
||||
|
||||
if ( blockFactor <= 0 )
|
||||
{
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("blockFactor");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("blockFactor", "Factor cannot be negative");
|
||||
#endif
|
||||
}
|
||||
|
||||
TarBuffer tarBuffer = new TarBuffer();
|
||||
tarBuffer.inputStream = null;
|
||||
tarBuffer.outputStream = outputStream;
|
||||
tarBuffer.Initialize(blockFactor);
|
||||
|
||||
return tarBuffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialization common to all constructors.
|
||||
/// </summary>
|
||||
void Initialize(int archiveBlockFactor)
|
||||
{
|
||||
blockFactor = archiveBlockFactor;
|
||||
recordSize = archiveBlockFactor * BlockSize;
|
||||
recordBuffer = new byte[RecordSize];
|
||||
|
||||
if (inputStream != null) {
|
||||
currentRecordIndex = -1;
|
||||
currentBlockIndex = BlockFactor;
|
||||
}
|
||||
else {
|
||||
currentRecordIndex = 0;
|
||||
currentBlockIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if an archive block indicates End of Archive. End of
|
||||
/// archive is indicated by a block that consists entirely of null bytes.
|
||||
/// All remaining blocks for the record should also be null's
|
||||
/// However some older tars only do a couple of null blocks (Old GNU tar for one)
|
||||
/// and also partial records
|
||||
/// </summary>
|
||||
/// <param name = "block">The data block to check.</param>
|
||||
/// <returns>Returns true if the block is an EOF block; false otherwise.</returns>
|
||||
[Obsolete("Use IsEndOfArchiveBlock instead")]
|
||||
public bool IsEOFBlock(byte[] block)
|
||||
{
|
||||
if ( block == null ) {
|
||||
throw new ArgumentNullException("block");
|
||||
}
|
||||
|
||||
if ( block.Length != BlockSize )
|
||||
{
|
||||
throw new ArgumentException("block length is invalid");
|
||||
}
|
||||
|
||||
for (int i = 0; i < BlockSize; ++i) {
|
||||
if (block[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Determine if an archive block indicates the End of an Archive has been reached.
|
||||
/// End of archive is indicated by a block that consists entirely of null bytes.
|
||||
/// All remaining blocks for the record should also be null's
|
||||
/// However some older tars only do a couple of null blocks (Old GNU tar for one)
|
||||
/// and also partial records
|
||||
/// </summary>
|
||||
/// <param name = "block">The data block to check.</param>
|
||||
/// <returns>Returns true if the block is an EOF block; false otherwise.</returns>
|
||||
public static bool IsEndOfArchiveBlock(byte[] block)
|
||||
{
|
||||
if ( block == null ) {
|
||||
throw new ArgumentNullException("block");
|
||||
}
|
||||
|
||||
if ( block.Length != BlockSize ) {
|
||||
throw new ArgumentException("block length is invalid");
|
||||
}
|
||||
|
||||
for ( int i = 0; i < BlockSize; ++i ) {
|
||||
if ( block[i] != 0 ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skip over a block on the input stream.
|
||||
/// </summary>
|
||||
public void SkipBlock()
|
||||
{
|
||||
if (inputStream == null) {
|
||||
throw new TarException("no input stream defined");
|
||||
}
|
||||
|
||||
if (currentBlockIndex >= BlockFactor) {
|
||||
if (!ReadRecord()) {
|
||||
throw new TarException("Failed to read a record");
|
||||
}
|
||||
}
|
||||
|
||||
currentBlockIndex++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a block from the input stream.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The block of data read.
|
||||
/// </returns>
|
||||
public byte[] ReadBlock()
|
||||
{
|
||||
if (inputStream == null) {
|
||||
throw new TarException("TarBuffer.ReadBlock - no input stream defined");
|
||||
}
|
||||
|
||||
if (currentBlockIndex >= BlockFactor) {
|
||||
if (!ReadRecord()) {
|
||||
throw new TarException("Failed to read a record");
|
||||
}
|
||||
}
|
||||
|
||||
byte[] result = new byte[BlockSize];
|
||||
|
||||
Array.Copy(recordBuffer, (currentBlockIndex * BlockSize), result, 0, BlockSize );
|
||||
currentBlockIndex++;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a record from data stream.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// false if End-Of-File, else true.
|
||||
/// </returns>
|
||||
bool ReadRecord()
|
||||
{
|
||||
if (inputStream == null) {
|
||||
throw new TarException("no input stream stream defined");
|
||||
}
|
||||
|
||||
currentBlockIndex = 0;
|
||||
|
||||
int offset = 0;
|
||||
int bytesNeeded = RecordSize;
|
||||
|
||||
while (bytesNeeded > 0) {
|
||||
long numBytes = inputStream.Read(recordBuffer, offset, bytesNeeded);
|
||||
|
||||
//
|
||||
// NOTE
|
||||
// We have found EOF, and the record is not full!
|
||||
//
|
||||
// This is a broken archive. It does not follow the standard
|
||||
// blocking algorithm. However, because we are generous, and
|
||||
// it requires little effort, we will simply ignore the error
|
||||
// and continue as if the entire record were read. This does
|
||||
// not appear to break anything upstream. We used to return
|
||||
// false in this case.
|
||||
//
|
||||
// Thanks to 'Yohann.Roussel@alcatel.fr' for this fix.
|
||||
//
|
||||
if (numBytes <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
offset += (int)numBytes;
|
||||
bytesNeeded -= (int)numBytes;
|
||||
}
|
||||
|
||||
currentRecordIndex++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current block number, within the current record, zero based.
|
||||
/// </summary>
|
||||
/// <remarks>Block numbers are zero based values</remarks>
|
||||
/// <seealso cref="RecordSize"/>
|
||||
public int CurrentBlock
|
||||
{
|
||||
get { return currentBlockIndex; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set flag indicating ownership of the underlying stream.
|
||||
/// When the flag is true <see cref="Close"></see> will close the underlying stream also.
|
||||
/// </summary>
|
||||
public bool IsStreamOwner
|
||||
{
|
||||
get { return isStreamOwner_; }
|
||||
set { isStreamOwner_ = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current block number, within the current record, zero based.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The current zero based block number.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// The absolute block number = (<see cref="GetCurrentRecordNum">record number</see> * <see cref="BlockFactor">block factor</see>) + <see cref="GetCurrentBlockNum">block number</see>.
|
||||
/// </remarks>
|
||||
[Obsolete("Use CurrentBlock property instead")]
|
||||
public int GetCurrentBlockNum()
|
||||
{
|
||||
return currentBlockIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current record number.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The current zero based record number.
|
||||
/// </returns>
|
||||
public int CurrentRecord
|
||||
{
|
||||
get { return currentRecordIndex; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current record number.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The current zero based record number.
|
||||
/// </returns>
|
||||
[Obsolete("Use CurrentRecord property instead")]
|
||||
public int GetCurrentRecordNum()
|
||||
{
|
||||
return currentRecordIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a block of data to the archive.
|
||||
/// </summary>
|
||||
/// <param name="block">
|
||||
/// The data to write to the archive.
|
||||
/// </param>
|
||||
public void WriteBlock(byte[] block)
|
||||
{
|
||||
if ( block == null ) {
|
||||
throw new ArgumentNullException("block");
|
||||
}
|
||||
|
||||
if (outputStream == null) {
|
||||
throw new TarException("TarBuffer.WriteBlock - no output stream defined");
|
||||
}
|
||||
|
||||
if (block.Length != BlockSize) {
|
||||
string errorText = string.Format("TarBuffer.WriteBlock - block to write has length '{0}' which is not the block size of '{1}'",
|
||||
block.Length, BlockSize );
|
||||
throw new TarException(errorText);
|
||||
}
|
||||
|
||||
if (currentBlockIndex >= BlockFactor) {
|
||||
WriteRecord();
|
||||
}
|
||||
|
||||
Array.Copy(block, 0, recordBuffer, (currentBlockIndex * BlockSize), BlockSize);
|
||||
currentBlockIndex++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an archive record to the archive, where the record may be
|
||||
/// inside of a larger array buffer. The buffer must be "offset plus
|
||||
/// record size" long.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// The buffer containing the record data to write.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// The offset of the record data within buffer.
|
||||
/// </param>
|
||||
public void WriteBlock(byte[] buffer, int offset)
|
||||
{
|
||||
if ( buffer == null ) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
if (outputStream == null) {
|
||||
throw new TarException("TarBuffer.WriteBlock - no output stream stream defined");
|
||||
}
|
||||
|
||||
if ( (offset < 0) || (offset >= buffer.Length) )
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
}
|
||||
|
||||
if ((offset + BlockSize) > buffer.Length) {
|
||||
string errorText = string.Format("TarBuffer.WriteBlock - record has length '{0}' with offset '{1}' which is less than the record size of '{2}'",
|
||||
buffer.Length, offset, recordSize);
|
||||
throw new TarException(errorText);
|
||||
}
|
||||
|
||||
if (currentBlockIndex >= BlockFactor) {
|
||||
WriteRecord();
|
||||
}
|
||||
|
||||
Array.Copy(buffer, offset, recordBuffer, (currentBlockIndex * BlockSize), BlockSize);
|
||||
|
||||
currentBlockIndex++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a TarBuffer record to the archive.
|
||||
/// </summary>
|
||||
void WriteRecord()
|
||||
{
|
||||
if (outputStream == null) {
|
||||
throw new TarException("TarBuffer.WriteRecord no output stream defined");
|
||||
}
|
||||
|
||||
outputStream.Write(recordBuffer, 0, RecordSize);
|
||||
outputStream.Flush();
|
||||
|
||||
currentBlockIndex = 0;
|
||||
currentRecordIndex++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WriteFinalRecord writes the current record buffer to output any unwritten data is present.
|
||||
/// </summary>
|
||||
/// <remarks>Any trailing bytes are set to zero which is by definition correct behaviour
|
||||
/// for the end of a tar stream.</remarks>
|
||||
void WriteFinalRecord()
|
||||
{
|
||||
if (outputStream == null) {
|
||||
throw new TarException("TarBuffer.WriteFinalRecord no output stream defined");
|
||||
}
|
||||
|
||||
if (currentBlockIndex > 0) {
|
||||
int dataBytes = currentBlockIndex * BlockSize;
|
||||
Array.Clear(recordBuffer, dataBytes, RecordSize - dataBytes);
|
||||
WriteRecord();
|
||||
}
|
||||
|
||||
outputStream.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the TarBuffer. If this is an output buffer, also flush the
|
||||
/// current block before closing.
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
if (outputStream != null) {
|
||||
WriteFinalRecord();
|
||||
|
||||
if (isStreamOwner_) {
|
||||
outputStream.Close();
|
||||
}
|
||||
outputStream = null;
|
||||
}
|
||||
else if (inputStream != null) {
|
||||
if (isStreamOwner_) {
|
||||
inputStream.Close();
|
||||
}
|
||||
inputStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
Stream inputStream;
|
||||
Stream outputStream;
|
||||
|
||||
byte[] recordBuffer;
|
||||
int currentBlockIndex;
|
||||
int currentRecordIndex;
|
||||
|
||||
int recordSize = DefaultRecordSize;
|
||||
int blockFactor = DefaultBlockFactor;
|
||||
bool isStreamOwner_ = true;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
/* The original Java file had this header:
|
||||
*
|
||||
** Authored by Timothy Gerard Endres
|
||||
** <mailto:time@gjt.org> <http://www.trustice.com>
|
||||
**
|
||||
** This work has been placed into the public domain.
|
||||
** You may use this work in any way and for any purpose you wish.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
|
||||
** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
|
||||
** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
|
||||
** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
|
||||
** REDISTRIBUTION OF THIS SOFTWARE.
|
||||
**
|
||||
*/
|
|
@ -0,0 +1,559 @@
|
|||
// TarEntry.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Tar
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents an entry in a Tar archive. It consists
|
||||
/// of the entry's header, as well as the entry's File. Entries
|
||||
/// can be instantiated in one of three ways, depending on how
|
||||
/// they are to be used.
|
||||
/// <p>
|
||||
/// TarEntries that are created from the header bytes read from
|
||||
/// an archive are instantiated with the TarEntry( byte[] )
|
||||
/// constructor. These entries will be used when extracting from
|
||||
/// or listing the contents of an archive. These entries have their
|
||||
/// header filled in using the header bytes. They also set the File
|
||||
/// to null, since they reference an archive entry not a file.</p>
|
||||
/// <p>
|
||||
/// TarEntries that are created from files that are to be written
|
||||
/// into an archive are instantiated with the CreateEntryFromFile(string)
|
||||
/// pseudo constructor. These entries have their header filled in using
|
||||
/// the File's information. They also keep a reference to the File
|
||||
/// for convenience when writing entries.</p>
|
||||
/// <p>
|
||||
/// Finally, TarEntries can be constructed from nothing but a name.
|
||||
/// This allows the programmer to construct the entry by hand, for
|
||||
/// instance when only an InputStream is available for writing to
|
||||
/// the archive, and the header information is constructed from
|
||||
/// other information. In this case the header fields are set to
|
||||
/// defaults and the File is set to null.</p>
|
||||
/// <see cref="TarHeader"/>
|
||||
/// </summary>
|
||||
public class TarEntry : ICloneable
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialise a default instance of <see cref="TarEntry"/>.
|
||||
/// </summary>
|
||||
private TarEntry()
|
||||
{
|
||||
header = new TarHeader();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct an entry from an archive's header bytes. File is set
|
||||
/// to null.
|
||||
/// </summary>
|
||||
/// <param name = "headerBuffer">
|
||||
/// The header bytes from a tar archive entry.
|
||||
/// </param>
|
||||
public TarEntry(byte[] headerBuffer)
|
||||
{
|
||||
header = new TarHeader();
|
||||
header.ParseBuffer(headerBuffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a TarEntry using the <paramref name="header">header</paramref> provided
|
||||
/// </summary>
|
||||
/// <param name="header">Header details for entry</param>
|
||||
public TarEntry(TarHeader header)
|
||||
{
|
||||
if ( header == null )
|
||||
{
|
||||
throw new ArgumentNullException("header");
|
||||
}
|
||||
|
||||
this.header = (TarHeader)header.Clone();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ICloneable Members
|
||||
/// <summary>
|
||||
/// Clone this tar entry.
|
||||
/// </summary>
|
||||
/// <returns>Returns a clone of this entry.</returns>
|
||||
public object Clone()
|
||||
{
|
||||
TarEntry entry = new TarEntry();
|
||||
entry.file = file;
|
||||
entry.header = (TarHeader)header.Clone();
|
||||
entry.Name = Name;
|
||||
return entry;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Construct an entry with only a <paramref name="name">name</paramref>.
|
||||
/// This allows the programmer to construct the entry's header "by hand".
|
||||
/// </summary>
|
||||
/// <param name="name">The name to use for the entry</param>
|
||||
/// <returns>Returns the newly created <see cref="TarEntry"/></returns>
|
||||
public static TarEntry CreateTarEntry(string name)
|
||||
{
|
||||
TarEntry entry = new TarEntry();
|
||||
TarEntry.NameTarHeader(entry.header, name);
|
||||
return entry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct an entry for a file. File is set to file, and the
|
||||
/// header is constructed from information from the file.
|
||||
/// </summary>
|
||||
/// <param name = "fileName">The file name that the entry represents.</param>
|
||||
/// <returns>Returns the newly created <see cref="TarEntry"/></returns>
|
||||
public static TarEntry CreateEntryFromFile(string fileName)
|
||||
{
|
||||
TarEntry entry = new TarEntry();
|
||||
entry.GetFileTarHeader(entry.header, fileName);
|
||||
return entry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if the two entries are equal. Equality is determined
|
||||
/// by the header names being equal.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="Object"/> to compare with the current Object.</param>
|
||||
/// <returns>
|
||||
/// True if the entries are equal; false if not.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
TarEntry localEntry = obj as TarEntry;
|
||||
|
||||
if ( localEntry != null )
|
||||
{
|
||||
return Name.Equals(localEntry.Name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Derive a Hash value for the current <see cref="Object"/>
|
||||
/// </summary>
|
||||
/// <returns>A Hash code for the current <see cref="Object"/></returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Name.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if the given entry is a descendant of this entry.
|
||||
/// Descendancy is determined by the name of the descendant
|
||||
/// starting with this entry's name.
|
||||
/// </summary>
|
||||
/// <param name = "toTest">
|
||||
/// Entry to be checked as a descendent of this.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True if entry is a descendant of this.
|
||||
/// </returns>
|
||||
public bool IsDescendent(TarEntry toTest)
|
||||
{
|
||||
if ( toTest == null ) {
|
||||
throw new ArgumentNullException("toTest");
|
||||
}
|
||||
|
||||
return toTest.Name.StartsWith(Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get this entry's header.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// This entry's TarHeader.
|
||||
/// </returns>
|
||||
public TarHeader TarHeader
|
||||
{
|
||||
get {
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set this entry's name.
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get {
|
||||
return header.Name;
|
||||
}
|
||||
set {
|
||||
header.Name = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set this entry's user id.
|
||||
/// </summary>
|
||||
public int UserId
|
||||
{
|
||||
get {
|
||||
return header.UserId;
|
||||
}
|
||||
set {
|
||||
header.UserId = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set this entry's group id.
|
||||
/// </summary>
|
||||
public int GroupId
|
||||
{
|
||||
get {
|
||||
return header.GroupId;
|
||||
}
|
||||
set {
|
||||
header.GroupId = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set this entry's user name.
|
||||
/// </summary>
|
||||
public string UserName
|
||||
{
|
||||
get {
|
||||
return header.UserName;
|
||||
}
|
||||
set {
|
||||
header.UserName = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set this entry's group name.
|
||||
/// </summary>
|
||||
public string GroupName
|
||||
{
|
||||
get {
|
||||
return header.GroupName;
|
||||
}
|
||||
set {
|
||||
header.GroupName = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience method to set this entry's group and user ids.
|
||||
/// </summary>
|
||||
/// <param name="userId">
|
||||
/// This entry's new user id.
|
||||
/// </param>
|
||||
/// <param name="groupId">
|
||||
/// This entry's new group id.
|
||||
/// </param>
|
||||
public void SetIds(int userId, int groupId)
|
||||
{
|
||||
UserId = userId;
|
||||
GroupId = groupId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience method to set this entry's group and user names.
|
||||
/// </summary>
|
||||
/// <param name="userName">
|
||||
/// This entry's new user name.
|
||||
/// </param>
|
||||
/// <param name="groupName">
|
||||
/// This entry's new group name.
|
||||
/// </param>
|
||||
public void SetNames(string userName, string groupName)
|
||||
{
|
||||
UserName = userName;
|
||||
GroupName = groupName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the modification time for this entry
|
||||
/// </summary>
|
||||
public DateTime ModTime {
|
||||
get {
|
||||
return header.ModTime;
|
||||
}
|
||||
set {
|
||||
header.ModTime = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get this entry's file.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// This entry's file.
|
||||
/// </returns>
|
||||
public string File {
|
||||
get {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set this entry's recorded file size.
|
||||
/// </summary>
|
||||
public long Size {
|
||||
get {
|
||||
return header.Size;
|
||||
}
|
||||
set {
|
||||
header.Size = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return true if this entry represents a directory, false otherwise
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// True if this entry is a directory.
|
||||
/// </returns>
|
||||
public bool IsDirectory {
|
||||
get {
|
||||
if (file != null) {
|
||||
return Directory.Exists(file);
|
||||
}
|
||||
|
||||
if (header != null) {
|
||||
if ((header.TypeFlag == TarHeader.LF_DIR) || Name.EndsWith( "/" )) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill in a TarHeader with information from a File.
|
||||
/// </summary>
|
||||
/// <param name="header">
|
||||
/// The TarHeader to fill in.
|
||||
/// </param>
|
||||
/// <param name="file">
|
||||
/// The file from which to get the header information.
|
||||
/// </param>
|
||||
public void GetFileTarHeader(TarHeader header, string file)
|
||||
{
|
||||
if ( header == null ) {
|
||||
throw new ArgumentNullException("header");
|
||||
}
|
||||
|
||||
if ( file == null ) {
|
||||
throw new ArgumentNullException("file");
|
||||
}
|
||||
|
||||
this.file = file;
|
||||
|
||||
// bugfix from torhovl from #D forum:
|
||||
string name = file;
|
||||
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
// 23-Jan-2004 GnuTar allows device names in path where the name is not local to the current directory
|
||||
if (name.IndexOf(Environment.CurrentDirectory) == 0) {
|
||||
name = name.Substring(Environment.CurrentDirectory.Length);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
if (Path.DirectorySeparatorChar == '\\')
|
||||
{
|
||||
// check if the OS is Windows
|
||||
// Strip off drive letters!
|
||||
if (name.Length > 2)
|
||||
{
|
||||
char ch1 = name[0];
|
||||
char ch2 = name[1];
|
||||
|
||||
if (ch2 == ':' && Char.IsLetter(ch1))
|
||||
{
|
||||
name = name.Substring(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
name = name.Replace(Path.DirectorySeparatorChar, '/');
|
||||
|
||||
// No absolute pathnames
|
||||
// Windows (and Posix?) paths can start with UNC style "\\NetworkDrive\",
|
||||
// so we loop on starting /'s.
|
||||
while (name.StartsWith("/")) {
|
||||
name = name.Substring(1);
|
||||
}
|
||||
|
||||
header.LinkName = String.Empty;
|
||||
header.Name = name;
|
||||
|
||||
if (Directory.Exists(file)) {
|
||||
header.Mode = 1003; // Magic number for security access for a UNIX filesystem
|
||||
header.TypeFlag = TarHeader.LF_DIR;
|
||||
if ( (header.Name.Length == 0) || header.Name[header.Name.Length - 1] != '/') {
|
||||
header.Name = header.Name + "/";
|
||||
}
|
||||
|
||||
header.Size = 0;
|
||||
} else {
|
||||
header.Mode = 33216; // Magic number for security access for a UNIX filesystem
|
||||
header.TypeFlag = TarHeader.LF_NORMAL;
|
||||
header.Size = new FileInfo(file.Replace('/', Path.DirectorySeparatorChar)).Length;
|
||||
}
|
||||
|
||||
header.ModTime = System.IO.File.GetLastWriteTime(file.Replace('/', Path.DirectorySeparatorChar)).ToUniversalTime();
|
||||
header.DevMajor = 0;
|
||||
header.DevMinor = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get entries for all files present in this entries directory.
|
||||
/// If this entry doesnt represent a directory zero entries are returned.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// An array of TarEntry's for this entry's children.
|
||||
/// </returns>
|
||||
public TarEntry[] GetDirectoryEntries()
|
||||
{
|
||||
if ( (file == null) || !Directory.Exists(file)) {
|
||||
return new TarEntry[0];
|
||||
}
|
||||
|
||||
string[] list = Directory.GetFileSystemEntries(file);
|
||||
TarEntry[] result = new TarEntry[list.Length];
|
||||
|
||||
for (int i = 0; i < list.Length; ++i) {
|
||||
result[i] = TarEntry.CreateEntryFromFile(list[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an entry's header information to a header buffer.
|
||||
/// </summary>
|
||||
/// <param name = "outBuffer">
|
||||
/// The tar entry header buffer to fill in.
|
||||
/// </param>
|
||||
public void WriteEntryHeader(byte[] outBuffer)
|
||||
{
|
||||
header.WriteHeader(outBuffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience method that will modify an entry's name directly
|
||||
/// in place in an entry header buffer byte array.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// The buffer containing the entry header to modify.
|
||||
/// </param>
|
||||
/// <param name="newName">
|
||||
/// The new name to place into the header buffer.
|
||||
/// </param>
|
||||
static public void AdjustEntryName(byte[] buffer, string newName)
|
||||
{
|
||||
TarHeader.GetNameBytes(newName, buffer, 0, TarHeader.NAMELEN);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill in a TarHeader given only the entry's name.
|
||||
/// </summary>
|
||||
/// <param name="header">
|
||||
/// The TarHeader to fill in.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// The tar entry name.
|
||||
/// </param>
|
||||
static public void NameTarHeader(TarHeader header, string name)
|
||||
{
|
||||
if ( header == null ) {
|
||||
throw new ArgumentNullException("header");
|
||||
}
|
||||
|
||||
if ( name == null ) {
|
||||
throw new ArgumentNullException("name");
|
||||
}
|
||||
|
||||
bool isDir = name.EndsWith("/");
|
||||
|
||||
header.Name = name;
|
||||
header.Mode = isDir ? 1003 : 33216;
|
||||
header.UserId = 0;
|
||||
header.GroupId = 0;
|
||||
header.Size = 0;
|
||||
|
||||
header.ModTime = DateTime.UtcNow;
|
||||
|
||||
header.TypeFlag = isDir ? TarHeader.LF_DIR : TarHeader.LF_NORMAL;
|
||||
|
||||
header.LinkName = String.Empty;
|
||||
header.UserName = String.Empty;
|
||||
header.GroupName = String.Empty;
|
||||
|
||||
header.DevMajor = 0;
|
||||
header.DevMinor = 0;
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// The name of the file this entry represents or null if the entry is not based on a file.
|
||||
/// </summary>
|
||||
string file;
|
||||
|
||||
/// <summary>
|
||||
/// The entry's header information.
|
||||
/// </summary>
|
||||
TarHeader header;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The original Java file had this header:
|
||||
*
|
||||
** Authored by Timothy Gerard Endres
|
||||
** <mailto:time@gjt.org> <http://www.trustice.com>
|
||||
**
|
||||
** This work has been placed into the public domain.
|
||||
** You may use this work in any way and for any purpose you wish.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
|
||||
** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
|
||||
** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
|
||||
** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
|
||||
** REDISTRIBUTION OF THIS SOFTWARE.
|
||||
**
|
||||
*/
|
|
@ -0,0 +1,91 @@
|
|||
// TarException.cs
|
||||
//
|
||||
// Copyright 2004 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
using System.Runtime.Serialization;
|
||||
#endif
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Tar {
|
||||
|
||||
/// <summary>
|
||||
/// TarExceptions are used for exceptions specific to tar classes and code.
|
||||
/// </summary>
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
[Serializable]
|
||||
#endif
|
||||
public class TarException : SharpZipBaseException
|
||||
{
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
/// <summary>
|
||||
/// Deserialization constructor
|
||||
/// </summary>
|
||||
/// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>
|
||||
/// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
|
||||
protected TarException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Initialises a new instance of the TarException class.
|
||||
/// </summary>
|
||||
public TarException()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialises a new instance of the TarException class with a specified message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public TarException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message">A message describing the error.</param>
|
||||
/// <param name="exception">The exception that is the cause of the current exception.</param>
|
||||
public TarException(string message, Exception exception)
|
||||
: base(message, exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,695 @@
|
|||
// TarInputStream.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Tar
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The TarInputStream reads a UNIX tar archive as an InputStream.
|
||||
/// methods are provided to position at each successive entry in
|
||||
/// the archive, and the read each entry as a normal input stream
|
||||
/// using read().
|
||||
/// </summary>
|
||||
public class TarInputStream : Stream
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Construct a TarInputStream with default block factor
|
||||
/// </summary>
|
||||
/// <param name="inputStream">stream to source data from</param>
|
||||
public TarInputStream(Stream inputStream)
|
||||
: this(inputStream, TarBuffer.DefaultBlockFactor)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a TarInputStream with user specified block factor
|
||||
/// </summary>
|
||||
/// <param name="inputStream">stream to source data from</param>
|
||||
/// <param name="blockFactor">block factor to apply to archive</param>
|
||||
public TarInputStream(Stream inputStream, int blockFactor)
|
||||
{
|
||||
this.inputStream = inputStream;
|
||||
tarBuffer = TarBuffer.CreateInputTarBuffer(inputStream, blockFactor);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Get/set flag indicating ownership of the underlying stream.
|
||||
/// When the flag is true <see cref="Close"></see> will close the underlying stream also.
|
||||
/// </summary>
|
||||
public bool IsStreamOwner
|
||||
{
|
||||
get { return tarBuffer.IsStreamOwner; }
|
||||
set { tarBuffer.IsStreamOwner = value; }
|
||||
}
|
||||
|
||||
#region Stream Overrides
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current stream supports reading
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get {
|
||||
return inputStream.CanRead;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current stream supports seeking
|
||||
/// This property always returns false.
|
||||
/// </summary>
|
||||
public override bool CanSeek {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating if the stream supports writing.
|
||||
/// This property always returns false.
|
||||
/// </summary>
|
||||
public override bool CanWrite {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The length in bytes of the stream
|
||||
/// </summary>
|
||||
public override long Length {
|
||||
get {
|
||||
return inputStream.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position within the stream.
|
||||
/// Setting the Position is not supported and throws a NotSupportedExceptionNotSupportedException
|
||||
/// </summary>
|
||||
/// <exception cref="NotSupportedException">Any attempt to set position</exception>
|
||||
public override long Position {
|
||||
get {
|
||||
return inputStream.Position;
|
||||
}
|
||||
set {
|
||||
throw new NotSupportedException("TarInputStream Seek not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the baseInputStream
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
inputStream.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the streams position. This operation is not supported and will throw a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset relative to the origin to seek to.</param>
|
||||
/// <param name="origin">The <see cref="SeekOrigin"/> to start seeking from.</param>
|
||||
/// <returns>The new position in the stream.</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException("TarInputStream Seek not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the length of the stream
|
||||
/// This operation is not supported and will throw a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="value">The new stream length.</param>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException("TarInputStream SetLength not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a block of bytes to this stream using data from a buffer.
|
||||
/// This operation is not supported and will throw a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer containing bytes to write.</param>
|
||||
/// <param name="offset">The offset in the buffer of the frist byte to write.</param>
|
||||
/// <param name="count">The number of bytes to write.</param>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException("TarInputStream Write not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte to the current position in the file stream.
|
||||
/// This operation is not supported and will throw a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="value">The byte value to write.</param>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
throw new NotSupportedException("TarInputStream WriteByte not supported");
|
||||
}
|
||||
/// <summary>
|
||||
/// Reads a byte from the current tar archive entry.
|
||||
/// </summary>
|
||||
/// <returns>A byte cast to an int; -1 if the at the end of the stream.</returns>
|
||||
public override int ReadByte()
|
||||
{
|
||||
byte[] oneByteBuffer = new byte[1];
|
||||
int num = Read(oneByteBuffer, 0, 1);
|
||||
if (num <= 0)
|
||||
{
|
||||
// return -1 to indicate that no byte was read.
|
||||
return -1;
|
||||
}
|
||||
return oneByteBuffer[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads bytes from the current tar archive entry.
|
||||
///
|
||||
/// This method is aware of the boundaries of the current
|
||||
/// entry in the archive and will deal with them appropriately
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// The buffer into which to place bytes read.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// The offset at which to place bytes read.
|
||||
/// </param>
|
||||
/// <param name="count">
|
||||
/// The number of bytes to read.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The number of bytes read, or 0 at end of stream/EOF.
|
||||
/// </returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if ( buffer == null )
|
||||
{
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
int totalRead = 0;
|
||||
|
||||
if (entryOffset >= entrySize)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
long numToRead = count;
|
||||
|
||||
if ((numToRead + entryOffset) > entrySize)
|
||||
{
|
||||
numToRead = entrySize - entryOffset;
|
||||
}
|
||||
|
||||
if (readBuffer != null)
|
||||
{
|
||||
int sz = (numToRead > readBuffer.Length) ? readBuffer.Length : (int)numToRead;
|
||||
|
||||
Array.Copy(readBuffer, 0, buffer, offset, sz);
|
||||
|
||||
if (sz >= readBuffer.Length)
|
||||
{
|
||||
readBuffer = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
int newLen = readBuffer.Length - sz;
|
||||
byte[] newBuf = new byte[newLen];
|
||||
Array.Copy(readBuffer, sz, newBuf, 0, newLen);
|
||||
readBuffer = newBuf;
|
||||
}
|
||||
|
||||
totalRead += sz;
|
||||
numToRead -= sz;
|
||||
offset += sz;
|
||||
}
|
||||
|
||||
while (numToRead > 0)
|
||||
{
|
||||
byte[] rec = tarBuffer.ReadBlock();
|
||||
if (rec == null)
|
||||
{
|
||||
// Unexpected EOF!
|
||||
throw new TarException("unexpected EOF with " + numToRead + " bytes unread");
|
||||
}
|
||||
|
||||
int sz = (int)numToRead;
|
||||
int recLen = rec.Length;
|
||||
|
||||
if (recLen > sz)
|
||||
{
|
||||
Array.Copy(rec, 0, buffer, offset, sz);
|
||||
readBuffer = new byte[recLen - sz];
|
||||
Array.Copy(rec, sz, readBuffer, 0, recLen - sz);
|
||||
}
|
||||
else
|
||||
{
|
||||
sz = recLen;
|
||||
Array.Copy(rec, 0, buffer, offset, recLen);
|
||||
}
|
||||
|
||||
totalRead += sz;
|
||||
numToRead -= sz;
|
||||
offset += sz;
|
||||
}
|
||||
|
||||
entryOffset += totalRead;
|
||||
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes this stream. Calls the TarBuffer's close() method.
|
||||
/// The underlying stream is closed by the TarBuffer.
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
tarBuffer.Close();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Set the entry factory for this instance.
|
||||
/// </summary>
|
||||
/// <param name="factory">The factory for creating new entries</param>
|
||||
public void SetEntryFactory(IEntryFactory factory)
|
||||
{
|
||||
entryFactory = factory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the record size being used by this stream's TarBuffer.
|
||||
/// </summary>
|
||||
public int RecordSize
|
||||
{
|
||||
get { return tarBuffer.RecordSize; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the record size being used by this stream's TarBuffer.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// TarBuffer record size.
|
||||
/// </returns>
|
||||
[Obsolete("Use RecordSize property instead")]
|
||||
public int GetRecordSize()
|
||||
{
|
||||
return tarBuffer.RecordSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the available data that can be read from the current
|
||||
/// entry in the archive. This does not indicate how much data
|
||||
/// is left in the entire archive, only in the current entry.
|
||||
/// This value is determined from the entry's size header field
|
||||
/// and the amount of data already read from the current entry.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The number of available bytes for the current entry.
|
||||
/// </returns>
|
||||
public long Available {
|
||||
get {
|
||||
return entrySize - entryOffset;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skip bytes in the input buffer. This skips bytes in the
|
||||
/// current entry's data, not the entire archive, and will
|
||||
/// stop at the end of the current entry's data if the number
|
||||
/// to skip extends beyond that point.
|
||||
/// </summary>
|
||||
/// <param name="skipCount">
|
||||
/// The number of bytes to skip.
|
||||
/// </param>
|
||||
public void Skip(long skipCount)
|
||||
{
|
||||
// TODO: REVIEW efficiency of TarInputStream.Skip
|
||||
// This is horribly inefficient, but it ensures that we
|
||||
// properly skip over bytes via the TarBuffer...
|
||||
//
|
||||
byte[] skipBuf = new byte[8 * 1024];
|
||||
|
||||
for (long num = skipCount; num > 0;) {
|
||||
int toRead = num > skipBuf.Length ? skipBuf.Length : (int)num;
|
||||
int numRead = Read(skipBuf, 0, toRead);
|
||||
|
||||
if (numRead == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
num -= numRead;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a value of true if marking is supported; false otherwise.
|
||||
/// </summary>
|
||||
/// <remarks>Currently marking is not supported, the return value is always false.</remarks>
|
||||
public bool IsMarkSupported {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Since we do not support marking just yet, we do nothing.
|
||||
/// </summary>
|
||||
/// <param name ="markLimit">
|
||||
/// The limit to mark.
|
||||
/// </param>
|
||||
public void Mark(int markLimit)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Since we do not support marking just yet, we do nothing.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the next entry in this tar archive. This will skip
|
||||
/// over any remaining data in the current entry, if there
|
||||
/// is one, and place the input stream at the header of the
|
||||
/// next entry, and read the header and instantiate a new
|
||||
/// TarEntry from the header bytes and return that entry.
|
||||
/// If there are no more entries in the archive, null will
|
||||
/// be returned to indicate that the end of the archive has
|
||||
/// been reached.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The next TarEntry in the archive, or null.
|
||||
/// </returns>
|
||||
public TarEntry GetNextEntry()
|
||||
{
|
||||
if (hasHitEOF) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (currentEntry != null) {
|
||||
SkipToNextEntry();
|
||||
}
|
||||
|
||||
byte[] headerBuf = tarBuffer.ReadBlock();
|
||||
|
||||
if (headerBuf == null) {
|
||||
hasHitEOF = true;
|
||||
} else if (TarBuffer.IsEndOfArchiveBlock(headerBuf)) {
|
||||
hasHitEOF = true;
|
||||
}
|
||||
|
||||
if (hasHitEOF) {
|
||||
currentEntry = null;
|
||||
} else {
|
||||
try {
|
||||
TarHeader header = new TarHeader();
|
||||
header.ParseBuffer(headerBuf);
|
||||
if ( !header.IsChecksumValid )
|
||||
{
|
||||
throw new TarException("Header checksum is invalid");
|
||||
}
|
||||
this.entryOffset = 0;
|
||||
this.entrySize = header.Size;
|
||||
|
||||
StringBuilder longName = null;
|
||||
|
||||
if (header.TypeFlag == TarHeader.LF_GNU_LONGNAME) {
|
||||
|
||||
byte[] nameBuffer = new byte[TarBuffer.BlockSize];
|
||||
long numToRead = this.entrySize;
|
||||
|
||||
longName = new StringBuilder();
|
||||
|
||||
while (numToRead > 0) {
|
||||
int numRead = this.Read(nameBuffer, 0, (numToRead > nameBuffer.Length ? nameBuffer.Length : (int)numToRead));
|
||||
|
||||
if (numRead == -1) {
|
||||
throw new InvalidHeaderException("Failed to read long name entry");
|
||||
}
|
||||
|
||||
longName.Append(TarHeader.ParseName(nameBuffer, 0, numRead).ToString());
|
||||
numToRead -= numRead;
|
||||
}
|
||||
|
||||
SkipToNextEntry();
|
||||
headerBuf = this.tarBuffer.ReadBlock();
|
||||
} else if (header.TypeFlag == TarHeader.LF_GHDR) { // POSIX global extended header
|
||||
// Ignore things we dont understand completely for now
|
||||
SkipToNextEntry();
|
||||
headerBuf = this.tarBuffer.ReadBlock();
|
||||
} else if (header.TypeFlag == TarHeader.LF_XHDR) { // POSIX extended header
|
||||
// Ignore things we dont understand completely for now
|
||||
SkipToNextEntry();
|
||||
headerBuf = this.tarBuffer.ReadBlock();
|
||||
} else if (header.TypeFlag == TarHeader.LF_GNU_VOLHDR) {
|
||||
// TODO: could show volume name when verbose
|
||||
SkipToNextEntry();
|
||||
headerBuf = this.tarBuffer.ReadBlock();
|
||||
} else if (header.TypeFlag != TarHeader.LF_NORMAL &&
|
||||
header.TypeFlag != TarHeader.LF_OLDNORM &&
|
||||
header.TypeFlag != TarHeader.LF_DIR) {
|
||||
// Ignore things we dont understand completely for now
|
||||
SkipToNextEntry();
|
||||
headerBuf = tarBuffer.ReadBlock();
|
||||
}
|
||||
|
||||
if (entryFactory == null) {
|
||||
currentEntry = new TarEntry(headerBuf);
|
||||
if (longName != null) {
|
||||
currentEntry.Name = longName.ToString();
|
||||
}
|
||||
} else {
|
||||
currentEntry = entryFactory.CreateEntry(headerBuf);
|
||||
}
|
||||
|
||||
// Magic was checked here for 'ustar' but there are multiple valid possibilities
|
||||
// so this is not done anymore.
|
||||
|
||||
entryOffset = 0;
|
||||
|
||||
// TODO: Review How do we resolve this discrepancy?!
|
||||
entrySize = this.currentEntry.Size;
|
||||
} catch (InvalidHeaderException ex) {
|
||||
entrySize = 0;
|
||||
entryOffset = 0;
|
||||
currentEntry = null;
|
||||
string errorText = string.Format("Bad header in record {0} block {1} {2}",
|
||||
tarBuffer.CurrentRecord, tarBuffer.CurrentBlock, ex.Message);
|
||||
throw new InvalidHeaderException(errorText);
|
||||
}
|
||||
}
|
||||
return currentEntry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the contents of the current tar archive entry directly into
|
||||
/// an output stream.
|
||||
/// </summary>
|
||||
/// <param name="outputStream">
|
||||
/// The OutputStream into which to write the entry's data.
|
||||
/// </param>
|
||||
public void CopyEntryContents(Stream outputStream)
|
||||
{
|
||||
byte[] tempBuffer = new byte[32 * 1024];
|
||||
|
||||
while (true) {
|
||||
int numRead = Read(tempBuffer, 0, tempBuffer.Length);
|
||||
if (numRead <= 0) {
|
||||
break;
|
||||
}
|
||||
outputStream.Write(tempBuffer, 0, numRead);
|
||||
}
|
||||
}
|
||||
|
||||
void SkipToNextEntry()
|
||||
{
|
||||
long numToSkip = entrySize - entryOffset;
|
||||
|
||||
if (numToSkip > 0)
|
||||
{
|
||||
Skip(numToSkip);
|
||||
}
|
||||
|
||||
readBuffer = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface is provided, along with the method <see cref="SetEntryFactory"/>, to allow
|
||||
/// the programmer to have their own <see cref="TarEntry"/> subclass instantiated for the
|
||||
/// entries return from <see cref="GetNextEntry"/>.
|
||||
/// </summary>
|
||||
public interface IEntryFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an entry based on name alone
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// Name of the new EntryPointNotFoundException to create
|
||||
/// </param>
|
||||
/// <returns>created TarEntry or descendant class</returns>
|
||||
TarEntry CreateEntry(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance based on an actual file
|
||||
/// </summary>
|
||||
/// <param name="fileName">
|
||||
/// Name of file to represent in the entry
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Created TarEntry or descendant class
|
||||
/// </returns>
|
||||
TarEntry CreateEntryFromFile(string fileName);
|
||||
|
||||
/// <summary>
|
||||
/// Create a tar entry based on the header information passed
|
||||
/// </summary>
|
||||
/// <param name="headerBuffer">
|
||||
/// Buffer containing header information to create an an entry from.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Created TarEntry or descendant class
|
||||
/// </returns>
|
||||
TarEntry CreateEntry(byte[] headerBuffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Standard entry factory class creating instances of the class TarEntry
|
||||
/// </summary>
|
||||
public class EntryFactoryAdapter : IEntryFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a <see cref="TarEntry"/> based on named
|
||||
/// </summary>
|
||||
/// <param name="name">The name to use for the entry</param>
|
||||
/// <returns>A new <see cref="TarEntry"/></returns>
|
||||
public TarEntry CreateEntry(string name)
|
||||
{
|
||||
return TarEntry.CreateTarEntry(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a tar entry with details obtained from <paramref name="fileName">file</paramref>
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to retrieve details from.</param>
|
||||
/// <returns>A new <see cref="TarEntry"/></returns>
|
||||
public TarEntry CreateEntryFromFile(string fileName)
|
||||
{
|
||||
return TarEntry.CreateEntryFromFile(fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an entry based on details in <paramref name="headerBuffer">header</paramref>
|
||||
/// </summary>
|
||||
/// <param name="headerBuffer">The buffer containing entry details.</param>
|
||||
/// <returns>A new <see cref="TarEntry"/></returns>
|
||||
public TarEntry CreateEntry(byte[] headerBuffer)
|
||||
{
|
||||
return new TarEntry(headerBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// Flag set when last block has been read
|
||||
/// </summary>
|
||||
protected bool hasHitEOF;
|
||||
|
||||
/// <summary>
|
||||
/// Size of this entry as recorded in header
|
||||
/// </summary>
|
||||
protected long entrySize;
|
||||
|
||||
/// <summary>
|
||||
/// Number of bytes read for this entry so far
|
||||
/// </summary>
|
||||
protected long entryOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Buffer used with calls to <code>Read()</code>
|
||||
/// </summary>
|
||||
protected byte[] readBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Working buffer
|
||||
/// </summary>
|
||||
protected TarBuffer tarBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Current entry being read
|
||||
/// </summary>
|
||||
TarEntry currentEntry;
|
||||
|
||||
/// <summary>
|
||||
/// Factory used to create TarEntry or descendant class instance
|
||||
/// </summary>
|
||||
protected IEntryFactory entryFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Stream used as the source of input data.
|
||||
/// </summary>
|
||||
readonly Stream inputStream;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
/* The original Java file had this header:
|
||||
** Authored by Timothy Gerard Endres
|
||||
** <mailto:time@gjt.org> <http://www.trustice.com>
|
||||
**
|
||||
** This work has been placed into the public domain.
|
||||
** You may use this work in any way and for any purpose you wish.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
|
||||
** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
|
||||
** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
|
||||
** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
|
||||
** REDISTRIBUTION OF THIS SOFTWARE.
|
||||
**
|
||||
*/
|
||||
|
|
@ -0,0 +1,525 @@
|
|||
// TarOutputStream.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
// Copyright 2005 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Tar
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The TarOutputStream writes a UNIX tar archive as an OutputStream.
|
||||
/// Methods are provided to put entries, and then write their contents
|
||||
/// by writing to this stream using write().
|
||||
/// </summary>
|
||||
/// public
|
||||
public class TarOutputStream : Stream
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Construct TarOutputStream using default block factor
|
||||
/// </summary>
|
||||
/// <param name="outputStream">stream to write to</param>
|
||||
public TarOutputStream(Stream outputStream)
|
||||
: this(outputStream, TarBuffer.DefaultBlockFactor)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct TarOutputStream with user specified block factor
|
||||
/// </summary>
|
||||
/// <param name="outputStream">stream to write to</param>
|
||||
/// <param name="blockFactor">blocking factor</param>
|
||||
public TarOutputStream(Stream outputStream, int blockFactor)
|
||||
{
|
||||
if ( outputStream == null )
|
||||
{
|
||||
throw new ArgumentNullException("outputStream");
|
||||
}
|
||||
|
||||
this.outputStream = outputStream;
|
||||
buffer = TarBuffer.CreateOutputTarBuffer(outputStream, blockFactor);
|
||||
|
||||
assemblyBuffer = new byte[TarBuffer.BlockSize];
|
||||
blockBuffer = new byte[TarBuffer.BlockSize];
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Get/set flag indicating ownership of the underlying stream.
|
||||
/// When the flag is true <see cref="Close"></see> will close the underlying stream also.
|
||||
/// </summary>
|
||||
public bool IsStreamOwner
|
||||
{
|
||||
get { return buffer.IsStreamOwner; }
|
||||
set { buffer.IsStreamOwner = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// true if the stream supports reading; otherwise, false.
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
return outputStream.CanRead;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// true if the stream supports seeking; otherwise, false.
|
||||
/// </summary>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
{
|
||||
return outputStream.CanSeek;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// true if stream supports writing; otherwise, false.
|
||||
/// </summary>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
return outputStream.CanWrite;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// length of stream in bytes
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return outputStream.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// gets or sets the position within the current stream.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return outputStream.Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
outputStream.Position = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// set the position within the current stream
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset relative to the <paramref name="origin"/> to seek to</param>
|
||||
/// <param name="origin">The <see cref="SeekOrigin"/> to seek from.</param>
|
||||
/// <returns>The new position in the stream.</returns>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return outputStream.Seek(offset, origin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the length of the current stream
|
||||
/// </summary>
|
||||
/// <param name="value">The new stream length.</param>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
outputStream.SetLength(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a byte from the stream and advance the position within the stream
|
||||
/// by one byte or returns -1 if at the end of the stream.
|
||||
/// </summary>
|
||||
/// <returns>The byte value or -1 if at end of stream</returns>
|
||||
public override int ReadByte()
|
||||
{
|
||||
return outputStream.ReadByte();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// read bytes from the current stream and advance the position within the
|
||||
/// stream by the number of bytes read.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to store read bytes in.</param>
|
||||
/// <param name="offset">The index into the buffer to being storing bytes at.</param>
|
||||
/// <param name="count">The desired number of bytes to read.</param>
|
||||
/// <returns>The total number of bytes read, or zero if at the end of the stream.
|
||||
/// The number of bytes may be less than the <paramref name="count">count</paramref>
|
||||
/// requested if data is not avialable.</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return outputStream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// All buffered data is written to destination
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
outputStream.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ends the TAR archive without closing the underlying OutputStream.
|
||||
/// The result is that the EOF block of nulls is written.
|
||||
/// </summary>
|
||||
public void Finish()
|
||||
{
|
||||
if ( IsEntryOpen )
|
||||
{
|
||||
CloseEntry();
|
||||
}
|
||||
WriteEofBlock();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ends the TAR archive and closes the underlying OutputStream.
|
||||
/// </summary>
|
||||
/// <remarks>This means that Finish() is called followed by calling the
|
||||
/// TarBuffer's Close().</remarks>
|
||||
public override void Close()
|
||||
{
|
||||
if ( !isClosed )
|
||||
{
|
||||
isClosed = true;
|
||||
Finish();
|
||||
buffer.Close();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the record size being used by this stream's TarBuffer.
|
||||
/// </summary>
|
||||
public int RecordSize
|
||||
{
|
||||
get { return buffer.RecordSize; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the record size being used by this stream's TarBuffer.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The TarBuffer record size.
|
||||
/// </returns>
|
||||
[Obsolete("Use RecordSize property instead")]
|
||||
public int GetRecordSize()
|
||||
{
|
||||
return buffer.RecordSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a value indicating wether an entry is open, requiring more data to be written.
|
||||
/// </summary>
|
||||
bool IsEntryOpen
|
||||
{
|
||||
get { return (currBytes < currSize); }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Put an entry on the output stream. This writes the entry's
|
||||
/// header and positions the output stream for writing
|
||||
/// the contents of the entry. Once this method is called, the
|
||||
/// stream is ready for calls to write() to write the entry's
|
||||
/// contents. Once the contents are written, closeEntry()
|
||||
/// <B>MUST</B> be called to ensure that all buffered data
|
||||
/// is completely written to the output stream.
|
||||
/// </summary>
|
||||
/// <param name="entry">
|
||||
/// The TarEntry to be written to the archive.
|
||||
/// </param>
|
||||
public void PutNextEntry(TarEntry entry)
|
||||
{
|
||||
if ( entry == null ) {
|
||||
throw new ArgumentNullException("entry");
|
||||
}
|
||||
|
||||
if (entry.TarHeader.Name.Length >= TarHeader.NAMELEN) {
|
||||
TarHeader longHeader = new TarHeader();
|
||||
longHeader.TypeFlag = TarHeader.LF_GNU_LONGNAME;
|
||||
longHeader.Name = longHeader.Name + "././@LongLink";
|
||||
longHeader.UserId = 0;
|
||||
longHeader.GroupId = 0;
|
||||
longHeader.GroupName = "";
|
||||
longHeader.UserName = "";
|
||||
longHeader.LinkName = "";
|
||||
longHeader.Size = entry.TarHeader.Name.Length;
|
||||
|
||||
longHeader.WriteHeader(blockBuffer);
|
||||
buffer.WriteBlock(blockBuffer); // Add special long filename header block
|
||||
|
||||
int nameCharIndex = 0;
|
||||
|
||||
while (nameCharIndex < entry.TarHeader.Name.Length) {
|
||||
Array.Clear(blockBuffer, 0, blockBuffer.Length);
|
||||
TarHeader.GetAsciiBytes(entry.TarHeader.Name, nameCharIndex, this.blockBuffer, 0, TarBuffer.BlockSize);
|
||||
nameCharIndex += TarBuffer.BlockSize;
|
||||
buffer.WriteBlock(blockBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
entry.WriteEntryHeader(blockBuffer);
|
||||
buffer.WriteBlock(blockBuffer);
|
||||
|
||||
currBytes = 0;
|
||||
|
||||
currSize = entry.IsDirectory ? 0 : entry.Size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close an entry. This method MUST be called for all file
|
||||
/// entries that contain data. The reason is that we must
|
||||
/// buffer data written to the stream in order to satisfy
|
||||
/// the buffer's block based writes. Thus, there may be
|
||||
/// data fragments still being assembled that must be written
|
||||
/// to the output stream before this entry is closed and the
|
||||
/// next entry written.
|
||||
/// </summary>
|
||||
public void CloseEntry()
|
||||
{
|
||||
if (assemblyBufferLength > 0) {
|
||||
Array.Clear(assemblyBuffer, assemblyBufferLength, assemblyBuffer.Length - assemblyBufferLength);
|
||||
|
||||
buffer.WriteBlock(assemblyBuffer);
|
||||
|
||||
currBytes += assemblyBufferLength;
|
||||
assemblyBufferLength = 0;
|
||||
}
|
||||
|
||||
if (currBytes < currSize) {
|
||||
string errorText = string.Format(
|
||||
"Entry closed at '{0}' before the '{1}' bytes specified in the header were written",
|
||||
currBytes, currSize);
|
||||
throw new TarException(errorText);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte to the current tar archive entry.
|
||||
/// This method simply calls Write(byte[], int, int).
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// The byte to be written.
|
||||
/// </param>
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
Write(new byte[] { value }, 0, 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes bytes to the current tar archive entry. This method
|
||||
/// is aware of the current entry and will throw an exception if
|
||||
/// you attempt to write bytes past the length specified for the
|
||||
/// current entry. The method is also (painfully) aware of the
|
||||
/// record buffering required by TarBuffer, and manages buffers
|
||||
/// that are not a multiple of recordsize in length, including
|
||||
/// assembling records from small buffers.
|
||||
/// </summary>
|
||||
/// <param name = "buffer">
|
||||
/// The buffer to write to the archive.
|
||||
/// </param>
|
||||
/// <param name = "offset">
|
||||
/// The offset in the buffer from which to get bytes.
|
||||
/// </param>
|
||||
/// <param name = "count">
|
||||
/// The number of bytes to write.
|
||||
/// </param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if ( buffer == null ) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
if ( offset < 0 )
|
||||
{
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("offset", "Cannot be negative");
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( buffer.Length - offset < count )
|
||||
{
|
||||
throw new ArgumentException("offset and count combination is invalid");
|
||||
}
|
||||
|
||||
if ( count < 0 )
|
||||
{
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("count", "Cannot be negative");
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( (currBytes + count) > currSize ) {
|
||||
string errorText = string.Format("request to write '{0}' bytes exceeds size in header of '{1}' bytes",
|
||||
count, this.currSize);
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("count", errorText);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// We have to deal with assembly!!!
|
||||
// The programmer can be writing little 32 byte chunks for all
|
||||
// we know, and we must assemble complete blocks for writing.
|
||||
// TODO REVIEW Maybe this should be in TarBuffer? Could that help to
|
||||
// eliminate some of the buffer copying.
|
||||
//
|
||||
if (assemblyBufferLength > 0) {
|
||||
if ((assemblyBufferLength + count ) >= blockBuffer.Length) {
|
||||
int aLen = blockBuffer.Length - assemblyBufferLength;
|
||||
|
||||
Array.Copy(assemblyBuffer, 0, blockBuffer, 0, assemblyBufferLength);
|
||||
Array.Copy(buffer, offset, blockBuffer, assemblyBufferLength, aLen);
|
||||
|
||||
this.buffer.WriteBlock(blockBuffer);
|
||||
|
||||
currBytes += blockBuffer.Length;
|
||||
|
||||
offset += aLen;
|
||||
count -= aLen;
|
||||
|
||||
assemblyBufferLength = 0;
|
||||
} else {
|
||||
Array.Copy(buffer, offset, assemblyBuffer, assemblyBufferLength, count);
|
||||
offset += count;
|
||||
assemblyBufferLength += count;
|
||||
count -= count;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// When we get here we have EITHER:
|
||||
// o An empty "assembly" buffer.
|
||||
// o No bytes to write (count == 0)
|
||||
//
|
||||
while (count > 0) {
|
||||
if (count < blockBuffer.Length) {
|
||||
Array.Copy(buffer, offset, assemblyBuffer, assemblyBufferLength, count);
|
||||
assemblyBufferLength += count;
|
||||
break;
|
||||
}
|
||||
|
||||
this.buffer.WriteBlock(buffer, offset);
|
||||
|
||||
int bufferLength = blockBuffer.Length;
|
||||
currBytes += bufferLength;
|
||||
count -= bufferLength;
|
||||
offset += bufferLength;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an EOF (end of archive) block to the tar archive.
|
||||
/// An EOF block consists of all zeros.
|
||||
/// </summary>
|
||||
void WriteEofBlock()
|
||||
{
|
||||
Array.Clear(blockBuffer, 0, blockBuffer.Length);
|
||||
buffer.WriteBlock(blockBuffer);
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// bytes written for this entry so far
|
||||
/// </summary>
|
||||
long currBytes;
|
||||
|
||||
/// <summary>
|
||||
/// current 'Assembly' buffer length
|
||||
/// </summary>
|
||||
int assemblyBufferLength;
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating wether this instance has been closed or not.
|
||||
/// </summary>
|
||||
bool isClosed;
|
||||
|
||||
/// <summary>
|
||||
/// Size for the current entry
|
||||
/// </summary>
|
||||
protected long currSize;
|
||||
|
||||
/// <summary>
|
||||
/// single block working buffer
|
||||
/// </summary>
|
||||
protected byte[] blockBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// 'Assembly' buffer used to assemble data before writing
|
||||
/// </summary>
|
||||
protected byte[] assemblyBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// TarBuffer used to provide correct blocking factor
|
||||
/// </summary>
|
||||
protected TarBuffer buffer;
|
||||
|
||||
/// <summary>
|
||||
/// the destination stream for the archive contents
|
||||
/// </summary>
|
||||
protected Stream outputStream;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
/* The original Java file had this header:
|
||||
** Authored by Timothy Gerard Endres
|
||||
** <mailto:time@gjt.org> <http://www.trustice.com>
|
||||
**
|
||||
** This work has been placed into the public domain.
|
||||
** You may use this work in any way and for any purpose you wish.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
|
||||
** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
|
||||
** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
|
||||
** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
|
||||
** REDISTRIBUTION OF THIS SOFTWARE.
|
||||
**
|
||||
*/
|
|
@ -0,0 +1,557 @@
|
|||
// Deflater.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
// Copyright (C) 2004 John Reilly
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip.Compression
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This is the Deflater class. The deflater class compresses input
|
||||
/// with the deflate algorithm described in RFC 1951. It has several
|
||||
/// compression levels and three different strategies described below.
|
||||
///
|
||||
/// This class is <i>not</i> thread safe. This is inherent in the API, due
|
||||
/// to the split of deflate and setInput.
|
||||
///
|
||||
/// author of the original java version : Jochen Hoenicke
|
||||
/// </summary>
|
||||
public class Deflater
|
||||
{
|
||||
#region Deflater Documentation
|
||||
/*
|
||||
* The Deflater can do the following state transitions:
|
||||
*
|
||||
* (1) -> INIT_STATE ----> INIT_FINISHING_STATE ---.
|
||||
* / | (2) (5) |
|
||||
* / v (5) |
|
||||
* (3)| SETDICT_STATE ---> SETDICT_FINISHING_STATE |(3)
|
||||
* \ | (3) | ,--------'
|
||||
* | | | (3) /
|
||||
* v v (5) v v
|
||||
* (1) -> BUSY_STATE ----> FINISHING_STATE
|
||||
* | (6)
|
||||
* v
|
||||
* FINISHED_STATE
|
||||
* \_____________________________________/
|
||||
* | (7)
|
||||
* v
|
||||
* CLOSED_STATE
|
||||
*
|
||||
* (1) If we should produce a header we start in INIT_STATE, otherwise
|
||||
* we start in BUSY_STATE.
|
||||
* (2) A dictionary may be set only when we are in INIT_STATE, then
|
||||
* we change the state as indicated.
|
||||
* (3) Whether a dictionary is set or not, on the first call of deflate
|
||||
* we change to BUSY_STATE.
|
||||
* (4) -- intentionally left blank -- :)
|
||||
* (5) FINISHING_STATE is entered, when flush() is called to indicate that
|
||||
* there is no more INPUT. There are also states indicating, that
|
||||
* the header wasn't written yet.
|
||||
* (6) FINISHED_STATE is entered, when everything has been flushed to the
|
||||
* internal pending output buffer.
|
||||
* (7) At any time (7)
|
||||
*
|
||||
*/
|
||||
#endregion
|
||||
#region Public Constants
|
||||
/// <summary>
|
||||
/// The best and slowest compression level. This tries to find very
|
||||
/// long and distant string repetitions.
|
||||
/// </summary>
|
||||
public const int BEST_COMPRESSION = 9;
|
||||
|
||||
/// <summary>
|
||||
/// The worst but fastest compression level.
|
||||
/// </summary>
|
||||
public const int BEST_SPEED = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The default compression level.
|
||||
/// </summary>
|
||||
public const int DEFAULT_COMPRESSION = -1;
|
||||
|
||||
/// <summary>
|
||||
/// This level won't compress at all but output uncompressed blocks.
|
||||
/// </summary>
|
||||
public const int NO_COMPRESSION = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The compression method. This is the only method supported so far.
|
||||
/// There is no need to use this constant at all.
|
||||
/// </summary>
|
||||
public const int DEFLATED = 8;
|
||||
#endregion
|
||||
#region Local Constants
|
||||
private const int IS_SETDICT = 0x01;
|
||||
private const int IS_FLUSHING = 0x04;
|
||||
private const int IS_FINISHING = 0x08;
|
||||
|
||||
private const int INIT_STATE = 0x00;
|
||||
private const int SETDICT_STATE = 0x01;
|
||||
// private static int INIT_FINISHING_STATE = 0x08;
|
||||
// private static int SETDICT_FINISHING_STATE = 0x09;
|
||||
private const int BUSY_STATE = 0x10;
|
||||
private const int FLUSHING_STATE = 0x14;
|
||||
private const int FINISHING_STATE = 0x1c;
|
||||
private const int FINISHED_STATE = 0x1e;
|
||||
private const int CLOSED_STATE = 0x7f;
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Creates a new deflater with default compression level.
|
||||
/// </summary>
|
||||
public Deflater() : this(DEFAULT_COMPRESSION, false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new deflater with given compression level.
|
||||
/// </summary>
|
||||
/// <param name="level">
|
||||
/// the compression level, a value between NO_COMPRESSION
|
||||
/// and BEST_COMPRESSION, or DEFAULT_COMPRESSION.
|
||||
/// </param>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>
|
||||
public Deflater(int level) : this(level, false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new deflater with given compression level.
|
||||
/// </summary>
|
||||
/// <param name="level">
|
||||
/// the compression level, a value between NO_COMPRESSION
|
||||
/// and BEST_COMPRESSION.
|
||||
/// </param>
|
||||
/// <param name="noZlibHeaderOrFooter">
|
||||
/// true, if we should suppress the Zlib/RFC1950 header at the
|
||||
/// beginning and the adler checksum at the end of the output. This is
|
||||
/// useful for the GZIP/PKZIP formats.
|
||||
/// </param>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>
|
||||
public Deflater(int level, bool noZlibHeaderOrFooter)
|
||||
{
|
||||
if (level == DEFAULT_COMPRESSION) {
|
||||
level = 6;
|
||||
} else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) {
|
||||
throw new ArgumentOutOfRangeException("level");
|
||||
}
|
||||
|
||||
pending = new DeflaterPending();
|
||||
engine = new DeflaterEngine(pending);
|
||||
this.noZlibHeaderOrFooter = noZlibHeaderOrFooter;
|
||||
SetStrategy(DeflateStrategy.Default);
|
||||
SetLevel(level);
|
||||
Reset();
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Resets the deflater. The deflater acts afterwards as if it was
|
||||
/// just created with the same compression level and strategy as it
|
||||
/// had before.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
state = (noZlibHeaderOrFooter ? BUSY_STATE : INIT_STATE);
|
||||
totalOut = 0;
|
||||
pending.Reset();
|
||||
engine.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current adler checksum of the data that was processed so far.
|
||||
/// </summary>
|
||||
public int Adler {
|
||||
get {
|
||||
return engine.Adler;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of input bytes processed so far.
|
||||
/// </summary>
|
||||
public long TotalIn {
|
||||
get {
|
||||
return engine.TotalIn;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of output bytes so far.
|
||||
/// </summary>
|
||||
public long TotalOut {
|
||||
get {
|
||||
return totalOut;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the current input block. Further calls to deflate() will
|
||||
/// produce enough output to inflate everything in the current input
|
||||
/// block. This is not part of Sun's JDK so I have made it package
|
||||
/// private. It is used by DeflaterOutputStream to implement
|
||||
/// flush().
|
||||
/// </summary>
|
||||
public void Flush()
|
||||
{
|
||||
state |= IS_FLUSHING;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finishes the deflater with the current input block. It is an error
|
||||
/// to give more input after this method was called. This method must
|
||||
/// be called to force all bytes to be flushed.
|
||||
/// </summary>
|
||||
public void Finish()
|
||||
{
|
||||
state |= (IS_FLUSHING | IS_FINISHING);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the stream was finished and no more output bytes
|
||||
/// are available.
|
||||
/// </summary>
|
||||
public bool IsFinished {
|
||||
get {
|
||||
return (state == FINISHED_STATE) && pending.IsFlushed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true, if the input buffer is empty.
|
||||
/// You should then call setInput().
|
||||
/// NOTE: This method can also return true when the stream
|
||||
/// was finished.
|
||||
/// </summary>
|
||||
public bool IsNeedingInput {
|
||||
get {
|
||||
return engine.NeedsInput();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the data which should be compressed next. This should be only
|
||||
/// called when needsInput indicates that more input is needed.
|
||||
/// If you call setInput when needsInput() returns false, the
|
||||
/// previous input that is still pending will be thrown away.
|
||||
/// The given byte array should not be changed, before needsInput() returns
|
||||
/// true again.
|
||||
/// This call is equivalent to <code>setInput(input, 0, input.length)</code>.
|
||||
/// </summary>
|
||||
/// <param name="input">
|
||||
/// the buffer containing the input data.
|
||||
/// </param>
|
||||
/// <exception cref="System.InvalidOperationException">
|
||||
/// if the buffer was finished() or ended().
|
||||
/// </exception>
|
||||
public void SetInput(byte[] input)
|
||||
{
|
||||
SetInput(input, 0, input.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the data which should be compressed next. This should be
|
||||
/// only called when needsInput indicates that more input is needed.
|
||||
/// The given byte array should not be changed, before needsInput() returns
|
||||
/// true again.
|
||||
/// </summary>
|
||||
/// <param name="input">
|
||||
/// the buffer containing the input data.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// the start of the data.
|
||||
/// </param>
|
||||
/// <param name="count">
|
||||
/// the number of data bytes of input.
|
||||
/// </param>
|
||||
/// <exception cref="System.InvalidOperationException">
|
||||
/// if the buffer was Finish()ed or if previous input is still pending.
|
||||
/// </exception>
|
||||
public void SetInput(byte[] input, int offset, int count)
|
||||
{
|
||||
if ((state & IS_FINISHING) != 0) {
|
||||
throw new InvalidOperationException("Finish() already called");
|
||||
}
|
||||
engine.SetInput(input, offset, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the compression level. There is no guarantee of the exact
|
||||
/// position of the change, but if you call this when needsInput is
|
||||
/// true the change of compression level will occur somewhere near
|
||||
/// before the end of the so far given input.
|
||||
/// </summary>
|
||||
/// <param name="level">
|
||||
/// the new compression level.
|
||||
/// </param>
|
||||
public void SetLevel(int level)
|
||||
{
|
||||
if (level == DEFAULT_COMPRESSION) {
|
||||
level = 6;
|
||||
} else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) {
|
||||
throw new ArgumentOutOfRangeException("level");
|
||||
}
|
||||
|
||||
if (this.level != level) {
|
||||
this.level = level;
|
||||
engine.SetLevel(level);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get current compression level
|
||||
/// </summary>
|
||||
/// <returns>Returns the current compression level</returns>
|
||||
public int GetLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the compression strategy. Strategy is one of
|
||||
/// DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED. For the exact
|
||||
/// position where the strategy is changed, the same as for
|
||||
/// SetLevel() applies.
|
||||
/// </summary>
|
||||
/// <param name="strategy">
|
||||
/// The new compression strategy.
|
||||
/// </param>
|
||||
public void SetStrategy(DeflateStrategy strategy)
|
||||
{
|
||||
engine.Strategy = strategy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deflates the current input block with to the given array.
|
||||
/// </summary>
|
||||
/// <param name="output">
|
||||
/// The buffer where compressed data is stored
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The number of compressed bytes added to the output, or 0 if either
|
||||
/// IsNeedingInput() or IsFinished returns true or length is zero.
|
||||
/// </returns>
|
||||
public int Deflate(byte[] output)
|
||||
{
|
||||
return Deflate(output, 0, output.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deflates the current input block to the given array.
|
||||
/// </summary>
|
||||
/// <param name="output">
|
||||
/// Buffer to store the compressed data.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// Offset into the output array.
|
||||
/// </param>
|
||||
/// <param name="length">
|
||||
/// The maximum number of bytes that may be stored.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The number of compressed bytes added to the output, or 0 if either
|
||||
/// needsInput() or finished() returns true or length is zero.
|
||||
/// </returns>
|
||||
/// <exception cref="System.InvalidOperationException">
|
||||
/// If Finish() was previously called.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// If offset or length don't match the array length.
|
||||
/// </exception>
|
||||
public int Deflate(byte[] output, int offset, int length)
|
||||
{
|
||||
int origLength = length;
|
||||
|
||||
if (state == CLOSED_STATE) {
|
||||
throw new InvalidOperationException("Deflater closed");
|
||||
}
|
||||
|
||||
if (state < BUSY_STATE) {
|
||||
// output header
|
||||
int header = (DEFLATED +
|
||||
((DeflaterConstants.MAX_WBITS - 8) << 4)) << 8;
|
||||
int level_flags = (level - 1) >> 1;
|
||||
if (level_flags < 0 || level_flags > 3) {
|
||||
level_flags = 3;
|
||||
}
|
||||
header |= level_flags << 6;
|
||||
if ((state & IS_SETDICT) != 0) {
|
||||
// Dictionary was set
|
||||
header |= DeflaterConstants.PRESET_DICT;
|
||||
}
|
||||
header += 31 - (header % 31);
|
||||
|
||||
pending.WriteShortMSB(header);
|
||||
if ((state & IS_SETDICT) != 0) {
|
||||
int chksum = engine.Adler;
|
||||
engine.ResetAdler();
|
||||
pending.WriteShortMSB(chksum >> 16);
|
||||
pending.WriteShortMSB(chksum & 0xffff);
|
||||
}
|
||||
|
||||
state = BUSY_STATE | (state & (IS_FLUSHING | IS_FINISHING));
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int count = pending.Flush(output, offset, length);
|
||||
offset += count;
|
||||
totalOut += count;
|
||||
length -= count;
|
||||
|
||||
if (length == 0 || state == FINISHED_STATE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!engine.Deflate((state & IS_FLUSHING) != 0, (state & IS_FINISHING) != 0)) {
|
||||
if (state == BUSY_STATE) {
|
||||
// We need more input now
|
||||
return origLength - length;
|
||||
} else if (state == FLUSHING_STATE) {
|
||||
if (level != NO_COMPRESSION) {
|
||||
/* We have to supply some lookahead. 8 bit lookahead
|
||||
* is needed by the zlib inflater, and we must fill
|
||||
* the next byte, so that all bits are flushed.
|
||||
*/
|
||||
int neededbits = 8 + ((-pending.BitCount) & 7);
|
||||
while (neededbits > 0) {
|
||||
/* write a static tree block consisting solely of
|
||||
* an EOF:
|
||||
*/
|
||||
pending.WriteBits(2, 10);
|
||||
neededbits -= 10;
|
||||
}
|
||||
}
|
||||
state = BUSY_STATE;
|
||||
} else if (state == FINISHING_STATE) {
|
||||
pending.AlignToByte();
|
||||
|
||||
// Compressed data is complete. Write footer information if required.
|
||||
if (!noZlibHeaderOrFooter) {
|
||||
int adler = engine.Adler;
|
||||
pending.WriteShortMSB(adler >> 16);
|
||||
pending.WriteShortMSB(adler & 0xffff);
|
||||
}
|
||||
state = FINISHED_STATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return origLength - length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the dictionary which should be used in the deflate process.
|
||||
/// This call is equivalent to <code>setDictionary(dict, 0, dict.Length)</code>.
|
||||
/// </summary>
|
||||
/// <param name="dictionary">
|
||||
/// the dictionary.
|
||||
/// </param>
|
||||
/// <exception cref="System.InvalidOperationException">
|
||||
/// if SetInput () or Deflate () were already called or another dictionary was already set.
|
||||
/// </exception>
|
||||
public void SetDictionary(byte[] dictionary)
|
||||
{
|
||||
SetDictionary(dictionary, 0, dictionary.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the dictionary which should be used in the deflate process.
|
||||
/// The dictionary is a byte array containing strings that are
|
||||
/// likely to occur in the data which should be compressed. The
|
||||
/// dictionary is not stored in the compressed output, only a
|
||||
/// checksum. To decompress the output you need to supply the same
|
||||
/// dictionary again.
|
||||
/// </summary>
|
||||
/// <param name="dictionary">
|
||||
/// The dictionary data
|
||||
/// </param>
|
||||
/// <param name="index">
|
||||
/// The index where dictionary information commences.
|
||||
/// </param>
|
||||
/// <param name="count">
|
||||
/// The number of bytes in the dictionary.
|
||||
/// </param>
|
||||
/// <exception cref="System.InvalidOperationException">
|
||||
/// If SetInput () or Deflate() were already called or another dictionary was already set.
|
||||
/// </exception>
|
||||
public void SetDictionary(byte[] dictionary, int index, int count)
|
||||
{
|
||||
if (state != INIT_STATE) {
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
state = SETDICT_STATE;
|
||||
engine.SetDictionary(dictionary, index, count);
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// Compression level.
|
||||
/// </summary>
|
||||
int level;
|
||||
|
||||
/// <summary>
|
||||
/// If true no Zlib/RFC1950 headers or footers are generated
|
||||
/// </summary>
|
||||
bool noZlibHeaderOrFooter;
|
||||
|
||||
/// <summary>
|
||||
/// The current state.
|
||||
/// </summary>
|
||||
int state;
|
||||
|
||||
/// <summary>
|
||||
/// The total bytes of output written.
|
||||
/// </summary>
|
||||
long totalOut;
|
||||
|
||||
/// <summary>
|
||||
/// The pending output.
|
||||
/// </summary>
|
||||
DeflaterPending pending;
|
||||
|
||||
/// <summary>
|
||||
/// The deflater engine.
|
||||
/// </summary>
|
||||
DeflaterEngine engine;
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
// DeflaterConstants.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
// Copyright (C) 2004 John Reilly
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip.Compression
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This class contains constants used for deflation.
|
||||
/// </summary>
|
||||
public class DeflaterConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// Set to true to enable debugging
|
||||
/// </summary>
|
||||
public const bool DEBUGGING = false;
|
||||
|
||||
/// <summary>
|
||||
/// Written to Zip file to identify a stored block
|
||||
/// </summary>
|
||||
public const int STORED_BLOCK = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Identifies static tree in Zip file
|
||||
/// </summary>
|
||||
public const int STATIC_TREES = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Identifies dynamic tree in Zip file
|
||||
/// </summary>
|
||||
public const int DYN_TREES = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Header flag indicating a preset dictionary for deflation
|
||||
/// </summary>
|
||||
public const int PRESET_DICT = 0x20;
|
||||
|
||||
/// <summary>
|
||||
/// Sets internal buffer sizes for Huffman encoding
|
||||
/// </summary>
|
||||
public const int DEFAULT_MEM_LEVEL = 8;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int MAX_MATCH = 258;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int MIN_MATCH = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int MAX_WBITS = 15;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int WSIZE = 1 << MAX_WBITS;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int WMASK = WSIZE - 1;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int HASH_BITS = DEFAULT_MEM_LEVEL + 7;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int HASH_SIZE = 1 << HASH_BITS;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int HASH_MASK = HASH_SIZE - 1;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int MAX_DIST = WSIZE - MIN_LOOKAHEAD;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8);
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public static int MAX_BLOCK_SIZE = Math.Min(65535, PENDING_BUF_SIZE - 5);
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int DEFLATE_STORED = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int DEFLATE_FAST = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public const int DEFLATE_SLOW = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public static int[] GOOD_LENGTH = { 0, 4, 4, 4, 4, 8, 8, 8, 32, 32 };
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public static int[] MAX_LAZY = { 0, 4, 5, 6, 4, 16, 16, 32, 128, 258 };
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public static int[] NICE_LENGTH = { 0, 8, 16, 32, 16, 32, 128, 128, 258, 258 };
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public static int[] MAX_CHAIN = { 0, 4, 8, 32, 16, 32, 128, 256, 1024, 4096 };
|
||||
|
||||
/// <summary>
|
||||
/// Internal compression engine constant
|
||||
/// </summary>
|
||||
public static int[] COMPR_FUNC = { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2 };
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,869 @@
|
|||
// DeflaterEngine.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
// Copyright (C) 2004 John Reilly
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
using ICSharpCode.SharpZipLib.Checksums;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip.Compression
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Strategies for deflater
|
||||
/// </summary>
|
||||
public enum DeflateStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// The default strategy
|
||||
/// </summary>
|
||||
Default = 0,
|
||||
|
||||
/// <summary>
|
||||
/// This strategy will only allow longer string repetitions. It is
|
||||
/// useful for random data with a small character set.
|
||||
/// </summary>
|
||||
Filtered = 1,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This strategy will not look for string repetitions at all. It
|
||||
/// only encodes with Huffman trees (which means, that more common
|
||||
/// characters get a smaller encoding.
|
||||
/// </summary>
|
||||
HuffmanOnly = 2
|
||||
}
|
||||
|
||||
// DEFLATE ALGORITHM:
|
||||
//
|
||||
// The uncompressed stream is inserted into the window array. When
|
||||
// the window array is full the first half is thrown away and the
|
||||
// second half is copied to the beginning.
|
||||
//
|
||||
// The head array is a hash table. Three characters build a hash value
|
||||
// and they the value points to the corresponding index in window of
|
||||
// the last string with this hash. The prev array implements a
|
||||
// linked list of matches with the same hash: prev[index & WMASK] points
|
||||
// to the previous index with the same hash.
|
||||
//
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Low level compression engine for deflate algorithm which uses a 32K sliding window
|
||||
/// with secondary compression from Huffman/Shannon-Fano codes.
|
||||
/// </summary>
|
||||
public class DeflaterEngine : DeflaterConstants
|
||||
{
|
||||
#region Constants
|
||||
const int TooFar = 4096;
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Construct instance with pending buffer
|
||||
/// </summary>
|
||||
/// <param name="pending">
|
||||
/// Pending buffer to use
|
||||
/// </param>>
|
||||
public DeflaterEngine(DeflaterPending pending)
|
||||
{
|
||||
this.pending = pending;
|
||||
huffman = new DeflaterHuffman(pending);
|
||||
adler = new Adler32();
|
||||
|
||||
window = new byte[2 * WSIZE];
|
||||
head = new short[HASH_SIZE];
|
||||
prev = new short[WSIZE];
|
||||
|
||||
// We start at index 1, to avoid an implementation deficiency, that
|
||||
// we cannot build a repeat pattern at index 0.
|
||||
blockStart = strstart = 1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Deflate drives actual compression of data
|
||||
/// </summary>
|
||||
/// <param name="flush">True to flush input buffers</param>
|
||||
/// <param name="finish">Finish deflation with the current input.</param>
|
||||
/// <returns>Returns true if progress has been made.</returns>
|
||||
public bool Deflate(bool flush, bool finish)
|
||||
{
|
||||
bool progress;
|
||||
do
|
||||
{
|
||||
FillWindow();
|
||||
bool canFlush = flush && (inputOff == inputEnd);
|
||||
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING) {
|
||||
Console.WriteLine("window: [" + blockStart + "," + strstart + ","
|
||||
+ lookahead + "], " + compressionFunction + "," + canFlush);
|
||||
}
|
||||
#endif
|
||||
switch (compressionFunction)
|
||||
{
|
||||
case DEFLATE_STORED:
|
||||
progress = DeflateStored(canFlush, finish);
|
||||
break;
|
||||
case DEFLATE_FAST:
|
||||
progress = DeflateFast(canFlush, finish);
|
||||
break;
|
||||
case DEFLATE_SLOW:
|
||||
progress = DeflateSlow(canFlush, finish);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("unknown compressionFunction");
|
||||
}
|
||||
} while (pending.IsFlushed && progress); // repeat while we have no pending output and progress was made
|
||||
return progress;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets input data to be deflated. Should only be called when <code>NeedsInput()</code>
|
||||
/// returns true
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer containing input data.</param>
|
||||
/// <param name="offset">The offset of the first byte of data.</param>
|
||||
/// <param name="count">The number of bytes of data to use as input.</param>
|
||||
public void SetInput(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if ( buffer == null )
|
||||
{
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
if ( offset < 0 )
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
}
|
||||
|
||||
if ( count < 0 )
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
}
|
||||
|
||||
if (inputOff < inputEnd)
|
||||
{
|
||||
throw new InvalidOperationException("Old input was not completely processed");
|
||||
}
|
||||
|
||||
int end = offset + count;
|
||||
|
||||
/* We want to throw an ArrayIndexOutOfBoundsException early. The
|
||||
* check is very tricky: it also handles integer wrap around.
|
||||
*/
|
||||
if ((offset > end) || (end > buffer.Length) )
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
}
|
||||
|
||||
inputBuf = buffer;
|
||||
inputOff = offset;
|
||||
inputEnd = end;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if more <see cref="SetInput">input</see> is needed.
|
||||
/// </summary>
|
||||
/// <returns>Return true if input is needed via <see cref="SetInput">SetInput</see></returns>
|
||||
public bool NeedsInput()
|
||||
{
|
||||
return (inputEnd == inputOff);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set compression dictionary
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer containing the dictionary data</param>
|
||||
/// <param name="offset">The offset in the buffer for the first byte of data</param>
|
||||
/// <param name="length">The length of the dictionary data.</param>
|
||||
public void SetDictionary(byte[] buffer, int offset, int length)
|
||||
{
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING && (strstart != 1) )
|
||||
{
|
||||
throw new InvalidOperationException("strstart not 1");
|
||||
}
|
||||
#endif
|
||||
adler.Update(buffer, offset, length);
|
||||
if (length < MIN_MATCH)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (length > MAX_DIST)
|
||||
{
|
||||
offset += length - MAX_DIST;
|
||||
length = MAX_DIST;
|
||||
}
|
||||
|
||||
System.Array.Copy(buffer, offset, window, strstart, length);
|
||||
|
||||
UpdateHash();
|
||||
--length;
|
||||
while (--length > 0)
|
||||
{
|
||||
InsertString();
|
||||
strstart++;
|
||||
}
|
||||
strstart += 2;
|
||||
blockStart = strstart;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset internal state
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
huffman.Reset();
|
||||
adler.Reset();
|
||||
blockStart = strstart = 1;
|
||||
lookahead = 0;
|
||||
totalIn = 0;
|
||||
prevAvailable = false;
|
||||
matchLen = MIN_MATCH - 1;
|
||||
|
||||
for (int i = 0; i < HASH_SIZE; i++) {
|
||||
head[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < WSIZE; i++) {
|
||||
prev[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset Adler checksum
|
||||
/// </summary>
|
||||
public void ResetAdler()
|
||||
{
|
||||
adler.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get current value of Adler checksum
|
||||
/// </summary>
|
||||
public int Adler {
|
||||
get {
|
||||
return unchecked((int)adler.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Total data processed
|
||||
/// </summary>
|
||||
public long TotalIn {
|
||||
get {
|
||||
return totalIn;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the <see cref="DeflateStrategy">deflate strategy</see>
|
||||
/// </summary>
|
||||
public DeflateStrategy Strategy {
|
||||
get {
|
||||
return strategy;
|
||||
}
|
||||
set {
|
||||
strategy = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the deflate level (0-9)
|
||||
/// </summary>
|
||||
/// <param name="level">The value to set the level to.</param>
|
||||
public void SetLevel(int level)
|
||||
{
|
||||
if ( (level < 0) || (level > 9) )
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("level");
|
||||
}
|
||||
|
||||
goodLength = DeflaterConstants.GOOD_LENGTH[level];
|
||||
max_lazy = DeflaterConstants.MAX_LAZY[level];
|
||||
niceLength = DeflaterConstants.NICE_LENGTH[level];
|
||||
max_chain = DeflaterConstants.MAX_CHAIN[level];
|
||||
|
||||
if (DeflaterConstants.COMPR_FUNC[level] != compressionFunction) {
|
||||
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING) {
|
||||
Console.WriteLine("Change from " + compressionFunction + " to "
|
||||
+ DeflaterConstants.COMPR_FUNC[level]);
|
||||
}
|
||||
#endif
|
||||
switch (compressionFunction) {
|
||||
case DEFLATE_STORED:
|
||||
if (strstart > blockStart) {
|
||||
huffman.FlushStoredBlock(window, blockStart,
|
||||
strstart - blockStart, false);
|
||||
blockStart = strstart;
|
||||
}
|
||||
UpdateHash();
|
||||
break;
|
||||
|
||||
case DEFLATE_FAST:
|
||||
if (strstart > blockStart) {
|
||||
huffman.FlushBlock(window, blockStart, strstart - blockStart,
|
||||
false);
|
||||
blockStart = strstart;
|
||||
}
|
||||
break;
|
||||
|
||||
case DEFLATE_SLOW:
|
||||
if (prevAvailable) {
|
||||
huffman.TallyLit(window[strstart-1] & 0xff);
|
||||
}
|
||||
if (strstart > blockStart) {
|
||||
huffman.FlushBlock(window, blockStart, strstart - blockStart, false);
|
||||
blockStart = strstart;
|
||||
}
|
||||
prevAvailable = false;
|
||||
matchLen = MIN_MATCH - 1;
|
||||
break;
|
||||
}
|
||||
compressionFunction = COMPR_FUNC[level];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill the window
|
||||
/// </summary>
|
||||
public void FillWindow()
|
||||
{
|
||||
/* 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.
|
||||
*/
|
||||
if (strstart >= WSIZE + MAX_DIST)
|
||||
{
|
||||
SlideWindow();
|
||||
}
|
||||
|
||||
/* If there is not enough lookahead, but still some input left,
|
||||
* read in the input
|
||||
*/
|
||||
while (lookahead < DeflaterConstants.MIN_LOOKAHEAD && inputOff < inputEnd)
|
||||
{
|
||||
int more = 2 * WSIZE - lookahead - strstart;
|
||||
|
||||
if (more > inputEnd - inputOff)
|
||||
{
|
||||
more = inputEnd - inputOff;
|
||||
}
|
||||
|
||||
System.Array.Copy(inputBuf, inputOff, window, strstart + lookahead, more);
|
||||
adler.Update(inputBuf, inputOff, more);
|
||||
|
||||
inputOff += more;
|
||||
totalIn += more;
|
||||
lookahead += more;
|
||||
}
|
||||
|
||||
if (lookahead >= MIN_MATCH)
|
||||
{
|
||||
UpdateHash();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateHash()
|
||||
{
|
||||
/*
|
||||
if (DEBUGGING) {
|
||||
Console.WriteLine("updateHash: "+strstart);
|
||||
}
|
||||
*/
|
||||
ins_h = (window[strstart] << HASH_SHIFT) ^ window[strstart + 1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts the current string in the head hash and returns the previous
|
||||
/// value for this hash.
|
||||
/// </summary>
|
||||
/// <returns>The previous hash value</returns>
|
||||
int InsertString()
|
||||
{
|
||||
short match;
|
||||
int hash = ((ins_h << HASH_SHIFT) ^ window[strstart + (MIN_MATCH -1)]) & HASH_MASK;
|
||||
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING)
|
||||
{
|
||||
if (hash != (((window[strstart] << (2*HASH_SHIFT)) ^
|
||||
(window[strstart + 1] << HASH_SHIFT) ^
|
||||
(window[strstart + 2])) & HASH_MASK)) {
|
||||
throw new SharpZipBaseException("hash inconsistent: " + hash + "/"
|
||||
+window[strstart] + ","
|
||||
+window[strstart + 1] + ","
|
||||
+window[strstart + 2] + "," + HASH_SHIFT);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
prev[strstart & WMASK] = match = head[hash];
|
||||
head[hash] = unchecked((short)strstart);
|
||||
ins_h = hash;
|
||||
return match & 0xffff;
|
||||
}
|
||||
|
||||
void SlideWindow()
|
||||
{
|
||||
Array.Copy(window, WSIZE, window, 0, WSIZE);
|
||||
matchStart -= WSIZE;
|
||||
strstart -= WSIZE;
|
||||
blockStart -= WSIZE;
|
||||
|
||||
// Slide the hash table (could be avoided with 32 bit values
|
||||
// at the expense of memory usage).
|
||||
for (int i = 0; i < HASH_SIZE; ++i) {
|
||||
int m = head[i] & 0xffff;
|
||||
head[i] = (short)(m >= WSIZE ? (m - WSIZE) : 0);
|
||||
}
|
||||
|
||||
// Slide the prev table.
|
||||
for (int i = 0; i < WSIZE; i++) {
|
||||
int m = prev[i] & 0xffff;
|
||||
prev[i] = (short)(m >= WSIZE ? (m - WSIZE) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the best (longest) string in the window matching the
|
||||
/// string starting at strstart.
|
||||
///
|
||||
/// Preconditions:
|
||||
/// <code>
|
||||
/// strstart + MAX_MATCH <= window.length.</code>
|
||||
/// </summary>
|
||||
/// <param name="curMatch"></param>
|
||||
/// <returns>True if a match greater than the minimum length is found</returns>
|
||||
bool FindLongestMatch(int curMatch)
|
||||
{
|
||||
int chainLength = this.max_chain;
|
||||
int niceLength = this.niceLength;
|
||||
short[] prev = this.prev;
|
||||
int scan = this.strstart;
|
||||
int match;
|
||||
int best_end = this.strstart + matchLen;
|
||||
int best_len = Math.Max(matchLen, MIN_MATCH - 1);
|
||||
|
||||
int limit = Math.Max(strstart - MAX_DIST, 0);
|
||||
|
||||
int strend = strstart + MAX_MATCH - 1;
|
||||
byte scan_end1 = window[best_end - 1];
|
||||
byte scan_end = window[best_end];
|
||||
|
||||
// Do not waste too much time if we already have a good match:
|
||||
if (best_len >= this.goodLength) {
|
||||
chainLength >>= 2;
|
||||
}
|
||||
|
||||
/* Do not look for matches beyond the end of the input. This is necessary
|
||||
* to make deflate deterministic.
|
||||
*/
|
||||
if (niceLength > lookahead) {
|
||||
niceLength = lookahead;
|
||||
}
|
||||
|
||||
#if DebugDeflation
|
||||
|
||||
if (DeflaterConstants.DEBUGGING && (strstart > 2 * WSIZE - MIN_LOOKAHEAD))
|
||||
{
|
||||
throw new InvalidOperationException("need lookahead");
|
||||
}
|
||||
#endif
|
||||
|
||||
do {
|
||||
|
||||
#if DebugDeflation
|
||||
|
||||
if (DeflaterConstants.DEBUGGING && (curMatch >= strstart) )
|
||||
{
|
||||
throw new InvalidOperationException("no future");
|
||||
}
|
||||
#endif
|
||||
if (window[curMatch + best_len] != scan_end ||
|
||||
window[curMatch + best_len - 1] != scan_end1 ||
|
||||
window[curMatch] != window[scan] ||
|
||||
window[curMatch + 1] != window[scan + 1]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
match = curMatch + 2;
|
||||
scan += 2;
|
||||
|
||||
/* We check for insufficient lookahead only every 8th comparison;
|
||||
* the 256th check will be made at strstart + 258.
|
||||
*/
|
||||
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))
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
if (scan > best_end) {
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING && (ins_h == 0) )
|
||||
Console.Error.WriteLine("Found match: " + curMatch + "-" + (scan - strstart));
|
||||
#endif
|
||||
matchStart = curMatch;
|
||||
best_end = scan;
|
||||
best_len = scan - strstart;
|
||||
|
||||
if (best_len >= niceLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
scan_end1 = window[best_end - 1];
|
||||
scan_end = window[best_end];
|
||||
}
|
||||
scan = strstart;
|
||||
} while ((curMatch = (prev[curMatch & WMASK] & 0xffff)) > limit && --chainLength != 0);
|
||||
|
||||
matchLen = Math.Min(best_len, lookahead);
|
||||
return matchLen >= MIN_MATCH;
|
||||
}
|
||||
|
||||
bool DeflateStored(bool flush, bool finish)
|
||||
{
|
||||
if (!flush && (lookahead == 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strstart += lookahead;
|
||||
lookahead = 0;
|
||||
|
||||
int storedLength = strstart - blockStart;
|
||||
|
||||
if ((storedLength >= DeflaterConstants.MAX_BLOCK_SIZE) || // Block is full
|
||||
(blockStart < WSIZE && storedLength >= MAX_DIST) || // Block may move out of window
|
||||
flush) {
|
||||
bool lastBlock = finish;
|
||||
if (storedLength > DeflaterConstants.MAX_BLOCK_SIZE) {
|
||||
storedLength = DeflaterConstants.MAX_BLOCK_SIZE;
|
||||
lastBlock = false;
|
||||
}
|
||||
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING)
|
||||
{
|
||||
Console.WriteLine("storedBlock[" + storedLength + "," + lastBlock + "]");
|
||||
}
|
||||
#endif
|
||||
|
||||
huffman.FlushStoredBlock(window, blockStart, storedLength, lastBlock);
|
||||
blockStart += storedLength;
|
||||
return !lastBlock;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeflateFast(bool flush, bool finish)
|
||||
{
|
||||
if (lookahead < MIN_LOOKAHEAD && !flush) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (lookahead >= MIN_LOOKAHEAD || flush) {
|
||||
if (lookahead == 0) {
|
||||
// We are flushing everything
|
||||
huffman.FlushBlock(window, blockStart, strstart - blockStart, finish);
|
||||
blockStart = strstart;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strstart > 2 * WSIZE - MIN_LOOKAHEAD) {
|
||||
/* slide window, as FindLongestMatch needs this.
|
||||
* This should only happen when flushing and the window
|
||||
* is almost full.
|
||||
*/
|
||||
SlideWindow();
|
||||
}
|
||||
|
||||
int hashHead;
|
||||
if (lookahead >= MIN_MATCH &&
|
||||
(hashHead = InsertString()) != 0 &&
|
||||
strategy != DeflateStrategy.HuffmanOnly &&
|
||||
strstart - hashHead <= MAX_DIST &&
|
||||
FindLongestMatch(hashHead)) {
|
||||
// longestMatch sets matchStart and matchLen
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING)
|
||||
{
|
||||
for (int i = 0 ; i < matchLen; i++) {
|
||||
if (window[strstart + i] != window[matchStart + i]) {
|
||||
throw new SharpZipBaseException("Match failure");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool full = huffman.TallyDist(strstart - matchStart, matchLen);
|
||||
|
||||
lookahead -= matchLen;
|
||||
if (matchLen <= max_lazy && lookahead >= MIN_MATCH) {
|
||||
while (--matchLen > 0) {
|
||||
++strstart;
|
||||
InsertString();
|
||||
}
|
||||
++strstart;
|
||||
} else {
|
||||
strstart += matchLen;
|
||||
if (lookahead >= MIN_MATCH - 1) {
|
||||
UpdateHash();
|
||||
}
|
||||
}
|
||||
matchLen = MIN_MATCH - 1;
|
||||
if (!full) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// No match found
|
||||
huffman.TallyLit(window[strstart] & 0xff);
|
||||
++strstart;
|
||||
--lookahead;
|
||||
}
|
||||
|
||||
if (huffman.IsFull()) {
|
||||
bool lastBlock = finish && (lookahead == 0);
|
||||
huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock);
|
||||
blockStart = strstart;
|
||||
return !lastBlock;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeflateSlow(bool flush, bool finish)
|
||||
{
|
||||
if (lookahead < MIN_LOOKAHEAD && !flush) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (lookahead >= MIN_LOOKAHEAD || flush) {
|
||||
if (lookahead == 0) {
|
||||
if (prevAvailable) {
|
||||
huffman.TallyLit(window[strstart-1] & 0xff);
|
||||
}
|
||||
prevAvailable = false;
|
||||
|
||||
// We are flushing everything
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING && !flush)
|
||||
{
|
||||
throw new SharpZipBaseException("Not flushing, but no lookahead");
|
||||
}
|
||||
#endif
|
||||
huffman.FlushBlock(window, blockStart, strstart - blockStart,
|
||||
finish);
|
||||
blockStart = strstart;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strstart >= 2 * WSIZE - MIN_LOOKAHEAD) {
|
||||
/* slide window, as FindLongestMatch needs this.
|
||||
* This should only happen when flushing and the window
|
||||
* is almost full.
|
||||
*/
|
||||
SlideWindow();
|
||||
}
|
||||
|
||||
int prevMatch = matchStart;
|
||||
int prevLen = matchLen;
|
||||
if (lookahead >= MIN_MATCH) {
|
||||
|
||||
int hashHead = InsertString();
|
||||
|
||||
if (strategy != DeflateStrategy.HuffmanOnly &&
|
||||
hashHead != 0 &&
|
||||
strstart - hashHead <= MAX_DIST &&
|
||||
FindLongestMatch(hashHead)) {
|
||||
|
||||
// longestMatch sets matchStart and matchLen
|
||||
|
||||
// Discard match if too small and too far away
|
||||
if (matchLen <= 5 && (strategy == DeflateStrategy.Filtered || (matchLen == MIN_MATCH && strstart - matchStart > TooFar))) {
|
||||
matchLen = MIN_MATCH - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// previous match was better
|
||||
if ((prevLen >= MIN_MATCH) && (matchLen <= prevLen) ) {
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING)
|
||||
{
|
||||
for (int i = 0 ; i < matchLen; i++) {
|
||||
if (window[strstart-1+i] != window[prevMatch + i])
|
||||
throw new SharpZipBaseException();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
huffman.TallyDist(strstart - 1 - prevMatch, prevLen);
|
||||
prevLen -= 2;
|
||||
do {
|
||||
strstart++;
|
||||
lookahead--;
|
||||
if (lookahead >= MIN_MATCH) {
|
||||
InsertString();
|
||||
}
|
||||
} while (--prevLen > 0);
|
||||
|
||||
strstart ++;
|
||||
lookahead--;
|
||||
prevAvailable = false;
|
||||
matchLen = MIN_MATCH - 1;
|
||||
} else {
|
||||
if (prevAvailable) {
|
||||
huffman.TallyLit(window[strstart-1] & 0xff);
|
||||
}
|
||||
prevAvailable = true;
|
||||
strstart++;
|
||||
lookahead--;
|
||||
}
|
||||
|
||||
if (huffman.IsFull()) {
|
||||
int len = strstart - blockStart;
|
||||
if (prevAvailable) {
|
||||
len--;
|
||||
}
|
||||
bool lastBlock = (finish && (lookahead == 0) && !prevAvailable);
|
||||
huffman.FlushBlock(window, blockStart, len, lastBlock);
|
||||
blockStart += len;
|
||||
return !lastBlock;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
|
||||
// Hash index of string to be inserted
|
||||
int ins_h;
|
||||
|
||||
/// <summary>
|
||||
/// Hashtable, hashing three characters to an index for window, so
|
||||
/// that window[index]..window[index+2] have this hash code.
|
||||
/// Note that the array should really be unsigned short, so you need
|
||||
/// to and the values with 0xffff.
|
||||
/// </summary>
|
||||
short[] head;
|
||||
|
||||
/// <summary>
|
||||
/// <code>prev[index & WMASK]</code> points to the previous index that has the
|
||||
/// same hash code as the string starting at index. This way
|
||||
/// entries with the same hash code are in a linked list.
|
||||
/// Note that the array should really be unsigned short, so you need
|
||||
/// to and the values with 0xffff.
|
||||
/// </summary>
|
||||
short[] prev;
|
||||
|
||||
int matchStart;
|
||||
// Length of best match
|
||||
int matchLen;
|
||||
// Set if previous match exists
|
||||
bool prevAvailable;
|
||||
int blockStart;
|
||||
|
||||
/// <summary>
|
||||
/// Points to the current character in the window.
|
||||
/// </summary>
|
||||
int strstart;
|
||||
|
||||
/// <summary>
|
||||
/// lookahead is the number of characters starting at strstart in
|
||||
/// window that are valid.
|
||||
/// So window[strstart] until window[strstart+lookahead-1] are valid
|
||||
/// characters.
|
||||
/// </summary>
|
||||
int lookahead;
|
||||
|
||||
/// <summary>
|
||||
/// This array contains the part of the uncompressed stream that
|
||||
/// is of relevance. The current character is indexed by strstart.
|
||||
/// </summary>
|
||||
byte[] window;
|
||||
|
||||
DeflateStrategy strategy;
|
||||
int max_chain, max_lazy, niceLength, goodLength;
|
||||
|
||||
/// <summary>
|
||||
/// The current compression function.
|
||||
/// </summary>
|
||||
int compressionFunction;
|
||||
|
||||
/// <summary>
|
||||
/// The input data for compression.
|
||||
/// </summary>
|
||||
byte[] inputBuf;
|
||||
|
||||
/// <summary>
|
||||
/// The total bytes of input read.
|
||||
/// </summary>
|
||||
long totalIn;
|
||||
|
||||
/// <summary>
|
||||
/// The offset into inputBuf, where input data starts.
|
||||
/// </summary>
|
||||
int inputOff;
|
||||
|
||||
/// <summary>
|
||||
/// The end offset of the input data.
|
||||
/// </summary>
|
||||
int inputEnd;
|
||||
|
||||
DeflaterPending pending;
|
||||
DeflaterHuffman huffman;
|
||||
|
||||
/// <summary>
|
||||
/// The adler checksum
|
||||
/// </summary>
|
||||
Adler32 adler;
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,908 @@
|
|||
// DeflaterHuffman.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
// Copyright (C) 2004 John Reilly
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip.Compression
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This is the DeflaterHuffman class.
|
||||
///
|
||||
/// This class is <i>not</i> thread safe. This is inherent in the API, due
|
||||
/// to the split of Deflate and SetInput.
|
||||
///
|
||||
/// author of the original java version : Jochen Hoenicke
|
||||
/// </summary>
|
||||
public class DeflaterHuffman
|
||||
{
|
||||
const int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6);
|
||||
const int LITERAL_NUM = 286;
|
||||
|
||||
// Number of distance codes
|
||||
const int DIST_NUM = 30;
|
||||
// Number of codes used to transfer bit lengths
|
||||
const int BITLEN_NUM = 19;
|
||||
|
||||
// repeat previous bit length 3-6 times (2 bits of repeat count)
|
||||
const int REP_3_6 = 16;
|
||||
// repeat a zero length 3-10 times (3 bits of repeat count)
|
||||
const int REP_3_10 = 17;
|
||||
// repeat a zero length 11-138 times (7 bits of repeat count)
|
||||
const int REP_11_138 = 18;
|
||||
|
||||
const int EOF_SYMBOL = 256;
|
||||
|
||||
// The lengths of the bit length codes are sent in order of decreasing
|
||||
// probability, to avoid transmitting the lengths for unused bit length codes.
|
||||
static readonly int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
|
||||
|
||||
static readonly byte[] bit4Reverse = {
|
||||
0,
|
||||
8,
|
||||
4,
|
||||
12,
|
||||
2,
|
||||
10,
|
||||
6,
|
||||
14,
|
||||
1,
|
||||
9,
|
||||
5,
|
||||
13,
|
||||
3,
|
||||
11,
|
||||
7,
|
||||
15
|
||||
};
|
||||
|
||||
static short[] staticLCodes;
|
||||
static byte[] staticLLength;
|
||||
static short[] staticDCodes;
|
||||
static byte[] staticDLength;
|
||||
|
||||
class Tree
|
||||
{
|
||||
#region Instance Fields
|
||||
public short[] freqs;
|
||||
|
||||
public byte[] length;
|
||||
|
||||
public int minNumCodes;
|
||||
|
||||
public int numCodes;
|
||||
|
||||
short[] codes;
|
||||
int[] bl_counts;
|
||||
int maxLength;
|
||||
DeflaterHuffman dh;
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public Tree(DeflaterHuffman dh, int elems, int minCodes, int maxLength)
|
||||
{
|
||||
this.dh = dh;
|
||||
this.minNumCodes = minCodes;
|
||||
this.maxLength = maxLength;
|
||||
freqs = new short[elems];
|
||||
bl_counts = new int[maxLength];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Resets the internal state of the tree
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
for (int i = 0; i < freqs.Length; i++) {
|
||||
freqs[i] = 0;
|
||||
}
|
||||
codes = null;
|
||||
length = null;
|
||||
}
|
||||
|
||||
public void WriteSymbol(int code)
|
||||
{
|
||||
// if (DeflaterConstants.DEBUGGING) {
|
||||
// freqs[code]--;
|
||||
// // Console.Write("writeSymbol("+freqs.length+","+code+"): ");
|
||||
// }
|
||||
dh.pending.WriteBits(codes[code] & 0xffff, length[code]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that all frequencies are zero
|
||||
/// </summary>
|
||||
/// <exception cref="SharpZipBaseException">
|
||||
/// At least one frequency is non-zero
|
||||
/// </exception>
|
||||
public void CheckEmpty()
|
||||
{
|
||||
bool empty = true;
|
||||
for (int i = 0; i < freqs.Length; i++) {
|
||||
if (freqs[i] != 0) {
|
||||
//Console.WriteLine("freqs[" + i + "] == " + freqs[i]);
|
||||
empty = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty) {
|
||||
throw new SharpZipBaseException("!Empty");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set static codes and length
|
||||
/// </summary>
|
||||
/// <param name="staticCodes">new codes</param>
|
||||
/// <param name="staticLengths">length for new codes</param>
|
||||
public void SetStaticCodes(short[] staticCodes, byte[] staticLengths)
|
||||
{
|
||||
codes = staticCodes;
|
||||
length = staticLengths;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build dynamic codes and lengths
|
||||
/// </summary>
|
||||
public void BuildCodes()
|
||||
{
|
||||
int numSymbols = freqs.Length;
|
||||
int[] nextCode = new int[maxLength];
|
||||
int code = 0;
|
||||
|
||||
codes = new short[freqs.Length];
|
||||
|
||||
// if (DeflaterConstants.DEBUGGING) {
|
||||
// //Console.WriteLine("buildCodes: "+freqs.Length);
|
||||
// }
|
||||
|
||||
for (int bits = 0; bits < maxLength; bits++) {
|
||||
nextCode[bits] = code;
|
||||
code += bl_counts[bits] << (15 - bits);
|
||||
|
||||
// if (DeflaterConstants.DEBUGGING) {
|
||||
// //Console.WriteLine("bits: " + ( bits + 1) + " count: " + bl_counts[bits]
|
||||
// +" nextCode: "+code);
|
||||
// }
|
||||
}
|
||||
|
||||
#if DebugDeflation
|
||||
if ( DeflaterConstants.DEBUGGING && (code != 65536) )
|
||||
{
|
||||
throw new SharpZipBaseException("Inconsistent bl_counts!");
|
||||
}
|
||||
#endif
|
||||
for (int i=0; i < numCodes; i++) {
|
||||
int bits = length[i];
|
||||
if (bits > 0) {
|
||||
|
||||
// if (DeflaterConstants.DEBUGGING) {
|
||||
// //Console.WriteLine("codes["+i+"] = rev(" + nextCode[bits-1]+"),
|
||||
// +bits);
|
||||
// }
|
||||
|
||||
codes[i] = BitReverse(nextCode[bits-1]);
|
||||
nextCode[bits-1] += 1 << (16 - bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void BuildTree()
|
||||
{
|
||||
int numSymbols = freqs.Length;
|
||||
|
||||
/* heap is a priority queue, sorted by frequency, least frequent
|
||||
* nodes first. The heap is a binary tree, with the property, that
|
||||
* the parent node is smaller than both child nodes. This assures
|
||||
* that the smallest node is the first parent.
|
||||
*
|
||||
* The binary tree is encoded in an array: 0 is root node and
|
||||
* the nodes 2*n+1, 2*n+2 are the child nodes of node n.
|
||||
*/
|
||||
int[] heap = new int[numSymbols];
|
||||
int heapLen = 0;
|
||||
int maxCode = 0;
|
||||
for (int n = 0; n < numSymbols; n++) {
|
||||
int freq = freqs[n];
|
||||
if (freq != 0) {
|
||||
// Insert n into heap
|
||||
int pos = heapLen++;
|
||||
int ppos;
|
||||
while (pos > 0 && freqs[heap[ppos = (pos - 1) / 2]] > freq) {
|
||||
heap[pos] = heap[ppos];
|
||||
pos = ppos;
|
||||
}
|
||||
heap[pos] = n;
|
||||
|
||||
maxCode = n;
|
||||
}
|
||||
}
|
||||
|
||||
/* We could encode a single literal with 0 bits but then we
|
||||
* don't see the literals. Therefore we force at least two
|
||||
* literals to avoid this case. We don't care about order in
|
||||
* this case, both literals get a 1 bit code.
|
||||
*/
|
||||
while (heapLen < 2) {
|
||||
int node = maxCode < 2 ? ++maxCode : 0;
|
||||
heap[heapLen++] = node;
|
||||
}
|
||||
|
||||
numCodes = Math.Max(maxCode + 1, minNumCodes);
|
||||
|
||||
int numLeafs = heapLen;
|
||||
int[] childs = new int[4 * heapLen - 2];
|
||||
int[] values = new int[2 * heapLen - 1];
|
||||
int numNodes = numLeafs;
|
||||
for (int i = 0; i < heapLen; i++) {
|
||||
int node = heap[i];
|
||||
childs[2 * i] = node;
|
||||
childs[2 * i + 1] = -1;
|
||||
values[i] = freqs[node] << 8;
|
||||
heap[i] = i;
|
||||
}
|
||||
|
||||
/* Construct the Huffman tree by repeatedly combining the least two
|
||||
* frequent nodes.
|
||||
*/
|
||||
do {
|
||||
int first = heap[0];
|
||||
int last = heap[--heapLen];
|
||||
|
||||
// Propagate the hole to the leafs of the heap
|
||||
int ppos = 0;
|
||||
int path = 1;
|
||||
|
||||
while (path < heapLen) {
|
||||
if (path + 1 < heapLen && values[heap[path]] > values[heap[path+1]]) {
|
||||
path++;
|
||||
}
|
||||
|
||||
heap[ppos] = heap[path];
|
||||
ppos = path;
|
||||
path = path * 2 + 1;
|
||||
}
|
||||
|
||||
/* Now propagate the last element down along path. Normally
|
||||
* it shouldn't go too deep.
|
||||
*/
|
||||
int lastVal = values[last];
|
||||
while ((path = ppos) > 0 && values[heap[ppos = (path - 1)/2]] > lastVal) {
|
||||
heap[path] = heap[ppos];
|
||||
}
|
||||
heap[path] = last;
|
||||
|
||||
|
||||
int second = heap[0];
|
||||
|
||||
// Create a new node father of first and second
|
||||
last = numNodes++;
|
||||
childs[2 * last] = first;
|
||||
childs[2 * last + 1] = second;
|
||||
int mindepth = Math.Min(values[first] & 0xff, values[second] & 0xff);
|
||||
values[last] = lastVal = values[first] + values[second] - mindepth + 1;
|
||||
|
||||
// Again, propagate the hole to the leafs
|
||||
ppos = 0;
|
||||
path = 1;
|
||||
|
||||
while (path < heapLen) {
|
||||
if (path + 1 < heapLen && values[heap[path]] > values[heap[path+1]]) {
|
||||
path++;
|
||||
}
|
||||
|
||||
heap[ppos] = heap[path];
|
||||
ppos = path;
|
||||
path = ppos * 2 + 1;
|
||||
}
|
||||
|
||||
// Now propagate the new element down along path
|
||||
while ((path = ppos) > 0 && values[heap[ppos = (path - 1)/2]] > lastVal) {
|
||||
heap[path] = heap[ppos];
|
||||
}
|
||||
heap[path] = last;
|
||||
} while (heapLen > 1);
|
||||
|
||||
if (heap[0] != childs.Length / 2 - 1) {
|
||||
throw new SharpZipBaseException("Heap invariant violated");
|
||||
}
|
||||
|
||||
BuildLength(childs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get encoded length
|
||||
/// </summary>
|
||||
/// <returns>Encoded length, the sum of frequencies * lengths</returns>
|
||||
public int GetEncodedLength()
|
||||
{
|
||||
int len = 0;
|
||||
for (int i = 0; i < freqs.Length; i++) {
|
||||
len += freqs[i] * length[i];
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scan a literal or distance tree to determine the frequencies of the codes
|
||||
/// in the bit length tree.
|
||||
/// </summary>
|
||||
public void CalcBLFreq(Tree blTree)
|
||||
{
|
||||
int max_count; /* max repeat count */
|
||||
int min_count; /* min repeat count */
|
||||
int count; /* repeat count of the current code */
|
||||
int curlen = -1; /* length of current code */
|
||||
|
||||
int i = 0;
|
||||
while (i < numCodes) {
|
||||
count = 1;
|
||||
int nextlen = length[i];
|
||||
if (nextlen == 0) {
|
||||
max_count = 138;
|
||||
min_count = 3;
|
||||
} else {
|
||||
max_count = 6;
|
||||
min_count = 3;
|
||||
if (curlen != nextlen) {
|
||||
blTree.freqs[nextlen]++;
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
curlen = nextlen;
|
||||
i++;
|
||||
|
||||
while (i < numCodes && curlen == length[i]) {
|
||||
i++;
|
||||
if (++count >= max_count) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count < min_count) {
|
||||
blTree.freqs[curlen] += (short)count;
|
||||
} else if (curlen != 0) {
|
||||
blTree.freqs[REP_3_6]++;
|
||||
} else if (count <= 10) {
|
||||
blTree.freqs[REP_3_10]++;
|
||||
} else {
|
||||
blTree.freqs[REP_11_138]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write tree values
|
||||
/// </summary>
|
||||
/// <param name="blTree">Tree to write</param>
|
||||
public void WriteTree(Tree blTree)
|
||||
{
|
||||
int max_count; // max repeat count
|
||||
int min_count; // min repeat count
|
||||
int count; // repeat count of the current code
|
||||
int curlen = -1; // length of current code
|
||||
|
||||
int i = 0;
|
||||
while (i < numCodes) {
|
||||
count = 1;
|
||||
int nextlen = length[i];
|
||||
if (nextlen == 0) {
|
||||
max_count = 138;
|
||||
min_count = 3;
|
||||
} else {
|
||||
max_count = 6;
|
||||
min_count = 3;
|
||||
if (curlen != nextlen) {
|
||||
blTree.WriteSymbol(nextlen);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
curlen = nextlen;
|
||||
i++;
|
||||
|
||||
while (i < numCodes && curlen == length[i]) {
|
||||
i++;
|
||||
if (++count >= max_count) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count < min_count) {
|
||||
while (count-- > 0) {
|
||||
blTree.WriteSymbol(curlen);
|
||||
}
|
||||
} else if (curlen != 0) {
|
||||
blTree.WriteSymbol(REP_3_6);
|
||||
dh.pending.WriteBits(count - 3, 2);
|
||||
} else if (count <= 10) {
|
||||
blTree.WriteSymbol(REP_3_10);
|
||||
dh.pending.WriteBits(count - 3, 3);
|
||||
} else {
|
||||
blTree.WriteSymbol(REP_11_138);
|
||||
dh.pending.WriteBits(count - 11, 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BuildLength(int[] childs)
|
||||
{
|
||||
this.length = new byte [freqs.Length];
|
||||
int numNodes = childs.Length / 2;
|
||||
int numLeafs = (numNodes + 1) / 2;
|
||||
int overflow = 0;
|
||||
|
||||
for (int i = 0; i < maxLength; i++) {
|
||||
bl_counts[i] = 0;
|
||||
}
|
||||
|
||||
// First calculate optimal bit lengths
|
||||
int[] lengths = new int[numNodes];
|
||||
lengths[numNodes-1] = 0;
|
||||
|
||||
for (int i = numNodes - 1; i >= 0; i--) {
|
||||
if (childs[2 * i + 1] != -1) {
|
||||
int bitLength = lengths[i] + 1;
|
||||
if (bitLength > maxLength) {
|
||||
bitLength = maxLength;
|
||||
overflow++;
|
||||
}
|
||||
lengths[childs[2 * i]] = lengths[childs[2 * i + 1]] = bitLength;
|
||||
} else {
|
||||
// A leaf node
|
||||
int bitLength = lengths[i];
|
||||
bl_counts[bitLength - 1]++;
|
||||
this.length[childs[2*i]] = (byte) lengths[i];
|
||||
}
|
||||
}
|
||||
|
||||
// if (DeflaterConstants.DEBUGGING) {
|
||||
// //Console.WriteLine("Tree "+freqs.Length+" lengths:");
|
||||
// for (int i=0; i < numLeafs; i++) {
|
||||
// //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
|
||||
// + " len: "+length[childs[2*i]]);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (overflow == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int incrBitLen = maxLength - 1;
|
||||
do {
|
||||
// Find the first bit length which could increase:
|
||||
while (bl_counts[--incrBitLen] == 0)
|
||||
;
|
||||
|
||||
// Move this node one down and remove a corresponding
|
||||
// number of overflow nodes.
|
||||
do {
|
||||
bl_counts[incrBitLen]--;
|
||||
bl_counts[++incrBitLen]++;
|
||||
overflow -= 1 << (maxLength - 1 - incrBitLen);
|
||||
} while (overflow > 0 && incrBitLen < maxLength - 1);
|
||||
} while (overflow > 0);
|
||||
|
||||
/* We may have overshot above. Move some nodes from maxLength to
|
||||
* maxLength-1 in that case.
|
||||
*/
|
||||
bl_counts[maxLength-1] += overflow;
|
||||
bl_counts[maxLength-2] -= overflow;
|
||||
|
||||
/* Now recompute all bit lengths, scanning in increasing
|
||||
* frequency. It is simpler to reconstruct all lengths instead of
|
||||
* fixing only the wrong ones. This idea is taken from 'ar'
|
||||
* written by Haruhiko Okumura.
|
||||
*
|
||||
* The nodes were inserted with decreasing frequency into the childs
|
||||
* array.
|
||||
*/
|
||||
int nodePtr = 2 * numLeafs;
|
||||
for (int bits = maxLength; bits != 0; bits--) {
|
||||
int n = bl_counts[bits-1];
|
||||
while (n > 0) {
|
||||
int childPtr = 2*childs[nodePtr++];
|
||||
if (childs[childPtr + 1] == -1) {
|
||||
// We found another leaf
|
||||
length[childs[childPtr]] = (byte) bits;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (DeflaterConstants.DEBUGGING) {
|
||||
// //Console.WriteLine("*** After overflow elimination. ***");
|
||||
// for (int i=0; i < numLeafs; i++) {
|
||||
// //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
|
||||
// + " len: "+length[childs[2*i]]);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// Pending buffer to use
|
||||
/// </summary>
|
||||
public DeflaterPending pending;
|
||||
|
||||
Tree literalTree;
|
||||
Tree distTree;
|
||||
Tree blTree;
|
||||
|
||||
// Buffer for distances
|
||||
short[] d_buf;
|
||||
byte[] l_buf;
|
||||
int last_lit;
|
||||
int extra_bits;
|
||||
#endregion
|
||||
|
||||
static DeflaterHuffman()
|
||||
{
|
||||
// See RFC 1951 3.2.6
|
||||
// Literal codes
|
||||
staticLCodes = new short[LITERAL_NUM];
|
||||
staticLLength = new byte[LITERAL_NUM];
|
||||
|
||||
int i = 0;
|
||||
while (i < 144) {
|
||||
staticLCodes[i] = BitReverse((0x030 + i) << 8);
|
||||
staticLLength[i++] = 8;
|
||||
}
|
||||
|
||||
while (i < 256) {
|
||||
staticLCodes[i] = BitReverse((0x190 - 144 + i) << 7);
|
||||
staticLLength[i++] = 9;
|
||||
}
|
||||
|
||||
while (i < 280) {
|
||||
staticLCodes[i] = BitReverse((0x000 - 256 + i) << 9);
|
||||
staticLLength[i++] = 7;
|
||||
}
|
||||
|
||||
while (i < LITERAL_NUM) {
|
||||
staticLCodes[i] = BitReverse((0x0c0 - 280 + i) << 8);
|
||||
staticLLength[i++] = 8;
|
||||
}
|
||||
|
||||
// Distance codes
|
||||
staticDCodes = new short[DIST_NUM];
|
||||
staticDLength = new byte[DIST_NUM];
|
||||
for (i = 0; i < DIST_NUM; i++) {
|
||||
staticDCodes[i] = BitReverse(i << 11);
|
||||
staticDLength[i] = 5;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct instance with pending buffer
|
||||
/// </summary>
|
||||
/// <param name="pending">Pending buffer to use</param>
|
||||
public DeflaterHuffman(DeflaterPending pending)
|
||||
{
|
||||
this.pending = pending;
|
||||
|
||||
literalTree = new Tree(this, LITERAL_NUM, 257, 15);
|
||||
distTree = new Tree(this, DIST_NUM, 1, 15);
|
||||
blTree = new Tree(this, BITLEN_NUM, 4, 7);
|
||||
|
||||
d_buf = new short[BUFSIZE];
|
||||
l_buf = new byte [BUFSIZE];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset internal state
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
last_lit = 0;
|
||||
extra_bits = 0;
|
||||
literalTree.Reset();
|
||||
distTree.Reset();
|
||||
blTree.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write all trees to pending buffer
|
||||
/// </summary>
|
||||
/// <param name="blTreeCodes">The number/rank of treecodes to send.</param>
|
||||
public void SendAllTrees(int blTreeCodes)
|
||||
{
|
||||
blTree.BuildCodes();
|
||||
literalTree.BuildCodes();
|
||||
distTree.BuildCodes();
|
||||
pending.WriteBits(literalTree.numCodes - 257, 5);
|
||||
pending.WriteBits(distTree.numCodes - 1, 5);
|
||||
pending.WriteBits(blTreeCodes - 4, 4);
|
||||
for (int rank = 0; rank < blTreeCodes; rank++) {
|
||||
pending.WriteBits(blTree.length[BL_ORDER[rank]], 3);
|
||||
}
|
||||
literalTree.WriteTree(blTree);
|
||||
distTree.WriteTree(blTree);
|
||||
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING) {
|
||||
blTree.CheckEmpty();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compress current buffer writing data to pending buffer
|
||||
/// </summary>
|
||||
public void CompressBlock()
|
||||
{
|
||||
for (int i = 0; i < last_lit; i++) {
|
||||
int litlen = l_buf[i] & 0xff;
|
||||
int dist = d_buf[i];
|
||||
if (dist-- != 0) {
|
||||
// if (DeflaterConstants.DEBUGGING) {
|
||||
// Console.Write("["+(dist+1)+","+(litlen+3)+"]: ");
|
||||
// }
|
||||
|
||||
int lc = Lcode(litlen);
|
||||
literalTree.WriteSymbol(lc);
|
||||
|
||||
int bits = (lc - 261) / 4;
|
||||
if (bits > 0 && bits <= 5) {
|
||||
pending.WriteBits(litlen & ((1 << bits) - 1), bits);
|
||||
}
|
||||
|
||||
int dc = Dcode(dist);
|
||||
distTree.WriteSymbol(dc);
|
||||
|
||||
bits = dc / 2 - 1;
|
||||
if (bits > 0) {
|
||||
pending.WriteBits(dist & ((1 << bits) - 1), bits);
|
||||
}
|
||||
} else {
|
||||
// if (DeflaterConstants.DEBUGGING) {
|
||||
// if (litlen > 32 && litlen < 127) {
|
||||
// Console.Write("("+(char)litlen+"): ");
|
||||
// } else {
|
||||
// Console.Write("{"+litlen+"}: ");
|
||||
// }
|
||||
// }
|
||||
literalTree.WriteSymbol(litlen);
|
||||
}
|
||||
}
|
||||
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING) {
|
||||
Console.Write("EOF: ");
|
||||
}
|
||||
#endif
|
||||
literalTree.WriteSymbol(EOF_SYMBOL);
|
||||
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING) {
|
||||
literalTree.CheckEmpty();
|
||||
distTree.CheckEmpty();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flush block to output with no compression
|
||||
/// </summary>
|
||||
/// <param name="stored">Data to write</param>
|
||||
/// <param name="storedOffset">Index of first byte to write</param>
|
||||
/// <param name="storedLength">Count of bytes to write</param>
|
||||
/// <param name="lastBlock">True if this is the last block</param>
|
||||
public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
|
||||
{
|
||||
#if DebugDeflation
|
||||
// if (DeflaterConstants.DEBUGGING) {
|
||||
// //Console.WriteLine("Flushing stored block "+ storedLength);
|
||||
// }
|
||||
#endif
|
||||
pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3);
|
||||
pending.AlignToByte();
|
||||
pending.WriteShort(storedLength);
|
||||
pending.WriteShort(~storedLength);
|
||||
pending.WriteBlock(stored, storedOffset, storedLength);
|
||||
Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flush block to output with compression
|
||||
/// </summary>
|
||||
/// <param name="stored">Data to flush</param>
|
||||
/// <param name="storedOffset">Index of first byte to flush</param>
|
||||
/// <param name="storedLength">Count of bytes to flush</param>
|
||||
/// <param name="lastBlock">True if this is the last block</param>
|
||||
public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
|
||||
{
|
||||
literalTree.freqs[EOF_SYMBOL]++;
|
||||
|
||||
// Build trees
|
||||
literalTree.BuildTree();
|
||||
distTree.BuildTree();
|
||||
|
||||
// Calculate bitlen frequency
|
||||
literalTree.CalcBLFreq(blTree);
|
||||
distTree.CalcBLFreq(blTree);
|
||||
|
||||
// Build bitlen tree
|
||||
blTree.BuildTree();
|
||||
|
||||
int blTreeCodes = 4;
|
||||
for (int i = 18; i > blTreeCodes; i--) {
|
||||
if (blTree.length[BL_ORDER[i]] > 0) {
|
||||
blTreeCodes = i+1;
|
||||
}
|
||||
}
|
||||
int opt_len = 14 + blTreeCodes * 3 + blTree.GetEncodedLength() +
|
||||
literalTree.GetEncodedLength() + distTree.GetEncodedLength() +
|
||||
extra_bits;
|
||||
|
||||
int static_len = extra_bits;
|
||||
for (int i = 0; i < LITERAL_NUM; i++) {
|
||||
static_len += literalTree.freqs[i] * staticLLength[i];
|
||||
}
|
||||
for (int i = 0; i < DIST_NUM; i++) {
|
||||
static_len += distTree.freqs[i] * staticDLength[i];
|
||||
}
|
||||
if (opt_len >= static_len) {
|
||||
// Force static trees
|
||||
opt_len = static_len;
|
||||
}
|
||||
|
||||
if (storedOffset >= 0 && storedLength + 4 < opt_len >> 3) {
|
||||
// Store Block
|
||||
|
||||
// if (DeflaterConstants.DEBUGGING) {
|
||||
// //Console.WriteLine("Storing, since " + storedLength + " < " + opt_len
|
||||
// + " <= " + static_len);
|
||||
// }
|
||||
FlushStoredBlock(stored, storedOffset, storedLength, lastBlock);
|
||||
} else if (opt_len == static_len) {
|
||||
// Encode with static tree
|
||||
pending.WriteBits((DeflaterConstants.STATIC_TREES << 1) + (lastBlock ? 1 : 0), 3);
|
||||
literalTree.SetStaticCodes(staticLCodes, staticLLength);
|
||||
distTree.SetStaticCodes(staticDCodes, staticDLength);
|
||||
CompressBlock();
|
||||
Reset();
|
||||
} else {
|
||||
// Encode with dynamic tree
|
||||
pending.WriteBits((DeflaterConstants.DYN_TREES << 1) + (lastBlock ? 1 : 0), 3);
|
||||
SendAllTrees(blTreeCodes);
|
||||
CompressBlock();
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get value indicating if internal buffer is full
|
||||
/// </summary>
|
||||
/// <returns>true if buffer is full</returns>
|
||||
public bool IsFull()
|
||||
{
|
||||
return last_lit >= BUFSIZE;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add literal to buffer
|
||||
/// </summary>
|
||||
/// <param name="literal">Literal value to add to buffer.</param>
|
||||
/// <returns>Value indicating internal buffer is full</returns>
|
||||
public bool TallyLit(int literal)
|
||||
{
|
||||
// if (DeflaterConstants.DEBUGGING) {
|
||||
// if (lit > 32 && lit < 127) {
|
||||
// //Console.WriteLine("("+(char)lit+")");
|
||||
// } else {
|
||||
// //Console.WriteLine("{"+lit+"}");
|
||||
// }
|
||||
// }
|
||||
d_buf[last_lit] = 0;
|
||||
l_buf[last_lit++] = (byte)literal;
|
||||
literalTree.freqs[literal]++;
|
||||
return IsFull();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add distance code and length to literal and distance trees
|
||||
/// </summary>
|
||||
/// <param name="distance">Distance code</param>
|
||||
/// <param name="length">Length</param>
|
||||
/// <returns>Value indicating if internal buffer is full</returns>
|
||||
public bool TallyDist(int distance, int length)
|
||||
{
|
||||
// if (DeflaterConstants.DEBUGGING) {
|
||||
// //Console.WriteLine("[" + distance + "," + length + "]");
|
||||
// }
|
||||
|
||||
d_buf[last_lit] = (short)distance;
|
||||
l_buf[last_lit++] = (byte)(length - 3);
|
||||
|
||||
int lc = Lcode(length - 3);
|
||||
literalTree.freqs[lc]++;
|
||||
if (lc >= 265 && lc < 285) {
|
||||
extra_bits += (lc - 261) / 4;
|
||||
}
|
||||
|
||||
int dc = Dcode(distance - 1);
|
||||
distTree.freqs[dc]++;
|
||||
if (dc >= 4) {
|
||||
extra_bits += dc / 2 - 1;
|
||||
}
|
||||
return IsFull();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reverse the bits of a 16 bit value.
|
||||
/// </summary>
|
||||
/// <param name="toReverse">Value to reverse bits</param>
|
||||
/// <returns>Value with bits reversed</returns>
|
||||
public static short BitReverse(int toReverse)
|
||||
{
|
||||
return (short) (bit4Reverse[toReverse & 0xF] << 12 |
|
||||
bit4Reverse[(toReverse >> 4) & 0xF] << 8 |
|
||||
bit4Reverse[(toReverse >> 8) & 0xF] << 4 |
|
||||
bit4Reverse[toReverse >> 12]);
|
||||
}
|
||||
|
||||
static int Lcode(int length)
|
||||
{
|
||||
if (length == 255) {
|
||||
return 285;
|
||||
}
|
||||
|
||||
int code = 257;
|
||||
while (length >= 8) {
|
||||
code += 4;
|
||||
length >>= 1;
|
||||
}
|
||||
return code + length;
|
||||
}
|
||||
|
||||
static int Dcode(int distance)
|
||||
{
|
||||
int code = 0;
|
||||
while (distance >= 4) {
|
||||
code += 2;
|
||||
distance >>= 1;
|
||||
}
|
||||
return code + distance;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
// DeflaterPending.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
// Copyright (C) 2004 John Reilly
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip.Compression
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This class stores the pending output of the Deflater.
|
||||
///
|
||||
/// author of the original java version : Jochen Hoenicke
|
||||
/// </summary>
|
||||
public class DeflaterPending : PendingBuffer
|
||||
{
|
||||
/// <summary>
|
||||
/// Construct instance with default buffer size
|
||||
/// </summary>
|
||||
public DeflaterPending() : base(DeflaterConstants.PENDING_BUF_SIZE)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,864 @@
|
|||
// Inflater.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
// Copyright (C) 2004 John Reilly
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
using ICSharpCode.SharpZipLib.Checksums;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip.Compression
|
||||
{
|
||||
/// <summary>
|
||||
/// Inflater is used to decompress data that has been compressed according
|
||||
/// to the "deflate" standard described in rfc1951.
|
||||
///
|
||||
/// By default Zlib (rfc1950) headers and footers are expected in the input.
|
||||
/// You can use constructor <code> public Inflater(bool noHeader)</code> passing true
|
||||
/// if there is no Zlib header information
|
||||
///
|
||||
/// The usage is as following. First you have to set some input with
|
||||
/// <code>SetInput()</code>, then Inflate() it. If inflate doesn't
|
||||
/// inflate any bytes there may be three reasons:
|
||||
/// <ul>
|
||||
/// <li>IsNeedingInput() returns true because the input buffer is empty.
|
||||
/// You have to provide more input with <code>SetInput()</code>.
|
||||
/// NOTE: IsNeedingInput() also returns true when, the stream is finished.
|
||||
/// </li>
|
||||
/// <li>IsNeedingDictionary() returns true, you have to provide a preset
|
||||
/// dictionary with <code>SetDictionary()</code>.</li>
|
||||
/// <li>IsFinished returns true, the inflater has finished.</li>
|
||||
/// </ul>
|
||||
/// Once the first output byte is produced, a dictionary will not be
|
||||
/// needed at a later stage.
|
||||
///
|
||||
/// author of the original java version : John Leuner, Jochen Hoenicke
|
||||
/// </summary>
|
||||
public class Inflater
|
||||
{
|
||||
#region Constants/Readonly
|
||||
/// <summary>
|
||||
/// Copy lengths for literal codes 257..285
|
||||
/// </summary>
|
||||
static readonly int[] CPLENS = {
|
||||
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
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Extra bits for literal codes 257..285
|
||||
/// </summary>
|
||||
static readonly int[] CPLEXT = {
|
||||
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
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Copy offsets for distance codes 0..29
|
||||
/// </summary>
|
||||
static readonly int[] CPDIST = {
|
||||
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
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Extra bits for distance codes
|
||||
/// </summary>
|
||||
static readonly int[] CPDEXT = {
|
||||
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
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// These are the possible states for an inflater
|
||||
/// </summary>
|
||||
const int DECODE_HEADER = 0;
|
||||
const int DECODE_DICT = 1;
|
||||
const int DECODE_BLOCKS = 2;
|
||||
const int DECODE_STORED_LEN1 = 3;
|
||||
const int DECODE_STORED_LEN2 = 4;
|
||||
const int DECODE_STORED = 5;
|
||||
const int DECODE_DYN_HEADER = 6;
|
||||
const int DECODE_HUFFMAN = 7;
|
||||
const int DECODE_HUFFMAN_LENBITS = 8;
|
||||
const int DECODE_HUFFMAN_DIST = 9;
|
||||
const int DECODE_HUFFMAN_DISTBITS = 10;
|
||||
const int DECODE_CHKSUM = 11;
|
||||
const int FINISHED = 12;
|
||||
#endregion
|
||||
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// This variable contains the current state.
|
||||
/// </summary>
|
||||
int mode;
|
||||
|
||||
/// <summary>
|
||||
/// The adler checksum of the dictionary or of the decompressed
|
||||
/// stream, as it is written in the header resp. footer of the
|
||||
/// compressed stream.
|
||||
/// Only valid if mode is DECODE_DICT or DECODE_CHKSUM.
|
||||
/// </summary>
|
||||
int readAdler;
|
||||
|
||||
/// <summary>
|
||||
/// The number of bits needed to complete the current state. This
|
||||
/// is valid, if mode is DECODE_DICT, DECODE_CHKSUM,
|
||||
/// DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.
|
||||
/// </summary>
|
||||
int neededBits;
|
||||
int repLength;
|
||||
int repDist;
|
||||
int uncomprLen;
|
||||
|
||||
/// <summary>
|
||||
/// True, if the last block flag was set in the last block of the
|
||||
/// inflated stream. This means that the stream ends after the
|
||||
/// current block.
|
||||
/// </summary>
|
||||
bool isLastBlock;
|
||||
|
||||
/// <summary>
|
||||
/// The total number of inflated bytes.
|
||||
/// </summary>
|
||||
long totalOut;
|
||||
|
||||
/// <summary>
|
||||
/// The total number of bytes set with setInput(). This is not the
|
||||
/// value returned by the TotalIn property, since this also includes the
|
||||
/// unprocessed input.
|
||||
/// </summary>
|
||||
long totalIn;
|
||||
|
||||
/// <summary>
|
||||
/// This variable stores the noHeader flag that was given to the constructor.
|
||||
/// True means, that the inflated stream doesn't contain a Zlib header or
|
||||
/// footer.
|
||||
/// </summary>
|
||||
bool noHeader;
|
||||
|
||||
StreamManipulator input;
|
||||
OutputWindow outputWindow;
|
||||
InflaterDynHeader dynHeader;
|
||||
InflaterHuffmanTree litlenTree, distTree;
|
||||
Adler32 adler;
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Creates a new inflater or RFC1951 decompressor
|
||||
/// RFC1950/Zlib headers and footers will be expected in the input data
|
||||
/// </summary>
|
||||
public Inflater() : this(false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new inflater.
|
||||
/// </summary>
|
||||
/// <param name="noHeader">
|
||||
/// True if no RFC1950/Zlib header and footer fields are expected in the input data
|
||||
///
|
||||
/// This is used for GZIPed/Zipped input.
|
||||
///
|
||||
/// For compatibility with
|
||||
/// Sun JDK you should provide one byte of input more than needed in
|
||||
/// this case.
|
||||
/// </param>
|
||||
public Inflater(bool noHeader)
|
||||
{
|
||||
this.noHeader = noHeader;
|
||||
this.adler = new Adler32();
|
||||
input = new StreamManipulator();
|
||||
outputWindow = new OutputWindow();
|
||||
mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Resets the inflater so that a new stream can be decompressed. All
|
||||
/// pending input and output will be discarded.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
|
||||
totalIn = 0;
|
||||
totalOut = 0;
|
||||
input.Reset();
|
||||
outputWindow.Reset();
|
||||
dynHeader = null;
|
||||
litlenTree = null;
|
||||
distTree = null;
|
||||
isLastBlock = false;
|
||||
adler.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a zlib/RFC1950 header.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// False if more input is needed.
|
||||
/// </returns>
|
||||
/// <exception cref="SharpZipBaseException">
|
||||
/// The header is invalid.
|
||||
/// </exception>
|
||||
private bool DecodeHeader()
|
||||
{
|
||||
int header = input.PeekBits(16);
|
||||
if (header < 0) {
|
||||
return false;
|
||||
}
|
||||
input.DropBits(16);
|
||||
|
||||
// The header is written in "wrong" byte order
|
||||
header = ((header << 8) | (header >> 8)) & 0xffff;
|
||||
if (header % 31 != 0) {
|
||||
throw new SharpZipBaseException("Header checksum illegal");
|
||||
}
|
||||
|
||||
if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) {
|
||||
throw new SharpZipBaseException("Compression Method unknown");
|
||||
}
|
||||
|
||||
/* Maximum size of the backwards window in bits.
|
||||
* We currently ignore this, but we could use it to make the
|
||||
* inflater window more space efficient. On the other hand the
|
||||
* full window (15 bits) is needed most times, anyway.
|
||||
int max_wbits = ((header & 0x7000) >> 12) + 8;
|
||||
*/
|
||||
|
||||
if ((header & 0x0020) == 0) { // Dictionary flag?
|
||||
mode = DECODE_BLOCKS;
|
||||
} else {
|
||||
mode = DECODE_DICT;
|
||||
neededBits = 32;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes the dictionary checksum after the deflate header.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// False if more input is needed.
|
||||
/// </returns>
|
||||
private bool DecodeDict()
|
||||
{
|
||||
while (neededBits > 0) {
|
||||
int dictByte = input.PeekBits(8);
|
||||
if (dictByte < 0) {
|
||||
return false;
|
||||
}
|
||||
input.DropBits(8);
|
||||
readAdler = (readAdler << 8) | dictByte;
|
||||
neededBits -= 8;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes the huffman encoded symbols in the input stream.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// false if more input is needed, true if output window is
|
||||
/// full or the current block ends.
|
||||
/// </returns>
|
||||
/// <exception cref="SharpZipBaseException">
|
||||
/// if deflated stream is invalid.
|
||||
/// </exception>
|
||||
private bool DecodeHuffman()
|
||||
{
|
||||
int free = outputWindow.GetFreeSpace();
|
||||
while (free >= 258)
|
||||
{
|
||||
int symbol;
|
||||
switch (mode)
|
||||
{
|
||||
case DECODE_HUFFMAN:
|
||||
// This is the inner loop so it is optimized a bit
|
||||
while (((symbol = litlenTree.GetSymbol(input)) & ~0xff) == 0)
|
||||
{
|
||||
outputWindow.Write(symbol);
|
||||
if (--free < 258)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (symbol < 257)
|
||||
{
|
||||
if (symbol < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// symbol == 256: end of block
|
||||
distTree = null;
|
||||
litlenTree = null;
|
||||
mode = DECODE_BLOCKS;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
repLength = CPLENS[symbol - 257];
|
||||
neededBits = CPLEXT[symbol - 257];
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new SharpZipBaseException("Illegal rep length code");
|
||||
}
|
||||
goto case DECODE_HUFFMAN_LENBITS; // fall through
|
||||
|
||||
case DECODE_HUFFMAN_LENBITS:
|
||||
if (neededBits > 0)
|
||||
{
|
||||
mode = DECODE_HUFFMAN_LENBITS;
|
||||
int i = input.PeekBits(neededBits);
|
||||
if (i < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
input.DropBits(neededBits);
|
||||
repLength += i;
|
||||
}
|
||||
mode = DECODE_HUFFMAN_DIST;
|
||||
goto case DECODE_HUFFMAN_DIST; // fall through
|
||||
|
||||
case DECODE_HUFFMAN_DIST:
|
||||
symbol = distTree.GetSymbol(input);
|
||||
if (symbol < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
repDist = CPDIST[symbol];
|
||||
neededBits = CPDEXT[symbol];
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new SharpZipBaseException("Illegal rep dist code");
|
||||
}
|
||||
|
||||
goto case DECODE_HUFFMAN_DISTBITS; // fall through
|
||||
|
||||
case DECODE_HUFFMAN_DISTBITS:
|
||||
if (neededBits > 0)
|
||||
{
|
||||
mode = DECODE_HUFFMAN_DISTBITS;
|
||||
int i = input.PeekBits(neededBits);
|
||||
if (i < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
input.DropBits(neededBits);
|
||||
repDist += i;
|
||||
}
|
||||
|
||||
outputWindow.Repeat(repLength, repDist);
|
||||
free -= repLength;
|
||||
mode = DECODE_HUFFMAN;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new SharpZipBaseException("Inflater unknown mode");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes the adler checksum after the deflate stream.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// false if more input is needed.
|
||||
/// </returns>
|
||||
/// <exception cref="SharpZipBaseException">
|
||||
/// If checksum doesn't match.
|
||||
/// </exception>
|
||||
private bool DecodeChksum()
|
||||
{
|
||||
while (neededBits > 0) {
|
||||
int chkByte = input.PeekBits(8);
|
||||
if (chkByte < 0) {
|
||||
return false;
|
||||
}
|
||||
input.DropBits(8);
|
||||
readAdler = (readAdler << 8) | chkByte;
|
||||
neededBits -= 8;
|
||||
}
|
||||
|
||||
if ((int) adler.Value != readAdler) {
|
||||
throw new SharpZipBaseException("Adler chksum doesn't match: " + (int)adler.Value + " vs. " + readAdler);
|
||||
}
|
||||
|
||||
mode = FINISHED;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes the deflated stream.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// false if more input is needed, or if finished.
|
||||
/// </returns>
|
||||
/// <exception cref="SharpZipBaseException">
|
||||
/// if deflated stream is invalid.
|
||||
/// </exception>
|
||||
private bool Decode()
|
||||
{
|
||||
switch (mode) {
|
||||
case DECODE_HEADER:
|
||||
return DecodeHeader();
|
||||
|
||||
case DECODE_DICT:
|
||||
return DecodeDict();
|
||||
|
||||
case DECODE_CHKSUM:
|
||||
return DecodeChksum();
|
||||
|
||||
case DECODE_BLOCKS:
|
||||
if (isLastBlock) {
|
||||
if (noHeader) {
|
||||
mode = FINISHED;
|
||||
return false;
|
||||
} else {
|
||||
input.SkipToByteBoundary();
|
||||
neededBits = 32;
|
||||
mode = DECODE_CHKSUM;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int type = input.PeekBits(3);
|
||||
if (type < 0) {
|
||||
return false;
|
||||
}
|
||||
input.DropBits(3);
|
||||
|
||||
if ((type & 1) != 0) {
|
||||
isLastBlock = true;
|
||||
}
|
||||
switch (type >> 1){
|
||||
case DeflaterConstants.STORED_BLOCK:
|
||||
input.SkipToByteBoundary();
|
||||
mode = DECODE_STORED_LEN1;
|
||||
break;
|
||||
case DeflaterConstants.STATIC_TREES:
|
||||
litlenTree = InflaterHuffmanTree.defLitLenTree;
|
||||
distTree = InflaterHuffmanTree.defDistTree;
|
||||
mode = DECODE_HUFFMAN;
|
||||
break;
|
||||
case DeflaterConstants.DYN_TREES:
|
||||
dynHeader = new InflaterDynHeader();
|
||||
mode = DECODE_DYN_HEADER;
|
||||
break;
|
||||
default:
|
||||
throw new SharpZipBaseException("Unknown block type " + type);
|
||||
}
|
||||
return true;
|
||||
|
||||
case DECODE_STORED_LEN1:
|
||||
{
|
||||
if ((uncomprLen = input.PeekBits(16)) < 0) {
|
||||
return false;
|
||||
}
|
||||
input.DropBits(16);
|
||||
mode = DECODE_STORED_LEN2;
|
||||
}
|
||||
goto case DECODE_STORED_LEN2; // fall through
|
||||
|
||||
case DECODE_STORED_LEN2:
|
||||
{
|
||||
int nlen = input.PeekBits(16);
|
||||
if (nlen < 0) {
|
||||
return false;
|
||||
}
|
||||
input.DropBits(16);
|
||||
if (nlen != (uncomprLen ^ 0xffff)) {
|
||||
throw new SharpZipBaseException("broken uncompressed block");
|
||||
}
|
||||
mode = DECODE_STORED;
|
||||
}
|
||||
goto case DECODE_STORED; // fall through
|
||||
|
||||
case DECODE_STORED:
|
||||
{
|
||||
int more = outputWindow.CopyStored(input, uncomprLen);
|
||||
uncomprLen -= more;
|
||||
if (uncomprLen == 0) {
|
||||
mode = DECODE_BLOCKS;
|
||||
return true;
|
||||
}
|
||||
return !input.IsNeedingInput;
|
||||
}
|
||||
|
||||
case DECODE_DYN_HEADER:
|
||||
if (!dynHeader.Decode(input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
litlenTree = dynHeader.BuildLitLenTree();
|
||||
distTree = dynHeader.BuildDistTree();
|
||||
mode = DECODE_HUFFMAN;
|
||||
goto case DECODE_HUFFMAN; // fall through
|
||||
|
||||
case DECODE_HUFFMAN:
|
||||
case DECODE_HUFFMAN_LENBITS:
|
||||
case DECODE_HUFFMAN_DIST:
|
||||
case DECODE_HUFFMAN_DISTBITS:
|
||||
return DecodeHuffman();
|
||||
|
||||
case FINISHED:
|
||||
return false;
|
||||
|
||||
default:
|
||||
throw new SharpZipBaseException("Inflater.Decode unknown mode");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the preset dictionary. This should only be called, if
|
||||
/// needsDictionary() returns true and it should set the same
|
||||
/// dictionary, that was used for deflating. The getAdler()
|
||||
/// function returns the checksum of the dictionary needed.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// The dictionary.
|
||||
/// </param>
|
||||
public void SetDictionary(byte[] buffer)
|
||||
{
|
||||
SetDictionary(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the preset dictionary. This should only be called, if
|
||||
/// needsDictionary() returns true and it should set the same
|
||||
/// dictionary, that was used for deflating. The getAdler()
|
||||
/// function returns the checksum of the dictionary needed.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// The dictionary.
|
||||
/// </param>
|
||||
/// <param name="index">
|
||||
/// The index into buffer where the dictionary starts.
|
||||
/// </param>
|
||||
/// <param name="count">
|
||||
/// The number of bytes in the dictionary.
|
||||
/// </param>
|
||||
/// <exception cref="System.InvalidOperationException">
|
||||
/// No dictionary is needed.
|
||||
/// </exception>
|
||||
/// <exception cref="SharpZipBaseException">
|
||||
/// The adler checksum for the buffer is invalid
|
||||
/// </exception>
|
||||
public void SetDictionary(byte[] buffer, int index, int count)
|
||||
{
|
||||
if ( buffer == null ) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
if ( index < 0 ) {
|
||||
throw new ArgumentOutOfRangeException("index");
|
||||
}
|
||||
|
||||
if ( count < 0 ) {
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
}
|
||||
|
||||
if (!IsNeedingDictionary) {
|
||||
throw new InvalidOperationException("Dictionary is not needed");
|
||||
}
|
||||
|
||||
adler.Update(buffer, index, count);
|
||||
|
||||
if ((int)adler.Value != readAdler) {
|
||||
throw new SharpZipBaseException("Wrong adler checksum");
|
||||
}
|
||||
adler.Reset();
|
||||
outputWindow.CopyDict(buffer, index, count);
|
||||
mode = DECODE_BLOCKS;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the input. This should only be called, if needsInput()
|
||||
/// returns true.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// the input.
|
||||
/// </param>
|
||||
public void SetInput(byte[] buffer)
|
||||
{
|
||||
SetInput(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the input. This should only be called, if needsInput()
|
||||
/// returns true.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// The source of input data
|
||||
/// </param>
|
||||
/// <param name="index">
|
||||
/// The index into buffer where the input starts.
|
||||
/// </param>
|
||||
/// <param name="count">
|
||||
/// The number of bytes of input to use.
|
||||
/// </param>
|
||||
/// <exception cref="System.InvalidOperationException">
|
||||
/// No input is needed.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// The index and/or count are wrong.
|
||||
/// </exception>
|
||||
public void SetInput(byte[] buffer, int index, int count)
|
||||
{
|
||||
input.SetInput(buffer, index, count);
|
||||
totalIn += (long)count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inflates the compressed stream to the output buffer. If this
|
||||
/// returns 0, you should check, whether IsNeedingDictionary(),
|
||||
/// IsNeedingInput() or IsFinished() returns true, to determine why no
|
||||
/// further output is produced.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// the output buffer.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The number of bytes written to the buffer, 0 if no further
|
||||
/// output can be produced.
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// if buffer has length 0.
|
||||
/// </exception>
|
||||
/// <exception cref="System.FormatException">
|
||||
/// if deflated stream is invalid.
|
||||
/// </exception>
|
||||
public int Inflate(byte[] buffer)
|
||||
{
|
||||
if ( buffer == null )
|
||||
{
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
return Inflate(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inflates the compressed stream to the output buffer. If this
|
||||
/// returns 0, you should check, whether needsDictionary(),
|
||||
/// needsInput() or finished() returns true, to determine why no
|
||||
/// further output is produced.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// the output buffer.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// the offset in buffer where storing starts.
|
||||
/// </param>
|
||||
/// <param name="count">
|
||||
/// the maximum number of bytes to output.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// the number of bytes written to the buffer, 0 if no further output can be produced.
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// if count is less than 0.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// if the index and / or count are wrong.
|
||||
/// </exception>
|
||||
/// <exception cref="System.FormatException">
|
||||
/// if deflated stream is invalid.
|
||||
/// </exception>
|
||||
public int Inflate(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if ( buffer == null )
|
||||
{
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
if ( count < 0 ) {
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("count", "count cannot be negative");
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( offset < 0 ) {
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("offset", "offset cannot be negative");
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( offset + count > buffer.Length ) {
|
||||
throw new ArgumentException("count exceeds buffer bounds");
|
||||
}
|
||||
|
||||
// Special case: count may be zero
|
||||
if (count == 0)
|
||||
{
|
||||
if (!IsFinished) { // -jr- 08-Nov-2003 INFLATE_BUG fix..
|
||||
Decode();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bytesCopied = 0;
|
||||
|
||||
do {
|
||||
if (mode != DECODE_CHKSUM) {
|
||||
/* Don't give away any output, if we are waiting for the
|
||||
* checksum in the input stream.
|
||||
*
|
||||
* With this trick we have always:
|
||||
* IsNeedingInput() and not IsFinished()
|
||||
* implies more output can be produced.
|
||||
*/
|
||||
int more = outputWindow.CopyOutput(buffer, offset, count);
|
||||
if ( more > 0 ) {
|
||||
adler.Update(buffer, offset, more);
|
||||
offset += more;
|
||||
bytesCopied += more;
|
||||
totalOut += (long)more;
|
||||
count -= more;
|
||||
if (count == 0) {
|
||||
return bytesCopied;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (Decode() || ((outputWindow.GetAvailable() > 0) && (mode != DECODE_CHKSUM)));
|
||||
return bytesCopied;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true, if the input buffer is empty.
|
||||
/// You should then call setInput().
|
||||
/// NOTE: This method also returns true when the stream is finished.
|
||||
/// </summary>
|
||||
public bool IsNeedingInput {
|
||||
get {
|
||||
return input.IsNeedingInput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true, if a preset dictionary is needed to inflate the input.
|
||||
/// </summary>
|
||||
public bool IsNeedingDictionary {
|
||||
get {
|
||||
return mode == DECODE_DICT && neededBits == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true, if the inflater has finished. This means, that no
|
||||
/// input is needed and no output can be produced.
|
||||
/// </summary>
|
||||
public bool IsFinished {
|
||||
get {
|
||||
return mode == FINISHED && outputWindow.GetAvailable() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the adler checksum. This is either the checksum of all
|
||||
/// uncompressed bytes returned by inflate(), or if needsDictionary()
|
||||
/// returns true (and thus no output was yet produced) this is the
|
||||
/// adler checksum of the expected dictionary.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// the adler checksum.
|
||||
/// </returns>
|
||||
public int Adler {
|
||||
get {
|
||||
return IsNeedingDictionary ? readAdler : (int) adler.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total number of output bytes returned by Inflate().
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// the total number of output bytes.
|
||||
/// </returns>
|
||||
public long TotalOut {
|
||||
get {
|
||||
return totalOut;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total number of processed compressed input bytes.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The total number of bytes of processed input bytes.
|
||||
/// </returns>
|
||||
public long TotalIn {
|
||||
get {
|
||||
return totalIn - (long)RemainingInput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of unprocessed input bytes. Useful, if the end of the
|
||||
/// stream is reached and you want to further process the bytes after
|
||||
/// the deflate stream.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The number of bytes of the input which have not been processed.
|
||||
/// </returns>
|
||||
public int RemainingInput {
|
||||
// TODO: This should be a long?
|
||||
get {
|
||||
return input.AvailableBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
// InflaterDynHeader.cs
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip.Compression
|
||||
{
|
||||
|
||||
class InflaterDynHeader
|
||||
{
|
||||
#region Constants
|
||||
const int LNUM = 0;
|
||||
const int DNUM = 1;
|
||||
const int BLNUM = 2;
|
||||
const int BLLENS = 3;
|
||||
const int LENS = 4;
|
||||
const int REPS = 5;
|
||||
|
||||
static readonly int[] repMin = { 3, 3, 11 };
|
||||
static readonly int[] repBits = { 2, 3, 7 };
|
||||
|
||||
static readonly int[] BL_ORDER =
|
||||
{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public InflaterDynHeader()
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
public bool Decode(StreamManipulator input)
|
||||
{
|
||||
decode_loop:
|
||||
for (;;) {
|
||||
switch (mode) {
|
||||
case LNUM:
|
||||
lnum = input.PeekBits(5);
|
||||
if (lnum < 0) {
|
||||
return false;
|
||||
}
|
||||
lnum += 257;
|
||||
input.DropBits(5);
|
||||
// System.err.println("LNUM: "+lnum);
|
||||
mode = DNUM;
|
||||
goto case DNUM; // fall through
|
||||
case DNUM:
|
||||
dnum = input.PeekBits(5);
|
||||
if (dnum < 0) {
|
||||
return false;
|
||||
}
|
||||
dnum++;
|
||||
input.DropBits(5);
|
||||
// System.err.println("DNUM: "+dnum);
|
||||
num = lnum+dnum;
|
||||
litdistLens = new byte[num];
|
||||
mode = BLNUM;
|
||||
goto case BLNUM; // fall through
|
||||
case BLNUM:
|
||||
blnum = input.PeekBits(4);
|
||||
if (blnum < 0) {
|
||||
return false;
|
||||
}
|
||||
blnum += 4;
|
||||
input.DropBits(4);
|
||||
blLens = new byte[19];
|
||||
ptr = 0;
|
||||
// System.err.println("BLNUM: "+blnum);
|
||||
mode = BLLENS;
|
||||
goto case BLLENS; // fall through
|
||||
case BLLENS:
|
||||
while (ptr < blnum) {
|
||||
int len = input.PeekBits(3);
|
||||
if (len < 0) {
|
||||
return false;
|
||||
}
|
||||
input.DropBits(3);
|
||||
// System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len);
|
||||
blLens[BL_ORDER[ptr]] = (byte) len;
|
||||
ptr++;
|
||||
}
|
||||
blTree = new InflaterHuffmanTree(blLens);
|
||||
blLens = null;
|
||||
ptr = 0;
|
||||
mode = LENS;
|
||||
goto case LENS; // fall through
|
||||
case LENS:
|
||||
{
|
||||
int symbol;
|
||||
while (((symbol = blTree.GetSymbol(input)) & ~15) == 0) {
|
||||
/* Normal case: symbol in [0..15] */
|
||||
|
||||
// System.err.println("litdistLens["+ptr+"]: "+symbol);
|
||||
litdistLens[ptr++] = lastLen = (byte)symbol;
|
||||
|
||||
if (ptr == num) {
|
||||
/* Finished */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* need more input ? */
|
||||
if (symbol < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* otherwise repeat code */
|
||||
if (symbol >= 17) {
|
||||
/* repeat zero */
|
||||
// System.err.println("repeating zero");
|
||||
lastLen = 0;
|
||||
} else {
|
||||
if (ptr == 0) {
|
||||
throw new SharpZipBaseException();
|
||||
}
|
||||
}
|
||||
repSymbol = symbol-16;
|
||||
}
|
||||
mode = REPS;
|
||||
goto case REPS; // fall through
|
||||
case REPS:
|
||||
{
|
||||
int bits = repBits[repSymbol];
|
||||
int count = input.PeekBits(bits);
|
||||
if (count < 0) {
|
||||
return false;
|
||||
}
|
||||
input.DropBits(bits);
|
||||
count += repMin[repSymbol];
|
||||
// System.err.println("litdistLens repeated: "+count);
|
||||
|
||||
if (ptr + count > num) {
|
||||
throw new SharpZipBaseException();
|
||||
}
|
||||
while (count-- > 0) {
|
||||
litdistLens[ptr++] = lastLen;
|
||||
}
|
||||
|
||||
if (ptr == num) {
|
||||
/* Finished */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
mode = LENS;
|
||||
goto decode_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public InflaterHuffmanTree BuildLitLenTree()
|
||||
{
|
||||
byte[] litlenLens = new byte[lnum];
|
||||
Array.Copy(litdistLens, 0, litlenLens, 0, lnum);
|
||||
return new InflaterHuffmanTree(litlenLens);
|
||||
}
|
||||
|
||||
public InflaterHuffmanTree BuildDistTree()
|
||||
{
|
||||
byte[] distLens = new byte[dnum];
|
||||
Array.Copy(litdistLens, lnum, distLens, 0, dnum);
|
||||
return new InflaterHuffmanTree(distLens);
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
byte[] blLens;
|
||||
byte[] litdistLens;
|
||||
|
||||
InflaterHuffmanTree blTree;
|
||||
|
||||
/// <summary>
|
||||
/// The current decode mode
|
||||
/// </summary>
|
||||
int mode;
|
||||
int lnum, dnum, blnum, num;
|
||||
int repSymbol;
|
||||
byte lastLen;
|
||||
int ptr;
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
// InflaterHuffmanTree.cs
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip.Compression
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Huffman tree used for inflation
|
||||
/// </summary>
|
||||
public class InflaterHuffmanTree
|
||||
{
|
||||
#region Constants
|
||||
const int MAX_BITLEN = 15;
|
||||
#endregion
|
||||
|
||||
#region Instance Fields
|
||||
short[] tree;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Literal length tree
|
||||
/// </summary>
|
||||
public static InflaterHuffmanTree defLitLenTree;
|
||||
|
||||
/// <summary>
|
||||
/// Distance tree
|
||||
/// </summary>
|
||||
public static InflaterHuffmanTree defDistTree;
|
||||
|
||||
static InflaterHuffmanTree()
|
||||
{
|
||||
try {
|
||||
byte[] codeLengths = new byte[288];
|
||||
int i = 0;
|
||||
while (i < 144) {
|
||||
codeLengths[i++] = 8;
|
||||
}
|
||||
while (i < 256) {
|
||||
codeLengths[i++] = 9;
|
||||
}
|
||||
while (i < 280) {
|
||||
codeLengths[i++] = 7;
|
||||
}
|
||||
while (i < 288) {
|
||||
codeLengths[i++] = 8;
|
||||
}
|
||||
defLitLenTree = new InflaterHuffmanTree(codeLengths);
|
||||
|
||||
codeLengths = new byte[32];
|
||||
i = 0;
|
||||
while (i < 32) {
|
||||
codeLengths[i++] = 5;
|
||||
}
|
||||
defDistTree = new InflaterHuffmanTree(codeLengths);
|
||||
} catch (Exception) {
|
||||
throw new SharpZipBaseException("InflaterHuffmanTree: static tree length illegal");
|
||||
}
|
||||
}
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructs a Huffman tree from the array of code lengths.
|
||||
/// </summary>
|
||||
/// <param name = "codeLengths">
|
||||
/// the array of code lengths
|
||||
/// </param>
|
||||
public InflaterHuffmanTree(byte[] codeLengths)
|
||||
{
|
||||
BuildTree(codeLengths);
|
||||
}
|
||||
#endregion
|
||||
|
||||
void BuildTree(byte[] codeLengths)
|
||||
{
|
||||
int[] blCount = new int[MAX_BITLEN + 1];
|
||||
int[] nextCode = new int[MAX_BITLEN + 1];
|
||||
|
||||
for (int i = 0; i < codeLengths.Length; i++) {
|
||||
int bits = codeLengths[i];
|
||||
if (bits > 0) {
|
||||
blCount[bits]++;
|
||||
}
|
||||
}
|
||||
|
||||
int code = 0;
|
||||
int treeSize = 512;
|
||||
for (int bits = 1; bits <= MAX_BITLEN; bits++) {
|
||||
nextCode[bits] = code;
|
||||
code += blCount[bits] << (16 - bits);
|
||||
if (bits >= 10) {
|
||||
/* We need an extra table for bit lengths >= 10. */
|
||||
int start = nextCode[bits] & 0x1ff80;
|
||||
int end = code & 0x1ff80;
|
||||
treeSize += (end - start) >> (16 - bits);
|
||||
}
|
||||
}
|
||||
|
||||
/* -jr comment this out! doesnt work for dynamic trees and pkzip 2.04g
|
||||
if (code != 65536)
|
||||
{
|
||||
throw new SharpZipBaseException("Code lengths don't add up properly.");
|
||||
}
|
||||
*/
|
||||
/* Now create and fill the extra tables from longest to shortest
|
||||
* bit len. This way the sub trees will be aligned.
|
||||
*/
|
||||
tree = new short[treeSize];
|
||||
int treePtr = 512;
|
||||
for (int bits = MAX_BITLEN; bits >= 10; bits--) {
|
||||
int end = code & 0x1ff80;
|
||||
code -= blCount[bits] << (16 - bits);
|
||||
int start = code & 0x1ff80;
|
||||
for (int i = start; i < end; i += 1 << 7) {
|
||||
tree[DeflaterHuffman.BitReverse(i)] = (short) ((-treePtr << 4) | bits);
|
||||
treePtr += 1 << (bits-9);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < codeLengths.Length; i++) {
|
||||
int bits = codeLengths[i];
|
||||
if (bits == 0) {
|
||||
continue;
|
||||
}
|
||||
code = nextCode[bits];
|
||||
int revcode = DeflaterHuffman.BitReverse(code);
|
||||
if (bits <= 9) {
|
||||
do {
|
||||
tree[revcode] = (short) ((i << 4) | bits);
|
||||
revcode += 1 << bits;
|
||||
} while (revcode < 512);
|
||||
} else {
|
||||
int subTree = tree[revcode & 511];
|
||||
int treeLen = 1 << (subTree & 15);
|
||||
subTree = -(subTree >> 4);
|
||||
do {
|
||||
tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits);
|
||||
revcode += 1 << bits;
|
||||
} while (revcode < treeLen);
|
||||
}
|
||||
nextCode[bits] = code + (1 << (16 - bits));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next symbol from input. The symbol is encoded using the
|
||||
/// huffman tree.
|
||||
/// </summary>
|
||||
/// <param name="input">
|
||||
/// input the input source.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// the next symbol, or -1 if not enough input is available.
|
||||
/// </returns>
|
||||
public int GetSymbol(StreamManipulator input)
|
||||
{
|
||||
int lookahead, symbol;
|
||||
if ((lookahead = input.PeekBits(9)) >= 0) {
|
||||
if ((symbol = tree[lookahead]) >= 0) {
|
||||
input.DropBits(symbol & 15);
|
||||
return symbol >> 4;
|
||||
}
|
||||
int subtree = -(symbol >> 4);
|
||||
int bitlen = symbol & 15;
|
||||
if ((lookahead = input.PeekBits(bitlen)) >= 0) {
|
||||
symbol = tree[subtree | (lookahead >> 9)];
|
||||
input.DropBits(symbol & 15);
|
||||
return symbol >> 4;
|
||||
} else {
|
||||
int bits = input.AvailableBits;
|
||||
lookahead = input.PeekBits(bits);
|
||||
symbol = tree[subtree | (lookahead >> 9)];
|
||||
if ((symbol & 15) <= bits) {
|
||||
input.DropBits(symbol & 15);
|
||||
return symbol >> 4;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int bits = input.AvailableBits;
|
||||
lookahead = input.PeekBits(bits);
|
||||
symbol = tree[lookahead];
|
||||
if (symbol >= 0 && (symbol & 15) <= bits) {
|
||||
input.DropBits(symbol & 15);
|
||||
return symbol >> 4;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,295 @@
|
|||
// PendingBuffer.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
// Copyright (C) 2004 John Reilly
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip.Compression
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This class is general purpose class for writing data to a buffer.
|
||||
///
|
||||
/// It allows you to write bits as well as bytes
|
||||
/// Based on DeflaterPending.java
|
||||
///
|
||||
/// author of the original java version : Jochen Hoenicke
|
||||
/// </summary>
|
||||
public class PendingBuffer
|
||||
{
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// Internal work buffer
|
||||
/// </summary>
|
||||
byte[] buffer_;
|
||||
|
||||
int start;
|
||||
int end;
|
||||
|
||||
uint bits;
|
||||
int bitCount;
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// construct instance using default buffer size of 4096
|
||||
/// </summary>
|
||||
public PendingBuffer() : this( 4096 )
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// construct instance using specified buffer size
|
||||
/// </summary>
|
||||
/// <param name="bufferSize">
|
||||
/// size to use for internal buffer
|
||||
/// </param>
|
||||
public PendingBuffer(int bufferSize)
|
||||
{
|
||||
buffer_ = new byte[bufferSize];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Clear internal state/buffers
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
start = end = bitCount = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a byte to buffer
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// The value to write
|
||||
/// </param>
|
||||
public void WriteByte(int value)
|
||||
{
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING && (start != 0) )
|
||||
{
|
||||
throw new SharpZipBaseException("Debug check: start != 0");
|
||||
}
|
||||
#endif
|
||||
buffer_[end++] = unchecked((byte) value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a short value to buffer LSB first
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// The value to write.
|
||||
/// </param>
|
||||
public void WriteShort(int value)
|
||||
{
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING && (start != 0) )
|
||||
{
|
||||
throw new SharpZipBaseException("Debug check: start != 0");
|
||||
}
|
||||
#endif
|
||||
buffer_[end++] = unchecked((byte) value);
|
||||
buffer_[end++] = unchecked((byte) (value >> 8));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// write an integer LSB first
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public void WriteInt(int value)
|
||||
{
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING && (start != 0) )
|
||||
{
|
||||
throw new SharpZipBaseException("Debug check: start != 0");
|
||||
}
|
||||
#endif
|
||||
buffer_[end++] = unchecked((byte) value);
|
||||
buffer_[end++] = unchecked((byte) (value >> 8));
|
||||
buffer_[end++] = unchecked((byte) (value >> 16));
|
||||
buffer_[end++] = unchecked((byte) (value >> 24));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a block of data to buffer
|
||||
/// </summary>
|
||||
/// <param name="block">data to write</param>
|
||||
/// <param name="offset">offset of first byte to write</param>
|
||||
/// <param name="length">number of bytes to write</param>
|
||||
public void WriteBlock(byte[] block, int offset, int length)
|
||||
{
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING && (start != 0) )
|
||||
{
|
||||
throw new SharpZipBaseException("Debug check: start != 0");
|
||||
}
|
||||
#endif
|
||||
System.Array.Copy(block, offset, buffer_, end, length);
|
||||
end += length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of bits written to the buffer
|
||||
/// </summary>
|
||||
public int BitCount {
|
||||
get {
|
||||
return bitCount;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Align internal buffer on a byte boundary
|
||||
/// </summary>
|
||||
public void AlignToByte()
|
||||
{
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING && (start != 0) )
|
||||
{
|
||||
throw new SharpZipBaseException("Debug check: start != 0");
|
||||
}
|
||||
#endif
|
||||
if (bitCount > 0)
|
||||
{
|
||||
buffer_[end++] = unchecked((byte) bits);
|
||||
if (bitCount > 8) {
|
||||
buffer_[end++] = unchecked((byte) (bits >> 8));
|
||||
}
|
||||
}
|
||||
bits = 0;
|
||||
bitCount = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write bits to internal buffer
|
||||
/// </summary>
|
||||
/// <param name="b">source of bits</param>
|
||||
/// <param name="count">number of bits to write</param>
|
||||
public void WriteBits(int b, int count)
|
||||
{
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING && (start != 0) )
|
||||
{
|
||||
throw new SharpZipBaseException("Debug check: start != 0");
|
||||
}
|
||||
|
||||
// if (DeflaterConstants.DEBUGGING) {
|
||||
// //Console.WriteLine("writeBits("+b+","+count+")");
|
||||
// }
|
||||
#endif
|
||||
bits |= (uint)(b << bitCount);
|
||||
bitCount += count;
|
||||
if (bitCount >= 16) {
|
||||
buffer_[end++] = unchecked((byte) bits);
|
||||
buffer_[end++] = unchecked((byte) (bits >> 8));
|
||||
bits >>= 16;
|
||||
bitCount -= 16;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a short value to internal buffer most significant byte first
|
||||
/// </summary>
|
||||
/// <param name="s">value to write</param>
|
||||
public void WriteShortMSB(int s)
|
||||
{
|
||||
#if DebugDeflation
|
||||
if (DeflaterConstants.DEBUGGING && (start != 0) )
|
||||
{
|
||||
throw new SharpZipBaseException("Debug check: start != 0");
|
||||
}
|
||||
#endif
|
||||
buffer_[end++] = unchecked((byte) (s >> 8));
|
||||
buffer_[end++] = unchecked((byte) s);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if buffer has been flushed
|
||||
/// </summary>
|
||||
public bool IsFlushed {
|
||||
get {
|
||||
return end == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the pending buffer into the given output array. If the
|
||||
/// output array is to small, only a partial flush is done.
|
||||
/// </summary>
|
||||
/// <param name="output">The output array.</param>
|
||||
/// <param name="offset">The offset into output array.</param>
|
||||
/// <param name="length">The maximum number of bytes to store.</param>
|
||||
/// <returns>The number of bytes flushed.</returns>
|
||||
public int Flush(byte[] output, int offset, int length)
|
||||
{
|
||||
if (bitCount >= 8) {
|
||||
buffer_[end++] = unchecked((byte) bits);
|
||||
bits >>= 8;
|
||||
bitCount -= 8;
|
||||
}
|
||||
|
||||
if (length > end - start) {
|
||||
length = end - start;
|
||||
System.Array.Copy(buffer_, start, output, offset, length);
|
||||
start = 0;
|
||||
end = 0;
|
||||
} else {
|
||||
System.Array.Copy(buffer_, start, output, offset, length);
|
||||
start += length;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert internal buffer to byte array.
|
||||
/// Buffer is empty on completion
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The internal buffer contents converted to a byte array.
|
||||
/// </returns>
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
byte[] result = new byte[end - start];
|
||||
System.Array.Copy(buffer_, start, result, 0, result.Length);
|
||||
start = 0;
|
||||
end = 0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,602 @@
|
|||
// DeflaterOutputStream.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
// HISTORY
|
||||
// 22-12-2009 DavidPierson Added AES support
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
#if !NETCF_1_0
|
||||
using System.Security.Cryptography;
|
||||
using ICSharpCode.SharpZipLib.Encryption;
|
||||
#endif
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
|
||||
{
|
||||
/// <summary>
|
||||
/// A special stream deflating or compressing the bytes that are
|
||||
/// written to it. It uses a Deflater to perform actual deflating.<br/>
|
||||
/// Authors of the original java version : Tom Tromey, Jochen Hoenicke
|
||||
/// </summary>
|
||||
public class DeflaterOutputStream : Stream
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Creates a new DeflaterOutputStream with a default Deflater and default buffer size.
|
||||
/// </summary>
|
||||
/// <param name="baseOutputStream">
|
||||
/// the output stream where deflated output should be written.
|
||||
/// </param>
|
||||
public DeflaterOutputStream(Stream baseOutputStream)
|
||||
: this(baseOutputStream, new Deflater(), 512)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new DeflaterOutputStream with the given Deflater and
|
||||
/// default buffer size.
|
||||
/// </summary>
|
||||
/// <param name="baseOutputStream">
|
||||
/// the output stream where deflated output should be written.
|
||||
/// </param>
|
||||
/// <param name="deflater">
|
||||
/// the underlying deflater.
|
||||
/// </param>
|
||||
public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater)
|
||||
: this(baseOutputStream, deflater, 512)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new DeflaterOutputStream with the given Deflater and
|
||||
/// buffer size.
|
||||
/// </summary>
|
||||
/// <param name="baseOutputStream">
|
||||
/// The output stream where deflated output is written.
|
||||
/// </param>
|
||||
/// <param name="deflater">
|
||||
/// The underlying deflater to use
|
||||
/// </param>
|
||||
/// <param name="bufferSize">
|
||||
/// The buffer size in bytes to use when deflating (minimum value 512)
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// bufsize is less than or equal to zero.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// baseOutputStream does not support writing
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// deflater instance is null
|
||||
/// </exception>
|
||||
public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater, int bufferSize)
|
||||
{
|
||||
if ( baseOutputStream == null ) {
|
||||
throw new ArgumentNullException("baseOutputStream");
|
||||
}
|
||||
|
||||
if (baseOutputStream.CanWrite == false) {
|
||||
throw new ArgumentException("Must support writing", "baseOutputStream");
|
||||
}
|
||||
|
||||
if (deflater == null) {
|
||||
throw new ArgumentNullException("deflater");
|
||||
}
|
||||
|
||||
if (bufferSize < 512) {
|
||||
throw new ArgumentOutOfRangeException("bufferSize");
|
||||
}
|
||||
|
||||
baseOutputStream_ = baseOutputStream;
|
||||
buffer_ = new byte[bufferSize];
|
||||
deflater_ = deflater;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public API
|
||||
/// <summary>
|
||||
/// Finishes the stream by calling finish() on the deflater.
|
||||
/// </summary>
|
||||
/// <exception cref="SharpZipBaseException">
|
||||
/// Not all input is deflated
|
||||
/// </exception>
|
||||
public virtual void Finish()
|
||||
{
|
||||
deflater_.Finish();
|
||||
while (!deflater_.IsFinished) {
|
||||
int len = deflater_.Deflate(buffer_, 0, buffer_.Length);
|
||||
if (len <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
#if NETCF_1_0
|
||||
if ( keys != null ) {
|
||||
#else
|
||||
if (cryptoTransform_ != null) {
|
||||
#endif
|
||||
EncryptBlock(buffer_, 0, len);
|
||||
}
|
||||
|
||||
baseOutputStream_.Write(buffer_, 0, len);
|
||||
}
|
||||
|
||||
if (!deflater_.IsFinished) {
|
||||
throw new SharpZipBaseException("Can't deflate all input?");
|
||||
}
|
||||
|
||||
baseOutputStream_.Flush();
|
||||
|
||||
#if NETCF_1_0
|
||||
if ( keys != null ) {
|
||||
keys = null;
|
||||
}
|
||||
#else
|
||||
if (cryptoTransform_ != null) {
|
||||
#if !NET_1_1 && !NETCF_2_0
|
||||
if (cryptoTransform_ is ZipAESTransform) {
|
||||
AESAuthCode = ((ZipAESTransform)cryptoTransform_).GetAuthCode();
|
||||
}
|
||||
#endif
|
||||
cryptoTransform_.Dispose();
|
||||
cryptoTransform_ = null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set flag indicating ownership of the underlying stream.
|
||||
/// When the flag is true <see cref="Close"></see> will close the underlying stream also.
|
||||
/// </summary>
|
||||
public bool IsStreamOwner
|
||||
{
|
||||
get { return isStreamOwner_; }
|
||||
set { isStreamOwner_ = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows client to determine if an entry can be patched after its added
|
||||
/// </summary>
|
||||
public bool CanPatchEntries {
|
||||
get {
|
||||
return baseOutputStream_.CanSeek;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Encryption
|
||||
|
||||
string password;
|
||||
|
||||
#if NETCF_1_0
|
||||
uint[] keys;
|
||||
#else
|
||||
ICryptoTransform cryptoTransform_;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the 10 byte AUTH CODE to be appended immediately following the AES data stream.
|
||||
/// </summary>
|
||||
protected byte[] AESAuthCode;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the password used for encryption.
|
||||
/// </summary>
|
||||
/// <remarks>When set to null or if the password is empty no encryption is performed</remarks>
|
||||
public string Password {
|
||||
get {
|
||||
return password;
|
||||
}
|
||||
set {
|
||||
if ( (value != null) && (value.Length == 0) ) {
|
||||
password = null;
|
||||
} else {
|
||||
password = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encrypt a block of data
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// Data to encrypt. NOTE the original contents of the buffer are lost
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// Offset of first byte in buffer to encrypt
|
||||
/// </param>
|
||||
/// <param name="length">
|
||||
/// Number of bytes in buffer to encrypt
|
||||
/// </param>
|
||||
protected void EncryptBlock(byte[] buffer, int offset, int length)
|
||||
{
|
||||
#if NETCF_1_0
|
||||
for (int i = offset; i < offset + length; ++i) {
|
||||
byte oldbyte = buffer[i];
|
||||
buffer[i] ^= EncryptByte();
|
||||
UpdateKeys(oldbyte);
|
||||
}
|
||||
#else
|
||||
cryptoTransform_.TransformBlock(buffer, 0, length, buffer, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes encryption keys based on given <paramref name="password"/>.
|
||||
/// </summary>
|
||||
/// <param name="password">The password.</param>
|
||||
protected void InitializePassword(string password)
|
||||
{
|
||||
#if NETCF_1_0
|
||||
keys = new uint[] {
|
||||
0x12345678,
|
||||
0x23456789,
|
||||
0x34567890
|
||||
};
|
||||
|
||||
byte[] rawPassword = ZipConstants.ConvertToArray(password);
|
||||
|
||||
for (int i = 0; i < rawPassword.Length; ++i) {
|
||||
UpdateKeys((byte)rawPassword[i]);
|
||||
}
|
||||
|
||||
#else
|
||||
PkzipClassicManaged pkManaged = new PkzipClassicManaged();
|
||||
byte[] key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(password));
|
||||
cryptoTransform_ = pkManaged.CreateEncryptor(key, null);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !NET_1_1 && !NETCF_2_0
|
||||
/// <summary>
|
||||
/// Initializes encryption keys based on given password.
|
||||
/// </summary>
|
||||
protected void InitializeAESPassword(ZipEntry entry, string rawPassword,
|
||||
out byte[] salt, out byte[] pwdVerifier) {
|
||||
salt = new byte[entry.AESSaltLen];
|
||||
// Salt needs to be cryptographically random, and unique per file
|
||||
if (_aesRnd == null)
|
||||
_aesRnd = new RNGCryptoServiceProvider();
|
||||
_aesRnd.GetBytes(salt);
|
||||
int blockSize = entry.AESKeySize / 8; // bits to bytes
|
||||
|
||||
cryptoTransform_ = new ZipAESTransform(rawPassword, salt, blockSize, true);
|
||||
pwdVerifier = ((ZipAESTransform)cryptoTransform_).PwdVerifier;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NETCF_1_0
|
||||
|
||||
/// <summary>
|
||||
/// Encrypt a single byte
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The encrypted value
|
||||
/// </returns>
|
||||
protected byte EncryptByte()
|
||||
{
|
||||
uint temp = ((keys[2] & 0xFFFF) | 2);
|
||||
return (byte)((temp * (temp ^ 1)) >> 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update encryption keys
|
||||
/// </summary>
|
||||
protected void UpdateKeys(byte ch)
|
||||
{
|
||||
keys[0] = Crc32.ComputeCrc32(keys[0], ch);
|
||||
keys[1] = keys[1] + (byte)keys[0];
|
||||
keys[1] = keys[1] * 134775813 + 1;
|
||||
keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region Deflation Support
|
||||
/// <summary>
|
||||
/// Deflates everything in the input buffers. This will call
|
||||
/// <code>def.deflate()</code> until all bytes from the input buffers
|
||||
/// are processed.
|
||||
/// </summary>
|
||||
protected void Deflate()
|
||||
{
|
||||
while (!deflater_.IsNeedingInput)
|
||||
{
|
||||
int deflateCount = deflater_.Deflate(buffer_, 0, buffer_.Length);
|
||||
|
||||
if (deflateCount <= 0) {
|
||||
break;
|
||||
}
|
||||
#if NETCF_1_0
|
||||
if (keys != null)
|
||||
#else
|
||||
if (cryptoTransform_ != null)
|
||||
#endif
|
||||
{
|
||||
EncryptBlock(buffer_, 0, deflateCount);
|
||||
}
|
||||
|
||||
baseOutputStream_.Write(buffer_, 0, deflateCount);
|
||||
}
|
||||
|
||||
if (!deflater_.IsNeedingInput) {
|
||||
throw new SharpZipBaseException("DeflaterOutputStream can't deflate all input?");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Stream Overrides
|
||||
/// <summary>
|
||||
/// Gets value indicating stream can be read from
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating if seeking is supported for this stream
|
||||
/// This property always returns false
|
||||
/// </summary>
|
||||
public override bool CanSeek {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get value indicating if this stream supports writing
|
||||
/// </summary>
|
||||
public override bool CanWrite {
|
||||
get {
|
||||
return baseOutputStream_.CanWrite;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get current length of stream
|
||||
/// </summary>
|
||||
public override long Length {
|
||||
get {
|
||||
return baseOutputStream_.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current position within the stream.
|
||||
/// </summary>
|
||||
/// <exception cref="NotSupportedException">Any attempt to set position</exception>
|
||||
public override long Position {
|
||||
get {
|
||||
return baseOutputStream_.Position;
|
||||
}
|
||||
set {
|
||||
throw new NotSupportedException("Position property not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current position of this stream to the given value. Not supported by this class!
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset relative to the <paramref name="origin"/> to seek.</param>
|
||||
/// <param name="origin">The <see cref="SeekOrigin"/> to seek from.</param>
|
||||
/// <returns>The new position in the stream.</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException("DeflaterOutputStream Seek not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the length of this stream to the given value. Not supported by this class!
|
||||
/// </summary>
|
||||
/// <param name="value">The new stream length.</param>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException("DeflaterOutputStream SetLength not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a byte from stream advancing position by one
|
||||
/// </summary>
|
||||
/// <returns>The byte read cast to an int. THe value is -1 if at the end of the stream.</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override int ReadByte()
|
||||
{
|
||||
throw new NotSupportedException("DeflaterOutputStream ReadByte not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a block of bytes from stream
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to store read data in.</param>
|
||||
/// <param name="offset">The offset to start storing at.</param>
|
||||
/// <param name="count">The maximum number of bytes to read.</param>
|
||||
/// <returns>The actual number of bytes read. Zero if end of stream is detected.</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException("DeflaterOutputStream Read not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronous reads are not supported a NotSupportedException is always thrown
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to read into.</param>
|
||||
/// <param name="offset">The offset to start storing data at.</param>
|
||||
/// <param name="count">The number of bytes to read</param>
|
||||
/// <param name="callback">The async callback to use.</param>
|
||||
/// <param name="state">The state to use.</param>
|
||||
/// <returns>Returns an <see cref="IAsyncResult"/></returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
{
|
||||
throw new NotSupportedException("DeflaterOutputStream BeginRead not currently supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronous writes arent supported, a NotSupportedException is always thrown
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to write.</param>
|
||||
/// <param name="offset">The offset to begin writing at.</param>
|
||||
/// <param name="count">The number of bytes to write.</param>
|
||||
/// <param name="callback">The <see cref="AsyncCallback"/> to use.</param>
|
||||
/// <param name="state">The state object.</param>
|
||||
/// <returns>Returns an IAsyncResult.</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
{
|
||||
throw new NotSupportedException("BeginWrite is not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the stream by calling <see cref="DeflaterOutputStream.Flush">Flush</see> on the deflater and then
|
||||
/// on the underlying stream. This ensures that all bytes are flushed.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
deflater_.Flush();
|
||||
Deflate();
|
||||
baseOutputStream_.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls <see cref="Finish"/> and closes the underlying
|
||||
/// stream when <see cref="IsStreamOwner"></see> is true.
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
if ( !isClosed_ ) {
|
||||
isClosed_ = true;
|
||||
|
||||
try {
|
||||
Finish();
|
||||
#if NETCF_1_0
|
||||
keys=null;
|
||||
#else
|
||||
if ( cryptoTransform_ != null ) {
|
||||
GetAuthCodeIfAES();
|
||||
cryptoTransform_.Dispose();
|
||||
cryptoTransform_ = null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
finally {
|
||||
if( isStreamOwner_ ) {
|
||||
baseOutputStream_.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GetAuthCodeIfAES() {
|
||||
#if !NET_1_1 && !NETCF_2_0
|
||||
if (cryptoTransform_ is ZipAESTransform) {
|
||||
AESAuthCode = ((ZipAESTransform)cryptoTransform_).GetAuthCode();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a single byte to the compressed output stream.
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// The byte value.
|
||||
/// </param>
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
byte[] b = new byte[1];
|
||||
b[0] = value;
|
||||
Write(b, 0, 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes bytes from an array to the compressed stream.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// The byte array
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// The offset into the byte array where to start.
|
||||
/// </param>
|
||||
/// <param name="count">
|
||||
/// The number of bytes to write.
|
||||
/// </param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
deflater_.SetInput(buffer, offset, count);
|
||||
Deflate();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// This buffer is used temporarily to retrieve the bytes from the
|
||||
/// deflater and write them to the underlying output stream.
|
||||
/// </summary>
|
||||
byte[] buffer_;
|
||||
|
||||
/// <summary>
|
||||
/// The deflater which is used to deflate the stream.
|
||||
/// </summary>
|
||||
protected Deflater deflater_;
|
||||
|
||||
/// <summary>
|
||||
/// Base stream the deflater depends on.
|
||||
/// </summary>
|
||||
protected Stream baseOutputStream_;
|
||||
|
||||
bool isClosed_;
|
||||
|
||||
bool isStreamOwner_ = true;
|
||||
#endregion
|
||||
|
||||
#region Static Fields
|
||||
|
||||
#if !NET_1_1 && !NETCF_2_0
|
||||
// Static to help ensure that multiple files within a zip will get different random salt
|
||||
private static RNGCryptoServiceProvider _aesRnd;
|
||||
#endif
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,732 @@
|
|||
// InflaterInputStream.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
// Copyright (C) 2004 John Reilly
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
// HISTORY
|
||||
// 11-08-2009 GeoffHart T9121 Added Multi-member gzip support
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
#if !NETCF_1_0
|
||||
using System.Security.Cryptography;
|
||||
#endif
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// An input buffer customised for use by <see cref="InflaterInputStream"/>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The buffer supports decryption of incoming data.
|
||||
/// </remarks>
|
||||
public class InflaterInputBuffer
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="InflaterInputBuffer"/> with a default buffer size
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to buffer.</param>
|
||||
public InflaterInputBuffer(Stream stream) : this(stream , 4096)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="InflaterInputBuffer"/>
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to buffer.</param>
|
||||
/// <param name="bufferSize">The size to use for the buffer</param>
|
||||
/// <remarks>A minimum buffer size of 1KB is permitted. Lower sizes are treated as 1KB.</remarks>
|
||||
public InflaterInputBuffer(Stream stream, int bufferSize)
|
||||
{
|
||||
inputStream = stream;
|
||||
if ( bufferSize < 1024 ) {
|
||||
bufferSize = 1024;
|
||||
}
|
||||
rawData = new byte[bufferSize];
|
||||
clearText = rawData;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Get the length of bytes bytes in the <see cref="RawData"/>
|
||||
/// </summary>
|
||||
public int RawLength
|
||||
{
|
||||
get {
|
||||
return rawLength;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the contents of the raw data buffer.
|
||||
/// </summary>
|
||||
/// <remarks>This may contain encrypted data.</remarks>
|
||||
public byte[] RawData
|
||||
{
|
||||
get {
|
||||
return rawData;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of useable bytes in <see cref="ClearText"/>
|
||||
/// </summary>
|
||||
public int ClearTextLength
|
||||
{
|
||||
get {
|
||||
return clearTextLength;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the contents of the clear text buffer.
|
||||
/// </summary>
|
||||
public byte[] ClearText
|
||||
{
|
||||
get {
|
||||
return clearText;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the number of bytes available
|
||||
/// </summary>
|
||||
public int Available
|
||||
{
|
||||
get { return available; }
|
||||
set { available = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call <see cref="Inflater.SetInput(byte[], int, int)"/> passing the current clear text buffer contents.
|
||||
/// </summary>
|
||||
/// <param name="inflater">The inflater to set input for.</param>
|
||||
public void SetInflaterInput(Inflater inflater)
|
||||
{
|
||||
if ( available > 0 ) {
|
||||
inflater.SetInput(clearText, clearTextLength - available, available);
|
||||
available = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill the buffer from the underlying input stream.
|
||||
/// </summary>
|
||||
public void Fill()
|
||||
{
|
||||
rawLength = 0;
|
||||
int toRead = rawData.Length;
|
||||
|
||||
while (toRead > 0) {
|
||||
int count = inputStream.Read(rawData, rawLength, toRead);
|
||||
if ( count <= 0 ) {
|
||||
break;
|
||||
}
|
||||
rawLength += count;
|
||||
toRead -= count;
|
||||
}
|
||||
|
||||
#if !NETCF_1_0
|
||||
if ( cryptoTransform != null ) {
|
||||
clearTextLength = cryptoTransform.TransformBlock(rawData, 0, rawLength, clearText, 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
clearTextLength = rawLength;
|
||||
}
|
||||
|
||||
available = clearTextLength;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a buffer directly from the input stream
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to fill</param>
|
||||
/// <returns>Returns the number of bytes read.</returns>
|
||||
public int ReadRawBuffer(byte[] buffer)
|
||||
{
|
||||
return ReadRawBuffer(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a buffer directly from the input stream
|
||||
/// </summary>
|
||||
/// <param name="outBuffer">The buffer to read into</param>
|
||||
/// <param name="offset">The offset to start reading data into.</param>
|
||||
/// <param name="length">The number of bytes to read.</param>
|
||||
/// <returns>Returns the number of bytes read.</returns>
|
||||
public int ReadRawBuffer(byte[] outBuffer, int offset, int length)
|
||||
{
|
||||
if ( length < 0 ) {
|
||||
throw new ArgumentOutOfRangeException("length");
|
||||
}
|
||||
|
||||
int currentOffset = offset;
|
||||
int currentLength = length;
|
||||
|
||||
while ( currentLength > 0 ) {
|
||||
if ( available <= 0 ) {
|
||||
Fill();
|
||||
if (available <= 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
int toCopy = Math.Min(currentLength, available);
|
||||
System.Array.Copy(rawData, rawLength - (int)available, outBuffer, currentOffset, toCopy);
|
||||
currentOffset += toCopy;
|
||||
currentLength -= toCopy;
|
||||
available -= toCopy;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read clear text data from the input stream.
|
||||
/// </summary>
|
||||
/// <param name="outBuffer">The buffer to add data to.</param>
|
||||
/// <param name="offset">The offset to start adding data at.</param>
|
||||
/// <param name="length">The number of bytes to read.</param>
|
||||
/// <returns>Returns the number of bytes actually read.</returns>
|
||||
public int ReadClearTextBuffer(byte[] outBuffer, int offset, int length)
|
||||
{
|
||||
if ( length < 0 ) {
|
||||
throw new ArgumentOutOfRangeException("length");
|
||||
}
|
||||
|
||||
int currentOffset = offset;
|
||||
int currentLength = length;
|
||||
|
||||
while ( currentLength > 0 ) {
|
||||
if ( available <= 0 ) {
|
||||
Fill();
|
||||
if (available <= 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int toCopy = Math.Min(currentLength, available);
|
||||
Array.Copy(clearText, clearTextLength - (int)available, outBuffer, currentOffset, toCopy);
|
||||
currentOffset += toCopy;
|
||||
currentLength -= toCopy;
|
||||
available -= toCopy;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a <see cref="byte"/> from the input stream.
|
||||
/// </summary>
|
||||
/// <returns>Returns the byte read.</returns>
|
||||
public int ReadLeByte()
|
||||
{
|
||||
if (available <= 0) {
|
||||
Fill();
|
||||
if (available <= 0) {
|
||||
throw new ZipException("EOF in header");
|
||||
}
|
||||
}
|
||||
byte result = rawData[rawLength - available];
|
||||
available -= 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an <see cref="short"/> in little endian byte order.
|
||||
/// </summary>
|
||||
/// <returns>The short value read case to an int.</returns>
|
||||
public int ReadLeShort()
|
||||
{
|
||||
return ReadLeByte() | (ReadLeByte() << 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an <see cref="int"/> in little endian byte order.
|
||||
/// </summary>
|
||||
/// <returns>The int value read.</returns>
|
||||
public int ReadLeInt()
|
||||
{
|
||||
return ReadLeShort() | (ReadLeShort() << 16);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a <see cref="long"/> in little endian byte order.
|
||||
/// </summary>
|
||||
/// <returns>The long value read.</returns>
|
||||
public long ReadLeLong()
|
||||
{
|
||||
return (uint)ReadLeInt() | ((long)ReadLeInt() << 32);
|
||||
}
|
||||
|
||||
#if !NETCF_1_0
|
||||
/// <summary>
|
||||
/// Get/set the <see cref="ICryptoTransform"/> to apply to any data.
|
||||
/// </summary>
|
||||
/// <remarks>Set this value to null to have no transform applied.</remarks>
|
||||
public ICryptoTransform CryptoTransform
|
||||
{
|
||||
set {
|
||||
cryptoTransform = value;
|
||||
if ( cryptoTransform != null ) {
|
||||
if ( rawData == clearText ) {
|
||||
if ( internalClearText == null ) {
|
||||
internalClearText = new byte[rawData.Length];
|
||||
}
|
||||
clearText = internalClearText;
|
||||
}
|
||||
clearTextLength = rawLength;
|
||||
if ( available > 0 ) {
|
||||
cryptoTransform.TransformBlock(rawData, rawLength - available, available, clearText, rawLength - available);
|
||||
}
|
||||
} else {
|
||||
clearText = rawData;
|
||||
clearTextLength = rawLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#region Instance Fields
|
||||
int rawLength;
|
||||
byte[] rawData;
|
||||
|
||||
int clearTextLength;
|
||||
byte[] clearText;
|
||||
#if !NETCF_1_0
|
||||
byte[] internalClearText;
|
||||
#endif
|
||||
|
||||
int available;
|
||||
|
||||
#if !NETCF_1_0
|
||||
ICryptoTransform cryptoTransform;
|
||||
#endif
|
||||
Stream inputStream;
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This filter stream is used to decompress data compressed using the "deflate"
|
||||
/// format. The "deflate" format is described in RFC 1951.
|
||||
///
|
||||
/// This stream may form the basis for other decompression filters, such
|
||||
/// as the <see cref="ICSharpCode.SharpZipLib.GZip.GZipInputStream">GZipInputStream</see>.
|
||||
///
|
||||
/// Author of the original java version : John Leuner.
|
||||
/// </summary>
|
||||
public class InflaterInputStream : Stream
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Create an InflaterInputStream with the default decompressor
|
||||
/// and a default buffer size of 4KB.
|
||||
/// </summary>
|
||||
/// <param name = "baseInputStream">
|
||||
/// The InputStream to read bytes from
|
||||
/// </param>
|
||||
public InflaterInputStream(Stream baseInputStream)
|
||||
: this(baseInputStream, new Inflater(), 4096)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an InflaterInputStream with the specified decompressor
|
||||
/// and a default buffer size of 4KB.
|
||||
/// </summary>
|
||||
/// <param name = "baseInputStream">
|
||||
/// The source of input data
|
||||
/// </param>
|
||||
/// <param name = "inf">
|
||||
/// The decompressor used to decompress data read from baseInputStream
|
||||
/// </param>
|
||||
public InflaterInputStream(Stream baseInputStream, Inflater inf)
|
||||
: this(baseInputStream, inf, 4096)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an InflaterInputStream with the specified decompressor
|
||||
/// and the specified buffer size.
|
||||
/// </summary>
|
||||
/// <param name = "baseInputStream">
|
||||
/// The InputStream to read bytes from
|
||||
/// </param>
|
||||
/// <param name = "inflater">
|
||||
/// The decompressor to use
|
||||
/// </param>
|
||||
/// <param name = "bufferSize">
|
||||
/// Size of the buffer to use
|
||||
/// </param>
|
||||
public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize)
|
||||
{
|
||||
if (baseInputStream == null) {
|
||||
throw new ArgumentNullException("baseInputStream");
|
||||
}
|
||||
|
||||
if (inflater == null) {
|
||||
throw new ArgumentNullException("inflater");
|
||||
}
|
||||
|
||||
if (bufferSize <= 0) {
|
||||
throw new ArgumentOutOfRangeException("bufferSize");
|
||||
}
|
||||
|
||||
this.baseInputStream = baseInputStream;
|
||||
this.inf = inflater;
|
||||
|
||||
inputBuffer = new InflaterInputBuffer(baseInputStream, bufferSize);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Get/set flag indicating ownership of underlying stream.
|
||||
/// When the flag is true <see cref="Close"/> will close the underlying stream also.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is true.
|
||||
/// </remarks>
|
||||
public bool IsStreamOwner
|
||||
{
|
||||
get { return isStreamOwner; }
|
||||
set { isStreamOwner = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skip specified number of bytes of uncompressed data
|
||||
/// </summary>
|
||||
/// <param name ="count">
|
||||
/// Number of bytes to skip
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The number of bytes skipped, zero if the end of
|
||||
/// stream has been reached
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="count">The number of bytes</paramref> to skip is less than or equal to zero.
|
||||
/// </exception>
|
||||
public long Skip(long count)
|
||||
{
|
||||
if (count <= 0) {
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
}
|
||||
|
||||
// v0.80 Skip by seeking if underlying stream supports it...
|
||||
if (baseInputStream.CanSeek) {
|
||||
baseInputStream.Seek(count, SeekOrigin.Current);
|
||||
return count;
|
||||
}
|
||||
else {
|
||||
int length = 2048;
|
||||
if (count < length) {
|
||||
length = (int) count;
|
||||
}
|
||||
|
||||
byte[] tmp = new byte[length];
|
||||
int readCount = 1;
|
||||
long toSkip = count;
|
||||
|
||||
while ((toSkip > 0) && (readCount > 0) ) {
|
||||
if (toSkip < length) {
|
||||
length = (int)toSkip;
|
||||
}
|
||||
|
||||
readCount = baseInputStream.Read(tmp, 0, length);
|
||||
toSkip -= readCount;
|
||||
}
|
||||
|
||||
return count - toSkip;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear any cryptographic state.
|
||||
/// </summary>
|
||||
protected void StopDecrypting()
|
||||
{
|
||||
#if !NETCF_1_0
|
||||
inputBuffer.CryptoTransform = null;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns 0 once the end of the stream (EOF) has been reached.
|
||||
/// Otherwise returns 1.
|
||||
/// </summary>
|
||||
public virtual int Available
|
||||
{
|
||||
get {
|
||||
return inf.IsFinished ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills the buffer with more data to decompress.
|
||||
/// </summary>
|
||||
/// <exception cref="SharpZipBaseException">
|
||||
/// Stream ends early
|
||||
/// </exception>
|
||||
protected void Fill()
|
||||
{
|
||||
// Protect against redundant calls
|
||||
if (inputBuffer.Available <= 0) {
|
||||
inputBuffer.Fill();
|
||||
if (inputBuffer.Available <= 0) {
|
||||
throw new SharpZipBaseException("Unexpected EOF");
|
||||
}
|
||||
}
|
||||
inputBuffer.SetInflaterInput(inf);
|
||||
}
|
||||
|
||||
#region Stream Overrides
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current stream supports reading
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get {
|
||||
return baseInputStream.CanRead;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value of false indicating seeking is not supported for this stream.
|
||||
/// </summary>
|
||||
public override bool CanSeek {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value of false indicating that this stream is not writeable.
|
||||
/// </summary>
|
||||
public override bool CanWrite {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A value representing the length of the stream in bytes.
|
||||
/// </summary>
|
||||
public override long Length {
|
||||
get {
|
||||
return inputBuffer.RawLength;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The current position within the stream.
|
||||
/// Throws a NotSupportedException when attempting to set the position
|
||||
/// </summary>
|
||||
/// <exception cref="NotSupportedException">Attempting to set the position</exception>
|
||||
public override long Position {
|
||||
get {
|
||||
return baseInputStream.Position;
|
||||
}
|
||||
set {
|
||||
throw new NotSupportedException("InflaterInputStream Position not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the baseInputStream
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
baseInputStream.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the position within the current stream
|
||||
/// Always throws a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="offset">The relative offset to seek to.</param>
|
||||
/// <param name="origin">The <see cref="SeekOrigin"/> defining where to seek from.</param>
|
||||
/// <returns>The new position in the stream.</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException("Seek not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the length of the current stream
|
||||
/// Always throws a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="value">The new length value for the stream.</param>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException("InflaterInputStream SetLength not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a sequence of bytes to stream and advances the current position
|
||||
/// This method always throws a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="buffer">Thew buffer containing data to write.</param>
|
||||
/// <param name="offset">The offset of the first byte to write.</param>
|
||||
/// <param name="count">The number of bytes to write.</param>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException("InflaterInputStream Write not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes one byte to the current stream and advances the current position
|
||||
/// Always throws a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="value">The byte to write.</param>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
throw new NotSupportedException("InflaterInputStream WriteByte not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Entry point to begin an asynchronous write. Always throws a NotSupportedException.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to write data from</param>
|
||||
/// <param name="offset">Offset of first byte to write</param>
|
||||
/// <param name="count">The maximum number of bytes to write</param>
|
||||
/// <param name="callback">The method to be called when the asynchronous write operation is completed</param>
|
||||
/// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from other requests</param>
|
||||
/// <returns>An <see cref="System.IAsyncResult">IAsyncResult</see> that references the asynchronous write</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
{
|
||||
throw new NotSupportedException("InflaterInputStream BeginWrite not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the input stream. When <see cref="IsStreamOwner"></see>
|
||||
/// is true the underlying stream is also closed.
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
if ( !isClosed ) {
|
||||
isClosed = true;
|
||||
if ( isStreamOwner ) {
|
||||
baseInputStream.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads decompressed data into the provided buffer byte array
|
||||
/// </summary>
|
||||
/// <param name ="buffer">
|
||||
/// The array to read and decompress data into
|
||||
/// </param>
|
||||
/// <param name ="offset">
|
||||
/// The offset indicating where the data should be placed
|
||||
/// </param>
|
||||
/// <param name ="count">
|
||||
/// The number of bytes to decompress
|
||||
/// </param>
|
||||
/// <returns>The number of bytes read. Zero signals the end of stream</returns>
|
||||
/// <exception cref="SharpZipBaseException">
|
||||
/// Inflater needs a dictionary
|
||||
/// </exception>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (inf.IsNeedingDictionary)
|
||||
{
|
||||
throw new SharpZipBaseException("Need a dictionary");
|
||||
}
|
||||
|
||||
int remainingBytes = count;
|
||||
while (true) {
|
||||
int bytesRead = inf.Inflate(buffer, offset, remainingBytes);
|
||||
offset += bytesRead;
|
||||
remainingBytes -= bytesRead;
|
||||
|
||||
if (remainingBytes == 0 || inf.IsFinished) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( inf.IsNeedingInput ) {
|
||||
Fill();
|
||||
}
|
||||
else if ( bytesRead == 0 ) {
|
||||
throw new ZipException("Dont know what to do");
|
||||
}
|
||||
}
|
||||
return count - remainingBytes;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// Decompressor for this stream
|
||||
/// </summary>
|
||||
protected Inflater inf;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="InflaterInputBuffer">Input buffer</see> for this stream.
|
||||
/// </summary>
|
||||
protected InflaterInputBuffer inputBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Base stream the inflater reads from.
|
||||
/// </summary>
|
||||
private Stream baseInputStream;
|
||||
|
||||
/// <summary>
|
||||
/// The compressed size
|
||||
/// </summary>
|
||||
protected long csize;
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating wether this instance has been closed or not.
|
||||
/// </summary>
|
||||
bool isClosed;
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating wether this instance is designated the stream owner.
|
||||
/// When closing if this flag is true the underlying stream is closed.
|
||||
/// </summary>
|
||||
bool isStreamOwner = true;
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
// OutputWindow.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Contains the output from the Inflation process.
|
||||
/// We need to have a window so that we can refer backwards into the output stream
|
||||
/// to repeat stuff.<br/>
|
||||
/// Author of the original java version : John Leuner
|
||||
/// </summary>
|
||||
public class OutputWindow
|
||||
{
|
||||
#region Constants
|
||||
const int WindowSize = 1 << 15;
|
||||
const int WindowMask = WindowSize - 1;
|
||||
#endregion
|
||||
|
||||
#region Instance Fields
|
||||
byte[] window = new byte[WindowSize]; //The window is 2^15 bytes
|
||||
int windowEnd;
|
||||
int windowFilled;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Write a byte to this output window
|
||||
/// </summary>
|
||||
/// <param name="value">value to write</param>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// if window is full
|
||||
/// </exception>
|
||||
public void Write(int value)
|
||||
{
|
||||
if (windowFilled++ == WindowSize) {
|
||||
throw new InvalidOperationException("Window full");
|
||||
}
|
||||
window[windowEnd++] = (byte) value;
|
||||
windowEnd &= WindowMask;
|
||||
}
|
||||
|
||||
|
||||
private void SlowRepeat(int repStart, int length, int distance)
|
||||
{
|
||||
while (length-- > 0) {
|
||||
window[windowEnd++] = window[repStart++];
|
||||
windowEnd &= WindowMask;
|
||||
repStart &= WindowMask;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append a byte pattern already in the window itself
|
||||
/// </summary>
|
||||
/// <param name="length">length of pattern to copy</param>
|
||||
/// <param name="distance">distance from end of window pattern occurs</param>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// If the repeated data overflows the window
|
||||
/// </exception>
|
||||
public void Repeat(int length, int distance)
|
||||
{
|
||||
if ((windowFilled += length) > WindowSize) {
|
||||
throw new InvalidOperationException("Window full");
|
||||
}
|
||||
|
||||
int repStart = (windowEnd - distance) & WindowMask;
|
||||
int border = WindowSize - length;
|
||||
if ( (repStart <= border) && (windowEnd < border) ) {
|
||||
if (length <= distance) {
|
||||
System.Array.Copy(window, repStart, window, windowEnd, length);
|
||||
windowEnd += length;
|
||||
} else {
|
||||
// We have to copy manually, since the repeat pattern overlaps.
|
||||
while (length-- > 0) {
|
||||
window[windowEnd++] = window[repStart++];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SlowRepeat(repStart, length, distance);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy from input manipulator to internal window
|
||||
/// </summary>
|
||||
/// <param name="input">source of data</param>
|
||||
/// <param name="length">length of data to copy</param>
|
||||
/// <returns>the number of bytes copied</returns>
|
||||
public int CopyStored(StreamManipulator input, int length)
|
||||
{
|
||||
length = Math.Min(Math.Min(length, WindowSize - windowFilled), input.AvailableBytes);
|
||||
int copied;
|
||||
|
||||
int tailLen = WindowSize - windowEnd;
|
||||
if (length > tailLen) {
|
||||
copied = input.CopyBytes(window, windowEnd, tailLen);
|
||||
if (copied == tailLen) {
|
||||
copied += input.CopyBytes(window, 0, length - tailLen);
|
||||
}
|
||||
} else {
|
||||
copied = input.CopyBytes(window, windowEnd, length);
|
||||
}
|
||||
|
||||
windowEnd = (windowEnd + copied) & WindowMask;
|
||||
windowFilled += copied;
|
||||
return copied;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy dictionary to window
|
||||
/// </summary>
|
||||
/// <param name="dictionary">source dictionary</param>
|
||||
/// <param name="offset">offset of start in source dictionary</param>
|
||||
/// <param name="length">length of dictionary</param>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// If window isnt empty
|
||||
/// </exception>
|
||||
public void CopyDict(byte[] dictionary, int offset, int length)
|
||||
{
|
||||
if ( dictionary == null ) {
|
||||
throw new ArgumentNullException("dictionary");
|
||||
}
|
||||
|
||||
if (windowFilled > 0) {
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
if (length > WindowSize) {
|
||||
offset += length - WindowSize;
|
||||
length = WindowSize;
|
||||
}
|
||||
System.Array.Copy(dictionary, offset, window, 0, length);
|
||||
windowEnd = length & WindowMask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get remaining unfilled space in window
|
||||
/// </summary>
|
||||
/// <returns>Number of bytes left in window</returns>
|
||||
public int GetFreeSpace()
|
||||
{
|
||||
return WindowSize - windowFilled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get bytes available for output in window
|
||||
/// </summary>
|
||||
/// <returns>Number of bytes filled</returns>
|
||||
public int GetAvailable()
|
||||
{
|
||||
return windowFilled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy contents of window to output
|
||||
/// </summary>
|
||||
/// <param name="output">buffer to copy to</param>
|
||||
/// <param name="offset">offset to start at</param>
|
||||
/// <param name="len">number of bytes to count</param>
|
||||
/// <returns>The number of bytes copied</returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// If a window underflow occurs
|
||||
/// </exception>
|
||||
public int CopyOutput(byte[] output, int offset, int len)
|
||||
{
|
||||
int copyEnd = windowEnd;
|
||||
if (len > windowFilled) {
|
||||
len = windowFilled;
|
||||
} else {
|
||||
copyEnd = (windowEnd - windowFilled + len) & WindowMask;
|
||||
}
|
||||
|
||||
int copied = len;
|
||||
int tailLen = len - copyEnd;
|
||||
|
||||
if (tailLen > 0) {
|
||||
System.Array.Copy(window, WindowSize - tailLen, output, offset, tailLen);
|
||||
offset += tailLen;
|
||||
len = copyEnd;
|
||||
}
|
||||
System.Array.Copy(window, copyEnd - len, output, offset, len);
|
||||
windowFilled -= copied;
|
||||
if (windowFilled < 0) {
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see> returns 0
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
windowFilled = windowEnd = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,297 @@
|
|||
// StreamManipulator.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This class allows us to retrieve a specified number of bits from
|
||||
/// the input buffer, as well as copy big byte blocks.
|
||||
///
|
||||
/// It uses an int buffer to store up to 31 bits for direct
|
||||
/// manipulation. This guarantees that we can get at least 16 bits,
|
||||
/// but we only need at most 15, so this is all safe.
|
||||
///
|
||||
/// There are some optimizations in this class, for example, you must
|
||||
/// never peek more than 8 bits more than needed, and you must first
|
||||
/// peek bits before you may drop them. This is not a general purpose
|
||||
/// class but optimized for the behaviour of the Inflater.
|
||||
///
|
||||
/// authors of the original java version : John Leuner, Jochen Hoenicke
|
||||
/// </summary>
|
||||
public class StreamManipulator
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructs a default StreamManipulator with all buffers empty
|
||||
/// </summary>
|
||||
public StreamManipulator()
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Get the next sequence of bits but don't increase input pointer. bitCount must be
|
||||
/// less or equal 16 and if this call succeeds, you must drop
|
||||
/// at least n - 8 bits in the next call.
|
||||
/// </summary>
|
||||
/// <param name="bitCount">The number of bits to peek.</param>
|
||||
/// <returns>
|
||||
/// the value of the bits, or -1 if not enough bits available. */
|
||||
/// </returns>
|
||||
public int PeekBits(int bitCount)
|
||||
{
|
||||
if (bitsInBuffer_ < bitCount) {
|
||||
if (windowStart_ == windowEnd_) {
|
||||
return -1; // ok
|
||||
}
|
||||
buffer_ |= (uint)((window_[windowStart_++] & 0xff |
|
||||
(window_[windowStart_++] & 0xff) << 8) << bitsInBuffer_);
|
||||
bitsInBuffer_ += 16;
|
||||
}
|
||||
return (int)(buffer_ & ((1 << bitCount) - 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops the next n bits from the input. You should have called PeekBits
|
||||
/// with a bigger or equal n before, to make sure that enough bits are in
|
||||
/// the bit buffer.
|
||||
/// </summary>
|
||||
/// <param name="bitCount">The number of bits to drop.</param>
|
||||
public void DropBits(int bitCount)
|
||||
{
|
||||
buffer_ >>= bitCount;
|
||||
bitsInBuffer_ -= bitCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next n bits and increases input pointer. This is equivalent
|
||||
/// to <see cref="PeekBits"/> followed by <see cref="DropBits"/>, except for correct error handling.
|
||||
/// </summary>
|
||||
/// <param name="bitCount">The number of bits to retrieve.</param>
|
||||
/// <returns>
|
||||
/// the value of the bits, or -1 if not enough bits available.
|
||||
/// </returns>
|
||||
public int GetBits(int bitCount)
|
||||
{
|
||||
int bits = PeekBits(bitCount);
|
||||
if (bits >= 0) {
|
||||
DropBits(bitCount);
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bits available in the bit buffer. This must be
|
||||
/// only called when a previous PeekBits() returned -1.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// the number of bits available.
|
||||
/// </returns>
|
||||
public int AvailableBits {
|
||||
get {
|
||||
return bitsInBuffer_;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bytes available.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The number of bytes available.
|
||||
/// </returns>
|
||||
public int AvailableBytes {
|
||||
get {
|
||||
return windowEnd_ - windowStart_ + (bitsInBuffer_ >> 3);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skips to the next byte boundary.
|
||||
/// </summary>
|
||||
public void SkipToByteBoundary()
|
||||
{
|
||||
buffer_ >>= (bitsInBuffer_ & 7);
|
||||
bitsInBuffer_ &= ~7;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true when SetInput can be called
|
||||
/// </summary>
|
||||
public bool IsNeedingInput {
|
||||
get {
|
||||
return windowStart_ == windowEnd_;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies bytes from input buffer to output buffer starting
|
||||
/// at output[offset]. You have to make sure, that the buffer is
|
||||
/// byte aligned. If not enough bytes are available, copies fewer
|
||||
/// bytes.
|
||||
/// </summary>
|
||||
/// <param name="output">
|
||||
/// The buffer to copy bytes to.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// The offset in the buffer at which copying starts
|
||||
/// </param>
|
||||
/// <param name="length">
|
||||
/// The length to copy, 0 is allowed.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The number of bytes copied, 0 if no bytes were available.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Length is less than zero
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Bit buffer isnt byte aligned
|
||||
/// </exception>
|
||||
public int CopyBytes(byte[] output, int offset, int length)
|
||||
{
|
||||
if (length < 0) {
|
||||
throw new ArgumentOutOfRangeException("length");
|
||||
}
|
||||
|
||||
if ((bitsInBuffer_ & 7) != 0) {
|
||||
// bits_in_buffer may only be 0 or a multiple of 8
|
||||
throw new InvalidOperationException("Bit buffer is not byte aligned!");
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
while ((bitsInBuffer_ > 0) && (length > 0)) {
|
||||
output[offset++] = (byte) buffer_;
|
||||
buffer_ >>= 8;
|
||||
bitsInBuffer_ -= 8;
|
||||
length--;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
return count;
|
||||
}
|
||||
|
||||
int avail = windowEnd_ - windowStart_;
|
||||
if (length > avail) {
|
||||
length = avail;
|
||||
}
|
||||
System.Array.Copy(window_, windowStart_, output, offset, length);
|
||||
windowStart_ += length;
|
||||
|
||||
if (((windowStart_ - windowEnd_) & 1) != 0) {
|
||||
// We always want an even number of bytes in input, see peekBits
|
||||
buffer_ = (uint)(window_[windowStart_++] & 0xff);
|
||||
bitsInBuffer_ = 8;
|
||||
}
|
||||
return count + length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets state and empties internal buffers
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
buffer_ = 0;
|
||||
windowStart_ = windowEnd_ = bitsInBuffer_ = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add more input for consumption.
|
||||
/// Only call when IsNeedingInput returns true
|
||||
/// </summary>
|
||||
/// <param name="buffer">data to be input</param>
|
||||
/// <param name="offset">offset of first byte of input</param>
|
||||
/// <param name="count">number of bytes of input to add.</param>
|
||||
public void SetInput(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if ( buffer == null ) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
if ( offset < 0 ) {
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("offset", "Cannot be negative");
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( count < 0 ) {
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("count", "Cannot be negative");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (windowStart_ < windowEnd_) {
|
||||
throw new InvalidOperationException("Old input was not completely processed");
|
||||
}
|
||||
|
||||
int end = offset + count;
|
||||
|
||||
// We want to throw an ArrayIndexOutOfBoundsException early.
|
||||
// Note the check also handles integer wrap around.
|
||||
if ((offset > end) || (end > buffer.Length) ) {
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
}
|
||||
|
||||
if ((count & 1) != 0) {
|
||||
// We always want an even number of bytes in input, see PeekBits
|
||||
buffer_ |= (uint)((buffer[offset++] & 0xff) << bitsInBuffer_);
|
||||
bitsInBuffer_ += 8;
|
||||
}
|
||||
|
||||
window_ = buffer;
|
||||
windowStart_ = offset;
|
||||
windowEnd_ = end;
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
private byte[] window_;
|
||||
private int windowStart_;
|
||||
private int windowEnd_;
|
||||
|
||||
private uint buffer_;
|
||||
private int bitsInBuffer_;
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,729 @@
|
|||
// FastZip.cs
|
||||
//
|
||||
// Copyright 2005 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using ICSharpCode.SharpZipLib.Core;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip
|
||||
{
|
||||
/// <summary>
|
||||
/// FastZipEvents supports all events applicable to <see cref="FastZip">FastZip</see> operations.
|
||||
/// </summary>
|
||||
public class FastZipEvents
|
||||
{
|
||||
/// <summary>
|
||||
/// Delegate to invoke when processing directories.
|
||||
/// </summary>
|
||||
public ProcessDirectoryHandler ProcessDirectory;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate to invoke when processing files.
|
||||
/// </summary>
|
||||
public ProcessFileHandler ProcessFile;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate to invoke during processing of files.
|
||||
/// </summary>
|
||||
public ProgressHandler Progress;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate to invoke when processing for a file has been completed.
|
||||
/// </summary>
|
||||
public CompletedFileHandler CompletedFile;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate to invoke when processing directory failures.
|
||||
/// </summary>
|
||||
public DirectoryFailureHandler DirectoryFailure;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate to invoke when processing file failures.
|
||||
/// </summary>
|
||||
public FileFailureHandler FileFailure;
|
||||
|
||||
/// <summary>
|
||||
/// Raise the <see cref="DirectoryFailure">directory failure</see> event.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory causing the failure.</param>
|
||||
/// <param name="e">The exception for this event.</param>
|
||||
/// <returns>A boolean indicating if execution should continue or not.</returns>
|
||||
public bool OnDirectoryFailure(string directory, Exception e)
|
||||
{
|
||||
bool result = false;
|
||||
DirectoryFailureHandler handler = DirectoryFailure;
|
||||
|
||||
if ( handler != null ) {
|
||||
ScanFailureEventArgs args = new ScanFailureEventArgs(directory, e);
|
||||
handler(this, args);
|
||||
result = args.ContinueRunning;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires the <see cref="FileFailure"> file failure handler delegate</see>.
|
||||
/// </summary>
|
||||
/// <param name="file">The file causing the failure.</param>
|
||||
/// <param name="e">The exception for this failure.</param>
|
||||
/// <returns>A boolean indicating if execution should continue or not.</returns>
|
||||
public bool OnFileFailure(string file, Exception e)
|
||||
{
|
||||
FileFailureHandler handler = FileFailure;
|
||||
bool result = (handler != null);
|
||||
|
||||
if ( result ) {
|
||||
ScanFailureEventArgs args = new ScanFailureEventArgs(file, e);
|
||||
handler(this, args);
|
||||
result = args.ContinueRunning;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires the <see cref="ProcessFile">ProcessFile delegate</see>.
|
||||
/// </summary>
|
||||
/// <param name="file">The file being processed.</param>
|
||||
/// <returns>A boolean indicating if execution should continue or not.</returns>
|
||||
public bool OnProcessFile(string file)
|
||||
{
|
||||
bool result = true;
|
||||
ProcessFileHandler handler = ProcessFile;
|
||||
|
||||
if ( handler != null ) {
|
||||
ScanEventArgs args = new ScanEventArgs(file);
|
||||
handler(this, args);
|
||||
result = args.ContinueRunning;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires the <see cref="CompletedFile"/> delegate
|
||||
/// </summary>
|
||||
/// <param name="file">The file whose processing has been completed.</param>
|
||||
/// <returns>A boolean indicating if execution should continue or not.</returns>
|
||||
public bool OnCompletedFile(string file)
|
||||
{
|
||||
bool result = true;
|
||||
CompletedFileHandler handler = CompletedFile;
|
||||
if ( handler != null ) {
|
||||
ScanEventArgs args = new ScanEventArgs(file);
|
||||
handler(this, args);
|
||||
result = args.ContinueRunning;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires the <see cref="ProcessDirectory">process directory</see> delegate.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory being processed.</param>
|
||||
/// <param name="hasMatchingFiles">Flag indicating if the directory has matching files as determined by the current filter.</param>
|
||||
/// <returns>A <see cref="bool"/> of true if the operation should continue; false otherwise.</returns>
|
||||
public bool OnProcessDirectory(string directory, bool hasMatchingFiles)
|
||||
{
|
||||
bool result = true;
|
||||
ProcessDirectoryHandler handler = ProcessDirectory;
|
||||
if ( handler != null ) {
|
||||
DirectoryEventArgs args = new DirectoryEventArgs(directory, hasMatchingFiles);
|
||||
handler(this, args);
|
||||
result = args.ContinueRunning;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The minimum timespan between <see cref="Progress"/> events.
|
||||
/// </summary>
|
||||
/// <value>The minimum period of time between <see cref="Progress"/> events.</value>
|
||||
/// <seealso cref="Progress"/>
|
||||
/// <remarks>The default interval is three seconds.</remarks>
|
||||
public TimeSpan ProgressInterval
|
||||
{
|
||||
get { return progressInterval_; }
|
||||
set { progressInterval_ = value; }
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
TimeSpan progressInterval_ = TimeSpan.FromSeconds(3);
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FastZip provides facilities for creating and extracting zip files.
|
||||
/// </summary>
|
||||
public class FastZip
|
||||
{
|
||||
#region Enumerations
|
||||
/// <summary>
|
||||
/// Defines the desired handling when overwriting files during extraction.
|
||||
/// </summary>
|
||||
public enum Overwrite
|
||||
{
|
||||
/// <summary>
|
||||
/// Prompt the user to confirm overwriting
|
||||
/// </summary>
|
||||
Prompt,
|
||||
/// <summary>
|
||||
/// Never overwrite files.
|
||||
/// </summary>
|
||||
Never,
|
||||
/// <summary>
|
||||
/// Always overwrite files.
|
||||
/// </summary>
|
||||
Always
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialise a default instance of <see cref="FastZip"/>.
|
||||
/// </summary>
|
||||
public FastZip()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="FastZip"/>
|
||||
/// </summary>
|
||||
/// <param name="events">The <see cref="FastZipEvents">events</see> to use during operations.</param>
|
||||
public FastZip(FastZipEvents events)
|
||||
{
|
||||
events_ = events;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Get/set a value indicating wether empty directories should be created.
|
||||
/// </summary>
|
||||
public bool CreateEmptyDirectories
|
||||
{
|
||||
get { return createEmptyDirectories_; }
|
||||
set { createEmptyDirectories_ = value; }
|
||||
}
|
||||
|
||||
#if !NETCF_1_0
|
||||
/// <summary>
|
||||
/// Get / set the password value.
|
||||
/// </summary>
|
||||
public string Password
|
||||
{
|
||||
get { return password_; }
|
||||
set { password_ = value; }
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the <see cref="INameTransform"></see> active when creating Zip files.
|
||||
/// </summary>
|
||||
/// <seealso cref="EntryFactory"></seealso>
|
||||
public INameTransform NameTransform
|
||||
{
|
||||
get { return entryFactory_.NameTransform; }
|
||||
set {
|
||||
entryFactory_.NameTransform = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the <see cref="IEntryFactory"></see> active when creating Zip files.
|
||||
/// </summary>
|
||||
public IEntryFactory EntryFactory
|
||||
{
|
||||
get { return entryFactory_; }
|
||||
set {
|
||||
if ( value == null ) {
|
||||
entryFactory_ = new ZipEntryFactory();
|
||||
}
|
||||
else {
|
||||
entryFactory_ = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the setting for <see cref="UseZip64">Zip64 handling when writing.</see>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is dynamic which is not backwards compatible with old
|
||||
/// programs and can cause problems with XP's built in compression which cant
|
||||
/// read Zip64 archives. However it does avoid the situation were a large file
|
||||
/// is added and cannot be completed correctly.
|
||||
/// NOTE: Setting the size for entries before they are added is the best solution!
|
||||
/// By default the EntryFactory used by FastZip will set fhe file size.
|
||||
/// </remarks>
|
||||
public UseZip64 UseZip64
|
||||
{
|
||||
get { return useZip64_; }
|
||||
set { useZip64_ = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set a value indicating wether file dates and times should
|
||||
/// be restored when extracting files from an archive.
|
||||
/// </summary>
|
||||
/// <remarks>The default value is false.</remarks>
|
||||
public bool RestoreDateTimeOnExtract
|
||||
{
|
||||
get {
|
||||
return restoreDateTimeOnExtract_;
|
||||
}
|
||||
set {
|
||||
restoreDateTimeOnExtract_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set a value indicating wether file attributes should
|
||||
/// be restored during extract operations
|
||||
/// </summary>
|
||||
public bool RestoreAttributesOnExtract
|
||||
{
|
||||
get { return restoreAttributesOnExtract_; }
|
||||
set { restoreAttributesOnExtract_ = value; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Delegates
|
||||
/// <summary>
|
||||
/// Delegate called when confirming overwriting of files.
|
||||
/// </summary>
|
||||
public delegate bool ConfirmOverwriteDelegate(string fileName);
|
||||
#endregion
|
||||
|
||||
#region CreateZip
|
||||
/// <summary>
|
||||
/// Create a zip file.
|
||||
/// </summary>
|
||||
/// <param name="zipFileName">The name of the zip file to create.</param>
|
||||
/// <param name="sourceDirectory">The directory to source files from.</param>
|
||||
/// <param name="recurse">True to recurse directories, false for no recursion.</param>
|
||||
/// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
|
||||
/// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>
|
||||
public void CreateZip(string zipFileName, string sourceDirectory,
|
||||
bool recurse, string fileFilter, string directoryFilter)
|
||||
{
|
||||
CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, directoryFilter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a zip file/archive.
|
||||
/// </summary>
|
||||
/// <param name="zipFileName">The name of the zip file to create.</param>
|
||||
/// <param name="sourceDirectory">The directory to obtain files and directories from.</param>
|
||||
/// <param name="recurse">True to recurse directories, false for no recursion.</param>
|
||||
/// <param name="fileFilter">The file filter to apply.</param>
|
||||
public void CreateZip(string zipFileName, string sourceDirectory, bool recurse, string fileFilter)
|
||||
{
|
||||
CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a zip archive sending output to the <paramref name="outputStream"/> passed.
|
||||
/// </summary>
|
||||
/// <param name="outputStream">The stream to write archive data to.</param>
|
||||
/// <param name="sourceDirectory">The directory to source files from.</param>
|
||||
/// <param name="recurse">True to recurse directories, false for no recursion.</param>
|
||||
/// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
|
||||
/// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>
|
||||
/// <remarks>The <paramref name="outputStream"/> is closed after creation.</remarks>
|
||||
public void CreateZip(Stream outputStream, string sourceDirectory, bool recurse, string fileFilter, string directoryFilter)
|
||||
{
|
||||
NameTransform = new ZipNameTransform(sourceDirectory);
|
||||
sourceDirectory_ = sourceDirectory;
|
||||
|
||||
using ( outputStream_ = new ZipOutputStream(outputStream) ) {
|
||||
|
||||
#if !NETCF_1_0
|
||||
if ( password_ != null ) {
|
||||
outputStream_.Password = password_;
|
||||
}
|
||||
#endif
|
||||
|
||||
outputStream_.UseZip64 = UseZip64;
|
||||
FileSystemScanner scanner = new FileSystemScanner(fileFilter, directoryFilter);
|
||||
scanner.ProcessFile += new ProcessFileHandler(ProcessFile);
|
||||
if ( this.CreateEmptyDirectories ) {
|
||||
scanner.ProcessDirectory += new ProcessDirectoryHandler(ProcessDirectory);
|
||||
}
|
||||
|
||||
if (events_ != null) {
|
||||
if ( events_.FileFailure != null ) {
|
||||
scanner.FileFailure += events_.FileFailure;
|
||||
}
|
||||
|
||||
if ( events_.DirectoryFailure != null ) {
|
||||
scanner.DirectoryFailure += events_.DirectoryFailure;
|
||||
}
|
||||
}
|
||||
|
||||
scanner.Scan(sourceDirectory, recurse);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ExtractZip
|
||||
/// <summary>
|
||||
/// Extract the contents of a zip file.
|
||||
/// </summary>
|
||||
/// <param name="zipFileName">The zip file to extract from.</param>
|
||||
/// <param name="targetDirectory">The directory to save extracted information in.</param>
|
||||
/// <param name="fileFilter">A filter to apply to files.</param>
|
||||
public void ExtractZip(string zipFileName, string targetDirectory, string fileFilter)
|
||||
{
|
||||
ExtractZip(zipFileName, targetDirectory, Overwrite.Always, null, fileFilter, null, restoreDateTimeOnExtract_);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract the contents of a zip file.
|
||||
/// </summary>
|
||||
/// <param name="zipFileName">The zip file to extract from.</param>
|
||||
/// <param name="targetDirectory">The directory to save extracted information in.</param>
|
||||
/// <param name="overwrite">The style of <see cref="Overwrite">overwriting</see> to apply.</param>
|
||||
/// <param name="confirmDelegate">A delegate to invoke when confirming overwriting.</param>
|
||||
/// <param name="fileFilter">A filter to apply to files.</param>
|
||||
/// <param name="directoryFilter">A filter to apply to directories.</param>
|
||||
/// <param name="restoreDateTime">Flag indicating whether to restore the date and time for extracted files.</param>
|
||||
public void ExtractZip(string zipFileName, string targetDirectory,
|
||||
Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,
|
||||
string fileFilter, string directoryFilter, bool restoreDateTime)
|
||||
{
|
||||
Stream inputStream = File.Open(zipFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
ExtractZip(inputStream, targetDirectory, overwrite, confirmDelegate, fileFilter, directoryFilter, restoreDateTime, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract the contents of a zip file held in a stream.
|
||||
/// </summary>
|
||||
/// <param name="inputStream">The seekable input stream containing the zip to extract from.</param>
|
||||
/// <param name="targetDirectory">The directory to save extracted information in.</param>
|
||||
/// <param name="overwrite">The style of <see cref="Overwrite">overwriting</see> to apply.</param>
|
||||
/// <param name="confirmDelegate">A delegate to invoke when confirming overwriting.</param>
|
||||
/// <param name="fileFilter">A filter to apply to files.</param>
|
||||
/// <param name="directoryFilter">A filter to apply to directories.</param>
|
||||
/// <param name="restoreDateTime">Flag indicating whether to restore the date and time for extracted files.</param>
|
||||
/// <param name="isStreamOwner">Flag indicating whether the inputStream will be closed by this method.</param>
|
||||
public void ExtractZip(Stream inputStream, string targetDirectory,
|
||||
Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,
|
||||
string fileFilter, string directoryFilter, bool restoreDateTime,
|
||||
bool isStreamOwner)
|
||||
{
|
||||
if ((overwrite == Overwrite.Prompt) && (confirmDelegate == null)) {
|
||||
throw new ArgumentNullException("confirmDelegate");
|
||||
}
|
||||
|
||||
continueRunning_ = true;
|
||||
overwrite_ = overwrite;
|
||||
confirmDelegate_ = confirmDelegate;
|
||||
extractNameTransform_ = new WindowsNameTransform(targetDirectory);
|
||||
|
||||
fileFilter_ = new NameFilter(fileFilter);
|
||||
directoryFilter_ = new NameFilter(directoryFilter);
|
||||
restoreDateTimeOnExtract_ = restoreDateTime;
|
||||
|
||||
using (zipFile_ = new ZipFile(inputStream)) {
|
||||
|
||||
#if !NETCF_1_0
|
||||
if (password_ != null) {
|
||||
zipFile_.Password = password_;
|
||||
}
|
||||
#endif
|
||||
zipFile_.IsStreamOwner = isStreamOwner;
|
||||
System.Collections.IEnumerator enumerator = zipFile_.GetEnumerator();
|
||||
while (continueRunning_ && enumerator.MoveNext()) {
|
||||
ZipEntry entry = (ZipEntry)enumerator.Current;
|
||||
if (entry.IsFile)
|
||||
{
|
||||
// TODO Path.GetDirectory can fail here on invalid characters.
|
||||
if (directoryFilter_.IsMatch(Path.GetDirectoryName(entry.Name)) && fileFilter_.IsMatch(entry.Name)) {
|
||||
ExtractEntry(entry);
|
||||
}
|
||||
}
|
||||
else if (entry.IsDirectory) {
|
||||
if (directoryFilter_.IsMatch(entry.Name) && CreateEmptyDirectories) {
|
||||
ExtractEntry(entry);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Do nothing for volume labels etc...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Internal Processing
|
||||
void ProcessDirectory(object sender, DirectoryEventArgs e)
|
||||
{
|
||||
if ( !e.HasMatchingFiles && CreateEmptyDirectories ) {
|
||||
if ( events_ != null ) {
|
||||
events_.OnProcessDirectory(e.Name, e.HasMatchingFiles);
|
||||
}
|
||||
|
||||
if ( e.ContinueRunning ) {
|
||||
if (e.Name != sourceDirectory_) {
|
||||
ZipEntry entry = entryFactory_.MakeDirectoryEntry(e.Name);
|
||||
outputStream_.PutNextEntry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessFile(object sender, ScanEventArgs e)
|
||||
{
|
||||
if ( (events_ != null) && (events_.ProcessFile != null) ) {
|
||||
events_.ProcessFile(sender, e);
|
||||
}
|
||||
|
||||
if ( e.ContinueRunning ) {
|
||||
try {
|
||||
// The open below is equivalent to OpenRead which gaurantees that if opened the
|
||||
// file will not be changed by subsequent openers, but precludes opening in some cases
|
||||
// were it could succeed.
|
||||
using (FileStream stream = File.Open(e.Name, FileMode.Open, FileAccess.Read, FileShare.Read)) {
|
||||
ZipEntry entry = entryFactory_.MakeFileEntry(e.Name);
|
||||
outputStream_.PutNextEntry(entry);
|
||||
AddFileContents(e.Name, stream);
|
||||
}
|
||||
}
|
||||
catch(Exception ex) {
|
||||
if (events_ != null) {
|
||||
continueRunning_ = events_.OnFileFailure(e.Name, ex);
|
||||
}
|
||||
else {
|
||||
continueRunning_ = false;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddFileContents(string name, Stream stream)
|
||||
{
|
||||
if( stream==null ) {
|
||||
throw new ArgumentNullException("stream");
|
||||
}
|
||||
|
||||
if( buffer_==null ) {
|
||||
buffer_=new byte[4096];
|
||||
}
|
||||
|
||||
if( (events_!=null)&&(events_.Progress!=null) ) {
|
||||
StreamUtils.Copy(stream, outputStream_, buffer_,
|
||||
events_.Progress, events_.ProgressInterval, this, name);
|
||||
}
|
||||
else {
|
||||
StreamUtils.Copy(stream, outputStream_, buffer_);
|
||||
}
|
||||
|
||||
if( events_!=null ) {
|
||||
continueRunning_=events_.OnCompletedFile(name);
|
||||
}
|
||||
}
|
||||
|
||||
void ExtractFileEntry(ZipEntry entry, string targetName)
|
||||
{
|
||||
bool proceed = true;
|
||||
if ( overwrite_ != Overwrite.Always ) {
|
||||
if ( File.Exists(targetName) ) {
|
||||
if ( (overwrite_ == Overwrite.Prompt) && (confirmDelegate_ != null) ) {
|
||||
proceed = confirmDelegate_(targetName);
|
||||
}
|
||||
else {
|
||||
proceed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( proceed ) {
|
||||
if ( events_ != null ) {
|
||||
continueRunning_ = events_.OnProcessFile(entry.Name);
|
||||
}
|
||||
|
||||
if ( continueRunning_ ) {
|
||||
try {
|
||||
using ( FileStream outputStream = File.Create(targetName) ) {
|
||||
if ( buffer_ == null ) {
|
||||
buffer_ = new byte[4096];
|
||||
}
|
||||
if ((events_ != null) && (events_.Progress != null))
|
||||
{
|
||||
StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_,
|
||||
events_.Progress, events_.ProgressInterval, this, entry.Name, entry.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_);
|
||||
}
|
||||
|
||||
if (events_ != null) {
|
||||
continueRunning_ = events_.OnCompletedFile(entry.Name);
|
||||
}
|
||||
}
|
||||
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
if ( restoreDateTimeOnExtract_ ) {
|
||||
File.SetLastWriteTime(targetName, entry.DateTime);
|
||||
}
|
||||
|
||||
if ( RestoreAttributesOnExtract && entry.IsDOSEntry && (entry.ExternalFileAttributes != -1)) {
|
||||
FileAttributes fileAttributes = (FileAttributes) entry.ExternalFileAttributes;
|
||||
// TODO: FastZip - Setting of other file attributes on extraction is a little trickier.
|
||||
fileAttributes &= (FileAttributes.Archive | FileAttributes.Normal | FileAttributes.ReadOnly | FileAttributes.Hidden);
|
||||
File.SetAttributes(targetName, fileAttributes);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch(Exception ex) {
|
||||
if ( events_ != null ) {
|
||||
continueRunning_ = events_.OnFileFailure(targetName, ex);
|
||||
}
|
||||
else {
|
||||
continueRunning_ = false;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtractEntry(ZipEntry entry)
|
||||
{
|
||||
bool doExtraction = entry.IsCompressionMethodSupported();
|
||||
string targetName = entry.Name;
|
||||
|
||||
if ( doExtraction ) {
|
||||
if ( entry.IsFile ) {
|
||||
targetName = extractNameTransform_.TransformFile(targetName);
|
||||
}
|
||||
else if ( entry.IsDirectory ) {
|
||||
targetName = extractNameTransform_.TransformDirectory(targetName);
|
||||
}
|
||||
|
||||
doExtraction = !((targetName == null) || (targetName.Length == 0));
|
||||
}
|
||||
|
||||
// TODO: Fire delegate/throw exception were compression method not supported, or name is invalid?
|
||||
|
||||
string dirName = null;
|
||||
|
||||
if ( doExtraction ) {
|
||||
if ( entry.IsDirectory ) {
|
||||
dirName = targetName;
|
||||
}
|
||||
else {
|
||||
dirName = Path.GetDirectoryName(Path.GetFullPath(targetName));
|
||||
}
|
||||
}
|
||||
|
||||
if ( doExtraction && !Directory.Exists(dirName) ) {
|
||||
if ( !entry.IsDirectory || CreateEmptyDirectories ) {
|
||||
try {
|
||||
Directory.CreateDirectory(dirName);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
doExtraction = false;
|
||||
if ( events_ != null ) {
|
||||
if ( entry.IsDirectory ) {
|
||||
continueRunning_ = events_.OnDirectoryFailure(targetName, ex);
|
||||
}
|
||||
else {
|
||||
continueRunning_ = events_.OnFileFailure(targetName, ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
continueRunning_ = false;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( doExtraction && entry.IsFile ) {
|
||||
ExtractFileEntry(entry, targetName);
|
||||
}
|
||||
}
|
||||
|
||||
static int MakeExternalAttributes(FileInfo info)
|
||||
{
|
||||
return (int)info.Attributes;
|
||||
}
|
||||
|
||||
#if NET_1_0 || NET_1_1 || NETCF_1_0
|
||||
static bool NameIsValid(string name)
|
||||
{
|
||||
return (name != null) &&
|
||||
(name.Length > 0) &&
|
||||
(name.IndexOfAny(Path.InvalidPathChars) < 0);
|
||||
}
|
||||
#else
|
||||
static bool NameIsValid(string name)
|
||||
{
|
||||
return (name != null) &&
|
||||
(name.Length > 0) &&
|
||||
(name.IndexOfAny(Path.GetInvalidPathChars()) < 0);
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Instance Fields
|
||||
bool continueRunning_;
|
||||
byte[] buffer_;
|
||||
ZipOutputStream outputStream_;
|
||||
ZipFile zipFile_;
|
||||
string sourceDirectory_;
|
||||
NameFilter fileFilter_;
|
||||
NameFilter directoryFilter_;
|
||||
Overwrite overwrite_;
|
||||
ConfirmOverwriteDelegate confirmDelegate_;
|
||||
|
||||
bool restoreDateTimeOnExtract_;
|
||||
bool restoreAttributesOnExtract_;
|
||||
bool createEmptyDirectories_;
|
||||
FastZipEvents events_;
|
||||
IEntryFactory entryFactory_ = new ZipEntryFactory();
|
||||
INameTransform extractNameTransform_;
|
||||
UseZip64 useZip64_=UseZip64.Dynamic;
|
||||
|
||||
#if !NETCF_1_0
|
||||
string password_;
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
// IEntryFactory.cs
|
||||
//
|
||||
// Copyright 2006 John Reilly
|
||||
//
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using ICSharpCode.SharpZipLib.Core;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines factory methods for creating new <see cref="ZipEntry"></see> values.
|
||||
/// </summary>
|
||||
public interface IEntryFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a <see cref="ZipEntry"/> for a file given its name
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to create an entry for.</param>
|
||||
/// <returns>Returns a <see cref="ZipEntry">file entry</see> based on the <paramref name="fileName"/> passed.</returns>
|
||||
ZipEntry MakeFileEntry(string fileName);
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="ZipEntry"/> for a file given its name
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to create an entry for.</param>
|
||||
/// <param name="useFileSystem">If true get details from the file system if the file exists.</param>
|
||||
/// <returns>Returns a <see cref="ZipEntry">file entry</see> based on the <paramref name="fileName"/> passed.</returns>
|
||||
ZipEntry MakeFileEntry(string fileName, bool useFileSystem);
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="ZipEntry"/> for a directory given its name
|
||||
/// </summary>
|
||||
/// <param name="directoryName">The name of the directory to create an entry for.</param>
|
||||
/// <returns>Returns a <see cref="ZipEntry">directory entry</see> based on the <paramref name="directoryName"/> passed.</returns>
|
||||
ZipEntry MakeDirectoryEntry(string directoryName);
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="ZipEntry"/> for a directory given its name
|
||||
/// </summary>
|
||||
/// <param name="directoryName">The name of the directory to create an entry for.</param>
|
||||
/// <param name="useFileSystem">If true get details from the file system for this directory if it exists.</param>
|
||||
/// <returns>Returns a <see cref="ZipEntry">directory entry</see> based on the <paramref name="directoryName"/> passed.</returns>
|
||||
ZipEntry MakeDirectoryEntry(string directoryName, bool useFileSystem);
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the <see cref="INameTransform"></see> applicable.
|
||||
/// </summary>
|
||||
INameTransform NameTransform { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,272 @@
|
|||
// WindowsNameTransform.cs
|
||||
//
|
||||
// Copyright 2007 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using ICSharpCode.SharpZipLib.Core;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip
|
||||
{
|
||||
/// <summary>
|
||||
/// WindowsNameTransform transforms <see cref="ZipFile"/> names to windows compatible ones.
|
||||
/// </summary>
|
||||
public class WindowsNameTransform : INameTransform
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialises a new instance of <see cref="WindowsNameTransform"/>
|
||||
/// </summary>
|
||||
/// <param name="baseDirectory"></param>
|
||||
public WindowsNameTransform(string baseDirectory)
|
||||
{
|
||||
if ( baseDirectory == null ) {
|
||||
throw new ArgumentNullException("baseDirectory", "Directory name is invalid");
|
||||
}
|
||||
|
||||
BaseDirectory = baseDirectory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a default instance of <see cref="WindowsNameTransform"/>
|
||||
/// </summary>
|
||||
public WindowsNameTransform()
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value containing the target directory to prefix values with.
|
||||
/// </summary>
|
||||
public string BaseDirectory
|
||||
{
|
||||
get { return _baseDirectory; }
|
||||
set {
|
||||
if ( value == null ) {
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
_baseDirectory = Path.GetFullPath(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating wether paths on incoming values should be removed.
|
||||
/// </summary>
|
||||
public bool TrimIncomingPaths
|
||||
{
|
||||
get { return _trimIncomingPaths; }
|
||||
set { _trimIncomingPaths = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transform a Zip directory name to a windows directory name.
|
||||
/// </summary>
|
||||
/// <param name="name">The directory name to transform.</param>
|
||||
/// <returns>The transformed name.</returns>
|
||||
public string TransformDirectory(string name)
|
||||
{
|
||||
name = TransformFile(name);
|
||||
if (name.Length > 0) {
|
||||
while ( name.EndsWith(@"\") ) {
|
||||
name = name.Remove(name.Length - 1, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new ZipException("Cannot have an empty directory name");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transform a Zip format file name to a windows style one.
|
||||
/// </summary>
|
||||
/// <param name="name">The file name to transform.</param>
|
||||
/// <returns>The transformed name.</returns>
|
||||
public string TransformFile(string name)
|
||||
{
|
||||
if (name != null) {
|
||||
name = MakeValidName(name, _replacementChar);
|
||||
|
||||
if ( _trimIncomingPaths ) {
|
||||
name = Path.GetFileName(name);
|
||||
}
|
||||
|
||||
// This may exceed windows length restrictions.
|
||||
// Combine will throw a PathTooLongException in that case.
|
||||
if ( _baseDirectory != null ) {
|
||||
name = Path.Combine(_baseDirectory, name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
name = string.Empty;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test a name to see if it is a valid name for a windows filename as extracted from a Zip archive.
|
||||
/// </summary>
|
||||
/// <param name="name">The name to test.</param>
|
||||
/// <returns>Returns true if the name is a valid zip name; false otherwise.</returns>
|
||||
/// <remarks>The filename isnt a true windows path in some fundamental ways like no absolute paths, no rooted paths etc.</remarks>
|
||||
public static bool IsValidName(string name)
|
||||
{
|
||||
bool result =
|
||||
(name != null) &&
|
||||
(name.Length <= MaxPath) &&
|
||||
(string.Compare(name, MakeValidName(name, '_')) == 0)
|
||||
;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise static class information.
|
||||
/// </summary>
|
||||
static WindowsNameTransform()
|
||||
{
|
||||
char[] invalidPathChars;
|
||||
|
||||
#if NET_1_0 || NET_1_1 || NETCF_1_0
|
||||
invalidPathChars = Path.InvalidPathChars;
|
||||
#else
|
||||
invalidPathChars = Path.GetInvalidPathChars();
|
||||
#endif
|
||||
int howMany = invalidPathChars.Length + 3;
|
||||
|
||||
InvalidEntryChars = new char[howMany];
|
||||
Array.Copy(invalidPathChars, 0, InvalidEntryChars, 0, invalidPathChars.Length);
|
||||
InvalidEntryChars[howMany - 1] = '*';
|
||||
InvalidEntryChars[howMany - 2] = '?';
|
||||
InvalidEntryChars[howMany - 3] = ':';
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Force a name to be valid by replacing invalid characters with a fixed value
|
||||
/// </summary>
|
||||
/// <param name="name">The name to make valid</param>
|
||||
/// <param name="replacement">The replacement character to use for any invalid characters.</param>
|
||||
/// <returns>Returns a valid name</returns>
|
||||
public static string MakeValidName(string name, char replacement)
|
||||
{
|
||||
if ( name == null ) {
|
||||
throw new ArgumentNullException("name");
|
||||
}
|
||||
|
||||
name = WindowsPathUtils.DropPathRoot(name.Replace("/", @"\"));
|
||||
|
||||
// Drop any leading slashes.
|
||||
while ( (name.Length > 0) && (name[0] == '\\')) {
|
||||
name = name.Remove(0, 1);
|
||||
}
|
||||
|
||||
// Drop any trailing slashes.
|
||||
while ( (name.Length > 0) && (name[name.Length - 1] == '\\')) {
|
||||
name = name.Remove(name.Length - 1, 1);
|
||||
}
|
||||
|
||||
// Convert consecutive \\ characters to \
|
||||
int index = name.IndexOf(@"\\");
|
||||
while (index >= 0) {
|
||||
name = name.Remove(index, 1);
|
||||
index = name.IndexOf(@"\\");
|
||||
}
|
||||
|
||||
// Convert any invalid characters using the replacement one.
|
||||
index = name.IndexOfAny(InvalidEntryChars);
|
||||
if (index >= 0) {
|
||||
StringBuilder builder = new StringBuilder(name);
|
||||
|
||||
while (index >= 0 ) {
|
||||
builder[index] = replacement;
|
||||
|
||||
if (index >= name.Length) {
|
||||
index = -1;
|
||||
}
|
||||
else {
|
||||
index = name.IndexOfAny(InvalidEntryChars, index + 1);
|
||||
}
|
||||
}
|
||||
name = builder.ToString();
|
||||
}
|
||||
|
||||
// Check for names greater than MaxPath characters.
|
||||
// TODO: Were is CLR version of MaxPath defined? Can't find it in Environment.
|
||||
if ( name.Length > MaxPath ) {
|
||||
throw new PathTooLongException();
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or set the character to replace invalid characters during transformations.
|
||||
/// </summary>
|
||||
public char Replacement
|
||||
{
|
||||
get { return _replacementChar; }
|
||||
set {
|
||||
for ( int i = 0; i < InvalidEntryChars.Length; ++i ) {
|
||||
if ( InvalidEntryChars[i] == value ) {
|
||||
throw new ArgumentException("invalid path character");
|
||||
}
|
||||
}
|
||||
|
||||
if ((value == '\\') || (value == '/')) {
|
||||
throw new ArgumentException("invalid replacement character");
|
||||
}
|
||||
|
||||
_replacementChar = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The maximum windows path name permitted.
|
||||
/// </summary>
|
||||
/// <remarks>This may not valid for all windows systems - CE?, etc but I cant find the equivalent in the CLR.</remarks>
|
||||
const int MaxPath = 260;
|
||||
|
||||
#region Instance Fields
|
||||
string _baseDirectory;
|
||||
bool _trimIncomingPaths;
|
||||
char _replacementChar = '_';
|
||||
#endregion
|
||||
|
||||
#region Class Fields
|
||||
static readonly char[] InvalidEntryChars;
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,632 @@
|
|||
// ZipConstants.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
// Copyright (C) 2004 John Reilly
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
// HISTORY
|
||||
// 22-12-2009 DavidPierson Added AES support
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
#if NETCF_1_0 || NETCF_2_0
|
||||
using System.Globalization;
|
||||
#endif
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip
|
||||
{
|
||||
|
||||
#region Enumerations
|
||||
|
||||
/// <summary>
|
||||
/// Determines how entries are tested to see if they should use Zip64 extensions or not.
|
||||
/// </summary>
|
||||
public enum UseZip64
|
||||
{
|
||||
/// <summary>
|
||||
/// Zip64 will not be forced on entries during processing.
|
||||
/// </summary>
|
||||
/// <remarks>An entry can have this overridden if required <see cref="ZipEntry.ForceZip64"></see></remarks>
|
||||
Off,
|
||||
/// <summary>
|
||||
/// Zip64 should always be used.
|
||||
/// </summary>
|
||||
On,
|
||||
/// <summary>
|
||||
/// #ZipLib will determine use based on entry values when added to archive.
|
||||
/// </summary>
|
||||
Dynamic,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The kind of compression used for an entry in an archive
|
||||
/// </summary>
|
||||
public enum CompressionMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// A direct copy of the file contents is held in the archive
|
||||
/// </summary>
|
||||
Stored = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Common Zip compression method using a sliding dictionary
|
||||
/// of up to 32KB and secondary compression from Huffman/Shannon-Fano trees
|
||||
/// </summary>
|
||||
Deflated = 8,
|
||||
|
||||
/// <summary>
|
||||
/// An extension to deflate with a 64KB window. Not supported by #Zip currently
|
||||
/// </summary>
|
||||
Deflate64 = 9,
|
||||
|
||||
/// <summary>
|
||||
/// BZip2 compression. Not supported by #Zip.
|
||||
/// </summary>
|
||||
BZip2 = 11,
|
||||
|
||||
/// <summary>
|
||||
/// WinZip special for AES encryption, Now supported by #Zip.
|
||||
/// </summary>
|
||||
WinZipAES = 99,
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the encryption algorithm used for an entry
|
||||
/// </summary>
|
||||
public enum EncryptionAlgorithm
|
||||
{
|
||||
/// <summary>
|
||||
/// No encryption has been used.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
/// <summary>
|
||||
/// Encrypted using PKZIP 2.0 or 'classic' encryption.
|
||||
/// </summary>
|
||||
PkzipClassic = 1,
|
||||
/// <summary>
|
||||
/// DES encryption has been used.
|
||||
/// </summary>
|
||||
Des = 0x6601,
|
||||
/// <summary>
|
||||
/// RCS encryption has been used for encryption.
|
||||
/// </summary>
|
||||
RC2 = 0x6602,
|
||||
/// <summary>
|
||||
/// Triple DES encryption with 168 bit keys has been used for this entry.
|
||||
/// </summary>
|
||||
TripleDes168 = 0x6603,
|
||||
/// <summary>
|
||||
/// Triple DES with 112 bit keys has been used for this entry.
|
||||
/// </summary>
|
||||
TripleDes112 = 0x6609,
|
||||
/// <summary>
|
||||
/// AES 128 has been used for encryption.
|
||||
/// </summary>
|
||||
Aes128 = 0x660e,
|
||||
/// <summary>
|
||||
/// AES 192 has been used for encryption.
|
||||
/// </summary>
|
||||
Aes192 = 0x660f,
|
||||
/// <summary>
|
||||
/// AES 256 has been used for encryption.
|
||||
/// </summary>
|
||||
Aes256 = 0x6610,
|
||||
/// <summary>
|
||||
/// RC2 corrected has been used for encryption.
|
||||
/// </summary>
|
||||
RC2Corrected = 0x6702,
|
||||
/// <summary>
|
||||
/// Blowfish has been used for encryption.
|
||||
/// </summary>
|
||||
Blowfish = 0x6720,
|
||||
/// <summary>
|
||||
/// Twofish has been used for encryption.
|
||||
/// </summary>
|
||||
Twofish = 0x6721,
|
||||
/// <summary>
|
||||
/// RC4 has been used for encryption.
|
||||
/// </summary>
|
||||
RC4 = 0x6801,
|
||||
/// <summary>
|
||||
/// An unknown algorithm has been used for encryption.
|
||||
/// </summary>
|
||||
Unknown = 0xffff
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contents of the general bit flags field for an archive entry.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum GeneralBitFlags : int
|
||||
{
|
||||
/// <summary>
|
||||
/// Bit 0 if set indicates that the file is encrypted
|
||||
/// </summary>
|
||||
Encrypted = 0x0001,
|
||||
/// <summary>
|
||||
/// Bits 1 and 2 - Two bits defining the compression method (only for Method 6 Imploding and 8,9 Deflating)
|
||||
/// </summary>
|
||||
Method = 0x0006,
|
||||
/// <summary>
|
||||
/// Bit 3 if set indicates a trailing data desciptor is appended to the entry data
|
||||
/// </summary>
|
||||
Descriptor = 0x0008,
|
||||
/// <summary>
|
||||
/// Bit 4 is reserved for use with method 8 for enhanced deflation
|
||||
/// </summary>
|
||||
ReservedPKware4 = 0x0010,
|
||||
/// <summary>
|
||||
/// Bit 5 if set indicates the file contains Pkzip compressed patched data.
|
||||
/// Requires version 2.7 or greater.
|
||||
/// </summary>
|
||||
Patched = 0x0020,
|
||||
/// <summary>
|
||||
/// Bit 6 if set indicates strong encryption has been used for this entry.
|
||||
/// </summary>
|
||||
StrongEncryption = 0x0040,
|
||||
/// <summary>
|
||||
/// Bit 7 is currently unused
|
||||
/// </summary>
|
||||
Unused7 = 0x0080,
|
||||
/// <summary>
|
||||
/// Bit 8 is currently unused
|
||||
/// </summary>
|
||||
Unused8 = 0x0100,
|
||||
/// <summary>
|
||||
/// Bit 9 is currently unused
|
||||
/// </summary>
|
||||
Unused9 = 0x0200,
|
||||
/// <summary>
|
||||
/// Bit 10 is currently unused
|
||||
/// </summary>
|
||||
Unused10 = 0x0400,
|
||||
/// <summary>
|
||||
/// Bit 11 if set indicates the filename and
|
||||
/// comment fields for this file must be encoded using UTF-8.
|
||||
/// </summary>
|
||||
UnicodeText = 0x0800,
|
||||
/// <summary>
|
||||
/// Bit 12 is documented as being reserved by PKware for enhanced compression.
|
||||
/// </summary>
|
||||
EnhancedCompress = 0x1000,
|
||||
/// <summary>
|
||||
/// Bit 13 if set indicates that values in the local header are masked to hide
|
||||
/// their actual values, and the central directory is encrypted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used when encrypting the central directory contents.
|
||||
/// </remarks>
|
||||
HeaderMasked = 0x2000,
|
||||
/// <summary>
|
||||
/// Bit 14 is documented as being reserved for use by PKware
|
||||
/// </summary>
|
||||
ReservedPkware14 = 0x4000,
|
||||
/// <summary>
|
||||
/// Bit 15 is documented as being reserved for use by PKware
|
||||
/// </summary>
|
||||
ReservedPkware15 = 0x8000
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// This class contains constants used for Zip format files
|
||||
/// </summary>
|
||||
public sealed class ZipConstants
|
||||
{
|
||||
#region Versions
|
||||
/// <summary>
|
||||
/// The version made by field for entries in the central header when created by this library
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is also the Zip version for the library when comparing against the version required to extract
|
||||
/// for an entry. See <see cref="ZipEntry.CanDecompress"/>.
|
||||
/// </remarks>
|
||||
public const int VersionMadeBy = 51; // was 45 before AES
|
||||
|
||||
/// <summary>
|
||||
/// The version made by field for entries in the central header when created by this library
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is also the Zip version for the library when comparing against the version required to extract
|
||||
/// for an entry. See <see cref="ZipInputStream.CanDecompressEntry">ZipInputStream.CanDecompressEntry</see>.
|
||||
/// </remarks>
|
||||
[Obsolete("Use VersionMadeBy instead")]
|
||||
public const int VERSION_MADE_BY = 51;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum version required to support strong encryption
|
||||
/// </summary>
|
||||
public const int VersionStrongEncryption = 50;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum version required to support strong encryption
|
||||
/// </summary>
|
||||
[Obsolete("Use VersionStrongEncryption instead")]
|
||||
public const int VERSION_STRONG_ENCRYPTION = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Version indicating AES encryption
|
||||
/// </summary>
|
||||
public const int VERSION_AES = 51;
|
||||
|
||||
/// <summary>
|
||||
/// The version required for Zip64 extensions (4.5 or higher)
|
||||
/// </summary>
|
||||
public const int VersionZip64 = 45;
|
||||
#endregion
|
||||
|
||||
#region Header Sizes
|
||||
/// <summary>
|
||||
/// Size of local entry header (excluding variable length fields at end)
|
||||
/// </summary>
|
||||
public const int LocalHeaderBaseSize = 30;
|
||||
|
||||
/// <summary>
|
||||
/// Size of local entry header (excluding variable length fields at end)
|
||||
/// </summary>
|
||||
[Obsolete("Use LocalHeaderBaseSize instead")]
|
||||
public const int LOCHDR = 30;
|
||||
|
||||
/// <summary>
|
||||
/// Size of Zip64 data descriptor
|
||||
/// </summary>
|
||||
public const int Zip64DataDescriptorSize = 24;
|
||||
|
||||
/// <summary>
|
||||
/// Size of data descriptor
|
||||
/// </summary>
|
||||
public const int DataDescriptorSize = 16;
|
||||
|
||||
/// <summary>
|
||||
/// Size of data descriptor
|
||||
/// </summary>
|
||||
[Obsolete("Use DataDescriptorSize instead")]
|
||||
public const int EXTHDR = 16;
|
||||
|
||||
/// <summary>
|
||||
/// Size of central header entry (excluding variable fields)
|
||||
/// </summary>
|
||||
public const int CentralHeaderBaseSize = 46;
|
||||
|
||||
/// <summary>
|
||||
/// Size of central header entry
|
||||
/// </summary>
|
||||
[Obsolete("Use CentralHeaderBaseSize instead")]
|
||||
public const int CENHDR = 46;
|
||||
|
||||
/// <summary>
|
||||
/// Size of end of central record (excluding variable fields)
|
||||
/// </summary>
|
||||
public const int EndOfCentralRecordBaseSize = 22;
|
||||
|
||||
/// <summary>
|
||||
/// Size of end of central record (excluding variable fields)
|
||||
/// </summary>
|
||||
[Obsolete("Use EndOfCentralRecordBaseSize instead")]
|
||||
public const int ENDHDR = 22;
|
||||
|
||||
/// <summary>
|
||||
/// Size of 'classic' cryptographic header stored before any entry data
|
||||
/// </summary>
|
||||
public const int CryptoHeaderSize = 12;
|
||||
|
||||
/// <summary>
|
||||
/// Size of cryptographic header stored before entry data
|
||||
/// </summary>
|
||||
[Obsolete("Use CryptoHeaderSize instead")]
|
||||
public const int CRYPTO_HEADER_SIZE = 12;
|
||||
#endregion
|
||||
|
||||
#region Header Signatures
|
||||
|
||||
/// <summary>
|
||||
/// Signature for local entry header
|
||||
/// </summary>
|
||||
public const int LocalHeaderSignature = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Signature for local entry header
|
||||
/// </summary>
|
||||
[Obsolete("Use LocalHeaderSignature instead")]
|
||||
public const int LOCSIG = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Signature for spanning entry
|
||||
/// </summary>
|
||||
public const int SpanningSignature = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Signature for spanning entry
|
||||
/// </summary>
|
||||
[Obsolete("Use SpanningSignature instead")]
|
||||
public const int SPANNINGSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Signature for temporary spanning entry
|
||||
/// </summary>
|
||||
public const int SpanningTempSignature = 'P' | ('K' << 8) | ('0' << 16) | ('0' << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Signature for temporary spanning entry
|
||||
/// </summary>
|
||||
[Obsolete("Use SpanningTempSignature instead")]
|
||||
public const int SPANTEMPSIG = 'P' | ('K' << 8) | ('0' << 16) | ('0' << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Signature for data descriptor
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is only used where the length, Crc, or compressed size isnt known when the
|
||||
/// entry is created and the output stream doesnt support seeking.
|
||||
/// The local entry cannot be 'patched' with the correct values in this case
|
||||
/// so the values are recorded after the data prefixed by this header, as well as in the central directory.
|
||||
/// </remarks>
|
||||
public const int DataDescriptorSignature = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Signature for data descriptor
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is only used where the length, Crc, or compressed size isnt known when the
|
||||
/// entry is created and the output stream doesnt support seeking.
|
||||
/// The local entry cannot be 'patched' with the correct values in this case
|
||||
/// so the values are recorded after the data prefixed by this header, as well as in the central directory.
|
||||
/// </remarks>
|
||||
[Obsolete("Use DataDescriptorSignature instead")]
|
||||
public const int EXTSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Signature for central header
|
||||
/// </summary>
|
||||
[Obsolete("Use CentralHeaderSignature instead")]
|
||||
public const int CENSIG = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Signature for central header
|
||||
/// </summary>
|
||||
public const int CentralHeaderSignature = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Signature for Zip64 central file header
|
||||
/// </summary>
|
||||
public const int Zip64CentralFileHeaderSignature = 'P' | ('K' << 8) | (6 << 16) | (6 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Signature for Zip64 central file header
|
||||
/// </summary>
|
||||
[Obsolete("Use Zip64CentralFileHeaderSignature instead")]
|
||||
public const int CENSIG64 = 'P' | ('K' << 8) | (6 << 16) | (6 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Signature for Zip64 central directory locator
|
||||
/// </summary>
|
||||
public const int Zip64CentralDirLocatorSignature = 'P' | ('K' << 8) | (6 << 16) | (7 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Signature for archive extra data signature (were headers are encrypted).
|
||||
/// </summary>
|
||||
public const int ArchiveExtraDataSignature = 'P' | ('K' << 8) | (6 << 16) | (7 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Central header digitial signature
|
||||
/// </summary>
|
||||
public const int CentralHeaderDigitalSignature = 'P' | ('K' << 8) | (5 << 16) | (5 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// Central header digitial signature
|
||||
/// </summary>
|
||||
[Obsolete("Use CentralHeaderDigitalSignaure instead")]
|
||||
public const int CENDIGITALSIG = 'P' | ('K' << 8) | (5 << 16) | (5 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// End of central directory record signature
|
||||
/// </summary>
|
||||
public const int EndOfCentralDirectorySignature = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);
|
||||
|
||||
/// <summary>
|
||||
/// End of central directory record signature
|
||||
/// </summary>
|
||||
[Obsolete("Use EndOfCentralDirectorySignature instead")]
|
||||
public const int ENDSIG = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);
|
||||
#endregion
|
||||
|
||||
#if NETCF_1_0 || NETCF_2_0
|
||||
// This isnt so great but is better than nothing.
|
||||
// Trying to work out an appropriate OEM code page would be good.
|
||||
// 850 is a good default for english speakers particularly in Europe.
|
||||
static int defaultCodePage = CultureInfo.CurrentCulture.TextInfo.ANSICodePage;
|
||||
#else
|
||||
static int defaultCodePage = Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Default encoding used for string conversion. 0 gives the default system OEM code page.
|
||||
/// Dont use unicode encodings if you want to be Zip compatible!
|
||||
/// Using the default code page isnt the full solution neccessarily
|
||||
/// there are many variable factors, codepage 850 is often a good choice for
|
||||
/// European users, however be careful about compatability.
|
||||
/// </summary>
|
||||
public static int DefaultCodePage {
|
||||
get {
|
||||
return defaultCodePage;
|
||||
}
|
||||
set {
|
||||
defaultCodePage = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a portion of a byte array to a string.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// Data to convert to string
|
||||
/// </param>
|
||||
/// <param name="count">
|
||||
/// Number of bytes to convert starting from index 0
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// data[0]..data[length - 1] converted to a string
|
||||
/// </returns>
|
||||
public static string ConvertToString(byte[] data, int count)
|
||||
{
|
||||
if ( data == null ) {
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return Encoding.GetEncoding(DefaultCodePage).GetString(data, 0, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a byte array to string
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// Byte array to convert
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <paramref name="data">data</paramref>converted to a string
|
||||
/// </returns>
|
||||
public static string ConvertToString(byte[] data)
|
||||
{
|
||||
if ( data == null ) {
|
||||
return string.Empty;
|
||||
}
|
||||
return ConvertToString(data, data.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a byte array to string
|
||||
/// </summary>
|
||||
/// <param name="flags">The applicable general purpose bits flags</param>
|
||||
/// <param name="data">
|
||||
/// Byte array to convert
|
||||
/// </param>
|
||||
/// <param name="count">The number of bytes to convert.</param>
|
||||
/// <returns>
|
||||
/// <paramref name="data">data</paramref>converted to a string
|
||||
/// </returns>
|
||||
public static string ConvertToStringExt(int flags, byte[] data, int count)
|
||||
{
|
||||
if ( data == null ) {
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if ( (flags & (int)GeneralBitFlags.UnicodeText) != 0 ) {
|
||||
return Encoding.UTF8.GetString(data, 0, count);
|
||||
}
|
||||
else {
|
||||
return ConvertToString(data, count);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a byte array to string
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// Byte array to convert
|
||||
/// </param>
|
||||
/// <param name="flags">The applicable general purpose bits flags</param>
|
||||
/// <returns>
|
||||
/// <paramref name="data">data</paramref>converted to a string
|
||||
/// </returns>
|
||||
public static string ConvertToStringExt(int flags, byte[] data)
|
||||
{
|
||||
if ( data == null ) {
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if ( (flags & (int)GeneralBitFlags.UnicodeText) != 0 ) {
|
||||
return Encoding.UTF8.GetString(data, 0, data.Length);
|
||||
}
|
||||
else {
|
||||
return ConvertToString(data, data.Length);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a string to a byte array
|
||||
/// </summary>
|
||||
/// <param name="str">
|
||||
/// String to convert to an array
|
||||
/// </param>
|
||||
/// <returns>Converted array</returns>
|
||||
public static byte[] ConvertToArray(string str)
|
||||
{
|
||||
if ( str == null ) {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
return Encoding.GetEncoding(DefaultCodePage).GetBytes(str);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a string to a byte array
|
||||
/// </summary>
|
||||
/// <param name="flags">The applicable <see cref="GeneralBitFlags">general purpose bits flags</see></param>
|
||||
/// <param name="str">
|
||||
/// String to convert to an array
|
||||
/// </param>
|
||||
/// <returns>Converted array</returns>
|
||||
public static byte[] ConvertToArray(int flags, string str)
|
||||
{
|
||||
if (str == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
if ((flags & (int)GeneralBitFlags.UnicodeText) != 0) {
|
||||
return Encoding.UTF8.GetBytes(str);
|
||||
}
|
||||
else {
|
||||
return ConvertToArray(str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initialise default instance of <see cref="ZipConstants">ZipConstants</see>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Private to prevent instances being created.
|
||||
/// </remarks>
|
||||
ZipConstants()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,413 @@
|
|||
// ZipEntryFactory.cs
|
||||
//
|
||||
// Copyright 2006 John Reilly
|
||||
//
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using ICSharpCode.SharpZipLib.Core;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic implementation of <see cref="IEntryFactory"></see>
|
||||
/// </summary>
|
||||
public class ZipEntryFactory : IEntryFactory
|
||||
{
|
||||
#region Enumerations
|
||||
/// <summary>
|
||||
/// Defines the possible values to be used for the <see cref="ZipEntry.DateTime"/>.
|
||||
/// </summary>
|
||||
public enum TimeSetting
|
||||
{
|
||||
/// <summary>
|
||||
/// Use the recorded LastWriteTime value for the file.
|
||||
/// </summary>
|
||||
LastWriteTime,
|
||||
/// <summary>
|
||||
/// Use the recorded LastWriteTimeUtc value for the file
|
||||
/// </summary>
|
||||
LastWriteTimeUtc,
|
||||
/// <summary>
|
||||
/// Use the recorded CreateTime value for the file.
|
||||
/// </summary>
|
||||
CreateTime,
|
||||
/// <summary>
|
||||
/// Use the recorded CreateTimeUtc value for the file.
|
||||
/// </summary>
|
||||
CreateTimeUtc,
|
||||
/// <summary>
|
||||
/// Use the recorded LastAccessTime value for the file.
|
||||
/// </summary>
|
||||
LastAccessTime,
|
||||
/// <summary>
|
||||
/// Use the recorded LastAccessTimeUtc value for the file.
|
||||
/// </summary>
|
||||
LastAccessTimeUtc,
|
||||
/// <summary>
|
||||
/// Use a fixed value.
|
||||
/// </summary>
|
||||
/// <remarks>The actual <see cref="DateTime"/> value used can be
|
||||
/// specified via the <see cref="ZipEntryFactory(DateTime)"/> constructor or
|
||||
/// using the <see cref="ZipEntryFactory(TimeSetting)"/> with the setting set
|
||||
/// to <see cref="TimeSetting.Fixed"/> which will use the <see cref="DateTime"/> when this class was constructed.
|
||||
/// The <see cref="FixedDateTime"/> property can also be used to set this value.</remarks>
|
||||
Fixed,
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialise a new instance of the <see cref="ZipEntryFactory"/> class.
|
||||
/// </summary>
|
||||
/// <remarks>A default <see cref="INameTransform"/>, and the LastWriteTime for files is used.</remarks>
|
||||
public ZipEntryFactory()
|
||||
{
|
||||
nameTransform_ = new ZipNameTransform();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="ZipEntryFactory"/> using the specified <see cref="TimeSetting"/>
|
||||
/// </summary>
|
||||
/// <param name="timeSetting">The <see cref="TimeSetting">time setting</see> to use when creating <see cref="ZipEntry">Zip entries</see>.</param>
|
||||
public ZipEntryFactory(TimeSetting timeSetting)
|
||||
{
|
||||
timeSetting_ = timeSetting;
|
||||
nameTransform_ = new ZipNameTransform();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="ZipEntryFactory"/> using the specified <see cref="DateTime"/>
|
||||
/// </summary>
|
||||
/// <param name="time">The time to set all <see cref="ZipEntry.DateTime"/> values to.</param>
|
||||
public ZipEntryFactory(DateTime time)
|
||||
{
|
||||
timeSetting_ = TimeSetting.Fixed;
|
||||
FixedDateTime = time;
|
||||
nameTransform_ = new ZipNameTransform();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Get / set the <see cref="INameTransform"/> to be used when creating new <see cref="ZipEntry"/> values.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Setting this property to null will cause a default <see cref="ZipNameTransform">name transform</see> to be used.
|
||||
/// </remarks>
|
||||
public INameTransform NameTransform
|
||||
{
|
||||
get { return nameTransform_; }
|
||||
set
|
||||
{
|
||||
if (value == null) {
|
||||
nameTransform_ = new ZipNameTransform();
|
||||
}
|
||||
else {
|
||||
nameTransform_ = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get / set the <see cref="TimeSetting"/> in use.
|
||||
/// </summary>
|
||||
public TimeSetting Setting
|
||||
{
|
||||
get { return timeSetting_; }
|
||||
set { timeSetting_ = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get / set the <see cref="DateTime"/> value to use when <see cref="Setting"/> is set to <see cref="TimeSetting.Fixed"/>
|
||||
/// </summary>
|
||||
public DateTime FixedDateTime
|
||||
{
|
||||
get { return fixedDateTime_; }
|
||||
set
|
||||
{
|
||||
if (value.Year < 1970) {
|
||||
throw new ArgumentException("Value is too old to be valid", "value");
|
||||
}
|
||||
fixedDateTime_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A bitmask defining the attributes to be retrieved from the actual file.
|
||||
/// </summary>
|
||||
/// <remarks>The default is to get all possible attributes from the actual file.</remarks>
|
||||
public int GetAttributes
|
||||
{
|
||||
get { return getAttributes_; }
|
||||
set { getAttributes_ = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A bitmask defining which attributes are to be set on.
|
||||
/// </summary>
|
||||
/// <remarks>By default no attributes are set on.</remarks>
|
||||
public int SetAttributes
|
||||
{
|
||||
get { return setAttributes_; }
|
||||
set { setAttributes_ = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get set a value indicating wether unidoce text should be set on.
|
||||
/// </summary>
|
||||
public bool IsUnicodeText
|
||||
{
|
||||
get { return isUnicodeText_; }
|
||||
set { isUnicodeText_ = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEntryFactory Members
|
||||
|
||||
/// <summary>
|
||||
/// Make a new <see cref="ZipEntry"/> for a file.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to create a new entry for.</param>
|
||||
/// <returns>Returns a new <see cref="ZipEntry"/> based on the <paramref name="fileName"/>.</returns>
|
||||
public ZipEntry MakeFileEntry(string fileName)
|
||||
{
|
||||
return MakeFileEntry(fileName, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a new <see cref="ZipEntry"/> from a name.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to create a new entry for.</param>
|
||||
/// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>
|
||||
/// <returns>Returns a new <see cref="ZipEntry"/> based on the <paramref name="fileName"/>.</returns>
|
||||
public ZipEntry MakeFileEntry(string fileName, bool useFileSystem)
|
||||
{
|
||||
ZipEntry result = new ZipEntry(nameTransform_.TransformFile(fileName));
|
||||
result.IsUnicodeText = isUnicodeText_;
|
||||
|
||||
int externalAttributes = 0;
|
||||
bool useAttributes = (setAttributes_ != 0);
|
||||
|
||||
FileInfo fi = null;
|
||||
if (useFileSystem)
|
||||
{
|
||||
fi = new FileInfo(fileName);
|
||||
}
|
||||
|
||||
if ((fi != null) && fi.Exists)
|
||||
{
|
||||
switch (timeSetting_)
|
||||
{
|
||||
case TimeSetting.CreateTime:
|
||||
result.DateTime = fi.CreationTime;
|
||||
break;
|
||||
|
||||
case TimeSetting.CreateTimeUtc:
|
||||
#if NETCF_1_0 || NETCF_2_0
|
||||
result.DateTime = fi.CreationTime.ToUniversalTime();
|
||||
#else
|
||||
result.DateTime = fi.CreationTimeUtc;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TimeSetting.LastAccessTime:
|
||||
result.DateTime = fi.LastAccessTime;
|
||||
break;
|
||||
|
||||
case TimeSetting.LastAccessTimeUtc:
|
||||
#if NETCF_1_0 || NETCF_2_0
|
||||
result.DateTime = fi.LastAccessTime.ToUniversalTime();
|
||||
#else
|
||||
result.DateTime = fi.LastAccessTimeUtc;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TimeSetting.LastWriteTime:
|
||||
result.DateTime = fi.LastWriteTime;
|
||||
break;
|
||||
|
||||
case TimeSetting.LastWriteTimeUtc:
|
||||
#if NETCF_1_0 || NETCF_2_0
|
||||
result.DateTime = fi.LastWriteTime.ToUniversalTime();
|
||||
#else
|
||||
result.DateTime = fi.LastWriteTimeUtc;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TimeSetting.Fixed:
|
||||
result.DateTime = fixedDateTime_;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ZipException("Unhandled time setting in MakeFileEntry");
|
||||
}
|
||||
|
||||
result.Size = fi.Length;
|
||||
|
||||
useAttributes = true;
|
||||
externalAttributes = ((int)fi.Attributes & getAttributes_);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (timeSetting_ == TimeSetting.Fixed)
|
||||
{
|
||||
result.DateTime = fixedDateTime_;
|
||||
}
|
||||
}
|
||||
|
||||
if (useAttributes)
|
||||
{
|
||||
externalAttributes |= setAttributes_;
|
||||
result.ExternalFileAttributes = externalAttributes;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a new <see cref="ZipEntry"></see> for a directory.
|
||||
/// </summary>
|
||||
/// <param name="directoryName">The raw untransformed name for the new directory</param>
|
||||
/// <returns>Returns a new <see cref="ZipEntry"></see> representing a directory.</returns>
|
||||
public ZipEntry MakeDirectoryEntry(string directoryName)
|
||||
{
|
||||
return MakeDirectoryEntry(directoryName, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a new <see cref="ZipEntry"></see> for a directory.
|
||||
/// </summary>
|
||||
/// <param name="directoryName">The raw untransformed name for the new directory</param>
|
||||
/// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>
|
||||
/// <returns>Returns a new <see cref="ZipEntry"></see> representing a directory.</returns>
|
||||
public ZipEntry MakeDirectoryEntry(string directoryName, bool useFileSystem)
|
||||
{
|
||||
|
||||
ZipEntry result = new ZipEntry(nameTransform_.TransformDirectory(directoryName));
|
||||
result.IsUnicodeText = isUnicodeText_;
|
||||
result.Size = 0;
|
||||
|
||||
int externalAttributes = 0;
|
||||
|
||||
DirectoryInfo di = null;
|
||||
|
||||
if (useFileSystem)
|
||||
{
|
||||
di = new DirectoryInfo(directoryName);
|
||||
}
|
||||
|
||||
|
||||
if ((di != null) && di.Exists)
|
||||
{
|
||||
switch (timeSetting_)
|
||||
{
|
||||
case TimeSetting.CreateTime:
|
||||
result.DateTime = di.CreationTime;
|
||||
break;
|
||||
|
||||
case TimeSetting.CreateTimeUtc:
|
||||
#if NETCF_1_0 || NETCF_2_0
|
||||
result.DateTime = di.CreationTime.ToUniversalTime();
|
||||
#else
|
||||
result.DateTime = di.CreationTimeUtc;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TimeSetting.LastAccessTime:
|
||||
result.DateTime = di.LastAccessTime;
|
||||
break;
|
||||
|
||||
case TimeSetting.LastAccessTimeUtc:
|
||||
#if NETCF_1_0 || NETCF_2_0
|
||||
result.DateTime = di.LastAccessTime.ToUniversalTime();
|
||||
#else
|
||||
result.DateTime = di.LastAccessTimeUtc;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TimeSetting.LastWriteTime:
|
||||
result.DateTime = di.LastWriteTime;
|
||||
break;
|
||||
|
||||
case TimeSetting.LastWriteTimeUtc:
|
||||
#if NETCF_1_0 || NETCF_2_0
|
||||
result.DateTime = di.LastWriteTime.ToUniversalTime();
|
||||
#else
|
||||
result.DateTime = di.LastWriteTimeUtc;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TimeSetting.Fixed:
|
||||
result.DateTime = fixedDateTime_;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ZipException("Unhandled time setting in MakeDirectoryEntry");
|
||||
}
|
||||
|
||||
externalAttributes = ((int)di.Attributes & getAttributes_);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (timeSetting_ == TimeSetting.Fixed)
|
||||
{
|
||||
result.DateTime = fixedDateTime_;
|
||||
}
|
||||
}
|
||||
|
||||
// Always set directory attribute on.
|
||||
externalAttributes |= (setAttributes_ | 16);
|
||||
result.ExternalFileAttributes = externalAttributes;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Instance Fields
|
||||
INameTransform nameTransform_;
|
||||
DateTime fixedDateTime_ = DateTime.Now;
|
||||
TimeSetting timeSetting_;
|
||||
bool isUnicodeText_;
|
||||
|
||||
int getAttributes_ = -1;
|
||||
int setAttributes_;
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
// ZipException.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
using System.Runtime.Serialization;
|
||||
#endif
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Represents exception conditions specific to Zip archive handling
|
||||
/// </summary>
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
[Serializable]
|
||||
#endif
|
||||
public class ZipException : SharpZipBaseException
|
||||
{
|
||||
#if !NETCF_1_0 && !NETCF_2_0
|
||||
/// <summary>
|
||||
/// Deserialization constructor
|
||||
/// </summary>
|
||||
/// <param name="info"><see cref="SerializationInfo"/> for this constructor</param>
|
||||
/// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
|
||||
protected ZipException(SerializationInfo info, StreamingContext context )
|
||||
: base( info, context )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ZipException class.
|
||||
/// </summary>
|
||||
public ZipException()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ZipException class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
public ZipException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of ZipException.
|
||||
/// </summary>
|
||||
/// <param name="message">A message describing the error.</param>
|
||||
/// <param name="exception">The exception that is the cause of the current exception.</param>
|
||||
public ZipException(string message, Exception exception)
|
||||
: base(message, exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,987 @@
|
|||
//
|
||||
// ZipExtraData.cs
|
||||
//
|
||||
// Copyright 2004-2007 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip
|
||||
{
|
||||
// TODO: Sort out wether tagged data is useful and what a good implementation might look like.
|
||||
// Its just a sketch of an idea at the moment.
|
||||
|
||||
/// <summary>
|
||||
/// ExtraData tagged value interface.
|
||||
/// </summary>
|
||||
public interface ITaggedData
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the ID for this tagged data value.
|
||||
/// </summary>
|
||||
short TagID { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Set the contents of this instance from the data passed.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to extract contents from.</param>
|
||||
/// <param name="offset">The offset to begin extracting data from.</param>
|
||||
/// <param name="count">The number of bytes to extract.</param>
|
||||
void SetData(byte[] data, int offset, int count);
|
||||
|
||||
/// <summary>
|
||||
/// Get the data representing this instance.
|
||||
/// </summary>
|
||||
/// <returns>Returns the data for this instance.</returns>
|
||||
byte[] GetData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A raw binary tagged value
|
||||
/// </summary>
|
||||
public class RawTaggedData : ITaggedData
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialise a new instance.
|
||||
/// </summary>
|
||||
/// <param name="tag">The tag ID.</param>
|
||||
public RawTaggedData(short tag)
|
||||
{
|
||||
_tag = tag;
|
||||
}
|
||||
|
||||
#region ITaggedData Members
|
||||
|
||||
/// <summary>
|
||||
/// Get the ID for this tagged data value.
|
||||
/// </summary>
|
||||
public short TagID
|
||||
{
|
||||
get { return _tag; }
|
||||
set { _tag = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the data from the raw values provided.
|
||||
/// </summary>
|
||||
/// <param name="data">The raw data to extract values from.</param>
|
||||
/// <param name="offset">The index to start extracting values from.</param>
|
||||
/// <param name="count">The number of bytes available.</param>
|
||||
public void SetData(byte[] data, int offset, int count)
|
||||
{
|
||||
if( data==null )
|
||||
{
|
||||
throw new ArgumentNullException("data");
|
||||
}
|
||||
|
||||
_data=new byte[count];
|
||||
Array.Copy(data, offset, _data, 0, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the binary data representing this instance.
|
||||
/// </summary>
|
||||
/// <returns>The raw binary data representing this instance.</returns>
|
||||
public byte[] GetData()
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Get /set the binary data representing this instance.
|
||||
/// </summary>
|
||||
/// <returns>The raw binary data representing this instance.</returns>
|
||||
public byte[] Data
|
||||
{
|
||||
get { return _data; }
|
||||
set { _data=value; }
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// The tag ID for this instance.
|
||||
/// </summary>
|
||||
short _tag;
|
||||
|
||||
byte[] _data;
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class representing extended unix date time values.
|
||||
/// </summary>
|
||||
public class ExtendedUnixData : ITaggedData
|
||||
{
|
||||
/// <summary>
|
||||
/// Flags indicate which values are included in this instance.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum Flags : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// The modification time is included
|
||||
/// </summary>
|
||||
ModificationTime = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// The access time is included
|
||||
/// </summary>
|
||||
AccessTime = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// The create time is included.
|
||||
/// </summary>
|
||||
CreateTime = 0x04,
|
||||
}
|
||||
|
||||
#region ITaggedData Members
|
||||
|
||||
/// <summary>
|
||||
/// Get the ID
|
||||
/// </summary>
|
||||
public short TagID
|
||||
{
|
||||
get { return 0x5455; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the data from the raw values provided.
|
||||
/// </summary>
|
||||
/// <param name="data">The raw data to extract values from.</param>
|
||||
/// <param name="index">The index to start extracting values from.</param>
|
||||
/// <param name="count">The number of bytes available.</param>
|
||||
public void SetData(byte[] data, int index, int count)
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream(data, index, count, false))
|
||||
using (ZipHelperStream helperStream = new ZipHelperStream(ms))
|
||||
{
|
||||
// bit 0 if set, modification time is present
|
||||
// bit 1 if set, access time is present
|
||||
// bit 2 if set, creation time is present
|
||||
|
||||
_flags = (Flags)helperStream.ReadByte();
|
||||
if (((_flags & Flags.ModificationTime) != 0) && (count >= 5))
|
||||
{
|
||||
int iTime = helperStream.ReadLEInt();
|
||||
|
||||
_modificationTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
|
||||
new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
|
||||
}
|
||||
|
||||
if ((_flags & Flags.AccessTime) != 0)
|
||||
{
|
||||
int iTime = helperStream.ReadLEInt();
|
||||
|
||||
_lastAccessTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
|
||||
new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
|
||||
}
|
||||
|
||||
if ((_flags & Flags.CreateTime) != 0)
|
||||
{
|
||||
int iTime = helperStream.ReadLEInt();
|
||||
|
||||
_createTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
|
||||
new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the binary data representing this instance.
|
||||
/// </summary>
|
||||
/// <returns>The raw binary data representing this instance.</returns>
|
||||
public byte[] GetData()
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
using (ZipHelperStream helperStream = new ZipHelperStream(ms))
|
||||
{
|
||||
helperStream.IsStreamOwner = false;
|
||||
helperStream.WriteByte((byte)_flags); // Flags
|
||||
if ( (_flags & Flags.ModificationTime) != 0) {
|
||||
TimeSpan span = _modificationTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
|
||||
int seconds = (int)span.TotalSeconds;
|
||||
helperStream.WriteLEInt(seconds);
|
||||
}
|
||||
if ( (_flags & Flags.AccessTime) != 0) {
|
||||
TimeSpan span = _lastAccessTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
|
||||
int seconds = (int)span.TotalSeconds;
|
||||
helperStream.WriteLEInt(seconds);
|
||||
}
|
||||
if ( (_flags & Flags.CreateTime) != 0) {
|
||||
TimeSpan span = _createTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
|
||||
int seconds = (int)span.TotalSeconds;
|
||||
helperStream.WriteLEInt(seconds);
|
||||
}
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Test a <see cref="DateTime"> value to see if is valid and can be represented here.</see>
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="DateTime">value</see> to test.</param>
|
||||
/// <returns>Returns true if the value is valid and can be represented; false if not.</returns>
|
||||
/// <remarks>The standard Unix time is a signed integer data type, directly encoding the Unix time number,
|
||||
/// which is the number of seconds since 1970-01-01.
|
||||
/// Being 32 bits means the values here cover a range of about 136 years.
|
||||
/// The minimum representable time is 1901-12-13 20:45:52,
|
||||
/// and the maximum representable time is 2038-01-19 03:14:07.
|
||||
/// </remarks>
|
||||
public static bool IsValidValue(DateTime value)
|
||||
{
|
||||
return (( value >= new DateTime(1901, 12, 13, 20, 45, 52)) ||
|
||||
( value <= new DateTime(2038, 1, 19, 03, 14, 07) ));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get /set the Modification Time
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
/// <seealso cref="IsValidValue"></seealso>
|
||||
public DateTime ModificationTime
|
||||
{
|
||||
get { return _modificationTime; }
|
||||
set
|
||||
{
|
||||
if ( !IsValidValue(value) ) {
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
_flags |= Flags.ModificationTime;
|
||||
_modificationTime=value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get / set the Access Time
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
/// <seealso cref="IsValidValue"></seealso>
|
||||
public DateTime AccessTime
|
||||
{
|
||||
get { return _lastAccessTime; }
|
||||
set {
|
||||
if ( !IsValidValue(value) ) {
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
_flags |= Flags.AccessTime;
|
||||
_lastAccessTime=value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get / Set the Create Time
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
/// <seealso cref="IsValidValue"></seealso>
|
||||
public DateTime CreateTime
|
||||
{
|
||||
get { return _createTime; }
|
||||
set {
|
||||
if ( !IsValidValue(value) ) {
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
_flags |= Flags.CreateTime;
|
||||
_createTime=value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the <see cref="Flags">values</see> to include.
|
||||
/// </summary>
|
||||
Flags Include
|
||||
{
|
||||
get { return _flags; }
|
||||
set { _flags = value; }
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
Flags _flags;
|
||||
DateTime _modificationTime = new DateTime(1970,1,1);
|
||||
DateTime _lastAccessTime = new DateTime(1970, 1, 1);
|
||||
DateTime _createTime = new DateTime(1970, 1, 1);
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class handling NT date time values.
|
||||
/// </summary>
|
||||
public class NTTaggedData : ITaggedData
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the ID for this tagged data value.
|
||||
/// </summary>
|
||||
public short TagID
|
||||
{
|
||||
get { return 10; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the data from the raw values provided.
|
||||
/// </summary>
|
||||
/// <param name="data">The raw data to extract values from.</param>
|
||||
/// <param name="index">The index to start extracting values from.</param>
|
||||
/// <param name="count">The number of bytes available.</param>
|
||||
public void SetData(byte[] data, int index, int count)
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream(data, index, count, false))
|
||||
using (ZipHelperStream helperStream = new ZipHelperStream(ms))
|
||||
{
|
||||
helperStream.ReadLEInt(); // Reserved
|
||||
while (helperStream.Position < helperStream.Length)
|
||||
{
|
||||
int ntfsTag = helperStream.ReadLEShort();
|
||||
int ntfsLength = helperStream.ReadLEShort();
|
||||
if (ntfsTag == 1)
|
||||
{
|
||||
if (ntfsLength >= 24)
|
||||
{
|
||||
long lastModificationTicks = helperStream.ReadLELong();
|
||||
_lastModificationTime = DateTime.FromFileTime(lastModificationTicks);
|
||||
|
||||
long lastAccessTicks = helperStream.ReadLELong();
|
||||
_lastAccessTime = DateTime.FromFileTime(lastAccessTicks);
|
||||
|
||||
long createTimeTicks = helperStream.ReadLELong();
|
||||
_createTime = DateTime.FromFileTime(createTimeTicks);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// An unknown NTFS tag so simply skip it.
|
||||
helperStream.Seek(ntfsLength, SeekOrigin.Current);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the binary data representing this instance.
|
||||
/// </summary>
|
||||
/// <returns>The raw binary data representing this instance.</returns>
|
||||
public byte[] GetData()
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
using (ZipHelperStream helperStream = new ZipHelperStream(ms))
|
||||
{
|
||||
helperStream.IsStreamOwner = false;
|
||||
helperStream.WriteLEInt(0); // Reserved
|
||||
helperStream.WriteLEShort(1); // Tag
|
||||
helperStream.WriteLEShort(24); // Length = 3 x 8.
|
||||
helperStream.WriteLELong(_lastModificationTime.ToFileTime());
|
||||
helperStream.WriteLELong(_lastAccessTime.ToFileTime());
|
||||
helperStream.WriteLELong(_createTime.ToFileTime());
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test a <see cref="DateTime"> valuie to see if is valid and can be represented here.</see>
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="DateTime">value</see> to test.</param>
|
||||
/// <returns>Returns true if the value is valid and can be represented; false if not.</returns>
|
||||
/// <remarks>
|
||||
/// NTFS filetimes are 64-bit unsigned integers, stored in Intel
|
||||
/// (least significant byte first) byte order. They determine the
|
||||
/// number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",
|
||||
/// which is "01-Jan-1601 00:00:00 UTC". 28 May 60056 is the upper limit
|
||||
/// </remarks>
|
||||
public static bool IsValidValue(DateTime value)
|
||||
{
|
||||
bool result = true;
|
||||
try
|
||||
{
|
||||
value.ToFileTimeUtc();
|
||||
}
|
||||
catch
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the <see cref="DateTime">last modification time</see>.
|
||||
/// </summary>
|
||||
public DateTime LastModificationTime
|
||||
{
|
||||
get { return _lastModificationTime; }
|
||||
set {
|
||||
if (! IsValidValue(value))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
_lastModificationTime = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get /set the <see cref="DateTime">create time</see>
|
||||
/// </summary>
|
||||
public DateTime CreateTime
|
||||
{
|
||||
get { return _createTime; }
|
||||
set {
|
||||
if ( !IsValidValue(value)) {
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
_createTime = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get /set the <see cref="DateTime">last access time</see>.
|
||||
/// </summary>
|
||||
public DateTime LastAccessTime
|
||||
{
|
||||
get { return _lastAccessTime; }
|
||||
set {
|
||||
if (!IsValidValue(value)) {
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
_lastAccessTime = value;
|
||||
}
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
DateTime _lastAccessTime = DateTime.FromFileTime(0);
|
||||
DateTime _lastModificationTime = DateTime.FromFileTime(0);
|
||||
DateTime _createTime = DateTime.FromFileTime(0);
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A factory that creates <see cref="ITaggedData">tagged data</see> instances.
|
||||
/// </summary>
|
||||
interface ITaggedDataFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Get data for a specific tag value.
|
||||
/// </summary>
|
||||
/// <param name="tag">The tag ID to find.</param>
|
||||
/// <param name="data">The data to search.</param>
|
||||
/// <param name="offset">The offset to begin extracting data from.</param>
|
||||
/// <param name="count">The number of bytes to extract.</param>
|
||||
/// <returns>The located <see cref="ITaggedData">value found</see>, or null if not found.</returns>
|
||||
ITaggedData Create(short tag, byte[] data, int offset, int count);
|
||||
}
|
||||
|
||||
///
|
||||
/// <summary>
|
||||
/// A class to handle the extra data field for Zip entries
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Extra data contains 0 or more values each prefixed by a header tag and length.
|
||||
/// They contain zero or more bytes of actual data.
|
||||
/// The data is held internally using a copy on write strategy. This is more efficient but
|
||||
/// means that for extra data created by passing in data can have the values modified by the caller
|
||||
/// in some circumstances.
|
||||
/// </remarks>
|
||||
sealed public class ZipExtraData : IDisposable
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialise a default instance.
|
||||
/// </summary>
|
||||
public ZipExtraData()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise with known extra data.
|
||||
/// </summary>
|
||||
/// <param name="data">The extra data.</param>
|
||||
public ZipExtraData(byte[] data)
|
||||
{
|
||||
if ( data == null )
|
||||
{
|
||||
_data = new byte[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
_data = data;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Get the raw extra data value
|
||||
/// </summary>
|
||||
/// <returns>Returns the raw byte[] extra data this instance represents.</returns>
|
||||
public byte[] GetEntryData()
|
||||
{
|
||||
if ( Length > ushort.MaxValue ) {
|
||||
throw new ZipException("Data exceeds maximum length");
|
||||
}
|
||||
|
||||
return (byte[])_data.Clone();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear the stored data.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
if ( (_data == null) || (_data.Length != 0) ) {
|
||||
_data = new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current extra data length.
|
||||
/// </summary>
|
||||
public int Length
|
||||
{
|
||||
get { return _data.Length; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a read-only <see cref="Stream"/> for the associated tag.
|
||||
/// </summary>
|
||||
/// <param name="tag">The tag to locate data for.</param>
|
||||
/// <returns>Returns a <see cref="Stream"/> containing tag data or null if no tag was found.</returns>
|
||||
public Stream GetStreamForTag(int tag)
|
||||
{
|
||||
Stream result = null;
|
||||
if ( Find(tag) ) {
|
||||
result = new MemoryStream(_data, _index, _readValueLength, false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the <see cref="ITaggedData">tagged data</see> for a tag.
|
||||
/// </summary>
|
||||
/// <param name="tag">The tag to search for.</param>
|
||||
/// <returns>Returns a <see cref="ITaggedData">tagged value</see> or null if none found.</returns>
|
||||
private ITaggedData GetData(short tag)
|
||||
{
|
||||
ITaggedData result = null;
|
||||
if (Find(tag))
|
||||
{
|
||||
result = Create(tag, _data, _readValueStart, _readValueLength);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static ITaggedData Create(short tag, byte[] data, int offset, int count)
|
||||
{
|
||||
ITaggedData result = null;
|
||||
switch ( tag )
|
||||
{
|
||||
case 0x000A:
|
||||
result = new NTTaggedData();
|
||||
break;
|
||||
case 0x5455:
|
||||
result = new ExtendedUnixData();
|
||||
break;
|
||||
default:
|
||||
result = new RawTaggedData(tag);
|
||||
break;
|
||||
}
|
||||
result.SetData(data, offset, count);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the length of the last value found by <see cref="Find"/>
|
||||
/// </summary>
|
||||
/// <remarks>This is only valid if <see cref="Find"/> has previously returned true.</remarks>
|
||||
public int ValueLength
|
||||
{
|
||||
get { return _readValueLength; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the index for the current read value.
|
||||
/// </summary>
|
||||
/// <remarks>This is only valid if <see cref="Find"/> has previously returned true.
|
||||
/// Initially the result will be the index of the first byte of actual data. The value is updated after calls to
|
||||
/// <see cref="ReadInt"/>, <see cref="ReadShort"/> and <see cref="ReadLong"/>. </remarks>
|
||||
public int CurrentReadIndex
|
||||
{
|
||||
get { return _index; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of bytes remaining to be read for the current value;
|
||||
/// </summary>
|
||||
public int UnreadCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((_readValueStart > _data.Length) ||
|
||||
(_readValueStart < 4) ) {
|
||||
throw new ZipException("Find must be called before calling a Read method");
|
||||
}
|
||||
|
||||
return _readValueStart + _readValueLength - _index;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find an extra data value
|
||||
/// </summary>
|
||||
/// <param name="headerID">The identifier for the value to find.</param>
|
||||
/// <returns>Returns true if the value was found; false otherwise.</returns>
|
||||
public bool Find(int headerID)
|
||||
{
|
||||
_readValueStart = _data.Length;
|
||||
_readValueLength = 0;
|
||||
_index = 0;
|
||||
|
||||
int localLength = _readValueStart;
|
||||
int localTag = headerID - 1;
|
||||
|
||||
// Trailing bytes that cant make up an entry (as there arent enough
|
||||
// bytes for a tag and length) are ignored!
|
||||
while ( (localTag != headerID) && (_index < _data.Length - 3) ) {
|
||||
localTag = ReadShortInternal();
|
||||
localLength = ReadShortInternal();
|
||||
if ( localTag != headerID ) {
|
||||
_index += localLength;
|
||||
}
|
||||
}
|
||||
|
||||
bool result = (localTag == headerID) && ((_index + localLength) <= _data.Length);
|
||||
|
||||
if ( result ) {
|
||||
_readValueStart = _index;
|
||||
_readValueLength = localLength;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a new entry to extra data.
|
||||
/// </summary>
|
||||
/// <param name="taggedData">The <see cref="ITaggedData"/> value to add.</param>
|
||||
public void AddEntry(ITaggedData taggedData)
|
||||
{
|
||||
if (taggedData == null)
|
||||
{
|
||||
throw new ArgumentNullException("taggedData");
|
||||
}
|
||||
AddEntry(taggedData.TagID, taggedData.GetData());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a new entry to extra data
|
||||
/// </summary>
|
||||
/// <param name="headerID">The ID for this entry.</param>
|
||||
/// <param name="fieldData">The data to add.</param>
|
||||
/// <remarks>If the ID already exists its contents are replaced.</remarks>
|
||||
public void AddEntry(int headerID, byte[] fieldData)
|
||||
{
|
||||
if ( (headerID > ushort.MaxValue) || (headerID < 0)) {
|
||||
throw new ArgumentOutOfRangeException("headerID");
|
||||
}
|
||||
|
||||
int addLength = (fieldData == null) ? 0 : fieldData.Length;
|
||||
|
||||
if ( addLength > ushort.MaxValue ) {
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("fieldData");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("fieldData", "exceeds maximum length");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Test for new length before adjusting data.
|
||||
int newLength = _data.Length + addLength + 4;
|
||||
|
||||
if ( Find(headerID) )
|
||||
{
|
||||
newLength -= (ValueLength + 4);
|
||||
}
|
||||
|
||||
if ( newLength > ushort.MaxValue ) {
|
||||
throw new ZipException("Data exceeds maximum length");
|
||||
}
|
||||
|
||||
Delete(headerID);
|
||||
|
||||
byte[] newData = new byte[newLength];
|
||||
_data.CopyTo(newData, 0);
|
||||
int index = _data.Length;
|
||||
_data = newData;
|
||||
SetShort(ref index, headerID);
|
||||
SetShort(ref index, addLength);
|
||||
if ( fieldData != null ) {
|
||||
fieldData.CopyTo(newData, index);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start adding a new entry.
|
||||
/// </summary>
|
||||
/// <remarks>Add data using <see cref="AddData(byte[])"/>, <see cref="AddLeShort"/>, <see cref="AddLeInt"/>, or <see cref="AddLeLong"/>.
|
||||
/// The new entry is completed and actually added by calling <see cref="AddNewEntry"/></remarks>
|
||||
/// <seealso cref="AddEntry(ITaggedData)"/>
|
||||
public void StartNewEntry()
|
||||
{
|
||||
_newEntry = new MemoryStream();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add entry data added since <see cref="StartNewEntry"/> using the ID passed.
|
||||
/// </summary>
|
||||
/// <param name="headerID">The identifier to use for this entry.</param>
|
||||
public void AddNewEntry(int headerID)
|
||||
{
|
||||
byte[] newData = _newEntry.ToArray();
|
||||
_newEntry = null;
|
||||
AddEntry(headerID, newData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a byte of data to the pending new entry.
|
||||
/// </summary>
|
||||
/// <param name="data">The byte to add.</param>
|
||||
/// <seealso cref="StartNewEntry"/>
|
||||
public void AddData(byte data)
|
||||
{
|
||||
_newEntry.WriteByte(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add data to a pending new entry.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to add.</param>
|
||||
/// <seealso cref="StartNewEntry"/>
|
||||
public void AddData(byte[] data)
|
||||
{
|
||||
if ( data == null ) {
|
||||
throw new ArgumentNullException("data");
|
||||
}
|
||||
|
||||
_newEntry.Write(data, 0, data.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a short value in little endian order to the pending new entry.
|
||||
/// </summary>
|
||||
/// <param name="toAdd">The data to add.</param>
|
||||
/// <seealso cref="StartNewEntry"/>
|
||||
public void AddLeShort(int toAdd)
|
||||
{
|
||||
unchecked {
|
||||
_newEntry.WriteByte(( byte )toAdd);
|
||||
_newEntry.WriteByte(( byte )(toAdd >> 8));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an integer value in little endian order to the pending new entry.
|
||||
/// </summary>
|
||||
/// <param name="toAdd">The data to add.</param>
|
||||
/// <seealso cref="StartNewEntry"/>
|
||||
public void AddLeInt(int toAdd)
|
||||
{
|
||||
unchecked {
|
||||
AddLeShort(( short )toAdd);
|
||||
AddLeShort(( short )(toAdd >> 16));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a long value in little endian order to the pending new entry.
|
||||
/// </summary>
|
||||
/// <param name="toAdd">The data to add.</param>
|
||||
/// <seealso cref="StartNewEntry"/>
|
||||
public void AddLeLong(long toAdd)
|
||||
{
|
||||
unchecked {
|
||||
AddLeInt(( int )(toAdd & 0xffffffff));
|
||||
AddLeInt(( int )(toAdd >> 32));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete an extra data field.
|
||||
/// </summary>
|
||||
/// <param name="headerID">The identifier of the field to delete.</param>
|
||||
/// <returns>Returns true if the field was found and deleted.</returns>
|
||||
public bool Delete(int headerID)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if ( Find(headerID) ) {
|
||||
result = true;
|
||||
int trueStart = _readValueStart - 4;
|
||||
|
||||
byte[] newData = new byte[_data.Length - (ValueLength + 4)];
|
||||
Array.Copy(_data, 0, newData, 0, trueStart);
|
||||
|
||||
int trueEnd = trueStart + ValueLength + 4;
|
||||
Array.Copy(_data, trueEnd, newData, trueStart, _data.Length - trueEnd);
|
||||
_data = newData;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#region Reading Support
|
||||
/// <summary>
|
||||
/// Read a long in little endian form from the last <see cref="Find">found</see> data value
|
||||
/// </summary>
|
||||
/// <returns>Returns the long value read.</returns>
|
||||
public long ReadLong()
|
||||
{
|
||||
ReadCheck(8);
|
||||
return (ReadInt() & 0xffffffff) | ((( long )ReadInt()) << 32);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an integer in little endian form from the last <see cref="Find">found</see> data value.
|
||||
/// </summary>
|
||||
/// <returns>Returns the integer read.</returns>
|
||||
public int ReadInt()
|
||||
{
|
||||
ReadCheck(4);
|
||||
|
||||
int result = _data[_index] + (_data[_index + 1] << 8) +
|
||||
(_data[_index + 2] << 16) + (_data[_index + 3] << 24);
|
||||
_index += 4;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a short value in little endian form from the last <see cref="Find">found</see> data value.
|
||||
/// </summary>
|
||||
/// <returns>Returns the short value read.</returns>
|
||||
public int ReadShort()
|
||||
{
|
||||
ReadCheck(2);
|
||||
int result = _data[_index] + (_data[_index + 1] << 8);
|
||||
_index += 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a byte from an extra data
|
||||
/// </summary>
|
||||
/// <returns>The byte value read or -1 if the end of data has been reached.</returns>
|
||||
public int ReadByte()
|
||||
{
|
||||
int result = -1;
|
||||
if ( (_index < _data.Length) && (_readValueStart + _readValueLength > _index) ) {
|
||||
result = _data[_index];
|
||||
_index += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skip data during reading.
|
||||
/// </summary>
|
||||
/// <param name="amount">The number of bytes to skip.</param>
|
||||
public void Skip(int amount)
|
||||
{
|
||||
ReadCheck(amount);
|
||||
_index += amount;
|
||||
}
|
||||
|
||||
void ReadCheck(int length)
|
||||
{
|
||||
if ((_readValueStart > _data.Length) ||
|
||||
(_readValueStart < 4) ) {
|
||||
throw new ZipException("Find must be called before calling a Read method");
|
||||
}
|
||||
|
||||
if (_index > _readValueStart + _readValueLength - length ) {
|
||||
throw new ZipException("End of extra data");
|
||||
}
|
||||
|
||||
if ( _index + length < 4 ) {
|
||||
throw new ZipException("Cannot read before start of tag");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal form of <see cref="ReadShort"/> that reads data at any location.
|
||||
/// </summary>
|
||||
/// <returns>Returns the short value read.</returns>
|
||||
int ReadShortInternal()
|
||||
{
|
||||
if ( _index > _data.Length - 2) {
|
||||
throw new ZipException("End of extra data");
|
||||
}
|
||||
|
||||
int result = _data[_index] + (_data[_index + 1] << 8);
|
||||
_index += 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
void SetShort(ref int index, int source)
|
||||
{
|
||||
_data[index] = (byte)source;
|
||||
_data[index + 1] = (byte)(source >> 8);
|
||||
index += 2;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this instance.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if ( _newEntry != null ) {
|
||||
_newEntry.Close();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Instance Fields
|
||||
int _index;
|
||||
int _readValueStart;
|
||||
int _readValueLength;
|
||||
|
||||
MemoryStream _newEntry;
|
||||
byte[] _data;
|
||||
#endregion
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,623 @@
|
|||
// ZipHelperStream.cs
|
||||
//
|
||||
// Copyright 2006, 2007 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Holds data pertinent to a data descriptor.
|
||||
/// </summary>
|
||||
public class DescriptorData
|
||||
{
|
||||
/// <summary>
|
||||
/// Get /set the compressed size of data.
|
||||
/// </summary>
|
||||
public long CompressedSize
|
||||
{
|
||||
get { return compressedSize; }
|
||||
set { compressedSize = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get / set the uncompressed size of data
|
||||
/// </summary>
|
||||
public long Size
|
||||
{
|
||||
get { return size; }
|
||||
set { size = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get /set the crc value.
|
||||
/// </summary>
|
||||
public long Crc
|
||||
{
|
||||
get { return crc; }
|
||||
set { crc = (value & 0xffffffff); }
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
long size;
|
||||
long compressedSize;
|
||||
long crc;
|
||||
#endregion
|
||||
}
|
||||
|
||||
class EntryPatchData
|
||||
{
|
||||
public long SizePatchOffset
|
||||
{
|
||||
get { return sizePatchOffset_; }
|
||||
set { sizePatchOffset_ = value; }
|
||||
}
|
||||
|
||||
public long CrcPatchOffset
|
||||
{
|
||||
get { return crcPatchOffset_; }
|
||||
set { crcPatchOffset_ = value; }
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
long sizePatchOffset_;
|
||||
long crcPatchOffset_;
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class assists with writing/reading from Zip files.
|
||||
/// </summary>
|
||||
internal class ZipHelperStream : Stream
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialise an instance of this class.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the file to open.</param>
|
||||
public ZipHelperStream(string name)
|
||||
{
|
||||
stream_ = new FileStream(name, FileMode.Open, FileAccess.ReadWrite);
|
||||
isOwner_ = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="ZipHelperStream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to use.</param>
|
||||
public ZipHelperStream(Stream stream)
|
||||
{
|
||||
stream_ = stream;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Get / set a value indicating wether the the underlying stream is owned or not.
|
||||
/// </summary>
|
||||
/// <remarks>If the stream is owned it is closed when this instance is closed.</remarks>
|
||||
public bool IsStreamOwner
|
||||
{
|
||||
get { return isOwner_; }
|
||||
set { isOwner_ = value; }
|
||||
}
|
||||
|
||||
#region Base Stream Methods
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return stream_.CanRead; }
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return stream_.CanSeek; }
|
||||
}
|
||||
|
||||
#if !NET_1_0 && !NET_1_1 && !NETCF_1_0
|
||||
public override bool CanTimeout
|
||||
{
|
||||
get { return stream_.CanTimeout; }
|
||||
}
|
||||
#endif
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { return stream_.Length; }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { return stream_.Position; }
|
||||
set { stream_.Position = value; }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return stream_.CanWrite; }
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
stream_.Flush();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return stream_.Seek(offset, origin);
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
stream_.SetLength(value);
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return stream_.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
stream_.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The underlying stream is closed only if <see cref="IsStreamOwner"/> is true.
|
||||
/// </remarks>
|
||||
override public void Close()
|
||||
{
|
||||
Stream toClose = stream_;
|
||||
stream_ = null;
|
||||
if (isOwner_ && (toClose != null))
|
||||
{
|
||||
isOwner_ = false;
|
||||
toClose.Close();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
// Write the local file header
|
||||
// TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage
|
||||
void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)
|
||||
{
|
||||
CompressionMethod method = entry.CompressionMethod;
|
||||
bool headerInfoAvailable = true; // How to get this?
|
||||
bool patchEntryHeader = false;
|
||||
|
||||
WriteLEInt(ZipConstants.LocalHeaderSignature);
|
||||
|
||||
WriteLEShort(entry.Version);
|
||||
WriteLEShort(entry.Flags);
|
||||
WriteLEShort((byte)method);
|
||||
WriteLEInt((int)entry.DosTime);
|
||||
|
||||
if (headerInfoAvailable == true) {
|
||||
WriteLEInt((int)entry.Crc);
|
||||
if ( entry.LocalHeaderRequiresZip64 ) {
|
||||
WriteLEInt(-1);
|
||||
WriteLEInt(-1);
|
||||
}
|
||||
else {
|
||||
WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.CompressedSize);
|
||||
WriteLEInt((int)entry.Size);
|
||||
}
|
||||
} else {
|
||||
if (patchData != null) {
|
||||
patchData.CrcPatchOffset = stream_.Position;
|
||||
}
|
||||
WriteLEInt(0); // Crc
|
||||
|
||||
if ( patchData != null ) {
|
||||
patchData.SizePatchOffset = stream_.Position;
|
||||
}
|
||||
|
||||
// For local header both sizes appear in Zip64 Extended Information
|
||||
if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) {
|
||||
WriteLEInt(-1);
|
||||
WriteLEInt(-1);
|
||||
}
|
||||
else {
|
||||
WriteLEInt(0); // Compressed size
|
||||
WriteLEInt(0); // Uncompressed size
|
||||
}
|
||||
}
|
||||
|
||||
byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
|
||||
|
||||
if (name.Length > 0xFFFF) {
|
||||
throw new ZipException("Entry name too long.");
|
||||
}
|
||||
|
||||
ZipExtraData ed = new ZipExtraData(entry.ExtraData);
|
||||
|
||||
if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader)) {
|
||||
ed.StartNewEntry();
|
||||
if (headerInfoAvailable) {
|
||||
ed.AddLeLong(entry.Size);
|
||||
ed.AddLeLong(entry.CompressedSize);
|
||||
}
|
||||
else {
|
||||
ed.AddLeLong(-1);
|
||||
ed.AddLeLong(-1);
|
||||
}
|
||||
ed.AddNewEntry(1);
|
||||
|
||||
if ( !ed.Find(1) ) {
|
||||
throw new ZipException("Internal error cant find extra data");
|
||||
}
|
||||
|
||||
if ( patchData != null ) {
|
||||
patchData.SizePatchOffset = ed.CurrentReadIndex;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ed.Delete(1);
|
||||
}
|
||||
|
||||
byte[] extra = ed.GetEntryData();
|
||||
|
||||
WriteLEShort(name.Length);
|
||||
WriteLEShort(extra.Length);
|
||||
|
||||
if ( name.Length > 0 ) {
|
||||
stream_.Write(name, 0, name.Length);
|
||||
}
|
||||
|
||||
if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) {
|
||||
patchData.SizePatchOffset += stream_.Position;
|
||||
}
|
||||
|
||||
if ( extra.Length > 0 ) {
|
||||
stream_.Write(extra, 0, extra.Length);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Locates a block with the desired <paramref name="signature"/>.
|
||||
/// </summary>
|
||||
/// <param name="signature">The signature to find.</param>
|
||||
/// <param name="endLocation">Location, marking the end of block.</param>
|
||||
/// <param name="minimumBlockSize">Minimum size of the block.</param>
|
||||
/// <param name="maximumVariableData">The maximum variable data.</param>
|
||||
/// <returns>Eeturns the offset of the first byte after the signature; -1 if not found</returns>
|
||||
public long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
|
||||
{
|
||||
long pos = endLocation - minimumBlockSize;
|
||||
if ( pos < 0 ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
long giveUpMarker = Math.Max(pos - maximumVariableData, 0);
|
||||
|
||||
// TODO: This loop could be optimised for speed.
|
||||
do {
|
||||
if ( pos < giveUpMarker ) {
|
||||
return -1;
|
||||
}
|
||||
Seek(pos--, SeekOrigin.Begin);
|
||||
} while ( ReadLEInt() != signature );
|
||||
|
||||
return Position;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write Zip64 end of central directory records (File header and locator).
|
||||
/// </summary>
|
||||
/// <param name="noOfEntries">The number of entries in the central directory.</param>
|
||||
/// <param name="sizeEntries">The size of entries in the central directory.</param>
|
||||
/// <param name="centralDirOffset">The offset of the dentral directory.</param>
|
||||
public void WriteZip64EndOfCentralDirectory(long noOfEntries, long sizeEntries, long centralDirOffset)
|
||||
{
|
||||
long centralSignatureOffset = stream_.Position;
|
||||
WriteLEInt(ZipConstants.Zip64CentralFileHeaderSignature);
|
||||
WriteLELong(44); // Size of this record (total size of remaining fields in header or full size - 12)
|
||||
WriteLEShort(ZipConstants.VersionMadeBy); // Version made by
|
||||
WriteLEShort(ZipConstants.VersionZip64); // Version to extract
|
||||
WriteLEInt(0); // Number of this disk
|
||||
WriteLEInt(0); // number of the disk with the start of the central directory
|
||||
WriteLELong(noOfEntries); // No of entries on this disk
|
||||
WriteLELong(noOfEntries); // Total No of entries in central directory
|
||||
WriteLELong(sizeEntries); // Size of the central directory
|
||||
WriteLELong(centralDirOffset); // offset of start of central directory
|
||||
// zip64 extensible data sector not catered for here (variable size)
|
||||
|
||||
// Write the Zip64 end of central directory locator
|
||||
WriteLEInt(ZipConstants.Zip64CentralDirLocatorSignature);
|
||||
|
||||
// no of the disk with the start of the zip64 end of central directory
|
||||
WriteLEInt(0);
|
||||
|
||||
// relative offset of the zip64 end of central directory record
|
||||
WriteLELong(centralSignatureOffset);
|
||||
|
||||
// total number of disks
|
||||
WriteLEInt(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the required records to end the central directory.
|
||||
/// </summary>
|
||||
/// <param name="noOfEntries">The number of entries in the directory.</param>
|
||||
/// <param name="sizeEntries">The size of the entries in the directory.</param>
|
||||
/// <param name="startOfCentralDirectory">The start of the central directory.</param>
|
||||
/// <param name="comment">The archive comment. (This can be null).</param>
|
||||
public void WriteEndOfCentralDirectory(long noOfEntries, long sizeEntries,
|
||||
long startOfCentralDirectory, byte[] comment)
|
||||
{
|
||||
|
||||
if ( (noOfEntries >= 0xffff) ||
|
||||
(startOfCentralDirectory >= 0xffffffff) ||
|
||||
(sizeEntries >= 0xffffffff) ) {
|
||||
WriteZip64EndOfCentralDirectory(noOfEntries, sizeEntries, startOfCentralDirectory);
|
||||
}
|
||||
|
||||
WriteLEInt(ZipConstants.EndOfCentralDirectorySignature);
|
||||
|
||||
// TODO: ZipFile Multi disk handling not done
|
||||
WriteLEShort(0); // number of this disk
|
||||
WriteLEShort(0); // no of disk with start of central dir
|
||||
|
||||
|
||||
// Number of entries
|
||||
if ( noOfEntries >= 0xffff ) {
|
||||
WriteLEUshort(0xffff); // Zip64 marker
|
||||
WriteLEUshort(0xffff);
|
||||
}
|
||||
else {
|
||||
WriteLEShort(( short )noOfEntries); // entries in central dir for this disk
|
||||
WriteLEShort(( short )noOfEntries); // total entries in central directory
|
||||
}
|
||||
|
||||
// Size of the central directory
|
||||
if ( sizeEntries >= 0xffffffff ) {
|
||||
WriteLEUint(0xffffffff); // Zip64 marker
|
||||
}
|
||||
else {
|
||||
WriteLEInt(( int )sizeEntries);
|
||||
}
|
||||
|
||||
|
||||
// offset of start of central directory
|
||||
if ( startOfCentralDirectory >= 0xffffffff ) {
|
||||
WriteLEUint(0xffffffff); // Zip64 marker
|
||||
}
|
||||
else {
|
||||
WriteLEInt(( int )startOfCentralDirectory);
|
||||
}
|
||||
|
||||
int commentLength = (comment != null) ? comment.Length : 0;
|
||||
|
||||
if ( commentLength > 0xffff ) {
|
||||
throw new ZipException(string.Format("Comment length({0}) is too long can only be 64K", commentLength));
|
||||
}
|
||||
|
||||
WriteLEShort(commentLength);
|
||||
|
||||
if ( commentLength > 0 ) {
|
||||
Write(comment, 0, comment.Length);
|
||||
}
|
||||
}
|
||||
|
||||
#region LE value reading/writing
|
||||
/// <summary>
|
||||
/// Read an unsigned short in little endian byte order.
|
||||
/// </summary>
|
||||
/// <returns>Returns the value read.</returns>
|
||||
/// <exception cref="IOException">
|
||||
/// An i/o error occurs.
|
||||
/// </exception>
|
||||
/// <exception cref="EndOfStreamException">
|
||||
/// The file ends prematurely
|
||||
/// </exception>
|
||||
public int ReadLEShort()
|
||||
{
|
||||
int byteValue1 = stream_.ReadByte();
|
||||
|
||||
if (byteValue1 < 0) {
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
int byteValue2 = stream_.ReadByte();
|
||||
if (byteValue2 < 0) {
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
return byteValue1 | (byteValue2 << 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an int in little endian byte order.
|
||||
/// </summary>
|
||||
/// <returns>Returns the value read.</returns>
|
||||
/// <exception cref="IOException">
|
||||
/// An i/o error occurs.
|
||||
/// </exception>
|
||||
/// <exception cref="System.IO.EndOfStreamException">
|
||||
/// The file ends prematurely
|
||||
/// </exception>
|
||||
public int ReadLEInt()
|
||||
{
|
||||
return ReadLEShort() | (ReadLEShort() << 16);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a long in little endian byte order.
|
||||
/// </summary>
|
||||
/// <returns>The value read.</returns>
|
||||
public long ReadLELong()
|
||||
{
|
||||
return (uint)ReadLEInt() | ((long)ReadLEInt() << 32);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an unsigned short in little endian byte order.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public void WriteLEShort(int value)
|
||||
{
|
||||
stream_.WriteByte(( byte )(value & 0xff));
|
||||
stream_.WriteByte(( byte )((value >> 8) & 0xff));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a ushort in little endian byte order.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public void WriteLEUshort(ushort value)
|
||||
{
|
||||
stream_.WriteByte(( byte )(value & 0xff));
|
||||
stream_.WriteByte(( byte )(value >> 8));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an int in little endian byte order.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public void WriteLEInt(int value)
|
||||
{
|
||||
WriteLEShort(value);
|
||||
WriteLEShort(value >> 16);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a uint in little endian byte order.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public void WriteLEUint(uint value)
|
||||
{
|
||||
WriteLEUshort(( ushort )(value & 0xffff));
|
||||
WriteLEUshort(( ushort )(value >> 16));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a long in little endian byte order.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public void WriteLELong(long value)
|
||||
{
|
||||
WriteLEInt(( int )value);
|
||||
WriteLEInt(( int )(value >> 32));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a ulong in little endian byte order.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public void WriteLEUlong(ulong value)
|
||||
{
|
||||
WriteLEUint(( uint )(value & 0xffffffff));
|
||||
WriteLEUint(( uint )(value >> 32));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Write a data descriptor.
|
||||
/// </summary>
|
||||
/// <param name="entry">The entry to write a descriptor for.</param>
|
||||
/// <returns>Returns the number of descriptor bytes written.</returns>
|
||||
public int WriteDataDescriptor(ZipEntry entry)
|
||||
{
|
||||
if (entry == null) {
|
||||
throw new ArgumentNullException("entry");
|
||||
}
|
||||
|
||||
int result=0;
|
||||
|
||||
// Add data descriptor if flagged as required
|
||||
if ((entry.Flags & (int)GeneralBitFlags.Descriptor) != 0)
|
||||
{
|
||||
// The signature is not PKZIP originally but is now described as optional
|
||||
// in the PKZIP Appnote documenting trhe format.
|
||||
WriteLEInt(ZipConstants.DataDescriptorSignature);
|
||||
WriteLEInt(unchecked((int)(entry.Crc)));
|
||||
|
||||
result+=8;
|
||||
|
||||
if (entry.LocalHeaderRequiresZip64)
|
||||
{
|
||||
WriteLELong(entry.CompressedSize);
|
||||
WriteLELong(entry.Size);
|
||||
result+=16;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLEInt((int)entry.CompressedSize);
|
||||
WriteLEInt((int)entry.Size);
|
||||
result+=8;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read data descriptor at the end of compressed data.
|
||||
/// </summary>
|
||||
/// <param name="zip64">if set to <c>true</c> [zip64].</param>
|
||||
/// <param name="data">The data to fill in.</param>
|
||||
/// <returns>Returns the number of bytes read in the descriptor.</returns>
|
||||
public void ReadDataDescriptor(bool zip64, DescriptorData data)
|
||||
{
|
||||
int intValue = ReadLEInt();
|
||||
|
||||
// In theory this may not be a descriptor according to PKZIP appnote.
|
||||
// In practise its always there.
|
||||
if (intValue != ZipConstants.DataDescriptorSignature) {
|
||||
throw new ZipException("Data descriptor signature not found");
|
||||
}
|
||||
|
||||
data.Crc = ReadLEInt();
|
||||
|
||||
if (zip64) {
|
||||
data.CompressedSize = ReadLELong();
|
||||
data.Size = ReadLELong();
|
||||
}
|
||||
else {
|
||||
data.CompressedSize = ReadLEInt();
|
||||
data.Size = ReadLEInt();
|
||||
}
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
bool isOwner_;
|
||||
Stream stream_;
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,675 @@
|
|||
// ZipInputStream.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
// Copyright (C) 2004 John Reilly
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
// HISTORY
|
||||
// 2010-05-25 Z-1663 Fixed exception when testing local header compressed size of -1
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using ICSharpCode.SharpZipLib.Checksums;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
|
||||
|
||||
#if !NETCF_1_0
|
||||
using ICSharpCode.SharpZipLib.Encryption;
|
||||
#endif
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip
|
||||
{
|
||||
/// <summary>
|
||||
/// This is an InflaterInputStream that reads the files baseInputStream an zip archive
|
||||
/// one after another. It has a special method to get the zip entry of
|
||||
/// the next file. The zip entry contains information about the file name
|
||||
/// size, compressed size, Crc, etc.
|
||||
/// It includes support for Stored and Deflated entries.
|
||||
/// <br/>
|
||||
/// <br/>Author of the original java version : Jochen Hoenicke
|
||||
/// </summary>
|
||||
///
|
||||
/// <example> This sample shows how to read a zip file
|
||||
/// <code lang="C#">
|
||||
/// using System;
|
||||
/// using System.Text;
|
||||
/// using System.IO;
|
||||
///
|
||||
/// using ICSharpCode.SharpZipLib.Zip;
|
||||
///
|
||||
/// class MainClass
|
||||
/// {
|
||||
/// public static void Main(string[] args)
|
||||
/// {
|
||||
/// using ( ZipInputStream s = new ZipInputStream(File.OpenRead(args[0]))) {
|
||||
///
|
||||
/// ZipEntry theEntry;
|
||||
/// const int size = 2048;
|
||||
/// byte[] data = new byte[2048];
|
||||
///
|
||||
/// while ((theEntry = s.GetNextEntry()) != null) {
|
||||
/// if ( entry.IsFile ) {
|
||||
/// Console.Write("Show contents (y/n) ?");
|
||||
/// if (Console.ReadLine() == "y") {
|
||||
/// while (true) {
|
||||
/// size = s.Read(data, 0, data.Length);
|
||||
/// if (size > 0) {
|
||||
/// Console.Write(new ASCIIEncoding().GetString(data, 0, size));
|
||||
/// } else {
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class ZipInputStream : InflaterInputStream
|
||||
{
|
||||
#region Instance Fields
|
||||
|
||||
/// <summary>
|
||||
/// Delegate for reading bytes from a stream.
|
||||
/// </summary>
|
||||
delegate int ReadDataHandler(byte[] b, int offset, int length);
|
||||
|
||||
/// <summary>
|
||||
/// The current reader this instance.
|
||||
/// </summary>
|
||||
ReadDataHandler internalReader;
|
||||
|
||||
Crc32 crc = new Crc32();
|
||||
ZipEntry entry;
|
||||
|
||||
long size;
|
||||
int method;
|
||||
int flags;
|
||||
string password;
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Creates a new Zip input stream, for reading a zip archive.
|
||||
/// </summary>
|
||||
/// <param name="baseInputStream">The underlying <see cref="Stream"/> providing data.</param>
|
||||
public ZipInputStream(Stream baseInputStream)
|
||||
: base(baseInputStream, new Inflater(true))
|
||||
{
|
||||
internalReader = new ReadDataHandler(ReadingNotAvailable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Zip input stream, for reading a zip archive.
|
||||
/// </summary>
|
||||
/// <param name="baseInputStream">The underlying <see cref="Stream"/> providing data.</param>
|
||||
/// <param name="bufferSize">Size of the buffer.</param>
|
||||
public ZipInputStream( Stream baseInputStream, int bufferSize )
|
||||
: base(baseInputStream, new Inflater(true), bufferSize)
|
||||
{
|
||||
internalReader = new ReadDataHandler(ReadingNotAvailable);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Optional password used for encryption when non-null
|
||||
/// </summary>
|
||||
/// <value>A password for all encrypted <see cref="ZipEntry">entries </see> in this <see cref="ZipInputStream"/></value>
|
||||
public string Password
|
||||
{
|
||||
get {
|
||||
return password;
|
||||
}
|
||||
set {
|
||||
password = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating if there is a current entry and it can be decompressed
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The entry can only be decompressed if the library supports the zip features required to extract it.
|
||||
/// See the <see cref="ZipEntry.Version">ZipEntry Version</see> property for more details.
|
||||
/// </remarks>
|
||||
public bool CanDecompressEntry {
|
||||
get {
|
||||
return (entry != null) && entry.CanDecompress;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances to the next entry in the archive
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The next <see cref="ZipEntry">entry</see> in the archive or null if there are no more entries.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// If the previous entry is still open <see cref="CloseEntry">CloseEntry</see> is called.
|
||||
/// </remarks>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Input stream is closed
|
||||
/// </exception>
|
||||
/// <exception cref="ZipException">
|
||||
/// Password is not set, password is invalid, compression method is invalid,
|
||||
/// version required to extract is not supported
|
||||
/// </exception>
|
||||
public ZipEntry GetNextEntry()
|
||||
{
|
||||
if (crc == null) {
|
||||
throw new InvalidOperationException("Closed.");
|
||||
}
|
||||
|
||||
if (entry != null) {
|
||||
CloseEntry();
|
||||
}
|
||||
|
||||
int header = inputBuffer.ReadLeInt();
|
||||
|
||||
if (header == ZipConstants.CentralHeaderSignature ||
|
||||
header == ZipConstants.EndOfCentralDirectorySignature ||
|
||||
header == ZipConstants.CentralHeaderDigitalSignature ||
|
||||
header == ZipConstants.ArchiveExtraDataSignature ||
|
||||
header == ZipConstants.Zip64CentralFileHeaderSignature) {
|
||||
// No more individual entries exist
|
||||
Close();
|
||||
return null;
|
||||
}
|
||||
|
||||
// -jr- 07-Dec-2003 Ignore spanning temporary signatures if found
|
||||
// Spanning signature is same as descriptor signature and is untested as yet.
|
||||
if ( (header == ZipConstants.SpanningTempSignature) || (header == ZipConstants.SpanningSignature) ) {
|
||||
header = inputBuffer.ReadLeInt();
|
||||
}
|
||||
|
||||
if (header != ZipConstants.LocalHeaderSignature) {
|
||||
throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header));
|
||||
}
|
||||
|
||||
short versionRequiredToExtract = (short)inputBuffer.ReadLeShort();
|
||||
|
||||
flags = inputBuffer.ReadLeShort();
|
||||
method = inputBuffer.ReadLeShort();
|
||||
uint dostime = (uint)inputBuffer.ReadLeInt();
|
||||
int crc2 = inputBuffer.ReadLeInt();
|
||||
csize = inputBuffer.ReadLeInt();
|
||||
size = inputBuffer.ReadLeInt();
|
||||
int nameLen = inputBuffer.ReadLeShort();
|
||||
int extraLen = inputBuffer.ReadLeShort();
|
||||
|
||||
bool isCrypted = (flags & 1) == 1;
|
||||
|
||||
byte[] buffer = new byte[nameLen];
|
||||
inputBuffer.ReadRawBuffer(buffer);
|
||||
|
||||
string name = ZipConstants.ConvertToStringExt(flags, buffer);
|
||||
|
||||
entry = new ZipEntry(name, versionRequiredToExtract);
|
||||
entry.Flags = flags;
|
||||
|
||||
entry.CompressionMethod = (CompressionMethod)method;
|
||||
|
||||
if ((flags & 8) == 0) {
|
||||
entry.Crc = crc2 & 0xFFFFFFFFL;
|
||||
entry.Size = size & 0xFFFFFFFFL;
|
||||
entry.CompressedSize = csize & 0xFFFFFFFFL;
|
||||
|
||||
entry.CryptoCheckValue = (byte)((crc2 >> 24) & 0xff);
|
||||
|
||||
} else {
|
||||
|
||||
// This allows for GNU, WinZip and possibly other archives, the PKZIP spec
|
||||
// says these values are zero under these circumstances.
|
||||
if (crc2 != 0) {
|
||||
entry.Crc = crc2 & 0xFFFFFFFFL;
|
||||
}
|
||||
|
||||
if (size != 0) {
|
||||
entry.Size = size & 0xFFFFFFFFL;
|
||||
}
|
||||
|
||||
if (csize != 0) {
|
||||
entry.CompressedSize = csize & 0xFFFFFFFFL;
|
||||
}
|
||||
|
||||
entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
|
||||
}
|
||||
|
||||
entry.DosTime = dostime;
|
||||
|
||||
// If local header requires Zip64 is true then the extended header should contain
|
||||
// both values.
|
||||
|
||||
// Handle extra data if present. This can set/alter some fields of the entry.
|
||||
if (extraLen > 0) {
|
||||
byte[] extra = new byte[extraLen];
|
||||
inputBuffer.ReadRawBuffer(extra);
|
||||
entry.ExtraData = extra;
|
||||
}
|
||||
|
||||
entry.ProcessExtraData(true);
|
||||
if ( entry.CompressedSize >= 0 ) {
|
||||
csize = entry.CompressedSize;
|
||||
}
|
||||
|
||||
if ( entry.Size >= 0 ) {
|
||||
size = entry.Size;
|
||||
}
|
||||
|
||||
if (method == (int)CompressionMethod.Stored && (!isCrypted && csize != size || (isCrypted && csize - ZipConstants.CryptoHeaderSize != size))) {
|
||||
throw new ZipException("Stored, but compressed != uncompressed");
|
||||
}
|
||||
|
||||
// Determine how to handle reading of data if this is attempted.
|
||||
if (entry.IsCompressionMethodSupported()) {
|
||||
internalReader = new ReadDataHandler(InitialRead);
|
||||
} else {
|
||||
internalReader = new ReadDataHandler(ReadingNotSupported);
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read data descriptor at the end of compressed data.
|
||||
/// </summary>
|
||||
void ReadDataDescriptor()
|
||||
{
|
||||
if (inputBuffer.ReadLeInt() != ZipConstants.DataDescriptorSignature) {
|
||||
throw new ZipException("Data descriptor signature not found");
|
||||
}
|
||||
|
||||
entry.Crc = inputBuffer.ReadLeInt() & 0xFFFFFFFFL;
|
||||
|
||||
if ( entry.LocalHeaderRequiresZip64 ) {
|
||||
csize = inputBuffer.ReadLeLong();
|
||||
size = inputBuffer.ReadLeLong();
|
||||
} else {
|
||||
csize = inputBuffer.ReadLeInt();
|
||||
size = inputBuffer.ReadLeInt();
|
||||
}
|
||||
entry.CompressedSize = csize;
|
||||
entry.Size = size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Complete cleanup as the final part of closing.
|
||||
/// </summary>
|
||||
/// <param name="testCrc">True if the crc value should be tested</param>
|
||||
void CompleteCloseEntry(bool testCrc)
|
||||
{
|
||||
StopDecrypting();
|
||||
|
||||
if ((flags & 8) != 0) {
|
||||
ReadDataDescriptor();
|
||||
}
|
||||
|
||||
size = 0;
|
||||
|
||||
if ( testCrc &&
|
||||
((crc.Value & 0xFFFFFFFFL) != entry.Crc) && (entry.Crc != -1)) {
|
||||
throw new ZipException("CRC mismatch");
|
||||
}
|
||||
|
||||
crc.Reset();
|
||||
|
||||
if (method == (int)CompressionMethod.Deflated) {
|
||||
inf.Reset();
|
||||
}
|
||||
entry = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the current zip entry and moves to the next one.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The stream is closed
|
||||
/// </exception>
|
||||
/// <exception cref="ZipException">
|
||||
/// The Zip stream ends early
|
||||
/// </exception>
|
||||
public void CloseEntry()
|
||||
{
|
||||
if (crc == null) {
|
||||
throw new InvalidOperationException("Closed");
|
||||
}
|
||||
|
||||
if (entry == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (method == (int)CompressionMethod.Deflated) {
|
||||
if ((flags & 8) != 0) {
|
||||
// We don't know how much we must skip, read until end.
|
||||
byte[] tmp = new byte[4096];
|
||||
|
||||
// Read will close this entry
|
||||
while (Read(tmp, 0, tmp.Length) > 0) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
csize -= inf.TotalIn;
|
||||
inputBuffer.Available += inf.RemainingInput;
|
||||
}
|
||||
|
||||
if ( (inputBuffer.Available > csize) && (csize >= 0) ) {
|
||||
inputBuffer.Available = (int)((long)inputBuffer.Available - csize);
|
||||
} else {
|
||||
csize -= inputBuffer.Available;
|
||||
inputBuffer.Available = 0;
|
||||
while (csize != 0) {
|
||||
long skipped = base.Skip(csize);
|
||||
|
||||
if (skipped <= 0) {
|
||||
throw new ZipException("Zip archive ends early.");
|
||||
}
|
||||
|
||||
csize -= skipped;
|
||||
}
|
||||
}
|
||||
|
||||
CompleteCloseEntry(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns 1 if there is an entry available
|
||||
/// Otherwise returns 0.
|
||||
/// </summary>
|
||||
public override int Available {
|
||||
get {
|
||||
return entry != null ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current size that can be read from the current entry if available
|
||||
/// </summary>
|
||||
/// <exception cref="ZipException">Thrown if the entry size is not known.</exception>
|
||||
/// <exception cref="InvalidOperationException">Thrown if no entry is currently available.</exception>
|
||||
public override long Length
|
||||
{
|
||||
get {
|
||||
if ( entry != null ) {
|
||||
if ( entry.Size >= 0 ) {
|
||||
return entry.Size;
|
||||
} else {
|
||||
throw new ZipException("Length not available for the current entry");
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new InvalidOperationException("No current entry");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte from the current zip entry.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The byte or -1 if end of stream is reached.
|
||||
/// </returns>
|
||||
public override int ReadByte()
|
||||
{
|
||||
byte[] b = new byte[1];
|
||||
if (Read(b, 0, 1) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
return b[0] & 0xff;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle attempts to read by throwing an <see cref="InvalidOperationException"/>.
|
||||
/// </summary>
|
||||
/// <param name="destination">The destination array to store data in.</param>
|
||||
/// <param name="offset">The offset at which data read should be stored.</param>
|
||||
/// <param name="count">The maximum number of bytes to read.</param>
|
||||
/// <returns>Returns the number of bytes actually read.</returns>
|
||||
int ReadingNotAvailable(byte[] destination, int offset, int count)
|
||||
{
|
||||
throw new InvalidOperationException("Unable to read from this stream");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle attempts to read from this entry by throwing an exception
|
||||
/// </summary>
|
||||
int ReadingNotSupported(byte[] destination, int offset, int count)
|
||||
{
|
||||
throw new ZipException("The compression method for this entry is not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform the initial read on an entry which may include
|
||||
/// reading encryption headers and setting up inflation.
|
||||
/// </summary>
|
||||
/// <param name="destination">The destination to fill with data read.</param>
|
||||
/// <param name="offset">The offset to start reading at.</param>
|
||||
/// <param name="count">The maximum number of bytes to read.</param>
|
||||
/// <returns>The actual number of bytes read.</returns>
|
||||
int InitialRead(byte[] destination, int offset, int count)
|
||||
{
|
||||
if ( !CanDecompressEntry ) {
|
||||
throw new ZipException("Library cannot extract this entry. Version required is (" + entry.Version.ToString() + ")");
|
||||
}
|
||||
|
||||
// Handle encryption if required.
|
||||
if (entry.IsCrypted) {
|
||||
#if NETCF_1_0
|
||||
throw new ZipException("Encryption not supported for Compact Framework 1.0");
|
||||
#else
|
||||
if (password == null) {
|
||||
throw new ZipException("No password set.");
|
||||
}
|
||||
|
||||
// Generate and set crypto transform...
|
||||
PkzipClassicManaged managed = new PkzipClassicManaged();
|
||||
byte[] key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(password));
|
||||
|
||||
inputBuffer.CryptoTransform = managed.CreateDecryptor(key, null);
|
||||
|
||||
byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
|
||||
inputBuffer.ReadClearTextBuffer(cryptbuffer, 0, ZipConstants.CryptoHeaderSize);
|
||||
|
||||
if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {
|
||||
throw new ZipException("Invalid password");
|
||||
}
|
||||
|
||||
if (csize >= ZipConstants.CryptoHeaderSize) {
|
||||
csize -= ZipConstants.CryptoHeaderSize;
|
||||
}
|
||||
else if ( (entry.Flags & (int)GeneralBitFlags.Descriptor) == 0 ) {
|
||||
throw new ZipException(string.Format("Entry compressed size {0} too small for encryption", csize));
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#if !NETCF_1_0
|
||||
inputBuffer.CryptoTransform = null;
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((csize > 0) || ((flags & (int)GeneralBitFlags.Descriptor) != 0)) {
|
||||
if ((method == (int)CompressionMethod.Deflated) && (inputBuffer.Available > 0)) {
|
||||
inputBuffer.SetInflaterInput(inf);
|
||||
}
|
||||
|
||||
internalReader = new ReadDataHandler(BodyRead);
|
||||
return BodyRead(destination, offset, count);
|
||||
}
|
||||
else {
|
||||
internalReader = new ReadDataHandler(ReadingNotAvailable);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a block of bytes from the stream.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The destination for the bytes.</param>
|
||||
/// <param name="offset">The index to start storing data.</param>
|
||||
/// <param name="count">The number of bytes to attempt to read.</param>
|
||||
/// <returns>Returns the number of bytes read.</returns>
|
||||
/// <remarks>Zero bytes read means end of stream.</remarks>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if ( buffer == null ) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
if ( offset < 0 ) {
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("offset", "Cannot be negative");
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( count < 0 ) {
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("count", "Cannot be negative");
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( (buffer.Length - offset) < count ) {
|
||||
throw new ArgumentException("Invalid offset/count combination");
|
||||
}
|
||||
|
||||
return internalReader(buffer, offset, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a block of bytes from the current zip entry.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The number of bytes read (this may be less than the length requested, even before the end of stream), or 0 on end of stream.
|
||||
/// </returns>
|
||||
/// <exception name="IOException">
|
||||
/// An i/o error occured.
|
||||
/// </exception>
|
||||
/// <exception cref="ZipException">
|
||||
/// The deflated stream is corrupted.
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The stream is not open.
|
||||
/// </exception>
|
||||
int BodyRead(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if ( crc == null ) {
|
||||
throw new InvalidOperationException("Closed");
|
||||
}
|
||||
|
||||
if ( (entry == null) || (count <= 0) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( offset + count > buffer.Length ) {
|
||||
throw new ArgumentException("Offset + count exceeds buffer size");
|
||||
}
|
||||
|
||||
bool finished = false;
|
||||
|
||||
switch (method) {
|
||||
case (int)CompressionMethod.Deflated:
|
||||
count = base.Read(buffer, offset, count);
|
||||
if (count <= 0) {
|
||||
if (!inf.IsFinished) {
|
||||
throw new ZipException("Inflater not finished!");
|
||||
}
|
||||
inputBuffer.Available = inf.RemainingInput;
|
||||
|
||||
// A csize of -1 is from an unpatched local header
|
||||
if ((flags & 8) == 0 &&
|
||||
(inf.TotalIn != csize && csize != 0xFFFFFFFF && csize != -1 || inf.TotalOut != size)) {
|
||||
throw new ZipException("Size mismatch: " + csize + ";" + size + " <-> " + inf.TotalIn + ";" + inf.TotalOut);
|
||||
}
|
||||
inf.Reset();
|
||||
finished = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case (int)CompressionMethod.Stored:
|
||||
if ( (count > csize) && (csize >= 0) ) {
|
||||
count = (int)csize;
|
||||
}
|
||||
|
||||
if ( count > 0 ) {
|
||||
count = inputBuffer.ReadClearTextBuffer(buffer, offset, count);
|
||||
if (count > 0) {
|
||||
csize -= count;
|
||||
size -= count;
|
||||
}
|
||||
}
|
||||
|
||||
if (csize == 0) {
|
||||
finished = true;
|
||||
} else {
|
||||
if (count < 0) {
|
||||
throw new ZipException("EOF in stored block");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
crc.Update(buffer, offset, count);
|
||||
}
|
||||
|
||||
if (finished) {
|
||||
CompleteCloseEntry(true);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the zip input stream
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
internalReader = new ReadDataHandler(ReadingNotAvailable);
|
||||
crc = null;
|
||||
entry = null;
|
||||
|
||||
base.Close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,269 @@
|
|||
// ZipNameTransform.cs
|
||||
//
|
||||
// Copyright 2005 John Reilly
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using ICSharpCode.SharpZipLib.Core;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip
|
||||
{
|
||||
/// <summary>
|
||||
/// ZipNameTransform transforms names as per the Zip file naming convention.
|
||||
/// </summary>
|
||||
/// <remarks>The use of absolute names is supported although its use is not valid
|
||||
/// according to Zip naming conventions, and should not be used if maximum compatability is desired.</remarks>
|
||||
public class ZipNameTransform : INameTransform
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialize a new instance of <see cref="ZipNameTransform"></see>
|
||||
/// </summary>
|
||||
public ZipNameTransform()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of <see cref="ZipNameTransform"></see>
|
||||
/// </summary>
|
||||
/// <param name="trimPrefix">The string to trim from the front of paths if found.</param>
|
||||
public ZipNameTransform(string trimPrefix)
|
||||
{
|
||||
TrimPrefix = trimPrefix;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Static constructor.
|
||||
/// </summary>
|
||||
static ZipNameTransform()
|
||||
{
|
||||
char[] invalidPathChars;
|
||||
#if NET_1_0 || NET_1_1 || NETCF_1_0
|
||||
invalidPathChars = Path.InvalidPathChars;
|
||||
#else
|
||||
invalidPathChars = Path.GetInvalidPathChars();
|
||||
#endif
|
||||
int howMany = invalidPathChars.Length + 2;
|
||||
|
||||
InvalidEntryCharsRelaxed = new char[howMany];
|
||||
Array.Copy(invalidPathChars, 0, InvalidEntryCharsRelaxed, 0, invalidPathChars.Length);
|
||||
InvalidEntryCharsRelaxed[howMany - 1] = '*';
|
||||
InvalidEntryCharsRelaxed[howMany - 2] = '?';
|
||||
|
||||
howMany = invalidPathChars.Length + 4;
|
||||
InvalidEntryChars = new char[howMany];
|
||||
Array.Copy(invalidPathChars, 0, InvalidEntryChars, 0, invalidPathChars.Length);
|
||||
InvalidEntryChars[howMany - 1] = ':';
|
||||
InvalidEntryChars[howMany - 2] = '\\';
|
||||
InvalidEntryChars[howMany - 3] = '*';
|
||||
InvalidEntryChars[howMany - 4] = '?';
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transform a windows directory name according to the Zip file naming conventions.
|
||||
/// </summary>
|
||||
/// <param name="name">The directory name to transform.</param>
|
||||
/// <returns>The transformed name.</returns>
|
||||
public string TransformDirectory(string name)
|
||||
{
|
||||
name = TransformFile(name);
|
||||
if (name.Length > 0) {
|
||||
if ( !name.EndsWith("/") ) {
|
||||
name += "/";
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new ZipException("Cannot have an empty directory name");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transform a windows file name according to the Zip file naming conventions.
|
||||
/// </summary>
|
||||
/// <param name="name">The file name to transform.</param>
|
||||
/// <returns>The transformed name.</returns>
|
||||
public string TransformFile(string name)
|
||||
{
|
||||
if (name != null) {
|
||||
string lowerName = name.ToLower();
|
||||
if ( (trimPrefix_ != null) && (lowerName.IndexOf(trimPrefix_) == 0) ) {
|
||||
name = name.Substring(trimPrefix_.Length);
|
||||
}
|
||||
|
||||
name = name.Replace(@"\", "/");
|
||||
name = WindowsPathUtils.DropPathRoot(name);
|
||||
|
||||
// Drop any leading slashes.
|
||||
while ((name.Length > 0) && (name[0] == '/'))
|
||||
{
|
||||
name = name.Remove(0, 1);
|
||||
}
|
||||
|
||||
// Drop any trailing slashes.
|
||||
while ((name.Length > 0) && (name[name.Length - 1] == '/'))
|
||||
{
|
||||
name = name.Remove(name.Length - 1, 1);
|
||||
}
|
||||
|
||||
// Convert consecutive // characters to /
|
||||
int index = name.IndexOf("//");
|
||||
while (index >= 0)
|
||||
{
|
||||
name = name.Remove(index, 1);
|
||||
index = name.IndexOf("//");
|
||||
}
|
||||
|
||||
name = MakeValidName(name, '_');
|
||||
}
|
||||
else {
|
||||
name = string.Empty;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the path prefix to be trimmed from paths if present.
|
||||
/// </summary>
|
||||
/// <remarks>The prefix is trimmed before any conversion from
|
||||
/// a windows path is done.</remarks>
|
||||
public string TrimPrefix
|
||||
{
|
||||
get { return trimPrefix_; }
|
||||
set {
|
||||
trimPrefix_ = value;
|
||||
if (trimPrefix_ != null) {
|
||||
trimPrefix_ = trimPrefix_.ToLower();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Force a name to be valid by replacing invalid characters with a fixed value
|
||||
/// </summary>
|
||||
/// <param name="name">The name to force valid</param>
|
||||
/// <param name="replacement">The replacement character to use.</param>
|
||||
/// <returns>Returns a valid name</returns>
|
||||
static string MakeValidName(string name, char replacement)
|
||||
{
|
||||
int index = name.IndexOfAny(InvalidEntryChars);
|
||||
if (index >= 0) {
|
||||
StringBuilder builder = new StringBuilder(name);
|
||||
|
||||
while (index >= 0 ) {
|
||||
builder[index] = replacement;
|
||||
|
||||
if (index >= name.Length) {
|
||||
index = -1;
|
||||
}
|
||||
else {
|
||||
index = name.IndexOfAny(InvalidEntryChars, index + 1);
|
||||
}
|
||||
}
|
||||
name = builder.ToString();
|
||||
}
|
||||
|
||||
if (name.Length > 0xffff) {
|
||||
throw new PathTooLongException();
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test a name to see if it is a valid name for a zip entry.
|
||||
/// </summary>
|
||||
/// <param name="name">The name to test.</param>
|
||||
/// <param name="relaxed">If true checking is relaxed about windows file names and absolute paths.</param>
|
||||
/// <returns>Returns true if the name is a valid zip name; false otherwise.</returns>
|
||||
/// <remarks>Zip path names are actually in Unix format, and should only contain relative paths.
|
||||
/// This means that any path stored should not contain a drive or
|
||||
/// device letter, or a leading slash. All slashes should forward slashes '/'.
|
||||
/// An empty name is valid for a file where the input comes from standard input.
|
||||
/// A null name is not considered valid.
|
||||
/// </remarks>
|
||||
public static bool IsValidName(string name, bool relaxed)
|
||||
{
|
||||
bool result = (name != null);
|
||||
|
||||
if ( result ) {
|
||||
if ( relaxed ) {
|
||||
result = name.IndexOfAny(InvalidEntryCharsRelaxed) < 0;
|
||||
}
|
||||
else {
|
||||
result =
|
||||
(name.IndexOfAny(InvalidEntryChars) < 0) &&
|
||||
(name.IndexOf('/') != 0);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test a name to see if it is a valid name for a zip entry.
|
||||
/// </summary>
|
||||
/// <param name="name">The name to test.</param>
|
||||
/// <returns>Returns true if the name is a valid zip name; false otherwise.</returns>
|
||||
/// <remarks>Zip path names are actually in unix format,
|
||||
/// and should only contain relative paths if a path is present.
|
||||
/// This means that the path stored should not contain a drive or
|
||||
/// device letter, or a leading slash. All slashes should forward slashes '/'.
|
||||
/// An empty name is valid where the input comes from standard input.
|
||||
/// A null name is not considered valid.
|
||||
/// </remarks>
|
||||
public static bool IsValidName(string name)
|
||||
{
|
||||
bool result =
|
||||
(name != null) &&
|
||||
(name.IndexOfAny(InvalidEntryChars) < 0) &&
|
||||
(name.IndexOf('/') != 0)
|
||||
;
|
||||
return result;
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
string trimPrefix_;
|
||||
#endregion
|
||||
|
||||
#region Class Fields
|
||||
static readonly char[] InvalidEntryChars;
|
||||
static readonly char[] InvalidEntryCharsRelaxed;
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,900 @@
|
|||
// ZipOutputStream.cs
|
||||
//
|
||||
// Copyright (C) 2001 Mike Krueger
|
||||
// Copyright (C) 2004 John Reilly
|
||||
//
|
||||
// This file was translated from java, it was part of the GNU Classpath
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is
|
||||
// making a combined work based on this library. Thus, the terms and
|
||||
// conditions of the GNU General Public License cover the whole
|
||||
// combination.
|
||||
//
|
||||
// As a special exception, the copyright holders of this library give you
|
||||
// permission to link this library with independent modules to produce an
|
||||
// executable, regardless of the license terms of these independent
|
||||
// modules, and to copy and distribute the resulting executable under
|
||||
// terms of your choice, provided that you also meet, for each linked
|
||||
// independent module, the terms and conditions of the license of that
|
||||
// module. An independent module is a module which is not derived from
|
||||
// or based on this library. If you modify this library, you may extend
|
||||
// this exception to your version of the library, but you are not
|
||||
// obligated to do so. If you do not wish to do so, delete this
|
||||
// exception statement from your version.
|
||||
|
||||
// HISTORY
|
||||
// 22-12-2009 Z-1649 Added AES support
|
||||
// 22-02-2010 Z-1648 Zero byte entries would create invalid zip files
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
|
||||
using ICSharpCode.SharpZipLib.Checksums;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a DeflaterOutputStream that writes the files into a zip
|
||||
/// archive one after another. It has a special method to start a new
|
||||
/// zip entry. The zip entries contains information about the file name
|
||||
/// size, compressed size, CRC, etc.
|
||||
///
|
||||
/// It includes support for Stored and Deflated entries.
|
||||
/// This class is not thread safe.
|
||||
/// <br/>
|
||||
/// <br/>Author of the original java version : Jochen Hoenicke
|
||||
/// </summary>
|
||||
/// <example> This sample shows how to create a zip file
|
||||
/// <code>
|
||||
/// using System;
|
||||
/// using System.IO;
|
||||
///
|
||||
/// using ICSharpCode.SharpZipLib.Core;
|
||||
/// using ICSharpCode.SharpZipLib.Zip;
|
||||
///
|
||||
/// class MainClass
|
||||
/// {
|
||||
/// public static void Main(string[] args)
|
||||
/// {
|
||||
/// string[] filenames = Directory.GetFiles(args[0]);
|
||||
/// byte[] buffer = new byte[4096];
|
||||
///
|
||||
/// using ( ZipOutputStream s = new ZipOutputStream(File.Create(args[1])) ) {
|
||||
///
|
||||
/// s.SetLevel(9); // 0 - store only to 9 - means best compression
|
||||
///
|
||||
/// foreach (string file in filenames) {
|
||||
/// ZipEntry entry = new ZipEntry(file);
|
||||
/// s.PutNextEntry(entry);
|
||||
///
|
||||
/// using (FileStream fs = File.OpenRead(file)) {
|
||||
/// StreamUtils.Copy(fs, s, buffer);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class ZipOutputStream : DeflaterOutputStream
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Creates a new Zip output stream, writing a zip archive.
|
||||
/// </summary>
|
||||
/// <param name="baseOutputStream">
|
||||
/// The output stream to which the archive contents are written.
|
||||
/// </param>
|
||||
public ZipOutputStream(Stream baseOutputStream)
|
||||
: base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Zip output stream, writing a zip archive.
|
||||
/// </summary>
|
||||
/// <param name="baseOutputStream">The output stream to which the archive contents are written.</param>
|
||||
/// <param name="bufferSize">Size of the buffer to use.</param>
|
||||
public ZipOutputStream( Stream baseOutputStream, int bufferSize )
|
||||
: base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true), bufferSize)
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets a flag value of true if the central header has been added for this archive; false if it has not been added.
|
||||
/// </summary>
|
||||
/// <remarks>No further entries can be added once this has been done.</remarks>
|
||||
public bool IsFinished
|
||||
{
|
||||
get {
|
||||
return entries == null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the zip file comment.
|
||||
/// </summary>
|
||||
/// <param name="comment">
|
||||
/// The comment text for the entire archive.
|
||||
/// </param>
|
||||
/// <exception name ="ArgumentOutOfRangeException">
|
||||
/// The converted comment is longer than 0xffff bytes.
|
||||
/// </exception>
|
||||
public void SetComment(string comment)
|
||||
{
|
||||
// TODO: Its not yet clear how to handle unicode comments here.
|
||||
byte[] commentBytes = ZipConstants.ConvertToArray(comment);
|
||||
if (commentBytes.Length > 0xffff) {
|
||||
throw new ArgumentOutOfRangeException("comment");
|
||||
}
|
||||
zipComment = commentBytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the compression level. The new level will be activated
|
||||
/// immediately.
|
||||
/// </summary>
|
||||
/// <param name="level">The new compression level (1 to 9).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Level specified is not supported.
|
||||
/// </exception>
|
||||
/// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Deflater"/>
|
||||
public void SetLevel(int level)
|
||||
{
|
||||
deflater_.SetLevel(level);
|
||||
defaultCompressionLevel = level;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current deflater compression level
|
||||
/// </summary>
|
||||
/// <returns>The current compression level</returns>
|
||||
public int GetLevel()
|
||||
{
|
||||
return deflater_.GetLevel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get / set a value indicating how Zip64 Extension usage is determined when adding entries.
|
||||
/// </summary>
|
||||
/// <remarks>Older archivers may not understand Zip64 extensions.
|
||||
/// If backwards compatability is an issue be careful when adding <see cref="ZipEntry.Size">entries</see> to an archive.
|
||||
/// Setting this property to off is workable but less desirable as in those circumstances adding a file
|
||||
/// larger then 4GB will fail.</remarks>
|
||||
public UseZip64 UseZip64
|
||||
{
|
||||
get { return useZip64_; }
|
||||
set { useZip64_ = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an unsigned short in little endian byte order.
|
||||
/// </summary>
|
||||
private void WriteLeShort(int value)
|
||||
{
|
||||
unchecked {
|
||||
baseOutputStream_.WriteByte((byte)(value & 0xff));
|
||||
baseOutputStream_.WriteByte((byte)((value >> 8) & 0xff));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an int in little endian byte order.
|
||||
/// </summary>
|
||||
private void WriteLeInt(int value)
|
||||
{
|
||||
unchecked {
|
||||
WriteLeShort(value);
|
||||
WriteLeShort(value >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an int in little endian byte order.
|
||||
/// </summary>
|
||||
private void WriteLeLong(long value)
|
||||
{
|
||||
unchecked {
|
||||
WriteLeInt((int)value);
|
||||
WriteLeInt((int)(value >> 32));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts a new Zip entry. It automatically closes the previous
|
||||
/// entry if present.
|
||||
/// All entry elements bar name are optional, but must be correct if present.
|
||||
/// If the compression method is stored and the output is not patchable
|
||||
/// the compression for that entry is automatically changed to deflate level 0
|
||||
/// </summary>
|
||||
/// <param name="entry">
|
||||
/// the entry.
|
||||
/// </param>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// if entry passed is null.
|
||||
/// </exception>
|
||||
/// <exception cref="System.IO.IOException">
|
||||
/// if an I/O error occured.
|
||||
/// </exception>
|
||||
/// <exception cref="System.InvalidOperationException">
|
||||
/// if stream was finished
|
||||
/// </exception>
|
||||
/// <exception cref="ZipException">
|
||||
/// Too many entries in the Zip file<br/>
|
||||
/// Entry name is too long<br/>
|
||||
/// Finish has already been called<br/>
|
||||
/// </exception>
|
||||
public void PutNextEntry(ZipEntry entry)
|
||||
{
|
||||
if ( entry == null ) {
|
||||
throw new ArgumentNullException("entry");
|
||||
}
|
||||
|
||||
if (entries == null) {
|
||||
throw new InvalidOperationException("ZipOutputStream was finished");
|
||||
}
|
||||
|
||||
if (curEntry != null) {
|
||||
CloseEntry();
|
||||
}
|
||||
|
||||
if (entries.Count == int.MaxValue) {
|
||||
throw new ZipException("Too many entries for Zip file");
|
||||
}
|
||||
|
||||
CompressionMethod method = entry.CompressionMethod;
|
||||
int compressionLevel = defaultCompressionLevel;
|
||||
|
||||
// Clear flags that the library manages internally
|
||||
entry.Flags &= (int)GeneralBitFlags.UnicodeText;
|
||||
patchEntryHeader = false;
|
||||
|
||||
bool headerInfoAvailable;
|
||||
|
||||
// No need to compress - definitely no data.
|
||||
if (entry.Size == 0)
|
||||
{
|
||||
entry.CompressedSize = entry.Size;
|
||||
entry.Crc = 0;
|
||||
method = CompressionMethod.Stored;
|
||||
headerInfoAvailable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
headerInfoAvailable = (entry.Size >= 0) && entry.HasCrc;
|
||||
|
||||
// Switch to deflation if storing isnt possible.
|
||||
if (method == CompressionMethod.Stored)
|
||||
{
|
||||
if (!headerInfoAvailable)
|
||||
{
|
||||
if (!CanPatchEntries)
|
||||
{
|
||||
// Can't patch entries so storing is not possible.
|
||||
method = CompressionMethod.Deflated;
|
||||
compressionLevel = 0;
|
||||
}
|
||||
}
|
||||
else // entry.size must be > 0
|
||||
{
|
||||
entry.CompressedSize = entry.Size;
|
||||
headerInfoAvailable = entry.HasCrc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (headerInfoAvailable == false) {
|
||||
if (CanPatchEntries == false) {
|
||||
// Only way to record size and compressed size is to append a data descriptor
|
||||
// after compressed data.
|
||||
|
||||
// Stored entries of this form have already been converted to deflating.
|
||||
entry.Flags |= 8;
|
||||
} else {
|
||||
patchEntryHeader = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Password != null) {
|
||||
entry.IsCrypted = true;
|
||||
if (entry.Crc < 0) {
|
||||
// Need to append a data descriptor as the crc isnt available for use
|
||||
// with encryption, the date is used instead. Setting the flag
|
||||
// indicates this to the decompressor.
|
||||
entry.Flags |= 8;
|
||||
}
|
||||
}
|
||||
|
||||
entry.Offset = offset;
|
||||
entry.CompressionMethod = (CompressionMethod)method;
|
||||
|
||||
curMethod = method;
|
||||
sizePatchPos = -1;
|
||||
|
||||
if ( (useZip64_ == UseZip64.On) || ((entry.Size < 0) && (useZip64_ == UseZip64.Dynamic)) ) {
|
||||
entry.ForceZip64();
|
||||
}
|
||||
|
||||
// Write the local file header
|
||||
WriteLeInt(ZipConstants.LocalHeaderSignature);
|
||||
|
||||
WriteLeShort(entry.Version);
|
||||
WriteLeShort(entry.Flags);
|
||||
WriteLeShort((byte)entry.CompressionMethodForHeader);
|
||||
WriteLeInt((int)entry.DosTime);
|
||||
|
||||
// TODO: Refactor header writing. Its done in several places.
|
||||
if (headerInfoAvailable == true) {
|
||||
WriteLeInt((int)entry.Crc);
|
||||
if ( entry.LocalHeaderRequiresZip64 ) {
|
||||
WriteLeInt(-1);
|
||||
WriteLeInt(-1);
|
||||
}
|
||||
else {
|
||||
WriteLeInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.CompressedSize);
|
||||
WriteLeInt((int)entry.Size);
|
||||
}
|
||||
} else {
|
||||
if (patchEntryHeader) {
|
||||
crcPatchPos = baseOutputStream_.Position;
|
||||
}
|
||||
WriteLeInt(0); // Crc
|
||||
|
||||
if ( patchEntryHeader ) {
|
||||
sizePatchPos = baseOutputStream_.Position;
|
||||
}
|
||||
|
||||
// For local header both sizes appear in Zip64 Extended Information
|
||||
if ( entry.LocalHeaderRequiresZip64 || patchEntryHeader ) {
|
||||
WriteLeInt(-1);
|
||||
WriteLeInt(-1);
|
||||
}
|
||||
else {
|
||||
WriteLeInt(0); // Compressed size
|
||||
WriteLeInt(0); // Uncompressed size
|
||||
}
|
||||
}
|
||||
|
||||
byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
|
||||
|
||||
if (name.Length > 0xFFFF) {
|
||||
throw new ZipException("Entry name too long.");
|
||||
}
|
||||
|
||||
ZipExtraData ed = new ZipExtraData(entry.ExtraData);
|
||||
|
||||
if (entry.LocalHeaderRequiresZip64) {
|
||||
ed.StartNewEntry();
|
||||
if (headerInfoAvailable) {
|
||||
ed.AddLeLong(entry.Size);
|
||||
ed.AddLeLong(entry.CompressedSize);
|
||||
}
|
||||
else {
|
||||
ed.AddLeLong(-1);
|
||||
ed.AddLeLong(-1);
|
||||
}
|
||||
ed.AddNewEntry(1);
|
||||
|
||||
if ( !ed.Find(1) ) {
|
||||
throw new ZipException("Internal error cant find extra data");
|
||||
}
|
||||
|
||||
if ( patchEntryHeader ) {
|
||||
sizePatchPos = ed.CurrentReadIndex;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ed.Delete(1);
|
||||
}
|
||||
|
||||
#if !NET_1_1 && !NETCF_2_0
|
||||
if (entry.AESKeySize > 0) {
|
||||
AddExtraDataAES(entry, ed);
|
||||
}
|
||||
#endif
|
||||
byte[] extra = ed.GetEntryData();
|
||||
|
||||
WriteLeShort(name.Length);
|
||||
WriteLeShort(extra.Length);
|
||||
|
||||
if ( name.Length > 0 ) {
|
||||
baseOutputStream_.Write(name, 0, name.Length);
|
||||
}
|
||||
|
||||
if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) {
|
||||
sizePatchPos += baseOutputStream_.Position;
|
||||
}
|
||||
|
||||
if ( extra.Length > 0 ) {
|
||||
baseOutputStream_.Write(extra, 0, extra.Length);
|
||||
}
|
||||
|
||||
offset += ZipConstants.LocalHeaderBaseSize + name.Length + extra.Length;
|
||||
// Fix offsetOfCentraldir for AES
|
||||
if (entry.AESKeySize > 0)
|
||||
offset += entry.AESOverheadSize;
|
||||
|
||||
// Activate the entry.
|
||||
curEntry = entry;
|
||||
crc.Reset();
|
||||
if (method == CompressionMethod.Deflated) {
|
||||
deflater_.Reset();
|
||||
deflater_.SetLevel(compressionLevel);
|
||||
}
|
||||
size = 0;
|
||||
|
||||
if (entry.IsCrypted) {
|
||||
#if !NET_1_1 && !NETCF_2_0
|
||||
if (entry.AESKeySize > 0) {
|
||||
WriteAESHeader(entry);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (entry.Crc < 0) { // so testing Zip will says its ok
|
||||
WriteEncryptionHeader(entry.DosTime << 16);
|
||||
} else {
|
||||
WriteEncryptionHeader(entry.Crc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the current entry, updating header and footer information as required
|
||||
/// </summary>
|
||||
/// <exception cref="System.IO.IOException">
|
||||
/// An I/O error occurs.
|
||||
/// </exception>
|
||||
/// <exception cref="System.InvalidOperationException">
|
||||
/// No entry is active.
|
||||
/// </exception>
|
||||
public void CloseEntry()
|
||||
{
|
||||
if (curEntry == null) {
|
||||
throw new InvalidOperationException("No open entry");
|
||||
}
|
||||
|
||||
long csize = size;
|
||||
|
||||
// First finish the deflater, if appropriate
|
||||
if (curMethod == CompressionMethod.Deflated) {
|
||||
if (size >= 0) {
|
||||
base.Finish();
|
||||
csize = deflater_.TotalOut;
|
||||
}
|
||||
else {
|
||||
deflater_.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Write the AES Authentication Code (a hash of the compressed and encrypted data)
|
||||
if (curEntry.AESKeySize > 0) {
|
||||
baseOutputStream_.Write(AESAuthCode, 0, 10);
|
||||
}
|
||||
|
||||
if (curEntry.Size < 0) {
|
||||
curEntry.Size = size;
|
||||
} else if (curEntry.Size != size) {
|
||||
throw new ZipException("size was " + size + ", but I expected " + curEntry.Size);
|
||||
}
|
||||
|
||||
if (curEntry.CompressedSize < 0) {
|
||||
curEntry.CompressedSize = csize;
|
||||
} else if (curEntry.CompressedSize != csize) {
|
||||
throw new ZipException("compressed size was " + csize + ", but I expected " + curEntry.CompressedSize);
|
||||
}
|
||||
|
||||
if (curEntry.Crc < 0) {
|
||||
curEntry.Crc = crc.Value;
|
||||
} else if (curEntry.Crc != crc.Value) {
|
||||
throw new ZipException("crc was " + crc.Value + ", but I expected " + curEntry.Crc);
|
||||
}
|
||||
|
||||
offset += csize;
|
||||
|
||||
if (curEntry.IsCrypted) {
|
||||
if (curEntry.AESKeySize > 0) {
|
||||
curEntry.CompressedSize += curEntry.AESOverheadSize;
|
||||
|
||||
} else {
|
||||
curEntry.CompressedSize += ZipConstants.CryptoHeaderSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Patch the header if possible
|
||||
if (patchEntryHeader) {
|
||||
patchEntryHeader = false;
|
||||
|
||||
long curPos = baseOutputStream_.Position;
|
||||
baseOutputStream_.Seek(crcPatchPos, SeekOrigin.Begin);
|
||||
WriteLeInt((int)curEntry.Crc);
|
||||
|
||||
if ( curEntry.LocalHeaderRequiresZip64 ) {
|
||||
|
||||
if ( sizePatchPos == -1 ) {
|
||||
throw new ZipException("Entry requires zip64 but this has been turned off");
|
||||
}
|
||||
|
||||
baseOutputStream_.Seek(sizePatchPos, SeekOrigin.Begin);
|
||||
WriteLeLong(curEntry.Size);
|
||||
WriteLeLong(curEntry.CompressedSize);
|
||||
}
|
||||
else {
|
||||
WriteLeInt((int)curEntry.CompressedSize);
|
||||
WriteLeInt((int)curEntry.Size);
|
||||
}
|
||||
baseOutputStream_.Seek(curPos, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
// Add data descriptor if flagged as required
|
||||
if ((curEntry.Flags & 8) != 0) {
|
||||
WriteLeInt(ZipConstants.DataDescriptorSignature);
|
||||
WriteLeInt(unchecked((int)curEntry.Crc));
|
||||
|
||||
if ( curEntry.LocalHeaderRequiresZip64 ) {
|
||||
WriteLeLong(curEntry.CompressedSize);
|
||||
WriteLeLong(curEntry.Size);
|
||||
offset += ZipConstants.Zip64DataDescriptorSize;
|
||||
}
|
||||
else {
|
||||
WriteLeInt((int)curEntry.CompressedSize);
|
||||
WriteLeInt((int)curEntry.Size);
|
||||
offset += ZipConstants.DataDescriptorSize;
|
||||
}
|
||||
}
|
||||
|
||||
entries.Add(curEntry);
|
||||
curEntry = null;
|
||||
}
|
||||
|
||||
void WriteEncryptionHeader(long crcValue)
|
||||
{
|
||||
offset += ZipConstants.CryptoHeaderSize;
|
||||
|
||||
InitializePassword(Password);
|
||||
|
||||
byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];
|
||||
Random rnd = new Random();
|
||||
rnd.NextBytes(cryptBuffer);
|
||||
cryptBuffer[11] = (byte)(crcValue >> 24);
|
||||
|
||||
EncryptBlock(cryptBuffer, 0, cryptBuffer.Length);
|
||||
baseOutputStream_.Write(cryptBuffer, 0, cryptBuffer.Length);
|
||||
}
|
||||
|
||||
#if !NET_1_1 && !NETCF_2_0
|
||||
private static void AddExtraDataAES(ZipEntry entry, ZipExtraData extraData) {
|
||||
|
||||
// Vendor Version: AE-1 IS 1. AE-2 is 2. With AE-2 no CRC is required and 0 is stored.
|
||||
const int VENDOR_VERSION = 2;
|
||||
// Vendor ID is the two ASCII characters "AE".
|
||||
const int VENDOR_ID = 0x4541; //not 6965;
|
||||
extraData.StartNewEntry();
|
||||
// Pack AES extra data field see http://www.winzip.com/aes_info.htm
|
||||
//extraData.AddLeShort(7); // Data size (currently 7)
|
||||
extraData.AddLeShort(VENDOR_VERSION); // 2 = AE-2
|
||||
extraData.AddLeShort(VENDOR_ID); // "AE"
|
||||
extraData.AddData(entry.AESEncryptionStrength); // 1 = 128, 2 = 192, 3 = 256
|
||||
extraData.AddLeShort((int)entry.CompressionMethod); // The actual compression method used to compress the file
|
||||
extraData.AddNewEntry(0x9901);
|
||||
}
|
||||
|
||||
// Replaces WriteEncryptionHeader for AES
|
||||
//
|
||||
private void WriteAESHeader(ZipEntry entry) {
|
||||
byte[] salt;
|
||||
byte[] pwdVerifier;
|
||||
InitializeAESPassword(entry, Password, out salt, out pwdVerifier);
|
||||
// File format for AES:
|
||||
// Size (bytes) Content
|
||||
// ------------ -------
|
||||
// Variable Salt value
|
||||
// 2 Password verification value
|
||||
// Variable Encrypted file data
|
||||
// 10 Authentication code
|
||||
//
|
||||
// Value in the "compressed size" fields of the local file header and the central directory entry
|
||||
// is the total size of all the items listed above. In other words, it is the total size of the
|
||||
// salt value, password verification value, encrypted data, and authentication code.
|
||||
baseOutputStream_.Write(salt, 0, salt.Length);
|
||||
baseOutputStream_.Write(pwdVerifier, 0, pwdVerifier.Length);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given buffer to the current entry.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer containing data to write.</param>
|
||||
/// <param name="offset">The offset of the first byte to write.</param>
|
||||
/// <param name="count">The number of bytes to write.</param>
|
||||
/// <exception cref="ZipException">Archive size is invalid</exception>
|
||||
/// <exception cref="System.InvalidOperationException">No entry is active.</exception>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (curEntry == null) {
|
||||
throw new InvalidOperationException("No open entry.");
|
||||
}
|
||||
|
||||
if ( buffer == null ) {
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
if ( offset < 0 ) {
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("offset", "Cannot be negative");
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( count < 0 ) {
|
||||
#if NETCF_1_0
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("count", "Cannot be negative");
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( (buffer.Length - offset) < count ) {
|
||||
throw new ArgumentException("Invalid offset/count combination");
|
||||
}
|
||||
|
||||
crc.Update(buffer, offset, count);
|
||||
size += count;
|
||||
|
||||
switch (curMethod) {
|
||||
case CompressionMethod.Deflated:
|
||||
base.Write(buffer, offset, count);
|
||||
break;
|
||||
|
||||
case CompressionMethod.Stored:
|
||||
if (Password != null) {
|
||||
CopyAndEncrypt(buffer, offset, count);
|
||||
} else {
|
||||
baseOutputStream_.Write(buffer, offset, count);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CopyAndEncrypt(byte[] buffer, int offset, int count)
|
||||
{
|
||||
const int CopyBufferSize = 4096;
|
||||
byte[] localBuffer = new byte[CopyBufferSize];
|
||||
while ( count > 0 ) {
|
||||
int bufferCount = (count < CopyBufferSize) ? count : CopyBufferSize;
|
||||
|
||||
Array.Copy(buffer, offset, localBuffer, 0, bufferCount);
|
||||
EncryptBlock(localBuffer, 0, bufferCount);
|
||||
baseOutputStream_.Write(localBuffer, 0, bufferCount);
|
||||
count -= bufferCount;
|
||||
offset += bufferCount;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finishes the stream. This will write the central directory at the
|
||||
/// end of the zip file and flush the stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is automatically called when the stream is closed.
|
||||
/// </remarks>
|
||||
/// <exception cref="System.IO.IOException">
|
||||
/// An I/O error occurs.
|
||||
/// </exception>
|
||||
/// <exception cref="ZipException">
|
||||
/// Comment exceeds the maximum length<br/>
|
||||
/// Entry name exceeds the maximum length
|
||||
/// </exception>
|
||||
public override void Finish()
|
||||
{
|
||||
if (entries == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (curEntry != null) {
|
||||
CloseEntry();
|
||||
}
|
||||
|
||||
long numEntries = entries.Count;
|
||||
long sizeEntries = 0;
|
||||
|
||||
foreach (ZipEntry entry in entries) {
|
||||
WriteLeInt(ZipConstants.CentralHeaderSignature);
|
||||
WriteLeShort(ZipConstants.VersionMadeBy);
|
||||
WriteLeShort(entry.Version);
|
||||
WriteLeShort(entry.Flags);
|
||||
WriteLeShort((short)entry.CompressionMethodForHeader);
|
||||
WriteLeInt((int)entry.DosTime);
|
||||
WriteLeInt((int)entry.Crc);
|
||||
|
||||
if ( entry.IsZip64Forced() ||
|
||||
(entry.CompressedSize >= uint.MaxValue) )
|
||||
{
|
||||
WriteLeInt(-1);
|
||||
}
|
||||
else {
|
||||
WriteLeInt((int)entry.CompressedSize);
|
||||
}
|
||||
|
||||
if ( entry.IsZip64Forced() ||
|
||||
(entry.Size >= uint.MaxValue) )
|
||||
{
|
||||
WriteLeInt(-1);
|
||||
}
|
||||
else {
|
||||
WriteLeInt((int)entry.Size);
|
||||
}
|
||||
|
||||
byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
|
||||
|
||||
if (name.Length > 0xffff) {
|
||||
throw new ZipException("Name too long.");
|
||||
}
|
||||
|
||||
ZipExtraData ed = new ZipExtraData(entry.ExtraData);
|
||||
|
||||
if ( entry.CentralHeaderRequiresZip64 ) {
|
||||
ed.StartNewEntry();
|
||||
if ( entry.IsZip64Forced() ||
|
||||
(entry.Size >= 0xffffffff) )
|
||||
{
|
||||
ed.AddLeLong(entry.Size);
|
||||
}
|
||||
|
||||
if ( entry.IsZip64Forced() ||
|
||||
(entry.CompressedSize >= 0xffffffff) )
|
||||
{
|
||||
ed.AddLeLong(entry.CompressedSize);
|
||||
}
|
||||
|
||||
if ( entry.Offset >= 0xffffffff )
|
||||
{
|
||||
ed.AddLeLong(entry.Offset);
|
||||
}
|
||||
|
||||
ed.AddNewEntry(1);
|
||||
}
|
||||
else {
|
||||
ed.Delete(1);
|
||||
}
|
||||
|
||||
#if !NET_1_1 && !NETCF_2_0
|
||||
if (entry.AESKeySize > 0) {
|
||||
AddExtraDataAES(entry, ed);
|
||||
}
|
||||
#endif
|
||||
byte[] extra = ed.GetEntryData();
|
||||
|
||||
byte[] entryComment =
|
||||
(entry.Comment != null) ?
|
||||
ZipConstants.ConvertToArray(entry.Flags, entry.Comment) :
|
||||
new byte[0];
|
||||
|
||||
if (entryComment.Length > 0xffff) {
|
||||
throw new ZipException("Comment too long.");
|
||||
}
|
||||
|
||||
WriteLeShort(name.Length);
|
||||
WriteLeShort(extra.Length);
|
||||
WriteLeShort(entryComment.Length);
|
||||
WriteLeShort(0); // disk number
|
||||
WriteLeShort(0); // internal file attributes
|
||||
// external file attributes
|
||||
|
||||
if (entry.ExternalFileAttributes != -1) {
|
||||
WriteLeInt(entry.ExternalFileAttributes);
|
||||
} else {
|
||||
if (entry.IsDirectory) { // mark entry as directory (from nikolam.AT.perfectinfo.com)
|
||||
WriteLeInt(16);
|
||||
} else {
|
||||
WriteLeInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
if ( entry.Offset >= uint.MaxValue ) {
|
||||
WriteLeInt(-1);
|
||||
}
|
||||
else {
|
||||
WriteLeInt((int)entry.Offset);
|
||||
}
|
||||
|
||||
if ( name.Length > 0 ) {
|
||||
baseOutputStream_.Write(name, 0, name.Length);
|
||||
}
|
||||
|
||||
if ( extra.Length > 0 ) {
|
||||
baseOutputStream_.Write(extra, 0, extra.Length);
|
||||
}
|
||||
|
||||
if ( entryComment.Length > 0 ) {
|
||||
baseOutputStream_.Write(entryComment, 0, entryComment.Length);
|
||||
}
|
||||
|
||||
sizeEntries += ZipConstants.CentralHeaderBaseSize + name.Length + extra.Length + entryComment.Length;
|
||||
}
|
||||
|
||||
using ( ZipHelperStream zhs = new ZipHelperStream(baseOutputStream_) ) {
|
||||
zhs.WriteEndOfCentralDirectory(numEntries, sizeEntries, offset, zipComment);
|
||||
}
|
||||
|
||||
entries = null;
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// The entries for the archive.
|
||||
/// </summary>
|
||||
ArrayList entries = new ArrayList();
|
||||
|
||||
/// <summary>
|
||||
/// Used to track the crc of data added to entries.
|
||||
/// </summary>
|
||||
Crc32 crc = new Crc32();
|
||||
|
||||
/// <summary>
|
||||
/// The current entry being added.
|
||||
/// </summary>
|
||||
ZipEntry curEntry;
|
||||
|
||||
int defaultCompressionLevel = Deflater.DEFAULT_COMPRESSION;
|
||||
|
||||
CompressionMethod curMethod = CompressionMethod.Deflated;
|
||||
|
||||
/// <summary>
|
||||
/// Used to track the size of data for an entry during writing.
|
||||
/// </summary>
|
||||
long size;
|
||||
|
||||
/// <summary>
|
||||
/// Offset to be recorded for each entry in the central header.
|
||||
/// </summary>
|
||||
long offset;
|
||||
|
||||
/// <summary>
|
||||
/// Comment for the entire archive recorded in central header.
|
||||
/// </summary>
|
||||
byte[] zipComment = new byte[0];
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating that header patching is required for the current entry.
|
||||
/// </summary>
|
||||
bool patchEntryHeader;
|
||||
|
||||
/// <summary>
|
||||
/// Position to patch crc
|
||||
/// </summary>
|
||||
long crcPatchPos = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Position to patch size.
|
||||
/// </summary>
|
||||
long sizePatchPos = -1;
|
||||
|
||||
// Default is dynamic which is not backwards compatible and can cause problems
|
||||
// with XP's built in compression which cant read Zip64 archives.
|
||||
// However it does avoid the situation were a large file is added and cannot be completed correctly.
|
||||
// NOTE: Setting the size for entries before they are added is the best solution!
|
||||
UseZip64 useZip64_ = UseZip64.Dynamic;
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
// Copyright (c) 2006, ComponentAce
|
||||
// http://www.componentace.com
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
// Neither the name of ComponentAce nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
|
||||
/*
|
||||
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, so all credit should go authors
|
||||
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
* and contributors of zlib.
|
||||
*/
|
||||
using System;
|
||||
namespace ComponentAce.Compression.Libs.zlib
|
||||
{
|
||||
|
||||
sealed class Adler32
|
||||
{
|
||||
|
||||
// largest prime smaller than 65536
|
||||
private const int BASE = 65521;
|
||||
// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
|
||||
private const int NMAX = 5552;
|
||||
|
||||
internal long adler32(long adler, byte[] buf, int index, int len)
|
||||
{
|
||||
if (buf == null)
|
||||
{
|
||||
return 1L;
|
||||
}
|
||||
|
||||
long s1 = adler & 0xffff;
|
||||
long s2 = (adler >> 16) & 0xffff;
|
||||
int k;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
k = len < NMAX?len:NMAX;
|
||||
len -= k;
|
||||
while (k >= 16)
|
||||
{
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
k -= 16;
|
||||
}
|
||||
if (k != 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
}
|
||||
while (--k != 0);
|
||||
}
|
||||
s1 %= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
return (s2 << 16) | s1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,720 @@
|
|||
// Copyright (c) 2006, ComponentAce
|
||||
// http://www.componentace.com
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
// Neither the name of ComponentAce nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
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, so all credit should go authors
|
||||
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
* and contributors of zlib.
|
||||
*/
|
||||
using System;
|
||||
namespace ComponentAce.Compression.Libs.zlib
|
||||
{
|
||||
|
||||
sealed class InfBlocks
|
||||
{
|
||||
private const int MANY = 1440;
|
||||
|
||||
// And'ing with mask[n] masks the lower n bits
|
||||
private static readonly int[] inflate_mask = new int[]{0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff};
|
||||
|
||||
// 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 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;
|
||||
|
||||
private const int TYPE = 0; // get type bits (3, including end bit)
|
||||
private const int LENS = 1; // get lengths for stored
|
||||
private const int STORED = 2; // processing stored block
|
||||
private const int TABLE = 3; // get table lengths
|
||||
private const int BTREE = 4; // get bit lengths tree for a dynamic block
|
||||
private const int DTREE = 5; // get length, distance trees for a dynamic block
|
||||
private const int CODES = 6; // processing fixed or dynamic block
|
||||
private const int DRY = 7; // output remaining window bytes
|
||||
private const int DONE = 8; // finished last block, done
|
||||
private const int BAD = 9; // ot a data error--stuck here
|
||||
|
||||
internal int 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 InfCodes codes; // if CODES, current state
|
||||
|
||||
internal int last; // true if this block is the last block
|
||||
|
||||
// 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 read; // window read pointer
|
||||
internal int write; // window write pointer
|
||||
internal System.Object checkfn; // check function
|
||||
internal long check; // check on output
|
||||
|
||||
internal InfBlocks(ZStream z, System.Object checkfn, int w)
|
||||
{
|
||||
hufts = new int[MANY * 3];
|
||||
window = new byte[w];
|
||||
end = w;
|
||||
this.checkfn = checkfn;
|
||||
mode = TYPE;
|
||||
reset(z, null);
|
||||
}
|
||||
|
||||
internal void reset(ZStream z, long[] c)
|
||||
{
|
||||
if (c != null)
|
||||
c[0] = check;
|
||||
if (mode == BTREE || mode == DTREE)
|
||||
{
|
||||
blens = null;
|
||||
}
|
||||
if (mode == CODES)
|
||||
{
|
||||
codes.free(z);
|
||||
}
|
||||
mode = TYPE;
|
||||
bitk = 0;
|
||||
bitb = 0;
|
||||
read = write = 0;
|
||||
|
||||
if (checkfn != null)
|
||||
z.adler = check = z._adler.adler32(0L, null, 0, 0);
|
||||
}
|
||||
|
||||
internal int proc(ZStream z, 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 = z.next_in_index; n = z.avail_in; b = bitb; k = bitk;
|
||||
}
|
||||
{
|
||||
q = write; m = (int) (q < read?read - q - 1:end - q);
|
||||
}
|
||||
|
||||
// process input based on current state
|
||||
while (true)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
|
||||
case TYPE:
|
||||
|
||||
while (k < (3))
|
||||
{
|
||||
if (n != 0)
|
||||
{
|
||||
r = Z_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n;
|
||||
z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
;
|
||||
n--;
|
||||
b |= (z.next_in[p++] & 0xff) << k;
|
||||
k += 8;
|
||||
}
|
||||
t = (int) (b & 7);
|
||||
last = t & 1;
|
||||
|
||||
switch (SupportClass.URShift(t, 1))
|
||||
{
|
||||
|
||||
case 0: // stored
|
||||
{
|
||||
b = SupportClass.URShift(b, (3)); k -= (3);
|
||||
}
|
||||
t = k & 7; // go to byte boundary
|
||||
|
||||
{
|
||||
b = SupportClass.URShift(b, (t)); k -= (t);
|
||||
}
|
||||
mode = 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, z);
|
||||
codes = new InfCodes(bl[0], bd[0], tl[0], td[0], z);
|
||||
}
|
||||
|
||||
{
|
||||
b = SupportClass.URShift(b, (3)); k -= (3);
|
||||
}
|
||||
|
||||
mode = CODES;
|
||||
break;
|
||||
|
||||
case 2: // dynamic
|
||||
|
||||
{
|
||||
b = SupportClass.URShift(b, (3)); k -= (3);
|
||||
}
|
||||
|
||||
mode = TABLE;
|
||||
break;
|
||||
|
||||
case 3: // illegal
|
||||
|
||||
{
|
||||
b = SupportClass.URShift(b, (3)); k -= (3);
|
||||
}
|
||||
mode = BAD;
|
||||
z.msg = "invalid block type";
|
||||
r = Z_DATA_ERROR;
|
||||
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
break;
|
||||
|
||||
case LENS:
|
||||
|
||||
while (k < (32))
|
||||
{
|
||||
if (n != 0)
|
||||
{
|
||||
r = Z_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n;
|
||||
z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
;
|
||||
n--;
|
||||
b |= (z.next_in[p++] & 0xff) << k;
|
||||
k += 8;
|
||||
}
|
||||
|
||||
if (((SupportClass.URShift((~ b), 16)) & 0xffff) != (b & 0xffff))
|
||||
{
|
||||
mode = BAD;
|
||||
z.msg = "invalid stored block lengths";
|
||||
r = Z_DATA_ERROR;
|
||||
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
left = (b & 0xffff);
|
||||
b = k = 0; // dump bits
|
||||
mode = left != 0?STORED:(last != 0?DRY:TYPE);
|
||||
break;
|
||||
|
||||
case STORED:
|
||||
if (n == 0)
|
||||
{
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
if (q == end && read != 0)
|
||||
{
|
||||
q = 0; m = (int) (q < read?read - q - 1:end - q);
|
||||
}
|
||||
if (m == 0)
|
||||
{
|
||||
write = q;
|
||||
r = inflate_flush(z, r);
|
||||
q = write; m = (int) (q < read?read - q - 1:end - q);
|
||||
if (q == end && read != 0)
|
||||
{
|
||||
q = 0; m = (int) (q < read?read - q - 1:end - q);
|
||||
}
|
||||
if (m == 0)
|
||||
{
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
r = Z_OK;
|
||||
|
||||
t = left;
|
||||
if (t > n)
|
||||
t = n;
|
||||
if (t > m)
|
||||
t = m;
|
||||
Array.Copy(z.next_in, p, window, q, t);
|
||||
p += t; n -= t;
|
||||
q += t; m -= t;
|
||||
if ((left -= t) != 0)
|
||||
break;
|
||||
mode = last != 0?DRY:TYPE;
|
||||
break;
|
||||
|
||||
case TABLE:
|
||||
|
||||
while (k < (14))
|
||||
{
|
||||
if (n != 0)
|
||||
{
|
||||
r = Z_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n;
|
||||
z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
;
|
||||
n--;
|
||||
b |= (z.next_in[p++] & 0xff) << k;
|
||||
k += 8;
|
||||
}
|
||||
|
||||
table = t = (b & 0x3fff);
|
||||
if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
|
||||
{
|
||||
mode = BAD;
|
||||
z.msg = "too many length or distance symbols";
|
||||
r = Z_DATA_ERROR;
|
||||
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
|
||||
blens = new int[t];
|
||||
|
||||
{
|
||||
b = SupportClass.URShift(b, (14)); k -= (14);
|
||||
}
|
||||
|
||||
index = 0;
|
||||
mode = BTREE;
|
||||
goto case BTREE;
|
||||
|
||||
case BTREE:
|
||||
while (index < 4 + (SupportClass.URShift(table, 10)))
|
||||
{
|
||||
while (k < (3))
|
||||
{
|
||||
if (n != 0)
|
||||
{
|
||||
r = Z_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n;
|
||||
z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
;
|
||||
n--;
|
||||
b |= (z.next_in[p++] & 0xff) << k;
|
||||
k += 8;
|
||||
}
|
||||
|
||||
blens[border[index++]] = b & 7;
|
||||
|
||||
{
|
||||
b = SupportClass.URShift(b, (3)); k -= (3);
|
||||
}
|
||||
}
|
||||
|
||||
while (index < 19)
|
||||
{
|
||||
blens[border[index++]] = 0;
|
||||
}
|
||||
|
||||
bb[0] = 7;
|
||||
t = InfTree.inflate_trees_bits(blens, bb, tb, hufts, z);
|
||||
if (t != Z_OK)
|
||||
{
|
||||
r = t;
|
||||
if (r == Z_DATA_ERROR)
|
||||
{
|
||||
blens = null;
|
||||
mode = BAD;
|
||||
}
|
||||
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
|
||||
index = 0;
|
||||
mode = DTREE;
|
||||
goto case DTREE;
|
||||
|
||||
case 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 = Z_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n;
|
||||
z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
;
|
||||
n--;
|
||||
b |= (z.next_in[p++] & 0xff) << k;
|
||||
k += 8;
|
||||
}
|
||||
|
||||
if (tb[0] == - 1)
|
||||
{
|
||||
//System.err.println("null...");
|
||||
}
|
||||
|
||||
t = hufts[(tb[0] + (b & inflate_mask[t])) * 3 + 1];
|
||||
c = hufts[(tb[0] + (b & inflate_mask[t])) * 3 + 2];
|
||||
|
||||
if (c < 16)
|
||||
{
|
||||
b = SupportClass.URShift(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 = Z_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n;
|
||||
z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
;
|
||||
n--;
|
||||
b |= (z.next_in[p++] & 0xff) << k;
|
||||
k += 8;
|
||||
}
|
||||
|
||||
b = SupportClass.URShift(b, (t)); k -= (t);
|
||||
|
||||
j += (b & inflate_mask[i]);
|
||||
|
||||
b = SupportClass.URShift(b, (i)); k -= (i);
|
||||
|
||||
i = index;
|
||||
t = table;
|
||||
if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1))
|
||||
{
|
||||
blens = null;
|
||||
mode = BAD;
|
||||
z.msg = "invalid bit length repeat";
|
||||
r = Z_DATA_ERROR;
|
||||
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
|
||||
c = c == 16?blens[i - 1]:0;
|
||||
do
|
||||
{
|
||||
blens[i++] = c;
|
||||
}
|
||||
while (--j != 0);
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
tb[0] = - 1;
|
||||
{
|
||||
int[] bl = new int[1];
|
||||
int[] bd = new int[1];
|
||||
int[] tl = new int[1];
|
||||
int[] td = new int[1];
|
||||
|
||||
|
||||
bl[0] = 9; // must be <= 9 for lookahead assumptions
|
||||
bd[0] = 6; // must be <= 9 for lookahead assumptions
|
||||
t = table;
|
||||
t = InfTree.inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), blens, bl, bd, tl, td, hufts, z);
|
||||
if (t != Z_OK)
|
||||
{
|
||||
if (t == Z_DATA_ERROR)
|
||||
{
|
||||
blens = null;
|
||||
mode = BAD;
|
||||
}
|
||||
r = t;
|
||||
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
|
||||
codes = new InfCodes(bl[0], bd[0], hufts, tl[0], hufts, td[0], z);
|
||||
}
|
||||
blens = null;
|
||||
mode = CODES;
|
||||
goto case CODES;
|
||||
|
||||
case CODES:
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
|
||||
if ((r = codes.proc(this, z, r)) != Z_STREAM_END)
|
||||
{
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
r = Z_OK;
|
||||
codes.free(z);
|
||||
|
||||
p = z.next_in_index; n = z.avail_in; b = bitb; k = bitk;
|
||||
q = write; m = (int) (q < read?read - q - 1:end - q);
|
||||
|
||||
if (last == 0)
|
||||
{
|
||||
mode = TYPE;
|
||||
break;
|
||||
}
|
||||
mode = DRY;
|
||||
goto case DRY;
|
||||
|
||||
case DRY:
|
||||
write = q;
|
||||
r = inflate_flush(z, r);
|
||||
q = write; m = (int) (q < read?read - q - 1:end - q);
|
||||
if (read != write)
|
||||
{
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
}
|
||||
mode = DONE;
|
||||
goto case DONE;
|
||||
|
||||
case DONE:
|
||||
r = Z_STREAM_END;
|
||||
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
|
||||
case BAD:
|
||||
r = Z_DATA_ERROR;
|
||||
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
|
||||
|
||||
default:
|
||||
r = Z_STREAM_ERROR;
|
||||
|
||||
bitb = b; bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
write = q;
|
||||
return inflate_flush(z, r);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void free(ZStream z)
|
||||
{
|
||||
reset(z, null);
|
||||
window = null;
|
||||
hufts = null;
|
||||
//ZFREE(z, s);
|
||||
}
|
||||
|
||||
internal void set_dictionary(byte[] d, int start, int n)
|
||||
{
|
||||
Array.Copy(d, start, window, 0, n);
|
||||
read = write = n;
|
||||
}
|
||||
|
||||
// Returns true if inflate is currently at the end of a block generated
|
||||
// by Z_SYNC_FLUSH or Z_FULL_FLUSH.
|
||||
internal int sync_point()
|
||||
{
|
||||
return mode == LENS?1:0;
|
||||
}
|
||||
|
||||
// copy as much as possible from the sliding window to the output area
|
||||
internal int inflate_flush(ZStream z, int r)
|
||||
{
|
||||
int n;
|
||||
int p;
|
||||
int q;
|
||||
|
||||
// local copies of source and destination pointers
|
||||
p = z.next_out_index;
|
||||
q = read;
|
||||
|
||||
// compute number of bytes to copy as far as end of window
|
||||
n = (int) ((q <= write?write:end) - q);
|
||||
if (n > z.avail_out)
|
||||
n = z.avail_out;
|
||||
if (n != 0 && r == Z_BUF_ERROR)
|
||||
r = Z_OK;
|
||||
|
||||
// update counters
|
||||
z.avail_out -= n;
|
||||
z.total_out += n;
|
||||
|
||||
// update check information
|
||||
if (checkfn != null)
|
||||
z.adler = check = z._adler.adler32(check, window, q, n);
|
||||
|
||||
// copy as far as end of window
|
||||
Array.Copy(window, q, z.next_out, p, n);
|
||||
p += n;
|
||||
q += n;
|
||||
|
||||
// see if more to copy at beginning of window
|
||||
if (q == end)
|
||||
{
|
||||
// wrap pointers
|
||||
q = 0;
|
||||
if (write == end)
|
||||
write = 0;
|
||||
|
||||
// compute bytes to copy
|
||||
n = write - q;
|
||||
if (n > z.avail_out)
|
||||
n = z.avail_out;
|
||||
if (n != 0 && r == Z_BUF_ERROR)
|
||||
r = Z_OK;
|
||||
|
||||
// update counters
|
||||
z.avail_out -= n;
|
||||
z.total_out += n;
|
||||
|
||||
// update check information
|
||||
if (checkfn != null)
|
||||
z.adler = check = z._adler.adler32(check, window, q, n);
|
||||
|
||||
// copy
|
||||
Array.Copy(window, q, z.next_out, p, n);
|
||||
p += n;
|
||||
q += n;
|
||||
}
|
||||
|
||||
// update pointers
|
||||
z.next_out_index = p;
|
||||
read = q;
|
||||
|
||||
// done
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,716 @@
|
|||
// Copyright (c) 2006, ComponentAce
|
||||
// http://www.componentace.com
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
// Neither the name of ComponentAce nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
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, so all credit should go authors
|
||||
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
* and contributors of zlib.
|
||||
*/
|
||||
using System;
|
||||
namespace ComponentAce.Compression.Libs.zlib
|
||||
{
|
||||
|
||||
sealed class InfCodes
|
||||
{
|
||||
|
||||
private static readonly int[] inflate_mask = new int[]{0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff};
|
||||
|
||||
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;
|
||||
|
||||
// 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 get_Renamed; // 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 InfCodes(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, ZStream z)
|
||||
{
|
||||
mode = START;
|
||||
lbits = (byte) bl;
|
||||
dbits = (byte) bd;
|
||||
ltree = tl;
|
||||
ltree_index = tl_index;
|
||||
dtree = td;
|
||||
dtree_index = td_index;
|
||||
}
|
||||
|
||||
internal InfCodes(int bl, int bd, int[] tl, int[] td, ZStream z)
|
||||
{
|
||||
mode = START;
|
||||
lbits = (byte) bl;
|
||||
dbits = (byte) bd;
|
||||
ltree = tl;
|
||||
ltree_index = 0;
|
||||
dtree = td;
|
||||
dtree_index = 0;
|
||||
}
|
||||
|
||||
internal int proc(InfBlocks s, ZStream z, int r)
|
||||
{
|
||||
int j; // temporary storage
|
||||
//int[] t; // temporary pointer
|
||||
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
|
||||
|
||||
// copy input/output information to locals (UPDATE macro restores)
|
||||
p = z.next_in_index; n = z.avail_in; b = s.bitb; k = s.bitk;
|
||||
q = s.write; m = q < s.read?s.read - q - 1:s.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)
|
||||
{
|
||||
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
r = inflate_fast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, s, z);
|
||||
|
||||
p = z.next_in_index; n = z.avail_in; b = s.bitb; k = s.bitk;
|
||||
q = s.write; m = q < s.read?s.read - q - 1:s.end - q;
|
||||
|
||||
if (r != Z_OK)
|
||||
{
|
||||
mode = r == 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 = Z_OK;
|
||||
else
|
||||
{
|
||||
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
return s.inflate_flush(z, r);
|
||||
}
|
||||
n--;
|
||||
b |= (z.next_in[p++] & 0xff) << k;
|
||||
k += 8;
|
||||
}
|
||||
|
||||
tindex = (tree_index + (b & inflate_mask[j])) * 3;
|
||||
|
||||
b = SupportClass.URShift(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
|
||||
get_Renamed = 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.msg = "invalid literal/length code";
|
||||
r = Z_DATA_ERROR;
|
||||
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
return s.inflate_flush(z, r);
|
||||
|
||||
|
||||
case LENEXT: // i: getting length extra (have base)
|
||||
j = get_Renamed;
|
||||
|
||||
while (k < (j))
|
||||
{
|
||||
if (n != 0)
|
||||
r = Z_OK;
|
||||
else
|
||||
{
|
||||
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
return s.inflate_flush(z, r);
|
||||
}
|
||||
n--; b |= (z.next_in[p++] & 0xff) << k;
|
||||
k += 8;
|
||||
}
|
||||
|
||||
len += (b & inflate_mask[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 = Z_OK;
|
||||
else
|
||||
{
|
||||
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
return s.inflate_flush(z, r);
|
||||
}
|
||||
n--; b |= (z.next_in[p++] & 0xff) << k;
|
||||
k += 8;
|
||||
}
|
||||
|
||||
tindex = (tree_index + (b & inflate_mask[j])) * 3;
|
||||
|
||||
b >>= tree[tindex + 1];
|
||||
k -= tree[tindex + 1];
|
||||
|
||||
e = (tree[tindex]);
|
||||
if ((e & 16) != 0)
|
||||
{
|
||||
// distance
|
||||
get_Renamed = 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.msg = "invalid distance code";
|
||||
r = Z_DATA_ERROR;
|
||||
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
return s.inflate_flush(z, r);
|
||||
|
||||
|
||||
case DISTEXT: // i: getting distance extra
|
||||
j = get_Renamed;
|
||||
|
||||
while (k < (j))
|
||||
{
|
||||
if (n != 0)
|
||||
r = Z_OK;
|
||||
else
|
||||
{
|
||||
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
return s.inflate_flush(z, r);
|
||||
}
|
||||
n--; b |= (z.next_in[p++] & 0xff) << k;
|
||||
k += 8;
|
||||
}
|
||||
|
||||
dist += (b & inflate_mask[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 += s.end; // of "if" handles invalid distances
|
||||
}
|
||||
while (len != 0)
|
||||
{
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
if (q == s.end && s.read != 0)
|
||||
{
|
||||
q = 0; m = q < s.read?s.read - q - 1:s.end - q;
|
||||
}
|
||||
if (m == 0)
|
||||
{
|
||||
s.write = q; r = s.inflate_flush(z, r);
|
||||
q = s.write; m = q < s.read?s.read - q - 1:s.end - q;
|
||||
|
||||
if (q == s.end && s.read != 0)
|
||||
{
|
||||
q = 0; m = q < s.read?s.read - q - 1:s.end - q;
|
||||
}
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
return s.inflate_flush(z, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.window[q++] = s.window[f++]; m--;
|
||||
|
||||
if (f == s.end)
|
||||
f = 0;
|
||||
len--;
|
||||
}
|
||||
mode = START;
|
||||
break;
|
||||
|
||||
case LIT: // o: got literal, waiting for output space
|
||||
if (m == 0)
|
||||
{
|
||||
if (q == s.end && s.read != 0)
|
||||
{
|
||||
q = 0; m = q < s.read?s.read - q - 1:s.end - q;
|
||||
}
|
||||
if (m == 0)
|
||||
{
|
||||
s.write = q; r = s.inflate_flush(z, r);
|
||||
q = s.write; m = q < s.read?s.read - q - 1:s.end - q;
|
||||
|
||||
if (q == s.end && s.read != 0)
|
||||
{
|
||||
q = 0; m = q < s.read?s.read - q - 1:s.end - q;
|
||||
}
|
||||
if (m == 0)
|
||||
{
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
return s.inflate_flush(z, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
r = Z_OK;
|
||||
|
||||
s.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
|
||||
}
|
||||
|
||||
s.write = q; r = s.inflate_flush(z, r);
|
||||
q = s.write; m = q < s.read?s.read - q - 1:s.end - q;
|
||||
|
||||
if (s.read != s.write)
|
||||
{
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
return s.inflate_flush(z, r);
|
||||
}
|
||||
mode = END;
|
||||
goto case END;
|
||||
|
||||
case END:
|
||||
r = Z_STREAM_END;
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
return s.inflate_flush(z, r);
|
||||
|
||||
|
||||
case BADCODE: // x: got error
|
||||
|
||||
r = Z_DATA_ERROR;
|
||||
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
return s.inflate_flush(z, r);
|
||||
|
||||
|
||||
default:
|
||||
r = Z_STREAM_ERROR;
|
||||
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
return s.inflate_flush(z, r);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void free(ZStream z)
|
||||
{
|
||||
// ZFREE(z, c);
|
||||
}
|
||||
|
||||
// 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 inflate_fast(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, InfBlocks s, ZStream 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
|
||||
|
||||
// load input, output, bit values
|
||||
p = z.next_in_index; n = z.avail_in; b = s.bitb; k = s.bitk;
|
||||
q = s.write; m = q < s.read?s.read - q - 1:s.end - q;
|
||||
|
||||
// initialize masks
|
||||
ml = inflate_mask[bl];
|
||||
md = inflate_mask[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.next_in[p++] & 0xff) << k; k += 8;
|
||||
}
|
||||
|
||||
t = b & ml;
|
||||
tp = tl;
|
||||
tp_index = tl_index;
|
||||
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 & inflate_mask[e]);
|
||||
|
||||
b >>= e; k -= e;
|
||||
|
||||
// decode distance base of block to copy
|
||||
while (k < (15))
|
||||
{
|
||||
// max bits for distance code
|
||||
n--;
|
||||
b |= (z.next_in[p++] & 0xff) << k; k += 8;
|
||||
}
|
||||
|
||||
t = b & md;
|
||||
tp = td;
|
||||
tp_index = td_index;
|
||||
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.next_in[p++] & 0xff) << k; k += 8;
|
||||
}
|
||||
|
||||
d = tp[(tp_index + t) * 3 + 2] + (b & inflate_mask[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++]; c--; // minimum count is three,
|
||||
s.window[q++] = s.window[r++]; c--; // so unroll loop a little
|
||||
}
|
||||
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 & inflate_mask[e]);
|
||||
e = tp[(tp_index + t) * 3];
|
||||
}
|
||||
else
|
||||
{
|
||||
z.msg = "invalid distance code";
|
||||
|
||||
c = z.avail_in - n; c = (k >> 3) < c?k >> 3:c; n += c; p -= c; k -= (c << 3);
|
||||
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
|
||||
return Z_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((e & 64) == 0)
|
||||
{
|
||||
t += tp[(tp_index + t) * 3 + 2];
|
||||
t += (b & inflate_mask[e]);
|
||||
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.avail_in - n; c = (k >> 3) < c?k >> 3:c; n += c; p -= c; k -= (c << 3);
|
||||
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
|
||||
return Z_STREAM_END;
|
||||
}
|
||||
else
|
||||
{
|
||||
z.msg = "invalid literal/length code";
|
||||
|
||||
c = z.avail_in - n; c = (k >> 3) < c?k >> 3:c; n += c; p -= c; k -= (c << 3);
|
||||
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
|
||||
return Z_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
while (m >= 258 && n >= 10);
|
||||
|
||||
// not enough input or output--restore pointers and return
|
||||
c = z.avail_in - n; c = (k >> 3) < c?k >> 3:c; n += c; p -= c; k -= (c << 3);
|
||||
|
||||
s.bitb = b; s.bitk = k;
|
||||
z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p;
|
||||
s.write = q;
|
||||
|
||||
return Z_OK;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,377 @@
|
|||
// Copyright (c) 2006, ComponentAce
|
||||
// http://www.componentace.com
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
// Neither the name of ComponentAce nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
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, so all credit should go authors
|
||||
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
* and contributors of zlib.
|
||||
*/
|
||||
using System;
|
||||
namespace ComponentAce.Compression.Libs.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;
|
||||
|
||||
|
||||
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};
|
||||
|
||||
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.
|
||||
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};
|
||||
|
||||
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};
|
||||
|
||||
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};
|
||||
|
||||
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 static 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[] c = new int[BMAX + 1]; // bit length count table
|
||||
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[] r = new int[3]; // table entry for structure assignment
|
||||
int[] u = new int[BMAX]; // table stack
|
||||
int w; // bits before this table == (l * h)
|
||||
int[] x = new int[BMAX + 1]; // bit offsets, then code stack
|
||||
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] = (byte) j; // bits in this table
|
||||
r[1] = (byte) l; // bits to dump before this table
|
||||
j = SupportClass.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] = (byte) (k - w);
|
||||
if (p >= n)
|
||||
{
|
||||
r[0] = 128 + 64; // out of values--invalid code
|
||||
}
|
||||
else if (v[p] < s)
|
||||
{
|
||||
r[0] = (byte) (v[p] < 256?0:32 + 64); // 256 is end-of-block
|
||||
r[2] = v[p++]; // simple code is just the value
|
||||
}
|
||||
else
|
||||
{
|
||||
r[0] = (byte) (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 = SupportClass.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 = SupportClass.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 static int inflate_trees_bits(int[] c, int[] bb, int[] tb, int[] hp, ZStream z)
|
||||
{
|
||||
int r;
|
||||
int[] hn = new int[1]; // hufts used in space
|
||||
int[] v = new int[19]; // work area for huft_build
|
||||
|
||||
r = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);
|
||||
|
||||
if (r == Z_DATA_ERROR)
|
||||
{
|
||||
z.msg = "oversubscribed dynamic bit lengths tree";
|
||||
}
|
||||
else if (r == Z_BUF_ERROR || bb[0] == 0)
|
||||
{
|
||||
z.msg = "incomplete dynamic bit lengths tree";
|
||||
r = Z_DATA_ERROR;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
internal static int inflate_trees_dynamic(int nl, int nd, int[] c, int[] bl, int[] bd, int[] tl, int[] td, int[] hp, ZStream z)
|
||||
{
|
||||
int r;
|
||||
int[] hn = new int[1]; // hufts used in space
|
||||
int[] v = new int[288]; // work area for huft_build
|
||||
|
||||
// build literal/length tree
|
||||
r = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
|
||||
if (r != Z_OK || bl[0] == 0)
|
||||
{
|
||||
if (r == Z_DATA_ERROR)
|
||||
{
|
||||
z.msg = "oversubscribed literal/length tree";
|
||||
}
|
||||
else if (r != Z_MEM_ERROR)
|
||||
{
|
||||
z.msg = "incomplete literal/length tree";
|
||||
r = Z_DATA_ERROR;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// build distance tree
|
||||
r = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);
|
||||
|
||||
if (r != Z_OK || (bd[0] == 0 && nl > 257))
|
||||
{
|
||||
if (r == Z_DATA_ERROR)
|
||||
{
|
||||
z.msg = "oversubscribed distance tree";
|
||||
}
|
||||
else if (r == Z_BUF_ERROR)
|
||||
{
|
||||
z.msg = "incomplete distance tree";
|
||||
r = Z_DATA_ERROR;
|
||||
}
|
||||
else if (r != Z_MEM_ERROR)
|
||||
{
|
||||
z.msg = "empty distance tree with lengths";
|
||||
r = Z_DATA_ERROR;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
internal static int inflate_trees_fixed(int[] bl, int[] bd, int[][] tl, int[][] td, ZStream z)
|
||||
{
|
||||
bl[0] = fixed_bl;
|
||||
bd[0] = fixed_bd;
|
||||
tl[0] = fixed_tl;
|
||||
td[0] = fixed_td;
|
||||
return Z_OK;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,450 @@
|
|||
// Copyright (c) 2006, ComponentAce
|
||||
// http://www.componentace.com
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
// Neither the name of ComponentAce nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
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, so all credit should go authors
|
||||
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
* and contributors of zlib.
|
||||
*/
|
||||
using System;
|
||||
namespace ComponentAce.Compression.Libs.zlib
|
||||
{
|
||||
|
||||
sealed class Inflate
|
||||
{
|
||||
|
||||
private const int MAX_WBITS = 15; // 32K LZ77 window
|
||||
|
||||
// preset dictionary flag in zlib header
|
||||
private const int PRESET_DICT = 0x20;
|
||||
|
||||
internal const int Z_NO_FLUSH = 0;
|
||||
internal const int Z_PARTIAL_FLUSH = 1;
|
||||
internal const int Z_SYNC_FLUSH = 2;
|
||||
internal const int Z_FULL_FLUSH = 3;
|
||||
internal const int Z_FINISH = 4;
|
||||
|
||||
private const int Z_DEFLATED = 8;
|
||||
|
||||
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;
|
||||
|
||||
private const int METHOD = 0; // waiting for method byte
|
||||
private const int FLAG = 1; // waiting for flag byte
|
||||
private const int DICT4 = 2; // four dictionary check bytes to go
|
||||
private const int DICT3 = 3; // three dictionary check bytes to go
|
||||
private const int DICT2 = 4; // two dictionary check bytes to go
|
||||
private const int DICT1 = 5; // one dictionary check byte to go
|
||||
private const int DICT0 = 6; // waiting for inflateSetDictionary
|
||||
private const int BLOCKS = 7; // decompressing blocks
|
||||
private const int CHECK4 = 8; // four check bytes to go
|
||||
private const int CHECK3 = 9; // three check bytes to go
|
||||
private const int CHECK2 = 10; // two check bytes to go
|
||||
private const int CHECK1 = 11; // one check byte to go
|
||||
private const int DONE = 12; // finished check, done
|
||||
private const int BAD = 13; // got an error--stay here
|
||||
|
||||
internal int mode; // current inflate mode
|
||||
|
||||
// mode dependent information
|
||||
internal int method; // if FLAGS, method byte
|
||||
|
||||
// if CHECK, check values to compare
|
||||
internal long[] was = new long[1]; // computed check value
|
||||
internal long need; // stream check value
|
||||
|
||||
// if BAD, inflateSync's marker bytes count
|
||||
internal int marker;
|
||||
|
||||
// mode independent information
|
||||
internal int nowrap; // flag for no wrapper
|
||||
internal int wbits; // log2(window size) (8..15, defaults to 15)
|
||||
|
||||
internal InfBlocks blocks; // current inflate_blocks state
|
||||
|
||||
internal int inflateReset(ZStream z)
|
||||
{
|
||||
if (z == null || z.istate == null)
|
||||
return Z_STREAM_ERROR;
|
||||
|
||||
z.total_in = z.total_out = 0;
|
||||
z.msg = null;
|
||||
z.istate.mode = z.istate.nowrap != 0?BLOCKS:METHOD;
|
||||
z.istate.blocks.reset(z, null);
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
internal int inflateEnd(ZStream z)
|
||||
{
|
||||
if (blocks != null)
|
||||
blocks.free(z);
|
||||
blocks = null;
|
||||
// ZFREE(z, z->state);
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
internal int inflateInit(ZStream z, int w)
|
||||
{
|
||||
z.msg = 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)
|
||||
{
|
||||
inflateEnd(z);
|
||||
return Z_STREAM_ERROR;
|
||||
}
|
||||
wbits = w;
|
||||
|
||||
z.istate.blocks = new InfBlocks(z, z.istate.nowrap != 0?null:this, 1 << w);
|
||||
|
||||
// reset state
|
||||
inflateReset(z);
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
internal int inflate(ZStream z, int f)
|
||||
{
|
||||
int r;
|
||||
int b;
|
||||
|
||||
if (z == null || z.istate == null || z.next_in == null)
|
||||
return Z_STREAM_ERROR;
|
||||
f = f == Z_FINISH?Z_BUF_ERROR:Z_OK;
|
||||
r = Z_BUF_ERROR;
|
||||
while (true)
|
||||
{
|
||||
//System.out.println("mode: "+z.istate.mode);
|
||||
switch (z.istate.mode)
|
||||
{
|
||||
|
||||
case METHOD:
|
||||
|
||||
if (z.avail_in == 0)
|
||||
return r; r = f;
|
||||
|
||||
z.avail_in--; z.total_in++;
|
||||
if (((z.istate.method = z.next_in[z.next_in_index++]) & 0xf) != Z_DEFLATED)
|
||||
{
|
||||
z.istate.mode = BAD;
|
||||
z.msg = "unknown compression method";
|
||||
z.istate.marker = 5; // can't try inflateSync
|
||||
break;
|
||||
}
|
||||
if ((z.istate.method >> 4) + 8 > z.istate.wbits)
|
||||
{
|
||||
z.istate.mode = BAD;
|
||||
z.msg = "invalid window size";
|
||||
z.istate.marker = 5; // can't try inflateSync
|
||||
break;
|
||||
}
|
||||
z.istate.mode = FLAG;
|
||||
goto case FLAG;
|
||||
|
||||
case FLAG:
|
||||
|
||||
if (z.avail_in == 0)
|
||||
return r; r = f;
|
||||
|
||||
z.avail_in--; z.total_in++;
|
||||
b = (z.next_in[z.next_in_index++]) & 0xff;
|
||||
|
||||
if ((((z.istate.method << 8) + b) % 31) != 0)
|
||||
{
|
||||
z.istate.mode = BAD;
|
||||
z.msg = "incorrect header check";
|
||||
z.istate.marker = 5; // can't try inflateSync
|
||||
break;
|
||||
}
|
||||
|
||||
if ((b & PRESET_DICT) == 0)
|
||||
{
|
||||
z.istate.mode = BLOCKS;
|
||||
break;
|
||||
}
|
||||
z.istate.mode = DICT4;
|
||||
goto case DICT4;
|
||||
|
||||
case DICT4:
|
||||
|
||||
if (z.avail_in == 0)
|
||||
return r; r = f;
|
||||
|
||||
z.avail_in--; z.total_in++;
|
||||
z.istate.need = ((z.next_in[z.next_in_index++] & 0xff) << 24) & unchecked((int) 0xff000000L);
|
||||
z.istate.mode = DICT3;
|
||||
goto case DICT3;
|
||||
|
||||
case DICT3:
|
||||
|
||||
if (z.avail_in == 0)
|
||||
return r; r = f;
|
||||
|
||||
z.avail_in--; z.total_in++;
|
||||
z.istate.need += (((z.next_in[z.next_in_index++] & 0xff) << 16) & 0xff0000L);
|
||||
z.istate.mode = DICT2;
|
||||
goto case DICT2;
|
||||
|
||||
case DICT2:
|
||||
|
||||
if (z.avail_in == 0)
|
||||
return r; r = f;
|
||||
|
||||
z.avail_in--; z.total_in++;
|
||||
z.istate.need += (((z.next_in[z.next_in_index++] & 0xff) << 8) & 0xff00L);
|
||||
z.istate.mode = DICT1;
|
||||
goto case DICT1;
|
||||
|
||||
case DICT1:
|
||||
|
||||
if (z.avail_in == 0)
|
||||
return r; r = f;
|
||||
|
||||
z.avail_in--; z.total_in++;
|
||||
z.istate.need += (z.next_in[z.next_in_index++] & 0xffL);
|
||||
z.adler = z.istate.need;
|
||||
z.istate.mode = DICT0;
|
||||
return Z_NEED_DICT;
|
||||
|
||||
case DICT0:
|
||||
z.istate.mode = BAD;
|
||||
z.msg = "need dictionary";
|
||||
z.istate.marker = 0; // can try inflateSync
|
||||
return Z_STREAM_ERROR;
|
||||
|
||||
case BLOCKS:
|
||||
|
||||
r = z.istate.blocks.proc(z, r);
|
||||
if (r == Z_DATA_ERROR)
|
||||
{
|
||||
z.istate.mode = BAD;
|
||||
z.istate.marker = 0; // can try inflateSync
|
||||
break;
|
||||
}
|
||||
if (r == Z_OK)
|
||||
{
|
||||
r = f;
|
||||
}
|
||||
if (r != Z_STREAM_END)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
r = f;
|
||||
z.istate.blocks.reset(z, z.istate.was);
|
||||
if (z.istate.nowrap != 0)
|
||||
{
|
||||
z.istate.mode = DONE;
|
||||
break;
|
||||
}
|
||||
z.istate.mode = CHECK4;
|
||||
goto case CHECK4;
|
||||
|
||||
case CHECK4:
|
||||
|
||||
if (z.avail_in == 0)
|
||||
return r; r = f;
|
||||
|
||||
z.avail_in--; z.total_in++;
|
||||
z.istate.need = ((z.next_in[z.next_in_index++] & 0xff) << 24) & unchecked((int) 0xff000000L);
|
||||
z.istate.mode = CHECK3;
|
||||
goto case CHECK3;
|
||||
|
||||
case CHECK3:
|
||||
|
||||
if (z.avail_in == 0)
|
||||
return r; r = f;
|
||||
|
||||
z.avail_in--; z.total_in++;
|
||||
z.istate.need += (((z.next_in[z.next_in_index++] & 0xff) << 16) & 0xff0000L);
|
||||
z.istate.mode = CHECK2;
|
||||
goto case CHECK2;
|
||||
|
||||
case CHECK2:
|
||||
|
||||
if (z.avail_in == 0)
|
||||
return r; r = f;
|
||||
|
||||
z.avail_in--; z.total_in++;
|
||||
z.istate.need += (((z.next_in[z.next_in_index++] & 0xff) << 8) & 0xff00L);
|
||||
z.istate.mode = CHECK1;
|
||||
goto case CHECK1;
|
||||
|
||||
case CHECK1:
|
||||
|
||||
if (z.avail_in == 0)
|
||||
return r; r = f;
|
||||
|
||||
z.avail_in--; z.total_in++;
|
||||
z.istate.need += (z.next_in[z.next_in_index++] & 0xffL);
|
||||
|
||||
if (((int) (z.istate.was[0])) != ((int) (z.istate.need)))
|
||||
{
|
||||
z.istate.mode = BAD;
|
||||
z.msg = "incorrect data check";
|
||||
z.istate.marker = 5; // can't try inflateSync
|
||||
break;
|
||||
}
|
||||
|
||||
z.istate.mode = DONE;
|
||||
goto case DONE;
|
||||
|
||||
case DONE:
|
||||
return Z_STREAM_END;
|
||||
|
||||
case BAD:
|
||||
return Z_DATA_ERROR;
|
||||
|
||||
default:
|
||||
return Z_STREAM_ERROR;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal int inflateSetDictionary(ZStream z, byte[] dictionary, int dictLength)
|
||||
{
|
||||
int index = 0;
|
||||
int length = dictLength;
|
||||
if (z == null || z.istate == null || z.istate.mode != DICT0)
|
||||
return Z_STREAM_ERROR;
|
||||
|
||||
if (z._adler.adler32(1L, dictionary, 0, dictLength) != z.adler)
|
||||
{
|
||||
return Z_DATA_ERROR;
|
||||
}
|
||||
|
||||
z.adler = z._adler.adler32(0, null, 0, 0);
|
||||
|
||||
if (length >= (1 << z.istate.wbits))
|
||||
{
|
||||
length = (1 << z.istate.wbits) - 1;
|
||||
index = dictLength - length;
|
||||
}
|
||||
z.istate.blocks.set_dictionary(dictionary, index, length);
|
||||
z.istate.mode = BLOCKS;
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
private static byte[] mark = new byte[]{(byte) 0, (byte) 0, (byte) SupportClass.Identity(0xff), (byte) SupportClass.Identity(0xff)};
|
||||
|
||||
internal int inflateSync(ZStream z)
|
||||
{
|
||||
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 (z == null || z.istate == null)
|
||||
return Z_STREAM_ERROR;
|
||||
if (z.istate.mode != BAD)
|
||||
{
|
||||
z.istate.mode = BAD;
|
||||
z.istate.marker = 0;
|
||||
}
|
||||
if ((n = z.avail_in) == 0)
|
||||
return Z_BUF_ERROR;
|
||||
p = z.next_in_index;
|
||||
m = z.istate.marker;
|
||||
|
||||
// search
|
||||
while (n != 0 && m < 4)
|
||||
{
|
||||
if (z.next_in[p] == mark[m])
|
||||
{
|
||||
m++;
|
||||
}
|
||||
else if (z.next_in[p] != 0)
|
||||
{
|
||||
m = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m = 4 - m;
|
||||
}
|
||||
p++; n--;
|
||||
}
|
||||
|
||||
// restore
|
||||
z.total_in += p - z.next_in_index;
|
||||
z.next_in_index = p;
|
||||
z.avail_in = n;
|
||||
z.istate.marker = m;
|
||||
|
||||
// return no joy or set up to restart on a new block
|
||||
if (m != 4)
|
||||
{
|
||||
return Z_DATA_ERROR;
|
||||
}
|
||||
r = z.total_in; w = z.total_out;
|
||||
inflateReset(z);
|
||||
z.total_in = r; z.total_out = w;
|
||||
z.istate.mode = BLOCKS;
|
||||
return 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 inflateSyncPoint(ZStream z)
|
||||
{
|
||||
if (z == null || z.istate == null || z.istate.blocks == null)
|
||||
return Z_STREAM_ERROR;
|
||||
return z.istate.blocks.sync_point();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright (c) 2006, ComponentAce
|
||||
// http://www.componentace.com
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
// Neither the name of ComponentAce nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
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, so all credit should go authors
|
||||
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
* and contributors of zlib.
|
||||
*/
|
||||
using System;
|
||||
namespace ComponentAce.Compression.Libs.zlib
|
||||
{
|
||||
|
||||
sealed class StaticTree
|
||||
{
|
||||
private const int MAX_BITS = 15;
|
||||
|
||||
private const int BL_CODES = 19;
|
||||
private const int D_CODES = 30;
|
||||
private const int LITERALS = 256;
|
||||
private const int LENGTH_CODES = 29;
|
||||
private static readonly int L_CODES = (LITERALS + 1 + LENGTH_CODES);
|
||||
|
||||
// Bit length codes must not exceed MAX_BL_BITS bits
|
||||
internal const int MAX_BL_BITS = 7;
|
||||
|
||||
internal static readonly short[] static_ltree = 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[] static_dtree = 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 StaticTree static_l_desc;
|
||||
|
||||
internal static StaticTree static_d_desc;
|
||||
|
||||
internal static StaticTree static_bl_desc;
|
||||
|
||||
internal short[] static_tree; // static tree or null
|
||||
internal int[] extra_bits; // extra bits for each code or null
|
||||
internal int extra_base; // base index for extra_bits
|
||||
internal int elems; // max number of elements in the tree
|
||||
internal int max_length; // max bit length for the codes
|
||||
|
||||
internal StaticTree(short[] static_tree, int[] extra_bits, int extra_base, int elems, int max_length)
|
||||
{
|
||||
this.static_tree = static_tree;
|
||||
this.extra_bits = extra_bits;
|
||||
this.extra_base = extra_base;
|
||||
this.elems = elems;
|
||||
this.max_length = max_length;
|
||||
}
|
||||
static StaticTree()
|
||||
{
|
||||
static_l_desc = new StaticTree(static_ltree, Tree.extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);
|
||||
static_d_desc = new StaticTree(static_dtree, Tree.extra_dbits, 0, D_CODES, MAX_BITS);
|
||||
static_bl_desc = new StaticTree(null, Tree.extra_blbits, 0, BL_CODES, MAX_BL_BITS);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
|
||||
using System;
|
||||
|
||||
|
||||
namespace ComponentAce.Compression.Libs.zlib
|
||||
{
|
||||
public class SupportClass
|
||||
{
|
||||
/// <summary>
|
||||
/// This method returns the literal value received
|
||||
/// </summary>
|
||||
/// <param name="literal">The literal to return</param>
|
||||
/// <returns>The received value</returns>
|
||||
public static long Identity(long literal)
|
||||
{
|
||||
return literal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method returns the literal value received
|
||||
/// </summary>
|
||||
/// <param name="literal">The literal to return</param>
|
||||
/// <returns>The received value</returns>
|
||||
public static ulong Identity(ulong literal)
|
||||
{
|
||||
return literal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method returns the literal value received
|
||||
/// </summary>
|
||||
/// <param name="literal">The literal to return</param>
|
||||
/// <returns>The received value</returns>
|
||||
public static float Identity(float literal)
|
||||
{
|
||||
return literal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method returns the literal value received
|
||||
/// </summary>
|
||||
/// <param name="literal">The literal to return</param>
|
||||
/// <returns>The received value</returns>
|
||||
public static double Identity(double literal)
|
||||
{
|
||||
return literal;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
/// <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)
|
||||
{
|
||||
if ( number >= 0)
|
||||
return number >> bits;
|
||||
else
|
||||
return (number >> bits) + (2 << ~bits);
|
||||
}
|
||||
|
||||
/// <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, long bits)
|
||||
{
|
||||
return URShift(number, (int)bits);
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
if ( number >= 0)
|
||||
return number >> bits;
|
||||
else
|
||||
return (number >> bits) + (2L << ~bits);
|
||||
}
|
||||
|
||||
/// <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, long bits)
|
||||
{
|
||||
return URShift(number, (int)bits);
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
/// <summary>Reads a number of characters from the current source Stream and writes the data to the target array at the specified index.</summary>
|
||||
/// <param name="sourceStream">The source Stream to read from.</param>
|
||||
/// <param name="target">Contains the array of characteres read from the source Stream.</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 Stream.</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 Stream. Returns -1 if the end of the stream is reached.</returns>
|
||||
public static System.Int32 ReadInput(System.IO.Stream sourceStream, byte[] target, int start, int count)
|
||||
{
|
||||
// Returns 0 bytes if not enough space in target
|
||||
if (target.Length == 0)
|
||||
return 0;
|
||||
|
||||
byte[] receiver = new byte[target.Length];
|
||||
int bytesRead = sourceStream.Read(receiver, start, count);
|
||||
|
||||
// Returns -1 if EOF
|
||||
if (bytesRead == 0)
|
||||
return -1;
|
||||
|
||||
for(int i = start; i < start + bytesRead; i++)
|
||||
target[i] = (byte)receiver[i];
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string to an array of bytes
|
||||
/// </summary>
|
||||
/// <param name="sourceString">The string to be converted</param>
|
||||
/// <returns>The new array of bytes</returns>
|
||||
public static byte[] ToByteArray(System.String sourceString)
|
||||
{
|
||||
return System.Text.UTF8Encoding.UTF8.GetBytes(sourceString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an array of bytes to an array of chars
|
||||
/// </summary>
|
||||
/// <param name="byteArray">The array of bytes to convert</param>
|
||||
/// <returns>The new array of chars</returns>
|
||||
public static char[] ToCharArray(byte[] byteArray)
|
||||
{
|
||||
return System.Text.UTF8Encoding.UTF8.GetChars(byteArray);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,349 @@
|
|||
// Copyright (c) 2006, ComponentAce
|
||||
// http://www.componentace.com
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
// Neither the name of ComponentAce nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
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, so all credit should go authors
|
||||
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
* and contributors of zlib.
|
||||
*/
|
||||
using System;
|
||||
namespace ComponentAce.Compression.Libs.zlib
|
||||
{
|
||||
|
||||
sealed class Tree
|
||||
{
|
||||
private const int MAX_BITS = 15;
|
||||
private const int BL_CODES = 19;
|
||||
private const int D_CODES = 30;
|
||||
private const int LITERALS = 256;
|
||||
private const int LENGTH_CODES = 29;
|
||||
private static readonly int L_CODES = (LITERALS + 1 + LENGTH_CODES);
|
||||
private static readonly int HEAP_SIZE = (2 * L_CODES + 1);
|
||||
|
||||
// Bit length codes must not exceed MAX_BL_BITS bits
|
||||
internal const int MAX_BL_BITS = 7;
|
||||
|
||||
// end of block literal code
|
||||
internal const int END_BLOCK = 256;
|
||||
|
||||
// repeat previous bit length 3-6 times (2 bits of repeat count)
|
||||
internal const int REP_3_6 = 16;
|
||||
|
||||
// repeat a zero length 3-10 times (3 bits of repeat count)
|
||||
internal const int REPZ_3_10 = 17;
|
||||
|
||||
// repeat a zero length 11-138 times (7 bits of repeat count)
|
||||
internal const int REPZ_11_138 = 18;
|
||||
|
||||
// extra bits for each length code
|
||||
internal static readonly int[] extra_lbits = 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[] extra_dbits = 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 byte[] bl_order = new byte[]{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;
|
||||
|
||||
internal static readonly byte[] _dist_code = new byte[]{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 byte[] _length_code = new byte[]{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[] base_length = 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[] base_dist = 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};
|
||||
|
||||
// Mapping from a distance to a distance code. dist is the distance - 1 and
|
||||
// must not have side effects. _dist_code[256] and _dist_code[257] are never
|
||||
// used.
|
||||
internal static int d_code(int dist)
|
||||
{
|
||||
return ((dist) < 256?_dist_code[dist]:_dist_code[256 + (SupportClass.URShift((dist), 7))]);
|
||||
}
|
||||
|
||||
internal short[] dyn_tree; // the dynamic tree
|
||||
internal int max_code; // largest code with non zero frequency
|
||||
internal StaticTree stat_desc; // 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(Deflate s)
|
||||
{
|
||||
short[] tree = dyn_tree;
|
||||
short[] stree = stat_desc.static_tree;
|
||||
int[] extra = stat_desc.extra_bits;
|
||||
int base_Renamed = stat_desc.extra_base;
|
||||
int max_length = stat_desc.max_length;
|
||||
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 <= 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(Deflate s)
|
||||
{
|
||||
short[] tree = dyn_tree;
|
||||
short[] stree = stat_desc.static_tree;
|
||||
int elems = stat_desc.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] = (short) (tree[n * 2] + tree[m * 2]);
|
||||
s.depth[node] = (byte) (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[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 <= MAX_BITS; bits++)
|
||||
{
|
||||
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] = (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 = SupportClass.URShift(code, 1);
|
||||
res <<= 1;
|
||||
}
|
||||
while (--len > 0);
|
||||
return SupportClass.URShift(res, 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
// Copyright (c) 2006, ComponentAce
|
||||
// http://www.componentace.com
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
// Neither the name of ComponentAce nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
Copyright (c) 2001 Lapo Luchini.
|
||||
|
||||
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 THE AUTHORS
|
||||
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, so all credit should go authors
|
||||
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
* and contributors of zlib.
|
||||
*/
|
||||
using System;
|
||||
namespace ComponentAce.Compression.Libs.zlib
|
||||
{
|
||||
|
||||
public class ZInputStream:System.IO.BinaryReader
|
||||
{
|
||||
internal void InitBlock()
|
||||
{
|
||||
flush = zlibConst.Z_NO_FLUSH;
|
||||
buf = new byte[bufsize];
|
||||
}
|
||||
virtual public int FlushMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return (flush);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.flush = value;
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary> Returns the total number of bytes input so far.</summary>
|
||||
virtual public long TotalIn
|
||||
{
|
||||
get
|
||||
{
|
||||
return z.total_in;
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary> Returns the total number of bytes output so far.</summary>
|
||||
virtual public long TotalOut
|
||||
{
|
||||
get
|
||||
{
|
||||
return z.total_out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected ZStream z = new ZStream();
|
||||
protected int bufsize = 512;
|
||||
protected int flush;
|
||||
protected byte[] buf, buf1 = new byte[1];
|
||||
protected bool compress;
|
||||
|
||||
internal System.IO.Stream in_Renamed = null;
|
||||
|
||||
public ZInputStream(System.IO.Stream in_Renamed):base(in_Renamed)
|
||||
{
|
||||
InitBlock();
|
||||
this.in_Renamed = in_Renamed;
|
||||
z.inflateInit();
|
||||
compress = false;
|
||||
z.next_in = buf;
|
||||
z.next_in_index = 0;
|
||||
z.avail_in = 0;
|
||||
}
|
||||
|
||||
public ZInputStream(System.IO.Stream in_Renamed, int level):base(in_Renamed)
|
||||
{
|
||||
InitBlock();
|
||||
this.in_Renamed = in_Renamed;
|
||||
z.deflateInit(level);
|
||||
compress = true;
|
||||
z.next_in = buf;
|
||||
z.next_in_index = 0;
|
||||
z.avail_in = 0;
|
||||
}
|
||||
|
||||
/*public int available() throws IOException {
|
||||
return inf.finished() ? 0 : 1;
|
||||
}*/
|
||||
|
||||
public override int Read()
|
||||
{
|
||||
if (read(buf1, 0, 1) == - 1)
|
||||
return (- 1);
|
||||
return (buf1[0] & 0xFF);
|
||||
}
|
||||
|
||||
internal bool nomoreinput = false;
|
||||
|
||||
public int read(byte[] b, int off, int len)
|
||||
{
|
||||
if (len == 0)
|
||||
return (0);
|
||||
int err;
|
||||
z.next_out = b;
|
||||
z.next_out_index = off;
|
||||
z.avail_out = len;
|
||||
do
|
||||
{
|
||||
if ((z.avail_in == 0) && (!nomoreinput))
|
||||
{
|
||||
// if buffer is empty and more input is avaiable, refill it
|
||||
z.next_in_index = 0;
|
||||
z.avail_in = SupportClass.ReadInput(in_Renamed, buf, 0, bufsize); //(bufsize<z.avail_out ? bufsize : z.avail_out));
|
||||
if (z.avail_in == - 1)
|
||||
{
|
||||
z.avail_in = 0;
|
||||
nomoreinput = true;
|
||||
}
|
||||
}
|
||||
if (compress)
|
||||
err = z.deflate(flush);
|
||||
else
|
||||
err = z.inflate(flush);
|
||||
if (nomoreinput && (err == zlibConst.Z_BUF_ERROR))
|
||||
return (- 1);
|
||||
if (err != zlibConst.Z_OK && err != zlibConst.Z_STREAM_END)
|
||||
throw new ZStreamException((compress?"de":"in") + "flating: " + z.msg);
|
||||
if (nomoreinput && (z.avail_out == len))
|
||||
return (- 1);
|
||||
}
|
||||
while (z.avail_out == len && err == zlibConst.Z_OK);
|
||||
//System.err.print("("+(len-z.avail_out)+")");
|
||||
return (len - z.avail_out);
|
||||
}
|
||||
|
||||
public long skip(long n)
|
||||
{
|
||||
int len = 512;
|
||||
if (n < len)
|
||||
len = (int) n;
|
||||
byte[] tmp = new byte[len];
|
||||
return ((long) SupportClass.ReadInput(BaseStream, tmp, 0, tmp.Length));
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
in_Renamed.Close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
// Copyright (c) 2006, ComponentAce
|
||||
// http://www.componentace.com
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
// Neither the name of ComponentAce nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
/*
|
||||
Copyright (c) 2001 Lapo Luchini.
|
||||
|
||||
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 THE AUTHORS
|
||||
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, so all credit should go authors
|
||||
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
* and contributors of zlib.
|
||||
*/
|
||||
using System;
|
||||
namespace ComponentAce.Compression.Libs.zlib
|
||||
{
|
||||
|
||||
public class ZOutputStream:System.IO.Stream
|
||||
{
|
||||
private void InitBlock()
|
||||
{
|
||||
flush_Renamed_Field = zlibConst.Z_NO_FLUSH;
|
||||
buf = new byte[bufsize];
|
||||
}
|
||||
virtual public int FlushMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return (flush_Renamed_Field);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.flush_Renamed_Field = value;
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary> Returns the total number of bytes input so far.</summary>
|
||||
virtual public long TotalIn
|
||||
{
|
||||
get
|
||||
{
|
||||
return z.total_in;
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary> Returns the total number of bytes output so far.</summary>
|
||||
virtual public long TotalOut
|
||||
{
|
||||
get
|
||||
{
|
||||
return z.total_out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected internal ZStream z = new ZStream();
|
||||
protected internal int bufsize = 4096;
|
||||
protected internal int flush_Renamed_Field;
|
||||
protected internal byte[] buf, buf1 = new byte[1];
|
||||
protected internal bool compress;
|
||||
|
||||
private System.IO.Stream out_Renamed;
|
||||
|
||||
public ZOutputStream(System.IO.Stream out_Renamed):base()
|
||||
{
|
||||
InitBlock();
|
||||
this.out_Renamed = out_Renamed;
|
||||
z.inflateInit();
|
||||
compress = false;
|
||||
}
|
||||
|
||||
public ZOutputStream(System.IO.Stream out_Renamed, int level):base()
|
||||
{
|
||||
InitBlock();
|
||||
this.out_Renamed = out_Renamed;
|
||||
z.deflateInit(level);
|
||||
compress = true;
|
||||
}
|
||||
|
||||
public void WriteByte(int b)
|
||||
{
|
||||
buf1[0] = (byte) b;
|
||||
Write(buf1, 0, 1);
|
||||
}
|
||||
//UPGRADE_TODO: The differences in the Expected value of parameters for method 'WriteByte' may cause compilation errors. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1092_3"'
|
||||
public override void WriteByte(byte b)
|
||||
{
|
||||
WriteByte((int) b);
|
||||
}
|
||||
|
||||
public override void Write(System.Byte[] b1, int off, int len)
|
||||
{
|
||||
if (len == 0)
|
||||
return ;
|
||||
int err;
|
||||
byte[] b = new byte[b1.Length];
|
||||
System.Array.Copy(b1, 0, b, 0, b1.Length);
|
||||
z.next_in = b;
|
||||
z.next_in_index = off;
|
||||
z.avail_in = len;
|
||||
do
|
||||
{
|
||||
z.next_out = buf;
|
||||
z.next_out_index = 0;
|
||||
z.avail_out = bufsize;
|
||||
if (compress)
|
||||
err = z.deflate(flush_Renamed_Field);
|
||||
else
|
||||
err = z.inflate(flush_Renamed_Field);
|
||||
if (err != zlibConst.Z_OK && err != zlibConst.Z_STREAM_END)
|
||||
throw new ZStreamException((compress?"de":"in") + "flating: " + z.msg);
|
||||
out_Renamed.Write(buf, 0, bufsize - z.avail_out);
|
||||
}
|
||||
while (z.avail_in > 0 || z.avail_out == 0);
|
||||
}
|
||||
|
||||
public virtual void finish()
|
||||
{
|
||||
int err;
|
||||
do
|
||||
{
|
||||
z.next_out = buf;
|
||||
z.next_out_index = 0;
|
||||
z.avail_out = bufsize;
|
||||
if (compress)
|
||||
{
|
||||
err = z.deflate(zlibConst.Z_FINISH);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = z.inflate(zlibConst.Z_FINISH);
|
||||
}
|
||||
if (err != zlibConst.Z_STREAM_END && err != zlibConst.Z_OK)
|
||||
throw new ZStreamException((compress?"de":"in") + "flating: " + z.msg);
|
||||
if (bufsize - z.avail_out > 0)
|
||||
{
|
||||
out_Renamed.Write(buf, 0, bufsize - z.avail_out);
|
||||
}
|
||||
}
|
||||
while (z.avail_in > 0 || z.avail_out == 0);
|
||||
try
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
public virtual void end()
|
||||
{
|
||||
if (compress)
|
||||
{
|
||||
z.deflateEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
z.inflateEnd();
|
||||
}
|
||||
z.free();
|
||||
z = null;
|
||||
}
|
||||
public override void Close()
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
finish();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
end();
|
||||
out_Renamed.Close();
|
||||
out_Renamed = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
out_Renamed.Flush();
|
||||
}
|
||||
//UPGRADE_TODO: The following method was automatically generated and it must be implemented in order to preserve the class logic. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1232_3"'
|
||||
public override System.Int32 Read(System.Byte[] buffer, System.Int32 offset, System.Int32 count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
//UPGRADE_TODO: The following method was automatically generated and it must be implemented in order to preserve the class logic. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1232_3"'
|
||||
public override void SetLength(System.Int64 value)
|
||||
{
|
||||
}
|
||||
//UPGRADE_TODO: The following method was automatically generated and it must be implemented in order to preserve the class logic. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1232_3"'
|
||||
public override System.Int64 Seek(System.Int64 offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
//UPGRADE_TODO: The following property was automatically generated and it must be implemented in order to preserve the class logic. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1232_3"'
|
||||
public override System.Boolean CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
//UPGRADE_TODO: The following property was automatically generated and it must be implemented in order to preserve the class logic. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1232_3"'
|
||||
public override System.Boolean CanSeek
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
//UPGRADE_TODO: The following property was automatically generated and it must be implemented in order to preserve the class logic. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1232_3"'
|
||||
public override System.Boolean CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
//UPGRADE_TODO: The following property was automatically generated and it must be implemented in order to preserve the class logic. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1232_3"'
|
||||
public override System.Int64 Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
//UPGRADE_TODO: The following property was automatically generated and it must be implemented in order to preserve the class logic. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1232_3"'
|
||||
public override System.Int64 Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,233 @@
|
|||
// Copyright (c) 2006, ComponentAce
|
||||
// http://www.componentace.com
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
// Neither the name of ComponentAce nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
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, so all credit should go authors
|
||||
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
* and contributors of zlib.
|
||||
*/
|
||||
using System;
|
||||
namespace ComponentAce.Compression.Libs.zlib
|
||||
{
|
||||
|
||||
sealed public class ZStream
|
||||
{
|
||||
|
||||
private const int MAX_WBITS = 15; // 32K LZ77 window
|
||||
private static readonly int DEF_WBITS = MAX_WBITS;
|
||||
|
||||
private const int Z_NO_FLUSH = 0;
|
||||
private const int Z_PARTIAL_FLUSH = 1;
|
||||
private const int Z_SYNC_FLUSH = 2;
|
||||
private const int Z_FULL_FLUSH = 3;
|
||||
private const int Z_FINISH = 4;
|
||||
|
||||
private const int MAX_MEM_LEVEL = 9;
|
||||
|
||||
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;
|
||||
|
||||
public byte[] next_in; // next input byte
|
||||
public int next_in_index;
|
||||
public int avail_in; // number of bytes available at next_in
|
||||
public long total_in; // total nb of input bytes read so far
|
||||
|
||||
public byte[] next_out; // next output byte should be put there
|
||||
public int next_out_index;
|
||||
public int avail_out; // remaining free space at next_out
|
||||
public long total_out; // total nb of bytes output so far
|
||||
|
||||
public System.String msg;
|
||||
|
||||
internal Deflate dstate;
|
||||
internal Inflate istate;
|
||||
|
||||
internal int data_type; // best guess about the data type: ascii or binary
|
||||
|
||||
public long adler;
|
||||
internal Adler32 _adler = new Adler32();
|
||||
|
||||
public int inflateInit()
|
||||
{
|
||||
return inflateInit(DEF_WBITS);
|
||||
}
|
||||
public int inflateInit(int w)
|
||||
{
|
||||
istate = new Inflate();
|
||||
return istate.inflateInit(this, w);
|
||||
}
|
||||
|
||||
public int inflate(int f)
|
||||
{
|
||||
if (istate == null)
|
||||
return Z_STREAM_ERROR;
|
||||
return istate.inflate(this, f);
|
||||
}
|
||||
public int inflateEnd()
|
||||
{
|
||||
if (istate == null)
|
||||
return Z_STREAM_ERROR;
|
||||
int ret = istate.inflateEnd(this);
|
||||
istate = null;
|
||||
return ret;
|
||||
}
|
||||
public int inflateSync()
|
||||
{
|
||||
if (istate == null)
|
||||
return Z_STREAM_ERROR;
|
||||
return istate.inflateSync(this);
|
||||
}
|
||||
public int inflateSetDictionary(byte[] dictionary, int dictLength)
|
||||
{
|
||||
if (istate == null)
|
||||
return Z_STREAM_ERROR;
|
||||
return istate.inflateSetDictionary(this, dictionary, dictLength);
|
||||
}
|
||||
|
||||
public int deflateInit(int level)
|
||||
{
|
||||
return deflateInit(level, MAX_WBITS);
|
||||
}
|
||||
public int deflateInit(int level, int bits)
|
||||
{
|
||||
dstate = new Deflate();
|
||||
return dstate.deflateInit(this, level, bits);
|
||||
}
|
||||
public int deflate(int flush)
|
||||
{
|
||||
if (dstate == null)
|
||||
{
|
||||
return Z_STREAM_ERROR;
|
||||
}
|
||||
return dstate.deflate(this, flush);
|
||||
}
|
||||
public int deflateEnd()
|
||||
{
|
||||
if (dstate == null)
|
||||
return Z_STREAM_ERROR;
|
||||
int ret = dstate.deflateEnd();
|
||||
dstate = null;
|
||||
return ret;
|
||||
}
|
||||
public int deflateParams(int level, int strategy)
|
||||
{
|
||||
if (dstate == null)
|
||||
return Z_STREAM_ERROR;
|
||||
return dstate.deflateParams(this, level, strategy);
|
||||
}
|
||||
public int deflateSetDictionary(byte[] dictionary, int dictLength)
|
||||
{
|
||||
if (dstate == null)
|
||||
return Z_STREAM_ERROR;
|
||||
return dstate.deflateSetDictionary(this, dictionary, dictLength);
|
||||
}
|
||||
|
||||
// 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.pending;
|
||||
|
||||
if (len > avail_out)
|
||||
len = avail_out;
|
||||
if (len == 0)
|
||||
return ;
|
||||
|
||||
if (dstate.pending_buf.Length <= dstate.pending_out || next_out.Length <= next_out_index || dstate.pending_buf.Length < (dstate.pending_out + len) || next_out.Length < (next_out_index + len))
|
||||
{
|
||||
//System.Console.Out.WriteLine(dstate.pending_buf.Length + ", " + dstate.pending_out + ", " + next_out.Length + ", " + next_out_index + ", " + len);
|
||||
//System.Console.Out.WriteLine("avail_out=" + avail_out);
|
||||
}
|
||||
|
||||
Array.Copy(dstate.pending_buf, dstate.pending_out, next_out, next_out_index, len);
|
||||
|
||||
next_out_index += len;
|
||||
dstate.pending_out += len;
|
||||
total_out += len;
|
||||
avail_out -= len;
|
||||
dstate.pending -= len;
|
||||
if (dstate.pending == 0)
|
||||
{
|
||||
dstate.pending_out = 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 = avail_in;
|
||||
|
||||
if (len > size)
|
||||
len = size;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
avail_in -= len;
|
||||
|
||||
if (dstate.noheader == 0)
|
||||
{
|
||||
adler = _adler.adler32(adler, next_in, next_in_index, len);
|
||||
}
|
||||
Array.Copy(next_in, next_in_index, buf, start, len);
|
||||
next_in_index += len;
|
||||
total_in += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
public void free()
|
||||
{
|
||||
next_in = null;
|
||||
next_out = null;
|
||||
msg = null;
|
||||
_adler = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
// Copyright (c) 2006, ComponentAce
|
||||
// http://www.componentace.com
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
// Neither the name of ComponentAce nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
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, so all credit should go authors
|
||||
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
* and contributors of zlib.
|
||||
*/
|
||||
using System;
|
||||
namespace ComponentAce.Compression.Libs.zlib
|
||||
{
|
||||
|
||||
|
||||
public class ZStreamException:System.IO.IOException
|
||||
{
|
||||
public ZStreamException():base()
|
||||
{
|
||||
}
|
||||
public ZStreamException(System.String s):base(s)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright (c) 2006, ComponentAce
|
||||
// http://www.componentace.com
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
// Neither the name of ComponentAce nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
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, so all credit should go authors
|
||||
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
* and contributors of zlib.
|
||||
*/
|
||||
using System;
|
||||
namespace ComponentAce.Compression.Libs.zlib
|
||||
{
|
||||
|
||||
sealed public class zlibConst
|
||||
{
|
||||
private const System.String version_Renamed_Field = "1.0.2";
|
||||
public static System.String version()
|
||||
{
|
||||
return version_Renamed_Field;
|
||||
}
|
||||
|
||||
// compression levels
|
||||
public const int Z_NO_COMPRESSION = 0;
|
||||
public const int Z_BEST_SPEED = 1;
|
||||
public const int Z_BEST_COMPRESSION = 9;
|
||||
public const int Z_DEFAULT_COMPRESSION = (- 1);
|
||||
|
||||
// compression strategy
|
||||
public const int Z_FILTERED = 1;
|
||||
public const int Z_HUFFMAN_ONLY = 2;
|
||||
public const int Z_DEFAULT_STRATEGY = 0;
|
||||
|
||||
public const int Z_NO_FLUSH = 0;
|
||||
public const int Z_PARTIAL_FLUSH = 1;
|
||||
public const int Z_SYNC_FLUSH = 2;
|
||||
public const int Z_FULL_FLUSH = 3;
|
||||
public const int Z_FINISH = 4;
|
||||
|
||||
public const int Z_OK = 0;
|
||||
public const int Z_STREAM_END = 1;
|
||||
public const int Z_NEED_DICT = 2;
|
||||
public const int Z_ERRNO = - 1;
|
||||
public const int Z_STREAM_ERROR = - 2;
|
||||
public const int Z_DATA_ERROR = - 3;
|
||||
public const int Z_MEM_ERROR = - 4;
|
||||
public const int Z_BUF_ERROR = - 5;
|
||||
public const int Z_VERSION_ERROR = - 6;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
namespace RPFTool
|
||||
{
|
||||
partial class DownloadForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DownloadForm));
|
||||
this.btn_cancel = new DevExpress.XtraEditors.SimpleButton();
|
||||
this.downloadProgressBar = new DevExpress.XtraEditors.ProgressBarControl();
|
||||
((System.ComponentModel.ISupportInitialize)(this.downloadProgressBar.Properties)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btn_cancel
|
||||
//
|
||||
this.btn_cancel.Location = new System.Drawing.Point(156, 66);
|
||||
this.btn_cancel.Name = "btn_cancel";
|
||||
this.btn_cancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btn_cancel.TabIndex = 6;
|
||||
this.btn_cancel.Text = "Cancel";
|
||||
this.btn_cancel.Click += new System.EventHandler(this.btn_cancel_Click);
|
||||
//
|
||||
// downloadProgressBar
|
||||
//
|
||||
this.downloadProgressBar.Location = new System.Drawing.Point(60, 28);
|
||||
this.downloadProgressBar.Name = "downloadProgressBar";
|
||||
this.downloadProgressBar.Size = new System.Drawing.Size(257, 32);
|
||||
this.downloadProgressBar.TabIndex = 5;
|
||||
//
|
||||
// DownloadForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(375, 106);
|
||||
this.Controls.Add(this.btn_cancel);
|
||||
this.Controls.Add(this.downloadProgressBar);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "DownloadForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Downloading Update...";
|
||||
this.Shown += new System.EventHandler(this.DownloadForm_Shown);
|
||||
((System.ComponentModel.ISupportInitialize)(this.downloadProgressBar.Properties)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private DevExpress.XtraEditors.SimpleButton btn_cancel;
|
||||
private DevExpress.XtraEditors.ProgressBarControl downloadProgressBar;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using DevExpress.XtraEditors;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Security;
|
||||
|
||||
namespace RPFTool
|
||||
{
|
||||
public partial class DownloadForm : DevExpress.XtraEditors.XtraForm
|
||||
{
|
||||
public string URL;
|
||||
private WebClient wc = new WebClient();
|
||||
|
||||
public DownloadForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void DownloadForm_Shown(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (URL == null || URL == "")
|
||||
{
|
||||
MessageBox.Show("Download Failed, URL empty.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
string downloadPath = Path.GetTempPath() + @"latest.zip";
|
||||
wc.DownloadProgressChanged += (s, f) =>
|
||||
{
|
||||
downloadProgressBar.Position = f.ProgressPercentage;
|
||||
};
|
||||
wc.DownloadFileCompleted += (s, g) =>
|
||||
{
|
||||
if (g.Cancelled)
|
||||
return;
|
||||
System.Diagnostics.Process.Start(downloadPath);
|
||||
Application.Exit();
|
||||
};
|
||||
wc.DownloadFileAsync(new Uri(URL), downloadPath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show("Download Failed", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void btn_cancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
wc.CancelAsync();
|
||||
this.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,632 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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
|
||||
GCYe01eklFYinee1f3m8jljPSql5IUQfADz77LM/+ehHP/o9In4CoXkwAmBrJ+6BYVYJlxG698oATDrg
|
||||
kSNHfuXhhx/+KBCk9Eop+5c5viX4bcwwGYYVAMNkmI7MAQgh/kBrXRvmnwdwpiZ75plnnpJS9gHA0aNH
|
||||
z3/zm9/8f+TQMYRKqQ/AAJGNkG0XtpeBYW41ZYShuQp2gY45AEUiMxVBnnjiiX3ve9/7dgLBoh2/93u/
|
||||
9xo5rqS1fgFYWsmnXXTdg661nka1uOiJEye+vX///j8n4gcRKqWNAEaJbDeR9SBQEDV4JMPcCujk9hyA
|
||||
UnXbA3npAbgCYJzIXqoJTp48+Vt33333p6rNGSHEug7d67Jwx2GYDMMKgGEyzP8HLvrg+dAOZdoAAAAA
|
||||
SUVORK5CYIIoAAAAMAAAAGAAAAABACAAAAAAAIAlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
////BMXFxUSdnZ2zAAAAkwAAAMMAAADnAAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA7QAAAO0AAADt
|
||||
AAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA7QAAAO0AAADt
|
||||
AAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA5QAAAMEAAACRoKCgr8vLy0L+/v4EAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAGxsbKjk5OdcAAADrAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA5zs7O9EiIiIg
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAABOAAAA3wAAAP8AAAD/FxIF/z8yD/9eShb/ZlEY/2VRGP9lURj/
|
||||
ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/
|
||||
ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/XEkW/z0xD/8VEQX/
|
||||
AAAA/wAAAP8AAADXAAAASAAAAAAAAAAA////BBsbGygAAADfAAAA/wQEAf9NPhP/vZcs/+S2NP/wvzf/
|
||||
8sA3//LAN//ywDj/8sA3//LAN//ywDj/8sA3//LAN//ywDf/8sA3//LAN//ywDj/8sA4//LAN//ywDf/
|
||||
8sA3//LAN//ywDf/8sA4//LAN//ywDf/8sA4//LAN//ywDj/8sA3//LAN//ywDj/8sA3//LAN//ywDf/
|
||||
8L83/+O2NP+5lCv/RzkR/wMCAf8AAAD/AAAA1yYmJh7+/v4ExMTERDg4ONkAAAD/BAMB/3thHP/quTT/
|
||||
77w1//C8Nf/yvjb/8b02//G9Nf/xvTb/8b41//G9Nv/xvjb/8b42//G+Nf/xvTb/8b02//G9Nf/xvTb/
|
||||
8b02//G9Nv/xvTb/8b02//G9Nv/xvjb/8b02//G+Nf/xvTb/8b02//G+Nv/xvTb/8b01//G9Nv/xvTb/
|
||||
8b42//G9Nv/xvTX/8r42//C8Nv/vvDb/6Lg0/3FZGv8DAgD/AAAA/zs7O8/Nzc1AnJyctQAAAOsAAAD/
|
||||
SDgQ/+WyMf/otTH/57Qx/7+VKf+AZB3/cVga/3FYG/9xWBv/cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/
|
||||
cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/
|
||||
cVgb/3FYG/9xWBv/cVgb/3FYG/9xWRv/gmYe/8KXKv/otDH/6bUy/+KvMP8+MA7/AAAA/wAAAOeioqKt
|
||||
AAAAkwAAAP8VEAX/sogl/+OuL//hrS7/e18b/w8LA/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/xINBP+EZhz/4q4u/+SvL/+qgiP/
|
||||
EAwE/wAAAP8AAACFAAAAxQAAAP86LAz/0Z8p/+GqLP+ziCT/DAkC/wMDA/8bGxv/Gxsb/xsbG/8bGxv/
|
||||
Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/
|
||||
Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/wMDA/8RDQP/
|
||||
u44l/+CpK//OnCj/MycL/wAAAP8AAAC5AAAA6QAAAP9UPxD/1qEn/92mKP90WBf/AAAA/xsbG///////
|
||||
/////////////////////////////////////////////////v7+////////////////////////////
|
||||
///////////+/v7////////////////////////////+/v7//////////////////v7+////////////
|
||||
/////xsbG/8AAAD/gGEZ/92mKP/Unyf/SjgO/wAAAP8AAADbAAAA7wAAAP9ZQhD/1Z4l/9qhJf9oTRT/
|
||||
AAAA/xsbG//////////////////+/v7/////////////////////////////////////////////////
|
||||
//////////////////////7+/v////////////7+/v////////////7+/v/+/v7///////7+/v//////
|
||||
//////7+/v/+/v7//////xsbG/8AAAD/dFYW/9mgJf/RmyT/TzoO/wAAAP8AAADfAAAA6wAAAP9INQ3/
|
||||
rH4e/6+AHv9UPhH/AAAA/xsbG//+/v7//////8zMzPWHh4f5hISE/4SEhP+FhYX9hYWF/YSEhP+EhIT/
|
||||
hYWF/bKysu3+/v7////////////+/v7///////7+/v/Q0NDPjIyM8YWFhf+EhIT/hISE/4yMjPHp6en5
|
||||
/v7+/////////////v7+//7+/v/+/v7//v7+/xsbG/8AAAD/clMV/9WbI//NliL/TTkN/wAAAP8AAADf
|
||||
AAAAxwAAAP8IBgH/FQ8E/xUPBP8KBwL/AAAA/xwcHPf/////ycnJ+xgYGPsAAAD9AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wwMDPeZmZn3/f39//7+/v///////////9DQ0N0QEBDRAAAA+QAAAP8AAAD/
|
||||
AAAA/wAAAPk4ODj77e3t+/7+/v////////////7+/v///////////xsbG/8AAAD/cFEU/9GWIP/JkR//
|
||||
TDcL/wAAAP8AAADfAAAAyQAAAP8ODg7/IiIh/yIiIv8VFRX/AAAA/xwcHP//////NjY29QAAAP8MDAz/
|
||||
IiIi/yIiIv8UFBT/EhER/yIiIv8iIiL/EBAQ/wAAAP8AAADl9vb2/f///////////////6ioqPkAAAD5
|
||||
BAQE/xwcHP8iIiL/ICAg/wUFBf8AAAD7gICA6////////////////////////////////xsbG/8AAAD/
|
||||
bk8S/8ySHf/FjBz/SjUK/wAAAP8AAADfAAAA5wAAAP9eXl7/39/f/+Li4v+MjIz/AAAA/wQEBP8mJib/
|
||||
BwcH/wAAAP9RUVD/4uLi/+Li4v+GhYX/dHNz/+Li4v/i4uL/cHBw/wICAv8AAAD9JCQk/yYmJv8mJib/
|
||||
JiYm/xgYGP8AAAD/HR0d/7q6uf/i4uL/09PT/yQkJP8AAAD/YWFh+9DQ0P3Q0ND90NDQ/dDQ0P3d3d35
|
||||
/v7+/xsbG/8AAAD/a0wQ/8iNGv/BiBn/STMJ/wAAAP8AAADfAAAA6QAAAP9oaGj/+vr6//7+/v+ZmZn/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP9hYGD///////////+Wlpb/gH9////////+/v7/eXl4/wICAv8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/ICAg/9DQ0P/+/v7/7e3t/ycnJ/8AAAD/AAAA+wAAAPkAAAD5
|
||||
AAAA+QAAAPcZGRnxenp69w0NDfsAAAD/akoP/8WJF/++hBf/SDII/wAAAP8AAADfAAAA6QAAAP9oaGj/
|
||||
+vr6//7+/v/Kycn/d3d3/3l5eP95eXj/eXl4/39/fv/Ozs7///////r6+v96enr/f35+//7+/v/+/v7/
|
||||
wsLB/4mJiP+IiIj/iIiI/4iIiP+IiIj/ioqK/2JiYv8ZGRn/ICAg/9DQ0P/+/v7/7e3t/y4uLv8LCwv/
|
||||
CwsL/wsLC/8LCwv/CwsL/woKCv8BAQH/AAAA/QAAAP8AAAD/aEgO/8KFFv+7gBX/RjAI/wAAAP8AAADf
|
||||
AAAA6QAAAP9oaGj/+vr6///////+/v7//v7+///////+/v7//////////////////f39/6urqv8fHx//
|
||||
gH9////////+/v7//v7+//////////////////////////////////n5+f+ioqH/ISEg/9DPz///////
|
||||
+Pj4/7Cvr/+ioqL/oqKi/6Kiov+ioqL/o6Oj/46Ojv8QEBD/AAAA/wAAAP8AAAD/ZkYN/76BFP+4fRP/
|
||||
RS8H/wAAAP8AAADfAAAA6QAAAP9oaGj/+vr6///////t7e3/0dHR/9LS0f/S0tH/0tLR/9LS0v/p6en/
|
||||
/v7+/9nZ2f9FRUX/gH9////////+/v7/5eXl/83Nzf/Nzc3/zc3N/83Nzf/X19f/+Pf3///////z8/P/
|
||||
QkJB/83Nzf///////v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+/97e3v8aGhr/AAAA/wAAAP8AAAD/
|
||||
ZEML/7t9Ef+0eBD/RC0G/wAAAP8AAADfAAAA6QAAAP9oaGj/+vr6//////+kpKT/HBwc/x0dHf8dHR3/
|
||||
HR0d/x4eHv9qamr//Pz8//7+/v+SkpL/gH9////////+/v7/hIWE/xcXF/8WFhb/FhYW/xUVFf8wLy//
|
||||
ysrK///////5+fn/Y2Nj/8zMzP//////9/f3/56env+Ojo7/j46O/4+Ojv+Pjo7/j46O/319ff8ODg7/
|
||||
AAAA/wAAAP8AAAD/Y0IL/7h6EP+xdQ//QywF/wAAAP8AAADfAAAA6QAAAP9oaGj/+vr6//////+cm5v/
|
||||
BAQE/wQEBP8EBAT/BAQE/wYGBv9OTk7/+vr6//7+/v+goKD/gYGA//7+/v/+/v7/fX18/wcGBv8EBAT/
|
||||
BAQE/wQEBP8eHh7/wsLC///////5+fn/ZGNj/8zMzP//////7e3t/ygoKP8GBgb/BgYG/wYGBv8GBgb/
|
||||
BgYG/wYGBv8BAQH/AAAA/wAAAP8AAAD/YT8K/7R2Df+ucgz/QioE/wAAAP8AAADfAAAA6QAAAP9oaGj/
|
||||
+vr6///////V1dX/k5OT/5WVlP+VlZT/lZSU/5mZmP/MzMz//v7+//////+ZmZn/gICA///////+/v7/
|
||||
ycnI/5WVlP+VlZT/lZWU/5SUlP+xsbH/8fHx///////39/f/SklJ/83MzP/+/v7/9vb2/5qamv+IiIj/
|
||||
iYmJ/4mJif+JiYn/iYmJ/4uLiv8wLy//AAAA/wAAAP8AAAD/Xz4J/7FyDP+rbgz/QCkE/wAAAP8AAADf
|
||||
AAAA6QAAAP9qamr/+/v7///////+/v7//f39//7+/f/+/v3//v39//7+/v/+/v7///////Dw8P9cXFv/
|
||||
gICA//7+/v///////v7+//39/f/+/v3//v79//39/f/+/v7//v7+//r6+v+1tbT/IyMj/9DQ0P/+/v7/
|
||||
/v7+//39/f/9/f3//f39//39/f/9/f3//f39//39/f9YWFj/AAAA/wAAAP8AAAD/XjwH/65vCf+oawn/
|
||||
PygD/wAAAP8AAADfAAAA5wAAAP9SUlL/wMDA/8LCwv/CwsL/wsLC/8LCwv/CwsL/wsLC/8LCwv/DwsL/
|
||||
uLi4/21sbP8ODg7/ZGRk/8LCwv/CwsL/wsLC/8LCwv/CwsL/wsLC/8LCwv/Dw8P/vr29/35+fv8lJSX/
|
||||
GhkZ/6Cgn//CwsL/wsLC/8LCwv/CwsL/wsLC/8LCwv/CwsL/wsLC/8LCwv9ERET/AAAA/wAAAP8AAAD/
|
||||
XToG/6xsB/+maQf/PicC/wAAAP8AAADfAAAAvwAAAP8AAAD/AgIC/wICAv8CAgL/AgIC/wICAv8CAgL/
|
||||
AgIC/wICAv8CAgL/AQEB/wAAAP8AAAD/AQEB/wICAv8CAgL/AgIC/wICAv8CAgL/AgIC/wICAv8CAgL/
|
||||
AgIC/wAAAP8AAAD/AAAA/wEBAf8CAgL/AgIC/wICAv8CAgL/AgIC/wICAv8CAgL/AgIC/wICAv8AAAD/
|
||||
AAAA/wAAAP8AAAD/WzkG/6lpBv+jZQX/PiYB/wAAAP8AAADfAAAAzQAAAP8HBQD/EgsC/xILAv8IBQH/
|
||||
AAAA/wAAAP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/
|
||||
AwMD/wMDA/8DAwP/AwMD/wMDA/sDAwPtAwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/
|
||||
AwMD/wMDA/8DAwP/AwMD9QAAAP0AAAD/WjcF/6dlA/+hYQP/PCQB/wAAAP8AAADfAAAA7wAAAP9CKAH/
|
||||
nV4B/6FgAf9NLwP/AAAA/xsbG////////////////////////v7+/////////////v7+///////+/v7/
|
||||
///////////+/v7///////7+/v/+/v7///////7+/v///////////////////////v7+////////////
|
||||
//////7+/v///////v7+//7+/v/+/v7//////xsbG/8AAAD/WDUD/6RiAP+dXgD/OyQA/wAAAP8AAADf
|
||||
AAAA7QAAAP9FKwn/pWgY/6ttHv9SNhL/AAAA/xsbG////////v7+//7+/v/+/v7/////////////////
|
||||
//////////////////////////////////////7+/v///////v7+///////+/v7/////////////////
|
||||
///////////+/v7///////7+/v////////////7+/v///////////xsbG/8AAAD/VjQD/6JgAP+cXQD/
|
||||
OiMA/wAAAP8AAADfAAAA7QAAAP9MNiL/toFR/7qEU/9YQCj/AAAA/xsbG///////////////////////
|
||||
//////////////////////////////////////////////////////7+/v////////////7+/v//////
|
||||
//////7+/v////////////7+/v////////////7+/v////////////7+/v///////////xsbG/8AAAD/
|
||||
VjMC/6BdAP+aWgD/OiEA/wAAAP8AAADfAAAA7QAAAP9LNSH/tH5N/7iBTv9YPib/AAAA/xsbG///////
|
||||
//////7+/v///////////////////////v7+//7+/v///////////////////////v7+///////+/v7/
|
||||
///////////+/v7//v7+//7+/v///////v7+//7+/v///////////////////////v7+////////////
|
||||
/v7+/xsbG/8AAAD/VDEC/51bAP+XVwD/OSAA/wAAAP8AAADfAAAA7QAAAP9KNCD/sXxM/7V+Tf9WPSb/
|
||||
AAAA/xsbG//////////////////+/v7///////7+/v//////////////////////////////////////
|
||||
//////////////////////////////////////7+/v////////////7+/v////////////7+/v//////
|
||||
/////////////////////xsbG/8AAAD/UzAC/5tZAP+WVQD/OCAA/wAAAP8AAADfAAAA7QAAAP9KMx//
|
||||
sHpK/7R8TP9WPCb/AAAA/xsbG///////////////////////////////////////////////////////
|
||||
//////////////////////7+/v////////////7+/v///////v7+//7+/v////////////7+/v//////
|
||||
//////7+/v////////////7+/v///////////xsbG/8AAAD/UzAF/5pXA/+UVAD/Nx8A/wAAAP8AAADf
|
||||
AAAA7QAAAP9JMh7/rnhJ/7N6S/9VOyX/AAAA/xsbG////////v7+//////////////////7+/v//////
|
||||
/v7+//////////////////7+/v///////v7+/////////////////////////////v7+//7+/v/+/v7/
|
||||
///////////+/v7//v7+///////+/v7//v7+/////////////////xsbG/8AAAD/XkAl/6twNv+bXxz/
|
||||
OCEG/wAAAP8AAADfAAAA7QAAAP9JMh7/rndJ/7J6Sv9VOyX/AAAA/xsbG////////v7+////////////
|
||||
//////////////////////7+/v///////////////////////v7+//7+/v//////////////////////
|
||||
///////////////////////////+/v7//v7+//7+/v////////////7+/v///////////xsbG/8AAAD/
|
||||
X0Iq/7J6S/+qdEf/QCsZ/wAAAP8AAADfAAAA7QAAAP9IMR7/rXZH/7B4Sf9UOiT/AAAA/xsbG//+/v7/
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/v7+//7+/v///////////////////////v7+//7+/v//////////////////////////////////////
|
||||
/////xsbG/8AAAD/X0Eo/7F4Sf+qc0b/QCsa/wAAAP8AAADfAAAA7QAAAP9HMR7/rHRH/693Sf9TOST/
|
||||
AAAA/xsbG/////////////7+/v////////////7+/v////////////7+/v//////////////////////
|
||||
/v7+/////////////////////////////////////////////////////////////v7+///////+/v7/
|
||||
/v7+/////////////////xsbG/8AAAD/XkAo/7B3Sf+pc0b/QCsa/wAAAP8AAADfAAAA7QAAAP9HMB7/
|
||||
qnJH/651SP9TOCT/AAAA/xsbG///////////////////////////////////////////////////////
|
||||
//////////////////////7+/v////////////7+/v////////////7+/v//////////////////////
|
||||
//////7+/v///////////////////////////xsbG/8AAAD/Xj8o/650SP+ocUb/Pyoa/wAAAP8AAADf
|
||||
AAAA7QAAAP9GLx3/qXFG/610R/9TOCP/AAAA/xsbG////////v7+/////////////v7+////////////
|
||||
/v7+/////////////v7+//////////////////////////////////////////////////7+/v//////
|
||||
//////////////////////7+/v///////////////////////////xsbG/8AAAD/XT8n/61zR/+ncEX/
|
||||
Pyoa/wAAAP8AAADfAAAA7QAAAP9GLx3/qHFG/6xzR/9SNyP/AAAA/xsbG///////////////////////
|
||||
//////////////////////7+/v////////////7+/v/////////////////+/v7/////////////////
|
||||
/////////////////v7+//////////////////7+/v///////////////////////////xsbG/8AAAD/
|
||||
XT4n/6xzR/+mb0X/Pioa/wAAAP8AAADfAAAA7QAAAP9GLh3/p29F/6tyR/9SNyP/AAAA/xsbG///////
|
||||
/v7+///////+/v7///////7+/v///////v7+//7+/v/+/v7///////7+/v///////v7+////////////
|
||||
//////7+/v/+/v7///////7+/v///////////////////////v7+///////////////////////+/v7/
|
||||
/////xsbG/8AAAD/Wz4n/6tyR/+lbkT/Pika/wAAAP8AAADfAAAA5wAAAP9BKxv/pm5F/6tyR/9aPCb/
|
||||
AAAA/xsbG////////v7+///////////////////////+/v7////////////////////////////+/v7/
|
||||
//////7+/v////////////7+/v////////////7+/v////////////7+/v////////////7+/v//////
|
||||
//////7+/v///////////xsbG/8AAAD/ZEMq/6tyR/+kbUT/OSYY/wAAAP8AAADbAAAAxQAAAP8rHRL/
|
||||
nmhA/6lwRf+HWjf/CQYE/wMDA/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/
|
||||
Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/
|
||||
Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/wMDA/8NCQX/jV46/6lwRf+aZz7/JhoQ/wAAAP8AAAC5
|
||||
AAAAkwAAAP8PCgb/glc1/6hwRP+nbkP/XD0l/wsIBf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/w4JBv9iQSj/qG9E/6lwRP98UjL/
|
||||
CwgF/wAAAP0AAACDnJycswAAAOsAAAD/MyIV/6VtQ/+ob0T/pm5D/4tcOf9fPyf/WDok/1g6JP9YOiT/
|
||||
WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/
|
||||
WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/YEAn/41dOv+nb0T/
|
||||
qHBE/6NsQv8sHRL/AAAA/wAAAOWjo6OtxcXFRDk5OdcAAAD/AwIB/1U5I/+kbUL/qHBE/6hwRP+qcUX/
|
||||
qnBF/6lwRf+qcEX/qnBF/6lwRf+qcEX/qnBF/6pwRf+pcEX/qnBF/6pwRf+pcEX/qnBF/6pwRf+pcEX/
|
||||
qXBF/6pwRf+qcEX/qnBF/6pwRf+qcEX/qXBF/6pwRf+pcEX/qXBF/6pwRf+qcEX/qXBF/6lwRf+pcEX/
|
||||
qnFF/6lwRP+ocET/o2xC/040IP8CAQD/AAAA/zw8PM3Pz89A////BBwcHCgAAADdAAAA/wMCAf8zIhX/
|
||||
gVY1/51oP/+kbUP/pW5D/6VuQ/+mbkP/pm5D/6ZuQ/+lbkP/pW5D/6VuQ/+lbkP/pm5D/6ZuQ/+mbkP/
|
||||
pW5D/6VuQ/+mbkP/pm5D/6ZuQ/+lbkP/pm5D/6ZuQ/+mbkP/pW5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/
|
||||
pW5D/6ZuQ/+lbkP/pGxC/5xnP/9+VDP/Lh8T/wIBAP8AAAD/AAAA0ykpKRz///8EAAAAAAAAAAAAAABM
|
||||
AAAA3QAAAP8AAAD/DwoG/yocEf8+KRr/RC4c/0QuHf9ELh3/RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/
|
||||
RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/
|
||||
RC4d/0QuHf9ELh3/RC4d/0QuHf9ELhz/PSkZ/ygbEP8NCQX/AAAA/wAAAP8AAADRAAAAQgAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAGxsbKDo6OtMAAADpAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA5zs7O88lJSUe
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////BMrKykKgoKCvAAAAjwAAAL8AAADjAAAA6wAAAOsAAADr
|
||||
AAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADr
|
||||
AAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA4QAAAL0AAACP
|
||||
oqKirc3NzUD///8EAAAAAAAAAAAAAAAA4AAAAAAHAADgAAAAAAcAAMAAAAAAAwAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAADAADgAAAAAAcAAOAAAAAABwAAKAAAACAAAABAAAAA
|
||||
AQAgAAAAAACAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxcXFNltbW50AAAC/AAAA6QAAAPMAAADz
|
||||
AAAA8wAAAPMAAADzAAAA8wAAAPMAAADzAAAA8wAAAPMAAADzAAAA8wAAAPMAAADzAAAA8wAAAPMAAADz
|
||||
AAAA8wAAAPMAAADzAAAA5wAAAL1eXl6ZysrKNAAAAAAAAAAAAAAAAAAAACQAAAC/AAAA/RYSBf86Lg3/
|
||||
RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP9ENhD/
|
||||
RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP84LQ3/FRAF/wAAAP0AAAC3AAAAIgAAAADExMQ2AAAAvwEBAP9mUhj/
|
||||
1qox/++9Nv/xvzf/8b83//G/N//xvzf/8b83//G/N//xvzf/8b83//G/N//xvzf/8b83//G/N//xvzf/
|
||||
8b83//G/N//xvzf/8b83//G/N//xvzf/8b83/+69Nv/UqTH/YU0X/wAAAP8AAAC3zMzMNFpaWp8AAAD9
|
||||
YkwV/+i1Mv/jsTH/sYsn/5x6I/+ceiT/nHok/5x6JP+ceiT/nHok/5x6JP+ceiT/nHok/5x6JP+ceiT/
|
||||
nHok/5x6JP+ceiT/nHok/5x6JP+ceiT/nHok/5x6JP+ceiT/s4wo/+SyMf/ntDL/WkYU/wAAAP1fX1+X
|
||||
AAAAvxQPBP/ImSn/26cs/0IzDv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/STgQ/9ypLf/Elij/
|
||||
EQ0D/wAAALcAAADrNCcK/9eiKP+jeyD/AAAA/4uLi/+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/
|
||||
vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/4uLi/8AAAD/
|
||||
q4Eh/9WgKP8uIwn/AAAA4wAAAPM8LQr/2J8l/5FrGv8AAAD/vLy8////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
vLy8/wAAAP+Wbxv/0Zsk/zQnCf8AAADpAAAA4Q8LA/83KAr/JRsH/wAAAP2+vr79uLi4/QUFBfUDAwP/
|
||||
AwMD/QMDA/0DAwP/AwMD95SUlPf+/v7///////////9iYmLFAwMD9QMDA/8DAwP9SUlJ9ff39/3/////
|
||||
//////////+8vLz/AAAA/5JqGf/LkyD/MyUI/wAAAOkAAADhGRkZ/1hYWP9DQ0L/AAAA/5CQkP8bGxv7
|
||||
FRUV/1lZWf9BQED/PDw8/1lZWf8eHh7/AAAA876+vv/Dw8P/w8PD/xMTE/kaGhr/WVlZ/0BAP/8BAQH9
|
||||
qqqq9f///////////////7y8vP8AAAD/jmUV/8WMG/8xIwf/AAAA6QAAAPFGRkb//Pz8/7y7u/8AAAD/
|
||||
AAAA/wAAAP8/Pz///////7m5uf+rqqr//v7+/1NTU/8AAAD/AAAA/wAAAP8AAAD/AAAA/0xLS///////
|
||||
tra2/wICAv8iIiL7NTU1+TU1NflHR0fze3t7+wAAAP+KYBL/wIYY/zAhBv8AAADpAAAA8UZGRv/7+/v/
|
||||
5+fn/6WlpP+mpqX/paWl/87Ozv/9/f3/kJCQ/6mpqf/+/v7/ycnJ/7Cwr/+wsK//sLCv/6ysrP9PT0//
|
||||
TEtL//////+9vb3/IiIi/yAgIP8gICD/ICAg/woKCv8AAAD/AAAA/4dcEf+8gBX/LyAF/wAAAOkAAADx
|
||||
RkZG//v7+//39/f/4ODg/+Hh4P/h4OD/6+vr//Dw8P9TU1P/qqqq//7+/v/o6Oj/3d3d/93d3f/i4uL/
|
||||
+/v7//Dw8P9ZWVn///////7+/v/8/Pz//f39//39/f/8/Pz/UVFR/wAAAP8AAAD/g1gO/7Z6Ef8uHwT/
|
||||
AAAA6QAAAPFGRkb/+/v7/8DAwP8TExP/FBQT/xMTE/9DQ0P//Pz8/7m5uf+qqqr//v7+/1xcW/8ODg7/
|
||||
Dg4O/x0dHf/Y2Nf/+/v7/3Z2dv//////0NDQ/2NiYv9iYWH/YmFh/2JhYf8fHx//AAAA/wAAAP+AVAz/
|
||||
sXUO/ywdA/8AAADpAAAA8UZGRv/7+/v/19fW/2ZlZf9mZmb/ZmZm/5SUlP/+/v7/vLy8/6qqqv/+/v7/
|
||||
mZiY/2ZmZv9mZmb/e3t6/+3t7f/6+vr/amlp///////Pz8//XV1d/11dXf9dXV3/XV1d/zU1Nf8AAAD/
|
||||
AAAA/3xQCv+tcAz/KxwD/wAAAOkAAADxRUVF//T09P/19fX/9fX1//X19f/19fX/9fX1//Hx8f9xcXH/
|
||||
paWl//X19f/19fX/9fX1//X19f/19fX/8/Pz/6qqqf9KSkr/9vb1//X19f/09PT/9PT0//T09P/09PT/
|
||||
iouK/wAAAP8AAAD/eU0I/6hrCP8qGgL/AAAA6QAAAN0PDw//NjY2/zc3N/83Nzf/Nzc3/zc3N/83Nzf/
|
||||
KSkp/wMDA/8lJSX/Nzc3/zc3N/83Nzf/Nzc3/zc3N/8tLS3/BQUF/xAQEP83Nzf/Nzc3/zc3N/83Nzf/
|
||||
Nzc3/zc3N/8fHx//AAAA/wAAAP93Sgb/pWcG/ykZAf8AAADpAAAA5RILAP9AJwL/KxoC/wAAAP9AQED/
|
||||
V1dX/1dXV/9XV1f/V1dX/1dXV/9XV1f/V1dX/1dXV/9XV1f/V1dX/1dXV/9aWlr1V1dX/1dXV/9XV1f/
|
||||
V1dX/1dXV/9XV1f/V1dX/1dXV/9CQkL5AAAA/3RGA/+hYQL/KBgA/wAAAOkAAADzLhwE/6RlEf9vRhD/
|
||||
AAAA/7y8vP//////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////7y8vP8AAAD/cUMC/51eAP8nFwD/AAAA6QAAAPMzJBb/
|
||||
tYBQ/3pWNv8AAAD/vLy8////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////vLy8/wAAAP9vQQH/mloA/yYWAP8AAADp
|
||||
AAAA8zIjFf+yfUz/eFQ0/wAAAP+8vLz/////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////+8vLz/AAAA/2w+Af+XVgD/
|
||||
JRUA/wAAAOkAAADzMSIU/7B6Sv92UjP/AAAA/7y8vP//////////////////////////////////////
|
||||
///////////////////////////+/v7//////////////////////////////////////7y8vP8AAAD/
|
||||
b0MP/5ZVBP8lFQD/AAAA6QAAAPMxIRT/rndJ/3VRMv8AAAD/vLy8////////////////////////////
|
||||
//////////////////////////////////////7+/v//////////////////////////////////////
|
||||
vLy8/wAAAP98VjX/qnND/ykbDv8AAADpAAAA8zAhFP+tdUf/dE8x/wAAAP+8vLz/////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////+8vLz/AAAA/3tUM/+rdEf/Kx0R/wAAAOkAAADzMCAU/6tzR/9yTTD/AAAA/7y8vP//////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////7y8vP8AAAD/elIz/6lyRv8qHBH/AAAA6QAAAPMvHxT/qXFG/3JMMP8AAAD/
|
||||
vLy8////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////vLy8/wAAAP95UTL/qHBF/yocEf8AAADpAAAA8y8fE/+ocEb/
|
||||
cUsv/wAAAP+8vLz/////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////+8vLz/AAAA/3dQMv+mb0X/KRwR/wAAAOkAAADp
|
||||
KBoR/6VuRP9+VDT/AAAA/4uLi/+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/
|
||||
vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/4uLi/8AAAD/hFg3/6RtQ/8jFw7/
|
||||
AAAA4QAAAL8PCgb/lGI8/6NsQv8yIRT/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/zYkFv+kbUP/
|
||||
kWA7/wwIBf8AAAC1W1tbnwAAAP1GLhz/pm5D/6NsQv+AVTT/dE0v/3RNL/90TS//dE0v/3RNL/90TS//
|
||||
dE0v/3RNL/90TS//dE0v/3RNL/90TS//dE0v/3VNL/90TS//dE0v/3RNL/90TS//dE0v/3RNL/+CVjX/
|
||||
pG1C/6ZuQ/9AKxr/AAAA/WBgYJfGxsY2AAAAvQEAAP9GLhz/k2I8/6RtQv+mbkP/pm5D/6ZuQ/+mbkP/
|
||||
pm5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/
|
||||
pm5D/6RtQv+SYTv/Qiwb/wAAAP8AAACzzs7OMgAAAAAAAAAiAAAAvQAAAP0OCQb/JhkQ/y0fE/8uHxP/
|
||||
Lh8T/y4fE/8uHxP/LR8T/y4fE/8uHxP/Lh8T/y4fE/8uHxP/LR8T/y4fE/8uHxP/LR8T/y4fE/8uHxP/
|
||||
Lh8T/y4fE/8uHxP/JRkP/w0JBf8AAAD9AAAAswAAAB4AAAAAAAAAAAAAAADGxsY0XV1dmwAAAL0AAADn
|
||||
AAAA8QAAAPEAAADxAAAA8QAAAPEAAADxAAAA8QAAAPEAAADxAAAA8QAAAPEAAADxAAAA8QAAAPEAAADx
|
||||
AAAA8QAAAPEAAADxAAAA8QAAAPEAAADlAAAAvV9fX5fMzMw0AAAAAAAAAADAAAADgAAAAQAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAABwAAAAygAAAAYAAAA
|
||||
MAAAAAEAIAAAAAAAYAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTExDE1NTa8AAADVAAAA9QAAAPcAAAD3
|
||||
AAAA9wAAAPcAAAD3AAAA9wAAAPcAAAD3AAAA9wAAAPcAAAD3AAAA9wAAAPcAAAD3AAAA9QAAANNOTk6r
|
||||
PDw8CgAAAAAyMjIMAAAAwxQQBf9+ZB3/qYYn/6uJKP+siSj/rIko/6uJKP+siSj/q4ko/6yJKP+riSj/
|
||||
rIko/6yJKP+riSj/q4ko/6uJKP+siSj/qYYn/3xjHf8SDwT/AAAAvUJCQghMTEyvEw8E/82gLf/hsDH/
|
||||
tY4p/7GLKP+xiyj/sYso/7GLKP+xiyj/sYso/7GLKP+xiyj/sYso/7GLKP+xiyj/sYso/7GLKP+xiyj/
|
||||
to8p/+KxMv/JnSz/EAwD/09PT6kAAADVdFkY/9ajK/8mHQn/DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/
|
||||
DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/yohCv/YpSv/b1QW/wAAAM8AAAD1
|
||||
lnAb/6V7Hv8NDQ3//v7+//7+/v/+/v7//v7+//7+/v/////////////////+/v7////////////+/v7/
|
||||
/v7+/////////////////w0NDf+qfx//j2sa/wAAAO8AAADtRDIM/0k1Df8ODg798fHx/1paWvlCQkL/
|
||||
QkJC/UJCQv9QUFD35eXl/f/////09PT3WFhY40JCQv9DQ0P7w8PD+//////+/v7//////w0NDf+idRv/
|
||||
jGYW/wAAAO8AAADrW1tb/2pqaf8ICAj/WVlZ/RcXF/+CgoL/SEdH/4KCgv8hISD/SEhI95KSkv95eXn9
|
||||
CAgI/Xd2dv9HR0f/Nzc39+fn5/3n5+f99vb2/Q0NDf+bbhb/hl8S/wAAAO8AAADzsbGx/9jY2P88PDz/
|
||||
PDw8/2tra//9/f3/hISD//7+/v9xcXH/RERE/0RERP87Ozv/FhYW/+fn5/+MjIz/BQUF/wUFBfsFBQX7
|
||||
JCQk+QMDA/2WaBP/gloP/wAAAO8AAADzsbGx//r6+v/o6Oj/6Ojo/+7u7v/g4OD/WVlY//7+/v/s7Oz/
|
||||
5ubm/+jo6P/7+/v/fn5+/+bm5v/p6en/0NDQ/9DQ0P/Dw8P/CgoK/wAAAP+RYg//fVQM/wAAAO8AAADz
|
||||
sbGx/8/Pz/8QEBD/ERER/zc3N//9/f3/jY2M//7+/v9ISEf/DQ0N/xoaGv/i4uL/rq6u/+Xl5f+qqqr/
|
||||
SkpK/0pKSv9GRkb/BAQE/wAAAP+MXAz/eU8J/wAAAO8AAADzsrKy//T09P/Jycj/ycnJ/9jY2P/7+/v/
|
||||
fX19//7+/v/W1tb/ycnJ/9DQ0P/6+vr/hoaG/+bm5v/j4+P/w8PD/8PDw//ExMP/IiIh/wAAAP+HVwn/
|
||||
dUsH/wAAAO8AAADpRUVF/2JiYv9iYmL/YmJi/2JiYv9KSUn/HRwc/2JiYv9iYmL/YmJi/2JiYv9PT0//
|
||||
Dw8P/1lZWf9iYmL/YmJi/2JiYv9iYmL/ERER/wAAAP+DUgb/cUcE/wAAAO8AAADvPiUB/0IoAv8HBwf/
|
||||
gYGB/4GBgf+BgYH/gYGB/4GBgf+BgYH/gYGB/4GBgf+BgYH/g4OD+4GBgf+BgYH/gYGB/4GBgf+BgYH/
|
||||
goKC/QcHB/9/TQP/bUIB/wAAAO8AAAD3e1Il/4RZK/8NDQ3///////7+/v/+/v7///////7+/v/+/v7/
|
||||
///////////+/v7////////////+/v7///////7+/v/+/v7//v7+/w0NDf97SQH/az8A/wAAAO8AAAD3
|
||||
f1k2/4deOv8NDQ3/////////////////////////////////////////////////////////////////
|
||||
/////////////////////w0NDf94RQH/ZzsA/wAAAO8AAAD3fFY0/4RbOP8NDQ3/////////////////
|
||||
//////////////////////7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+/w0NDf9+Thn/
|
||||
aD0I/wAAAO8AAAD3e1Qz/4NaN/8NDQ3///////7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7/
|
||||
/v7+//7+/v/+/v7///////7+/v/+/v7//v7+/w0NDf+IXTn/dU8w/wAAAO8AAAD3eVIy/4FXNv8NDQ3/
|
||||
/////////////////////////////////////////////////v7+////////////////////////////
|
||||
/////w0NDf+GWzj/dE4w/wAAAO8AAAD3d1Ay/39VNf8NDQ3///////////////////////7+/v//////
|
||||
/////////////////v7+/////////////v7+/////////////v7+/w0NDf+FWTf/ck0v/wAAAO8AAAD1
|
||||
dU4w/4FWNv8NDQ3//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7/
|
||||
/v7+//7+/v/+/v7//v7+/w0NDf+FWTj/cEsu/wAAAO0AAADVVzkj/6BqQf8dEwz/DQ0N/w0NDf8NDQ3/
|
||||
DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/yAVDf+ia0L/
|
||||
Ujch/wAAAM9NTU2vDQkF/5JhO/+gakH/g1Y1/4FVNP+BVTT/gVU0/4FVNP+BVTT/gVU0/4FVNP+BVTT/
|
||||
gVU0/4FVNP+BVTT/gVU0/4FVNP+BVTT/g1c1/6FrQf+PXzr/CwcE/1BQUKkzMzMMAAAAwQ0JBf9VOSP/
|
||||
c0wv/3VOMP91TjD/dU4w/3VOMP91TjD/dU4w/3VOMP91TjD/dU4w/3VOMP91TjD/dU4w/3VOMP91TjD/
|
||||
c0wv/1Q4Iv8MCAX/AAAAuUdHRwgAAAAAMjIyDE5OTqsAAADTAAAA8wAAAPUAAAD1AAAA9QAAAPUAAAD1
|
||||
AAAA9QAAAPUAAAD1AAAA9QAAAPUAAAD1AAAA9QAAAPUAAAD1AAAA8wAAANNPT0+pQkJCCAAAAACAAAEA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAQAoAAAAEAAAACAAAAABACAAAAAAAEAEAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAACCYmJqUWEQXpIhsI+SIbCPkiGwj5IhsI+SIbCPkiGwj5IhsI+SIbCPkiGwj5
|
||||
IhsI+RURBeknJyahAAAACCYmJqVsVRj/1qkw/8edLf/HnS3/x50t/8edLf/HnS3/x50t/8edLf/HnS3/
|
||||
x50t/8edLf/WqTD/aVIX/ycnJ58TDwTrx5cn/zMvJv9eXl7/Xl5e/15eXv9eXl7/Xl5e/15eXv9eXl7/
|
||||
Xl5e/15eXv9eXl7/NTEn/8iYJ/8RDQPlEw4D9XFTFP9eXl7/sLCw/YGBgf+BgYH/p6en+/7+/v/f39/x
|
||||
goKC/ZOTk/v9/f3//////15eXv+xgh7/GxME9RkZGfOVlJT/JCQk/xwcG/2UlJT/j4+P/xwcHPtgYGD/
|
||||
NTU1/W9vb/8+Pj7/gICA+aCgoPtNTU39p3YX/xkSA/UkJCT39fX1/8PDw//Q0ND/tLS0/9TU1P/Q0M//
|
||||
yMjH/7q6uv+oqKj/tra2/46Ojv9eXl7/AAAA/59sEf8YEAL1JCQk9+Pj4/89PDz/VFRU/9zc3P/U1NT/
|
||||
Wlpa/0NDQ//u7u7/t7e3/5iYmP9fX1//RUVE/wAAAP+XYgz/Fw8B9RYWFvOVlZX/lpaW/5aWlv9jY2P/
|
||||
fn19/5aWlv+Wlpb/c3Nz/2JiYv+Wlpb/lpaW/3V1df8AAAD/j1oH/xUNAPUQCgH1XzsJ/z8/P/+rq6v/
|
||||
q6ur/6urq/+rq6v/q6ur/6ysrP2rq6v/q6ur/6urq/+rq6v/Pz8//YlSAv8UDAD1GRIL+ZZqQf9eXl7/
|
||||
/////////////////////////////////////////////////////15eXv+DTAD/FAsA9RkRCvmSZT7/
|
||||
Xl5e//////////////////////////////////7+/v////////////////9eXl7/i1gj/xQMA/UYEAr5
|
||||
j2E8/15eXv//////////////////////////////////////////////////////Xl5e/5JjPf8WDwn1
|
||||
GBAK+Y1eO/9eXl7//////////////////////////////////////////////////////15eXv+QYDz/
|
||||
FQ4J9Q8KBumWZD3/Lyso/15eXv9eXl7/Xl5e/15eXv9eXl7/Xl5e/15eXv9eXl7/Xl5e/15eXv8wLCj/
|
||||
l2Q+/w0JBeUmJialTTMf/5dkPf+NXTn/jV45/41eOf+NXjn/jV45/41eOf+NXjn/jV45/41eOf+NXjn/
|
||||
l2Q9/0oxHv8nJyefAAAACCYmJqMOCQbpFw8K+RcPCvkXDwr5Fw8K+RcPCvkXDwr5Fw8K+RcPCvkXDwr5
|
||||
Fw8K+Q4JBecnJyefAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
|
@ -0,0 +1,98 @@
|
|||
namespace RPFTool
|
||||
{
|
||||
partial class form_extract
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(form_extract));
|
||||
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
|
||||
this.label_filename = new System.Windows.Forms.Label();
|
||||
this.progressBar1 = new DevExpress.XtraEditors.ProgressBarControl();
|
||||
this.btn_cancel = new DevExpress.XtraEditors.SimpleButton();
|
||||
((System.ComponentModel.ISupportInitialize)(this.progressBar1.Properties)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// backgroundWorker1
|
||||
//
|
||||
this.backgroundWorker1.WorkerReportsProgress = true;
|
||||
this.backgroundWorker1.WorkerSupportsCancellation = true;
|
||||
//
|
||||
// label_filename
|
||||
//
|
||||
this.label_filename.AutoSize = true;
|
||||
this.label_filename.Location = new System.Drawing.Point(54, 9);
|
||||
this.label_filename.Name = "label_filename";
|
||||
this.label_filename.Size = new System.Drawing.Size(63, 13);
|
||||
this.label_filename.TabIndex = 1;
|
||||
this.label_filename.Text = "Extracting: ";
|
||||
//
|
||||
// progressBar1
|
||||
//
|
||||
this.progressBar1.Location = new System.Drawing.Point(45, 39);
|
||||
this.progressBar1.Name = "progressBar1";
|
||||
this.progressBar1.Size = new System.Drawing.Size(257, 32);
|
||||
this.progressBar1.TabIndex = 3;
|
||||
//
|
||||
// btn_cancel
|
||||
//
|
||||
this.btn_cancel.Location = new System.Drawing.Point(141, 77);
|
||||
this.btn_cancel.Name = "btn_cancel";
|
||||
this.btn_cancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btn_cancel.TabIndex = 4;
|
||||
this.btn_cancel.Text = "Cancel";
|
||||
this.btn_cancel.Click += new System.EventHandler(this.btn_cancel_Click_1);
|
||||
//
|
||||
// form_extract
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(351, 111);
|
||||
this.ControlBox = false;
|
||||
this.Controls.Add(this.btn_cancel);
|
||||
this.Controls.Add(this.progressBar1);
|
||||
this.Controls.Add(this.label_filename);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Name = "form_extract";
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Extracting...";
|
||||
this.Load += new System.EventHandler(this.form_extract_Load);
|
||||
((System.ComponentModel.ISupportInitialize)(this.progressBar1.Properties)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.ComponentModel.BackgroundWorker backgroundWorker1;
|
||||
private System.Windows.Forms.Label label_filename;
|
||||
private DevExpress.XtraEditors.ProgressBarControl progressBar1;
|
||||
private DevExpress.XtraEditors.SimpleButton btn_cancel;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using RPFLib.Common;
|
||||
using System.IO;
|
||||
using DevExpress.XtraEditors;
|
||||
|
||||
namespace RPFTool
|
||||
{
|
||||
public partial class form_extract : XtraForm
|
||||
{
|
||||
public form_extract(List<fileSystemObject> objectList, string pth)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
filesystem = objectList;
|
||||
path = pth;
|
||||
fileprogress = 0;
|
||||
progressBar1.Properties.PercentView = true;
|
||||
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
|
||||
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
|
||||
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
|
||||
}
|
||||
|
||||
private static List<fileSystemObject> filesystem;
|
||||
private static string path;
|
||||
private static int fileprogress = 0;
|
||||
private static int filecount = 0;
|
||||
|
||||
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
initialExtract(filesystem, path, e);
|
||||
}
|
||||
|
||||
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
||||
{
|
||||
progressBar1.Position = e.ProgressPercentage;
|
||||
}
|
||||
|
||||
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
if ((e.Cancelled == true))
|
||||
{
|
||||
}
|
||||
|
||||
else if (!(e.Error == null))
|
||||
{
|
||||
MessageBox.Show("Failed to extract all files :" + Environment.NewLine + e.Error.ToString());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
MessageBox.Show("All files in archive exported.", "Export All", MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Information);
|
||||
}
|
||||
this.Invoke(new MethodInvoker(delegate { this.Close(); }));
|
||||
}
|
||||
|
||||
private void form_extract_Load(object sender, EventArgs e)
|
||||
{
|
||||
backgroundWorker1.RunWorkerAsync();
|
||||
}
|
||||
|
||||
private void initialExtract(List<fileSystemObject> fileList, string path, DoWorkEventArgs e)
|
||||
{
|
||||
filecount = getFilecount(fileList);
|
||||
|
||||
foreach (fileSystemObject item in fileList)
|
||||
{
|
||||
if (item.IsReturnDirectory)
|
||||
continue;
|
||||
else if (item.IsDirectory)
|
||||
{
|
||||
try
|
||||
{
|
||||
//var dir = item as RPFLib.Common.Directory;
|
||||
if (item.Name == "Root")
|
||||
{
|
||||
ExtractToPath(item as RPFLib.Common.Directory, path + "\\", e);
|
||||
}
|
||||
else
|
||||
{
|
||||
System.IO.Directory.CreateDirectory(Path.Combine(path, item.Name));
|
||||
ExtractToPath(item as RPFLib.Common.Directory, Path.Combine(path, item.Name) + "\\", e);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
int test = Convert.ToInt32(((double)fileprogress / filecount)*100.0);
|
||||
backgroundWorker1.ReportProgress(test);
|
||||
|
||||
var file = item as RPFLib.Common.File;
|
||||
this.Invoke(new MethodInvoker(delegate { label_filename.Text = "Extracting: " + file.Name; }));
|
||||
byte[] data = file.GetData(false);
|
||||
System.IO.File.WriteAllBytes(Path.Combine(path, file.Name), data);
|
||||
fileprogress++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if ((backgroundWorker1.CancellationPending == true))
|
||||
{
|
||||
e.Cancel = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getFilecount(List<fileSystemObject> fileList)
|
||||
{
|
||||
int filecount = 0;
|
||||
foreach (fileSystemObject item in fileList)
|
||||
{
|
||||
if (item.IsReturnDirectory)
|
||||
continue;
|
||||
else if (item.IsDirectory)
|
||||
{
|
||||
filecount = dirCount(item as RPFLib.Common.Directory, filecount);
|
||||
}
|
||||
else
|
||||
{
|
||||
filecount++;
|
||||
}
|
||||
}
|
||||
return filecount;
|
||||
}
|
||||
|
||||
private int dirCount(RPFLib.Common.Directory dir, int filecount)
|
||||
{
|
||||
foreach (fileSystemObject item in dir)
|
||||
{
|
||||
if (item.IsReturnDirectory)
|
||||
continue;
|
||||
else if (item.IsDirectory)
|
||||
{
|
||||
filecount = dirCount(item as RPFLib.Common.Directory, filecount);
|
||||
}
|
||||
else
|
||||
{
|
||||
filecount++;
|
||||
}
|
||||
}
|
||||
return filecount;
|
||||
}
|
||||
|
||||
private void ExtractToPath(RPFLib.Common.Directory dir, string path, DoWorkEventArgs e)
|
||||
{
|
||||
foreach (fileSystemObject item in dir)
|
||||
{
|
||||
if ((backgroundWorker1.CancellationPending == true))
|
||||
{
|
||||
e.Cancel = true;
|
||||
break;
|
||||
}
|
||||
if (item.IsReturnDirectory)
|
||||
continue;
|
||||
else if (item.IsDirectory)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.IO.Directory.CreateDirectory(path + item.Name);
|
||||
ExtractToPath(item as RPFLib.Common.Directory, Path.Combine(path, item.Name) + "\\", e);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
int test = Convert.ToInt32(((double)fileprogress / filecount) * 100.0);
|
||||
backgroundWorker1.ReportProgress(test);
|
||||
var file = item as RPFLib.Common.File;
|
||||
this.Invoke(new MethodInvoker(delegate { label_filename.Text = "Extracting: " + file.Name; }));
|
||||
byte[] data = file.GetData(false);
|
||||
System.IO.File.WriteAllBytes(Path.Combine(path, file.Name), data);
|
||||
fileprogress++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void btn_cancel_Click_1(object sender, EventArgs e)
|
||||
{
|
||||
backgroundWorker1.CancelAsync();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,635 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="backgroundWorker1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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
|
||||
GCYe01eklFYinee1f3m8jljPSql5IUQfADz77LM/+ehHP/o9In4CoXkwAmBrJ+6BYVYJlxG698oATDrg
|
||||
kSNHfuXhhx/+KBCk9Eop+5c5viX4bcwwGYYVAMNkmI7MAQgh/kBrXRvmnwdwpiZ75plnnpJS9gHA0aNH
|
||||
z3/zm9/8f+TQMYRKqQ/AAJGNkG0XtpeBYW41ZYShuQp2gY45AEUiMxVBnnjiiX3ve9/7dgLBoh2/93u/
|
||||
9xo5rqS1fgFYWsmnXXTdg661nka1uOiJEye+vX///j8n4gcRKqWNAEaJbDeR9SBQEDV4JMPcCujk9hyA
|
||||
UnXbA3npAbgCYJzIXqoJTp48+Vt33333p6rNGSHEug7d67Jwx2GYDMMKgGEyzP8HLvrg+dAOZdoAAAAA
|
||||
SUVORK5CYIIoAAAAMAAAAGAAAAABACAAAAAAAIAlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
////BMXFxUSdnZ2zAAAAkwAAAMMAAADnAAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA7QAAAO0AAADt
|
||||
AAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA7QAAAO0AAADt
|
||||
AAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA5QAAAMEAAACRoKCgr8vLy0L+/v4EAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAGxsbKjk5OdcAAADrAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA5zs7O9EiIiIg
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAABOAAAA3wAAAP8AAAD/FxIF/z8yD/9eShb/ZlEY/2VRGP9lURj/
|
||||
ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/
|
||||
ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/XEkW/z0xD/8VEQX/
|
||||
AAAA/wAAAP8AAADXAAAASAAAAAAAAAAA////BBsbGygAAADfAAAA/wQEAf9NPhP/vZcs/+S2NP/wvzf/
|
||||
8sA3//LAN//ywDj/8sA3//LAN//ywDj/8sA3//LAN//ywDf/8sA3//LAN//ywDj/8sA4//LAN//ywDf/
|
||||
8sA3//LAN//ywDf/8sA4//LAN//ywDf/8sA4//LAN//ywDj/8sA3//LAN//ywDj/8sA3//LAN//ywDf/
|
||||
8L83/+O2NP+5lCv/RzkR/wMCAf8AAAD/AAAA1yYmJh7+/v4ExMTERDg4ONkAAAD/BAMB/3thHP/quTT/
|
||||
77w1//C8Nf/yvjb/8b02//G9Nf/xvTb/8b41//G9Nv/xvjb/8b42//G+Nf/xvTb/8b02//G9Nf/xvTb/
|
||||
8b02//G9Nv/xvTb/8b02//G9Nv/xvjb/8b02//G+Nf/xvTb/8b02//G+Nv/xvTb/8b01//G9Nv/xvTb/
|
||||
8b42//G9Nv/xvTX/8r42//C8Nv/vvDb/6Lg0/3FZGv8DAgD/AAAA/zs7O8/Nzc1AnJyctQAAAOsAAAD/
|
||||
SDgQ/+WyMf/otTH/57Qx/7+VKf+AZB3/cVga/3FYG/9xWBv/cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/
|
||||
cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/
|
||||
cVgb/3FYG/9xWBv/cVgb/3FYG/9xWRv/gmYe/8KXKv/otDH/6bUy/+KvMP8+MA7/AAAA/wAAAOeioqKt
|
||||
AAAAkwAAAP8VEAX/sogl/+OuL//hrS7/e18b/w8LA/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/xINBP+EZhz/4q4u/+SvL/+qgiP/
|
||||
EAwE/wAAAP8AAACFAAAAxQAAAP86LAz/0Z8p/+GqLP+ziCT/DAkC/wMDA/8bGxv/Gxsb/xsbG/8bGxv/
|
||||
Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/
|
||||
Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/wMDA/8RDQP/
|
||||
u44l/+CpK//OnCj/MycL/wAAAP8AAAC5AAAA6QAAAP9UPxD/1qEn/92mKP90WBf/AAAA/xsbG///////
|
||||
/////////////////////////////////////////////////v7+////////////////////////////
|
||||
///////////+/v7////////////////////////////+/v7//////////////////v7+////////////
|
||||
/////xsbG/8AAAD/gGEZ/92mKP/Unyf/SjgO/wAAAP8AAADbAAAA7wAAAP9ZQhD/1Z4l/9qhJf9oTRT/
|
||||
AAAA/xsbG//////////////////+/v7/////////////////////////////////////////////////
|
||||
//////////////////////7+/v////////////7+/v////////////7+/v/+/v7///////7+/v//////
|
||||
//////7+/v/+/v7//////xsbG/8AAAD/dFYW/9mgJf/RmyT/TzoO/wAAAP8AAADfAAAA6wAAAP9INQ3/
|
||||
rH4e/6+AHv9UPhH/AAAA/xsbG//+/v7//////8zMzPWHh4f5hISE/4SEhP+FhYX9hYWF/YSEhP+EhIT/
|
||||
hYWF/bKysu3+/v7////////////+/v7///////7+/v/Q0NDPjIyM8YWFhf+EhIT/hISE/4yMjPHp6en5
|
||||
/v7+/////////////v7+//7+/v/+/v7//v7+/xsbG/8AAAD/clMV/9WbI//NliL/TTkN/wAAAP8AAADf
|
||||
AAAAxwAAAP8IBgH/FQ8E/xUPBP8KBwL/AAAA/xwcHPf/////ycnJ+xgYGPsAAAD9AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wwMDPeZmZn3/f39//7+/v///////////9DQ0N0QEBDRAAAA+QAAAP8AAAD/
|
||||
AAAA/wAAAPk4ODj77e3t+/7+/v////////////7+/v///////////xsbG/8AAAD/cFEU/9GWIP/JkR//
|
||||
TDcL/wAAAP8AAADfAAAAyQAAAP8ODg7/IiIh/yIiIv8VFRX/AAAA/xwcHP//////NjY29QAAAP8MDAz/
|
||||
IiIi/yIiIv8UFBT/EhER/yIiIv8iIiL/EBAQ/wAAAP8AAADl9vb2/f///////////////6ioqPkAAAD5
|
||||
BAQE/xwcHP8iIiL/ICAg/wUFBf8AAAD7gICA6////////////////////////////////xsbG/8AAAD/
|
||||
bk8S/8ySHf/FjBz/SjUK/wAAAP8AAADfAAAA5wAAAP9eXl7/39/f/+Li4v+MjIz/AAAA/wQEBP8mJib/
|
||||
BwcH/wAAAP9RUVD/4uLi/+Li4v+GhYX/dHNz/+Li4v/i4uL/cHBw/wICAv8AAAD9JCQk/yYmJv8mJib/
|
||||
JiYm/xgYGP8AAAD/HR0d/7q6uf/i4uL/09PT/yQkJP8AAAD/YWFh+9DQ0P3Q0ND90NDQ/dDQ0P3d3d35
|
||||
/v7+/xsbG/8AAAD/a0wQ/8iNGv/BiBn/STMJ/wAAAP8AAADfAAAA6QAAAP9oaGj/+vr6//7+/v+ZmZn/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP9hYGD///////////+Wlpb/gH9////////+/v7/eXl4/wICAv8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/ICAg/9DQ0P/+/v7/7e3t/ycnJ/8AAAD/AAAA+wAAAPkAAAD5
|
||||
AAAA+QAAAPcZGRnxenp69w0NDfsAAAD/akoP/8WJF/++hBf/SDII/wAAAP8AAADfAAAA6QAAAP9oaGj/
|
||||
+vr6//7+/v/Kycn/d3d3/3l5eP95eXj/eXl4/39/fv/Ozs7///////r6+v96enr/f35+//7+/v/+/v7/
|
||||
wsLB/4mJiP+IiIj/iIiI/4iIiP+IiIj/ioqK/2JiYv8ZGRn/ICAg/9DQ0P/+/v7/7e3t/y4uLv8LCwv/
|
||||
CwsL/wsLC/8LCwv/CwsL/woKCv8BAQH/AAAA/QAAAP8AAAD/aEgO/8KFFv+7gBX/RjAI/wAAAP8AAADf
|
||||
AAAA6QAAAP9oaGj/+vr6///////+/v7//v7+///////+/v7//////////////////f39/6urqv8fHx//
|
||||
gH9////////+/v7//v7+//////////////////////////////////n5+f+ioqH/ISEg/9DPz///////
|
||||
+Pj4/7Cvr/+ioqL/oqKi/6Kiov+ioqL/o6Oj/46Ojv8QEBD/AAAA/wAAAP8AAAD/ZkYN/76BFP+4fRP/
|
||||
RS8H/wAAAP8AAADfAAAA6QAAAP9oaGj/+vr6///////t7e3/0dHR/9LS0f/S0tH/0tLR/9LS0v/p6en/
|
||||
/v7+/9nZ2f9FRUX/gH9////////+/v7/5eXl/83Nzf/Nzc3/zc3N/83Nzf/X19f/+Pf3///////z8/P/
|
||||
QkJB/83Nzf///////v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+/97e3v8aGhr/AAAA/wAAAP8AAAD/
|
||||
ZEML/7t9Ef+0eBD/RC0G/wAAAP8AAADfAAAA6QAAAP9oaGj/+vr6//////+kpKT/HBwc/x0dHf8dHR3/
|
||||
HR0d/x4eHv9qamr//Pz8//7+/v+SkpL/gH9////////+/v7/hIWE/xcXF/8WFhb/FhYW/xUVFf8wLy//
|
||||
ysrK///////5+fn/Y2Nj/8zMzP//////9/f3/56env+Ojo7/j46O/4+Ojv+Pjo7/j46O/319ff8ODg7/
|
||||
AAAA/wAAAP8AAAD/Y0IL/7h6EP+xdQ//QywF/wAAAP8AAADfAAAA6QAAAP9oaGj/+vr6//////+cm5v/
|
||||
BAQE/wQEBP8EBAT/BAQE/wYGBv9OTk7/+vr6//7+/v+goKD/gYGA//7+/v/+/v7/fX18/wcGBv8EBAT/
|
||||
BAQE/wQEBP8eHh7/wsLC///////5+fn/ZGNj/8zMzP//////7e3t/ygoKP8GBgb/BgYG/wYGBv8GBgb/
|
||||
BgYG/wYGBv8BAQH/AAAA/wAAAP8AAAD/YT8K/7R2Df+ucgz/QioE/wAAAP8AAADfAAAA6QAAAP9oaGj/
|
||||
+vr6///////V1dX/k5OT/5WVlP+VlZT/lZSU/5mZmP/MzMz//v7+//////+ZmZn/gICA///////+/v7/
|
||||
ycnI/5WVlP+VlZT/lZWU/5SUlP+xsbH/8fHx///////39/f/SklJ/83MzP/+/v7/9vb2/5qamv+IiIj/
|
||||
iYmJ/4mJif+JiYn/iYmJ/4uLiv8wLy//AAAA/wAAAP8AAAD/Xz4J/7FyDP+rbgz/QCkE/wAAAP8AAADf
|
||||
AAAA6QAAAP9qamr/+/v7///////+/v7//f39//7+/f/+/v3//v39//7+/v/+/v7///////Dw8P9cXFv/
|
||||
gICA//7+/v///////v7+//39/f/+/v3//v79//39/f/+/v7//v7+//r6+v+1tbT/IyMj/9DQ0P/+/v7/
|
||||
/v7+//39/f/9/f3//f39//39/f/9/f3//f39//39/f9YWFj/AAAA/wAAAP8AAAD/XjwH/65vCf+oawn/
|
||||
PygD/wAAAP8AAADfAAAA5wAAAP9SUlL/wMDA/8LCwv/CwsL/wsLC/8LCwv/CwsL/wsLC/8LCwv/DwsL/
|
||||
uLi4/21sbP8ODg7/ZGRk/8LCwv/CwsL/wsLC/8LCwv/CwsL/wsLC/8LCwv/Dw8P/vr29/35+fv8lJSX/
|
||||
GhkZ/6Cgn//CwsL/wsLC/8LCwv/CwsL/wsLC/8LCwv/CwsL/wsLC/8LCwv9ERET/AAAA/wAAAP8AAAD/
|
||||
XToG/6xsB/+maQf/PicC/wAAAP8AAADfAAAAvwAAAP8AAAD/AgIC/wICAv8CAgL/AgIC/wICAv8CAgL/
|
||||
AgIC/wICAv8CAgL/AQEB/wAAAP8AAAD/AQEB/wICAv8CAgL/AgIC/wICAv8CAgL/AgIC/wICAv8CAgL/
|
||||
AgIC/wAAAP8AAAD/AAAA/wEBAf8CAgL/AgIC/wICAv8CAgL/AgIC/wICAv8CAgL/AgIC/wICAv8AAAD/
|
||||
AAAA/wAAAP8AAAD/WzkG/6lpBv+jZQX/PiYB/wAAAP8AAADfAAAAzQAAAP8HBQD/EgsC/xILAv8IBQH/
|
||||
AAAA/wAAAP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/
|
||||
AwMD/wMDA/8DAwP/AwMD/wMDA/sDAwPtAwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/
|
||||
AwMD/wMDA/8DAwP/AwMD9QAAAP0AAAD/WjcF/6dlA/+hYQP/PCQB/wAAAP8AAADfAAAA7wAAAP9CKAH/
|
||||
nV4B/6FgAf9NLwP/AAAA/xsbG////////////////////////v7+/////////////v7+///////+/v7/
|
||||
///////////+/v7///////7+/v/+/v7///////7+/v///////////////////////v7+////////////
|
||||
//////7+/v///////v7+//7+/v/+/v7//////xsbG/8AAAD/WDUD/6RiAP+dXgD/OyQA/wAAAP8AAADf
|
||||
AAAA7QAAAP9FKwn/pWgY/6ttHv9SNhL/AAAA/xsbG////////v7+//7+/v/+/v7/////////////////
|
||||
//////////////////////////////////////7+/v///////v7+///////+/v7/////////////////
|
||||
///////////+/v7///////7+/v////////////7+/v///////////xsbG/8AAAD/VjQD/6JgAP+cXQD/
|
||||
OiMA/wAAAP8AAADfAAAA7QAAAP9MNiL/toFR/7qEU/9YQCj/AAAA/xsbG///////////////////////
|
||||
//////////////////////////////////////////////////////7+/v////////////7+/v//////
|
||||
//////7+/v////////////7+/v////////////7+/v////////////7+/v///////////xsbG/8AAAD/
|
||||
VjMC/6BdAP+aWgD/OiEA/wAAAP8AAADfAAAA7QAAAP9LNSH/tH5N/7iBTv9YPib/AAAA/xsbG///////
|
||||
//////7+/v///////////////////////v7+//7+/v///////////////////////v7+///////+/v7/
|
||||
///////////+/v7//v7+//7+/v///////v7+//7+/v///////////////////////v7+////////////
|
||||
/v7+/xsbG/8AAAD/VDEC/51bAP+XVwD/OSAA/wAAAP8AAADfAAAA7QAAAP9KNCD/sXxM/7V+Tf9WPSb/
|
||||
AAAA/xsbG//////////////////+/v7///////7+/v//////////////////////////////////////
|
||||
//////////////////////////////////////7+/v////////////7+/v////////////7+/v//////
|
||||
/////////////////////xsbG/8AAAD/UzAC/5tZAP+WVQD/OCAA/wAAAP8AAADfAAAA7QAAAP9KMx//
|
||||
sHpK/7R8TP9WPCb/AAAA/xsbG///////////////////////////////////////////////////////
|
||||
//////////////////////7+/v////////////7+/v///////v7+//7+/v////////////7+/v//////
|
||||
//////7+/v////////////7+/v///////////xsbG/8AAAD/UzAF/5pXA/+UVAD/Nx8A/wAAAP8AAADf
|
||||
AAAA7QAAAP9JMh7/rnhJ/7N6S/9VOyX/AAAA/xsbG////////v7+//////////////////7+/v//////
|
||||
/v7+//////////////////7+/v///////v7+/////////////////////////////v7+//7+/v/+/v7/
|
||||
///////////+/v7//v7+///////+/v7//v7+/////////////////xsbG/8AAAD/XkAl/6twNv+bXxz/
|
||||
OCEG/wAAAP8AAADfAAAA7QAAAP9JMh7/rndJ/7J6Sv9VOyX/AAAA/xsbG////////v7+////////////
|
||||
//////////////////////7+/v///////////////////////v7+//7+/v//////////////////////
|
||||
///////////////////////////+/v7//v7+//7+/v////////////7+/v///////////xsbG/8AAAD/
|
||||
X0Iq/7J6S/+qdEf/QCsZ/wAAAP8AAADfAAAA7QAAAP9IMR7/rXZH/7B4Sf9UOiT/AAAA/xsbG//+/v7/
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/v7+//7+/v///////////////////////v7+//7+/v//////////////////////////////////////
|
||||
/////xsbG/8AAAD/X0Eo/7F4Sf+qc0b/QCsa/wAAAP8AAADfAAAA7QAAAP9HMR7/rHRH/693Sf9TOST/
|
||||
AAAA/xsbG/////////////7+/v////////////7+/v////////////7+/v//////////////////////
|
||||
/v7+/////////////////////////////////////////////////////////////v7+///////+/v7/
|
||||
/v7+/////////////////xsbG/8AAAD/XkAo/7B3Sf+pc0b/QCsa/wAAAP8AAADfAAAA7QAAAP9HMB7/
|
||||
qnJH/651SP9TOCT/AAAA/xsbG///////////////////////////////////////////////////////
|
||||
//////////////////////7+/v////////////7+/v////////////7+/v//////////////////////
|
||||
//////7+/v///////////////////////////xsbG/8AAAD/Xj8o/650SP+ocUb/Pyoa/wAAAP8AAADf
|
||||
AAAA7QAAAP9GLx3/qXFG/610R/9TOCP/AAAA/xsbG////////v7+/////////////v7+////////////
|
||||
/v7+/////////////v7+//////////////////////////////////////////////////7+/v//////
|
||||
//////////////////////7+/v///////////////////////////xsbG/8AAAD/XT8n/61zR/+ncEX/
|
||||
Pyoa/wAAAP8AAADfAAAA7QAAAP9GLx3/qHFG/6xzR/9SNyP/AAAA/xsbG///////////////////////
|
||||
//////////////////////7+/v////////////7+/v/////////////////+/v7/////////////////
|
||||
/////////////////v7+//////////////////7+/v///////////////////////////xsbG/8AAAD/
|
||||
XT4n/6xzR/+mb0X/Pioa/wAAAP8AAADfAAAA7QAAAP9GLh3/p29F/6tyR/9SNyP/AAAA/xsbG///////
|
||||
/v7+///////+/v7///////7+/v///////v7+//7+/v/+/v7///////7+/v///////v7+////////////
|
||||
//////7+/v/+/v7///////7+/v///////////////////////v7+///////////////////////+/v7/
|
||||
/////xsbG/8AAAD/Wz4n/6tyR/+lbkT/Pika/wAAAP8AAADfAAAA5wAAAP9BKxv/pm5F/6tyR/9aPCb/
|
||||
AAAA/xsbG////////v7+///////////////////////+/v7////////////////////////////+/v7/
|
||||
//////7+/v////////////7+/v////////////7+/v////////////7+/v////////////7+/v//////
|
||||
//////7+/v///////////xsbG/8AAAD/ZEMq/6tyR/+kbUT/OSYY/wAAAP8AAADbAAAAxQAAAP8rHRL/
|
||||
nmhA/6lwRf+HWjf/CQYE/wMDA/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/
|
||||
Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/
|
||||
Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/wMDA/8NCQX/jV46/6lwRf+aZz7/JhoQ/wAAAP8AAAC5
|
||||
AAAAkwAAAP8PCgb/glc1/6hwRP+nbkP/XD0l/wsIBf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/w4JBv9iQSj/qG9E/6lwRP98UjL/
|
||||
CwgF/wAAAP0AAACDnJycswAAAOsAAAD/MyIV/6VtQ/+ob0T/pm5D/4tcOf9fPyf/WDok/1g6JP9YOiT/
|
||||
WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/
|
||||
WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/YEAn/41dOv+nb0T/
|
||||
qHBE/6NsQv8sHRL/AAAA/wAAAOWjo6OtxcXFRDk5OdcAAAD/AwIB/1U5I/+kbUL/qHBE/6hwRP+qcUX/
|
||||
qnBF/6lwRf+qcEX/qnBF/6lwRf+qcEX/qnBF/6pwRf+pcEX/qnBF/6pwRf+pcEX/qnBF/6pwRf+pcEX/
|
||||
qXBF/6pwRf+qcEX/qnBF/6pwRf+qcEX/qXBF/6pwRf+pcEX/qXBF/6pwRf+qcEX/qXBF/6lwRf+pcEX/
|
||||
qnFF/6lwRP+ocET/o2xC/040IP8CAQD/AAAA/zw8PM3Pz89A////BBwcHCgAAADdAAAA/wMCAf8zIhX/
|
||||
gVY1/51oP/+kbUP/pW5D/6VuQ/+mbkP/pm5D/6ZuQ/+lbkP/pW5D/6VuQ/+lbkP/pm5D/6ZuQ/+mbkP/
|
||||
pW5D/6VuQ/+mbkP/pm5D/6ZuQ/+lbkP/pm5D/6ZuQ/+mbkP/pW5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/
|
||||
pW5D/6ZuQ/+lbkP/pGxC/5xnP/9+VDP/Lh8T/wIBAP8AAAD/AAAA0ykpKRz///8EAAAAAAAAAAAAAABM
|
||||
AAAA3QAAAP8AAAD/DwoG/yocEf8+KRr/RC4c/0QuHf9ELh3/RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/
|
||||
RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/
|
||||
RC4d/0QuHf9ELh3/RC4d/0QuHf9ELhz/PSkZ/ygbEP8NCQX/AAAA/wAAAP8AAADRAAAAQgAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAGxsbKDo6OtMAAADpAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA5zs7O88lJSUe
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////BMrKykKgoKCvAAAAjwAAAL8AAADjAAAA6wAAAOsAAADr
|
||||
AAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADr
|
||||
AAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA4QAAAL0AAACP
|
||||
oqKirc3NzUD///8EAAAAAAAAAAAAAAAA4AAAAAAHAADgAAAAAAcAAMAAAAAAAwAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAADAADgAAAAAAcAAOAAAAAABwAAKAAAACAAAABAAAAA
|
||||
AQAgAAAAAACAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxcXFNltbW50AAAC/AAAA6QAAAPMAAADz
|
||||
AAAA8wAAAPMAAADzAAAA8wAAAPMAAADzAAAA8wAAAPMAAADzAAAA8wAAAPMAAADzAAAA8wAAAPMAAADz
|
||||
AAAA8wAAAPMAAADzAAAA5wAAAL1eXl6ZysrKNAAAAAAAAAAAAAAAAAAAACQAAAC/AAAA/RYSBf86Lg3/
|
||||
RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP9ENhD/
|
||||
RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP84LQ3/FRAF/wAAAP0AAAC3AAAAIgAAAADExMQ2AAAAvwEBAP9mUhj/
|
||||
1qox/++9Nv/xvzf/8b83//G/N//xvzf/8b83//G/N//xvzf/8b83//G/N//xvzf/8b83//G/N//xvzf/
|
||||
8b83//G/N//xvzf/8b83//G/N//xvzf/8b83/+69Nv/UqTH/YU0X/wAAAP8AAAC3zMzMNFpaWp8AAAD9
|
||||
YkwV/+i1Mv/jsTH/sYsn/5x6I/+ceiT/nHok/5x6JP+ceiT/nHok/5x6JP+ceiT/nHok/5x6JP+ceiT/
|
||||
nHok/5x6JP+ceiT/nHok/5x6JP+ceiT/nHok/5x6JP+ceiT/s4wo/+SyMf/ntDL/WkYU/wAAAP1fX1+X
|
||||
AAAAvxQPBP/ImSn/26cs/0IzDv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/STgQ/9ypLf/Elij/
|
||||
EQ0D/wAAALcAAADrNCcK/9eiKP+jeyD/AAAA/4uLi/+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/
|
||||
vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/4uLi/8AAAD/
|
||||
q4Eh/9WgKP8uIwn/AAAA4wAAAPM8LQr/2J8l/5FrGv8AAAD/vLy8////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
vLy8/wAAAP+Wbxv/0Zsk/zQnCf8AAADpAAAA4Q8LA/83KAr/JRsH/wAAAP2+vr79uLi4/QUFBfUDAwP/
|
||||
AwMD/QMDA/0DAwP/AwMD95SUlPf+/v7///////////9iYmLFAwMD9QMDA/8DAwP9SUlJ9ff39/3/////
|
||||
//////////+8vLz/AAAA/5JqGf/LkyD/MyUI/wAAAOkAAADhGRkZ/1hYWP9DQ0L/AAAA/5CQkP8bGxv7
|
||||
FRUV/1lZWf9BQED/PDw8/1lZWf8eHh7/AAAA876+vv/Dw8P/w8PD/xMTE/kaGhr/WVlZ/0BAP/8BAQH9
|
||||
qqqq9f///////////////7y8vP8AAAD/jmUV/8WMG/8xIwf/AAAA6QAAAPFGRkb//Pz8/7y7u/8AAAD/
|
||||
AAAA/wAAAP8/Pz///////7m5uf+rqqr//v7+/1NTU/8AAAD/AAAA/wAAAP8AAAD/AAAA/0xLS///////
|
||||
tra2/wICAv8iIiL7NTU1+TU1NflHR0fze3t7+wAAAP+KYBL/wIYY/zAhBv8AAADpAAAA8UZGRv/7+/v/
|
||||
5+fn/6WlpP+mpqX/paWl/87Ozv/9/f3/kJCQ/6mpqf/+/v7/ycnJ/7Cwr/+wsK//sLCv/6ysrP9PT0//
|
||||
TEtL//////+9vb3/IiIi/yAgIP8gICD/ICAg/woKCv8AAAD/AAAA/4dcEf+8gBX/LyAF/wAAAOkAAADx
|
||||
RkZG//v7+//39/f/4ODg/+Hh4P/h4OD/6+vr//Dw8P9TU1P/qqqq//7+/v/o6Oj/3d3d/93d3f/i4uL/
|
||||
+/v7//Dw8P9ZWVn///////7+/v/8/Pz//f39//39/f/8/Pz/UVFR/wAAAP8AAAD/g1gO/7Z6Ef8uHwT/
|
||||
AAAA6QAAAPFGRkb/+/v7/8DAwP8TExP/FBQT/xMTE/9DQ0P//Pz8/7m5uf+qqqr//v7+/1xcW/8ODg7/
|
||||
Dg4O/x0dHf/Y2Nf/+/v7/3Z2dv//////0NDQ/2NiYv9iYWH/YmFh/2JhYf8fHx//AAAA/wAAAP+AVAz/
|
||||
sXUO/ywdA/8AAADpAAAA8UZGRv/7+/v/19fW/2ZlZf9mZmb/ZmZm/5SUlP/+/v7/vLy8/6qqqv/+/v7/
|
||||
mZiY/2ZmZv9mZmb/e3t6/+3t7f/6+vr/amlp///////Pz8//XV1d/11dXf9dXV3/XV1d/zU1Nf8AAAD/
|
||||
AAAA/3xQCv+tcAz/KxwD/wAAAOkAAADxRUVF//T09P/19fX/9fX1//X19f/19fX/9fX1//Hx8f9xcXH/
|
||||
paWl//X19f/19fX/9fX1//X19f/19fX/8/Pz/6qqqf9KSkr/9vb1//X19f/09PT/9PT0//T09P/09PT/
|
||||
iouK/wAAAP8AAAD/eU0I/6hrCP8qGgL/AAAA6QAAAN0PDw//NjY2/zc3N/83Nzf/Nzc3/zc3N/83Nzf/
|
||||
KSkp/wMDA/8lJSX/Nzc3/zc3N/83Nzf/Nzc3/zc3N/8tLS3/BQUF/xAQEP83Nzf/Nzc3/zc3N/83Nzf/
|
||||
Nzc3/zc3N/8fHx//AAAA/wAAAP93Sgb/pWcG/ykZAf8AAADpAAAA5RILAP9AJwL/KxoC/wAAAP9AQED/
|
||||
V1dX/1dXV/9XV1f/V1dX/1dXV/9XV1f/V1dX/1dXV/9XV1f/V1dX/1dXV/9aWlr1V1dX/1dXV/9XV1f/
|
||||
V1dX/1dXV/9XV1f/V1dX/1dXV/9CQkL5AAAA/3RGA/+hYQL/KBgA/wAAAOkAAADzLhwE/6RlEf9vRhD/
|
||||
AAAA/7y8vP//////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////7y8vP8AAAD/cUMC/51eAP8nFwD/AAAA6QAAAPMzJBb/
|
||||
tYBQ/3pWNv8AAAD/vLy8////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////vLy8/wAAAP9vQQH/mloA/yYWAP8AAADp
|
||||
AAAA8zIjFf+yfUz/eFQ0/wAAAP+8vLz/////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////+8vLz/AAAA/2w+Af+XVgD/
|
||||
JRUA/wAAAOkAAADzMSIU/7B6Sv92UjP/AAAA/7y8vP//////////////////////////////////////
|
||||
///////////////////////////+/v7//////////////////////////////////////7y8vP8AAAD/
|
||||
b0MP/5ZVBP8lFQD/AAAA6QAAAPMxIRT/rndJ/3VRMv8AAAD/vLy8////////////////////////////
|
||||
//////////////////////////////////////7+/v//////////////////////////////////////
|
||||
vLy8/wAAAP98VjX/qnND/ykbDv8AAADpAAAA8zAhFP+tdUf/dE8x/wAAAP+8vLz/////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////+8vLz/AAAA/3tUM/+rdEf/Kx0R/wAAAOkAAADzMCAU/6tzR/9yTTD/AAAA/7y8vP//////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////7y8vP8AAAD/elIz/6lyRv8qHBH/AAAA6QAAAPMvHxT/qXFG/3JMMP8AAAD/
|
||||
vLy8////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////vLy8/wAAAP95UTL/qHBF/yocEf8AAADpAAAA8y8fE/+ocEb/
|
||||
cUsv/wAAAP+8vLz/////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////+8vLz/AAAA/3dQMv+mb0X/KRwR/wAAAOkAAADp
|
||||
KBoR/6VuRP9+VDT/AAAA/4uLi/+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/
|
||||
vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/4uLi/8AAAD/hFg3/6RtQ/8jFw7/
|
||||
AAAA4QAAAL8PCgb/lGI8/6NsQv8yIRT/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/zYkFv+kbUP/
|
||||
kWA7/wwIBf8AAAC1W1tbnwAAAP1GLhz/pm5D/6NsQv+AVTT/dE0v/3RNL/90TS//dE0v/3RNL/90TS//
|
||||
dE0v/3RNL/90TS//dE0v/3RNL/90TS//dE0v/3VNL/90TS//dE0v/3RNL/90TS//dE0v/3RNL/+CVjX/
|
||||
pG1C/6ZuQ/9AKxr/AAAA/WBgYJfGxsY2AAAAvQEAAP9GLhz/k2I8/6RtQv+mbkP/pm5D/6ZuQ/+mbkP/
|
||||
pm5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/
|
||||
pm5D/6RtQv+SYTv/Qiwb/wAAAP8AAACzzs7OMgAAAAAAAAAiAAAAvQAAAP0OCQb/JhkQ/y0fE/8uHxP/
|
||||
Lh8T/y4fE/8uHxP/LR8T/y4fE/8uHxP/Lh8T/y4fE/8uHxP/LR8T/y4fE/8uHxP/LR8T/y4fE/8uHxP/
|
||||
Lh8T/y4fE/8uHxP/JRkP/w0JBf8AAAD9AAAAswAAAB4AAAAAAAAAAAAAAADGxsY0XV1dmwAAAL0AAADn
|
||||
AAAA8QAAAPEAAADxAAAA8QAAAPEAAADxAAAA8QAAAPEAAADxAAAA8QAAAPEAAADxAAAA8QAAAPEAAADx
|
||||
AAAA8QAAAPEAAADxAAAA8QAAAPEAAADlAAAAvV9fX5fMzMw0AAAAAAAAAADAAAADgAAAAQAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAABwAAAAygAAAAYAAAA
|
||||
MAAAAAEAIAAAAAAAYAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTExDE1NTa8AAADVAAAA9QAAAPcAAAD3
|
||||
AAAA9wAAAPcAAAD3AAAA9wAAAPcAAAD3AAAA9wAAAPcAAAD3AAAA9wAAAPcAAAD3AAAA9QAAANNOTk6r
|
||||
PDw8CgAAAAAyMjIMAAAAwxQQBf9+ZB3/qYYn/6uJKP+siSj/rIko/6uJKP+siSj/q4ko/6yJKP+riSj/
|
||||
rIko/6yJKP+riSj/q4ko/6uJKP+siSj/qYYn/3xjHf8SDwT/AAAAvUJCQghMTEyvEw8E/82gLf/hsDH/
|
||||
tY4p/7GLKP+xiyj/sYso/7GLKP+xiyj/sYso/7GLKP+xiyj/sYso/7GLKP+xiyj/sYso/7GLKP+xiyj/
|
||||
to8p/+KxMv/JnSz/EAwD/09PT6kAAADVdFkY/9ajK/8mHQn/DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/
|
||||
DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/yohCv/YpSv/b1QW/wAAAM8AAAD1
|
||||
lnAb/6V7Hv8NDQ3//v7+//7+/v/+/v7//v7+//7+/v/////////////////+/v7////////////+/v7/
|
||||
/v7+/////////////////w0NDf+qfx//j2sa/wAAAO8AAADtRDIM/0k1Df8ODg798fHx/1paWvlCQkL/
|
||||
QkJC/UJCQv9QUFD35eXl/f/////09PT3WFhY40JCQv9DQ0P7w8PD+//////+/v7//////w0NDf+idRv/
|
||||
jGYW/wAAAO8AAADrW1tb/2pqaf8ICAj/WVlZ/RcXF/+CgoL/SEdH/4KCgv8hISD/SEhI95KSkv95eXn9
|
||||
CAgI/Xd2dv9HR0f/Nzc39+fn5/3n5+f99vb2/Q0NDf+bbhb/hl8S/wAAAO8AAADzsbGx/9jY2P88PDz/
|
||||
PDw8/2tra//9/f3/hISD//7+/v9xcXH/RERE/0RERP87Ozv/FhYW/+fn5/+MjIz/BQUF/wUFBfsFBQX7
|
||||
JCQk+QMDA/2WaBP/gloP/wAAAO8AAADzsbGx//r6+v/o6Oj/6Ojo/+7u7v/g4OD/WVlY//7+/v/s7Oz/
|
||||
5ubm/+jo6P/7+/v/fn5+/+bm5v/p6en/0NDQ/9DQ0P/Dw8P/CgoK/wAAAP+RYg//fVQM/wAAAO8AAADz
|
||||
sbGx/8/Pz/8QEBD/ERER/zc3N//9/f3/jY2M//7+/v9ISEf/DQ0N/xoaGv/i4uL/rq6u/+Xl5f+qqqr/
|
||||
SkpK/0pKSv9GRkb/BAQE/wAAAP+MXAz/eU8J/wAAAO8AAADzsrKy//T09P/Jycj/ycnJ/9jY2P/7+/v/
|
||||
fX19//7+/v/W1tb/ycnJ/9DQ0P/6+vr/hoaG/+bm5v/j4+P/w8PD/8PDw//ExMP/IiIh/wAAAP+HVwn/
|
||||
dUsH/wAAAO8AAADpRUVF/2JiYv9iYmL/YmJi/2JiYv9KSUn/HRwc/2JiYv9iYmL/YmJi/2JiYv9PT0//
|
||||
Dw8P/1lZWf9iYmL/YmJi/2JiYv9iYmL/ERER/wAAAP+DUgb/cUcE/wAAAO8AAADvPiUB/0IoAv8HBwf/
|
||||
gYGB/4GBgf+BgYH/gYGB/4GBgf+BgYH/gYGB/4GBgf+BgYH/g4OD+4GBgf+BgYH/gYGB/4GBgf+BgYH/
|
||||
goKC/QcHB/9/TQP/bUIB/wAAAO8AAAD3e1Il/4RZK/8NDQ3///////7+/v/+/v7///////7+/v/+/v7/
|
||||
///////////+/v7////////////+/v7///////7+/v/+/v7//v7+/w0NDf97SQH/az8A/wAAAO8AAAD3
|
||||
f1k2/4deOv8NDQ3/////////////////////////////////////////////////////////////////
|
||||
/////////////////////w0NDf94RQH/ZzsA/wAAAO8AAAD3fFY0/4RbOP8NDQ3/////////////////
|
||||
//////////////////////7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+/w0NDf9+Thn/
|
||||
aD0I/wAAAO8AAAD3e1Qz/4NaN/8NDQ3///////7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7/
|
||||
/v7+//7+/v/+/v7///////7+/v/+/v7//v7+/w0NDf+IXTn/dU8w/wAAAO8AAAD3eVIy/4FXNv8NDQ3/
|
||||
/////////////////////////////////////////////////v7+////////////////////////////
|
||||
/////w0NDf+GWzj/dE4w/wAAAO8AAAD3d1Ay/39VNf8NDQ3///////////////////////7+/v//////
|
||||
/////////////////v7+/////////////v7+/////////////v7+/w0NDf+FWTf/ck0v/wAAAO8AAAD1
|
||||
dU4w/4FWNv8NDQ3//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7/
|
||||
/v7+//7+/v/+/v7//v7+/w0NDf+FWTj/cEsu/wAAAO0AAADVVzkj/6BqQf8dEwz/DQ0N/w0NDf8NDQ3/
|
||||
DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/yAVDf+ia0L/
|
||||
Ujch/wAAAM9NTU2vDQkF/5JhO/+gakH/g1Y1/4FVNP+BVTT/gVU0/4FVNP+BVTT/gVU0/4FVNP+BVTT/
|
||||
gVU0/4FVNP+BVTT/gVU0/4FVNP+BVTT/g1c1/6FrQf+PXzr/CwcE/1BQUKkzMzMMAAAAwQ0JBf9VOSP/
|
||||
c0wv/3VOMP91TjD/dU4w/3VOMP91TjD/dU4w/3VOMP91TjD/dU4w/3VOMP91TjD/dU4w/3VOMP91TjD/
|
||||
c0wv/1Q4Iv8MCAX/AAAAuUdHRwgAAAAAMjIyDE5OTqsAAADTAAAA8wAAAPUAAAD1AAAA9QAAAPUAAAD1
|
||||
AAAA9QAAAPUAAAD1AAAA9QAAAPUAAAD1AAAA9QAAAPUAAAD1AAAA8wAAANNPT0+pQkJCCAAAAACAAAEA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAQAoAAAAEAAAACAAAAABACAAAAAAAEAEAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAACCYmJqUWEQXpIhsI+SIbCPkiGwj5IhsI+SIbCPkiGwj5IhsI+SIbCPkiGwj5
|
||||
IhsI+RURBeknJyahAAAACCYmJqVsVRj/1qkw/8edLf/HnS3/x50t/8edLf/HnS3/x50t/8edLf/HnS3/
|
||||
x50t/8edLf/WqTD/aVIX/ycnJ58TDwTrx5cn/zMvJv9eXl7/Xl5e/15eXv9eXl7/Xl5e/15eXv9eXl7/
|
||||
Xl5e/15eXv9eXl7/NTEn/8iYJ/8RDQPlEw4D9XFTFP9eXl7/sLCw/YGBgf+BgYH/p6en+/7+/v/f39/x
|
||||
goKC/ZOTk/v9/f3//////15eXv+xgh7/GxME9RkZGfOVlJT/JCQk/xwcG/2UlJT/j4+P/xwcHPtgYGD/
|
||||
NTU1/W9vb/8+Pj7/gICA+aCgoPtNTU39p3YX/xkSA/UkJCT39fX1/8PDw//Q0ND/tLS0/9TU1P/Q0M//
|
||||
yMjH/7q6uv+oqKj/tra2/46Ojv9eXl7/AAAA/59sEf8YEAL1JCQk9+Pj4/89PDz/VFRU/9zc3P/U1NT/
|
||||
Wlpa/0NDQ//u7u7/t7e3/5iYmP9fX1//RUVE/wAAAP+XYgz/Fw8B9RYWFvOVlZX/lpaW/5aWlv9jY2P/
|
||||
fn19/5aWlv+Wlpb/c3Nz/2JiYv+Wlpb/lpaW/3V1df8AAAD/j1oH/xUNAPUQCgH1XzsJ/z8/P/+rq6v/
|
||||
q6ur/6urq/+rq6v/q6ur/6ysrP2rq6v/q6ur/6urq/+rq6v/Pz8//YlSAv8UDAD1GRIL+ZZqQf9eXl7/
|
||||
/////////////////////////////////////////////////////15eXv+DTAD/FAsA9RkRCvmSZT7/
|
||||
Xl5e//////////////////////////////////7+/v////////////////9eXl7/i1gj/xQMA/UYEAr5
|
||||
j2E8/15eXv//////////////////////////////////////////////////////Xl5e/5JjPf8WDwn1
|
||||
GBAK+Y1eO/9eXl7//////////////////////////////////////////////////////15eXv+QYDz/
|
||||
FQ4J9Q8KBumWZD3/Lyso/15eXv9eXl7/Xl5e/15eXv9eXl7/Xl5e/15eXv9eXl7/Xl5e/15eXv8wLCj/
|
||||
l2Q+/w0JBeUmJialTTMf/5dkPf+NXTn/jV45/41eOf+NXjn/jV45/41eOf+NXjn/jV45/41eOf+NXjn/
|
||||
l2Q9/0oxHv8nJyefAAAACCYmJqMOCQbpFw8K+RcPCvkXDwr5Fw8K+RcPCvkXDwr5Fw8K+RcPCvkXDwr5
|
||||
Fw8K+Q4JBecnJyefAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
|
@ -0,0 +1,5 @@
|
|||
[Keys]
|
||||
RDR=
|
||||
MP3=
|
||||
MC=
|
||||
GTAV=
|
|
@ -0,0 +1,84 @@
|
|||
namespace RPFTool
|
||||
{
|
||||
partial class Loader
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Loader));
|
||||
this.marqueeProgressBarControl1 = new DevExpress.XtraEditors.MarqueeProgressBarControl();
|
||||
this.label_Loading = new DevExpress.XtraEditors.LabelControl();
|
||||
((System.ComponentModel.ISupportInitialize)(this.marqueeProgressBarControl1.Properties)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// marqueeProgressBarControl1
|
||||
//
|
||||
this.marqueeProgressBarControl1.EditValue = 0;
|
||||
this.marqueeProgressBarControl1.Location = new System.Drawing.Point(0, 137);
|
||||
this.marqueeProgressBarControl1.Name = "marqueeProgressBarControl1";
|
||||
this.marqueeProgressBarControl1.Size = new System.Drawing.Size(500, 30);
|
||||
this.marqueeProgressBarControl1.TabIndex = 0;
|
||||
this.marqueeProgressBarControl1.UseWaitCursor = true;
|
||||
//
|
||||
// label_Loading
|
||||
//
|
||||
this.label_Loading.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.label_Loading.Appearance.Font = new System.Drawing.Font("Tahoma", 14F);
|
||||
this.label_Loading.AutoSizeMode = DevExpress.XtraEditors.LabelAutoSizeMode.None;
|
||||
this.label_Loading.Location = new System.Drawing.Point(0, 59);
|
||||
this.label_Loading.Name = "label_Loading";
|
||||
this.label_Loading.Size = new System.Drawing.Size(500, 23);
|
||||
this.label_Loading.TabIndex = 1;
|
||||
this.label_Loading.Text = "Loading..";
|
||||
this.label_Loading.UseWaitCursor = true;
|
||||
//
|
||||
// Loader
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(500, 167);
|
||||
this.Controls.Add(this.label_Loading);
|
||||
this.Controls.Add(this.marqueeProgressBarControl1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.LookAndFeel.SkinName = "Sharp";
|
||||
this.LookAndFeel.UseDefaultLookAndFeel = false;
|
||||
this.Name = "Loader";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Loader";
|
||||
this.UseWaitCursor = true;
|
||||
this.Shown += new System.EventHandler(this.Loader_Shown);
|
||||
((System.ComponentModel.ISupportInitialize)(this.marqueeProgressBarControl1.Properties)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private DevExpress.XtraEditors.MarqueeProgressBarControl marqueeProgressBarControl1;
|
||||
private DevExpress.XtraEditors.LabelControl label_Loading;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using DevExpress.XtraEditors;
|
||||
using System.Xml.Linq;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace RPFTool
|
||||
{
|
||||
public partial class Loader : DevExpress.XtraEditors.XtraForm
|
||||
{
|
||||
double Version = 1.3;
|
||||
bool rdrEnabled = false;
|
||||
bool mp3_xboxEnabled = false;
|
||||
bool mcEnabled = false;
|
||||
bool gtavEnabled = false;
|
||||
BackgroundWorker bw = new BackgroundWorker();
|
||||
|
||||
public Loader()
|
||||
{
|
||||
InitializeComponent();
|
||||
label_Loading.Appearance.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Center;
|
||||
bw.WorkerReportsProgress = true;
|
||||
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
|
||||
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
|
||||
}
|
||||
|
||||
private void bw_DoWork(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
BackgroundWorker worker = sender as BackgroundWorker;
|
||||
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
label_Loading.Text = "Checking for updates...";
|
||||
});
|
||||
|
||||
|
||||
XDocument updateXML = XDocument.Load(@"http://tmacdev.com/updates/update.xml");
|
||||
|
||||
var latestVersion = updateXML.Element("application").Element("version");
|
||||
var updateURL = updateXML.Element("application").Element("url");
|
||||
|
||||
if (Version < Convert.ToDouble(latestVersion.Value))
|
||||
{
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
if (MessageBox.Show("There is an updated version of RPF Tool available, download now?", "Update?", MessageBoxButtons.YesNo) == DialogResult.Yes)
|
||||
{
|
||||
try
|
||||
{
|
||||
DownloadForm dlForm = new DownloadForm();
|
||||
dlForm.URL = updateURL.Value;
|
||||
this.Hide();
|
||||
//dlForm.Closed += (sender2, args) =>
|
||||
dlForm.ShowDialog();
|
||||
this.Show();
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
MessageBox.Show("Failed to download the latest version:" + ex.Message + Environment.NewLine + updateURL.Value.ToString(), "Error!", MessageBoxButtons.OK);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
MessageBox.Show("Failed to download the latest version:" + ex.Message, "Error!", MessageBoxButtons.OK);
|
||||
}
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
label_Loading.Text = "Getting Keys...";
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
string path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Keys.ini";
|
||||
iniReader iniFile = new iniReader(path);
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
if (MessageBox.Show("Keys.ini file not found, would you like to generate a blank config file?", "File not found", MessageBoxButtons.YesNo) == DialogResult.Yes)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create a new file
|
||||
using (FileStream fs = File.Create(path))
|
||||
{
|
||||
// Add some text to file
|
||||
Byte[] title = new UTF8Encoding(true).GetBytes(
|
||||
@"[Keys]" + Environment.NewLine +
|
||||
"RDR=" + Environment.NewLine +
|
||||
"MP3=" + Environment.NewLine +
|
||||
"MC=" + Environment.NewLine +
|
||||
"GTAV=");
|
||||
fs.Write(title, 0, title.Length);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
MessageBox.Show("Failed to create new config file, make sure you have permissions to write to the current directory or try running RPF Tool as Administrator.", "Error!", MessageBoxButtons.OK);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
string key = iniFile.IniReadValue("Keys", "RDR").ToUpper();
|
||||
|
||||
if (CreateMD5Hash(key) == "D24B88DD3D21F81AA2831DC7C10F3065")
|
||||
{
|
||||
rdrEnabled = true;
|
||||
keyHolder.rdrKey = StringToByteArray(key);
|
||||
}
|
||||
key = iniFile.IniReadValue("Keys", "MP3").ToUpper();
|
||||
if (CreateMD5Hash(key) == "C07777FD1730F0547D13F1B64CBBE59F")
|
||||
{
|
||||
mp3_xboxEnabled = true;
|
||||
keyHolder.mp3Key_xbox = StringToByteArray(key);
|
||||
}
|
||||
key = iniFile.IniReadValue("Keys", "MC").ToUpper();
|
||||
if (CreateMD5Hash(key) == "292616021EB70171EF8360821A386B6D")
|
||||
{
|
||||
mcEnabled = true;
|
||||
keyHolder.mcKey = StringToByteArray(key);
|
||||
}
|
||||
key = iniFile.IniReadValue("Keys", "GTAV").ToUpper();
|
||||
//if (CreateMD5Hash(key) == "2C37D9BD5602F87D27CE3D1791381E34")
|
||||
//{
|
||||
gtavEnabled = true;
|
||||
keyHolder.gtaVKey = StringToByteArray(key);
|
||||
// }
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
MessageBox.Show("Failed to read Keys.ini:" + ex.Message, "Error!", MessageBoxButtons.OK);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
label_Loading.Text = "Loading RPFTool...";
|
||||
});
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
throw new Exception(ex.Message, ex);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
this.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
this.Hide();
|
||||
var gameSelectForm = new gameSelection(rdrEnabled, mp3_xboxEnabled, mcEnabled, gtavEnabled);
|
||||
gameSelectForm.Closed += (sender2, args) => this.Close();
|
||||
gameSelectForm.Show();
|
||||
});
|
||||
}
|
||||
|
||||
private void Loader_Shown(object sender, EventArgs e)
|
||||
{
|
||||
bw.RunWorkerAsync();
|
||||
}
|
||||
|
||||
public string CreateMD5Hash(string input)
|
||||
{
|
||||
MD5 md5 = System.Security.Cryptography.MD5.Create();
|
||||
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
|
||||
byte[] hashBytes = md5.ComputeHash(inputBytes);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < hashBytes.Length; i++)
|
||||
{
|
||||
sb.Append(hashBytes[i].ToString("X2"));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public byte[] StringToByteArray(string hex)
|
||||
{
|
||||
if (hex.Length % 2 == 1)
|
||||
throw new Exception("The binary key cannot have an odd number of digits");
|
||||
|
||||
byte[] arr = new byte[hex.Length >> 1];
|
||||
|
||||
for (int i = 0; i < hex.Length >> 1; ++i)
|
||||
{
|
||||
arr[i] = (byte)((GetHexVal(hex[i << 1]) << 4) + (GetHexVal(hex[(i << 1) + 1])));
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
public int GetHexVal(char hex)
|
||||
{
|
||||
int val = (int)hex;
|
||||
return val - (val < 58 ? 48 : 55);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,632 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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
|
||||
GCYe01eklFYinee1f3m8jljPSql5IUQfADz77LM/+ehHP/o9In4CoXkwAmBrJ+6BYVYJlxG698oATDrg
|
||||
kSNHfuXhhx/+KBCk9Eop+5c5viX4bcwwGYYVAMNkmI7MAQgh/kBrXRvmnwdwpiZ75plnnpJS9gHA0aNH
|
||||
z3/zm9/8f+TQMYRKqQ/AAJGNkG0XtpeBYW41ZYShuQp2gY45AEUiMxVBnnjiiX3ve9/7dgLBoh2/93u/
|
||||
9xo5rqS1fgFYWsmnXXTdg661nka1uOiJEye+vX///j8n4gcRKqWNAEaJbDeR9SBQEDV4JMPcCujk9hyA
|
||||
UnXbA3npAbgCYJzIXqoJTp48+Vt33333p6rNGSHEug7d67Jwx2GYDMMKgGEyzP8HLvrg+dAOZdoAAAAA
|
||||
SUVORK5CYIIoAAAAMAAAAGAAAAABACAAAAAAAIAlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
////BMXFxUSdnZ2zAAAAkwAAAMMAAADnAAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA7QAAAO0AAADt
|
||||
AAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA7QAAAO0AAADt
|
||||
AAAA7QAAAO0AAADtAAAA7QAAAO0AAADtAAAA5QAAAMEAAACRoKCgr8vLy0L+/v4EAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAGxsbKjk5OdcAAADrAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA5zs7O9EiIiIg
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAABOAAAA3wAAAP8AAAD/FxIF/z8yD/9eShb/ZlEY/2VRGP9lURj/
|
||||
ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/
|
||||
ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/ZVEY/2VRGP9lURj/XEkW/z0xD/8VEQX/
|
||||
AAAA/wAAAP8AAADXAAAASAAAAAAAAAAA////BBsbGygAAADfAAAA/wQEAf9NPhP/vZcs/+S2NP/wvzf/
|
||||
8sA3//LAN//ywDj/8sA3//LAN//ywDj/8sA3//LAN//ywDf/8sA3//LAN//ywDj/8sA4//LAN//ywDf/
|
||||
8sA3//LAN//ywDf/8sA4//LAN//ywDf/8sA4//LAN//ywDj/8sA3//LAN//ywDj/8sA3//LAN//ywDf/
|
||||
8L83/+O2NP+5lCv/RzkR/wMCAf8AAAD/AAAA1yYmJh7+/v4ExMTERDg4ONkAAAD/BAMB/3thHP/quTT/
|
||||
77w1//C8Nf/yvjb/8b02//G9Nf/xvTb/8b41//G9Nv/xvjb/8b42//G+Nf/xvTb/8b02//G9Nf/xvTb/
|
||||
8b02//G9Nv/xvTb/8b02//G9Nv/xvjb/8b02//G+Nf/xvTb/8b02//G+Nv/xvTb/8b01//G9Nv/xvTb/
|
||||
8b42//G9Nv/xvTX/8r42//C8Nv/vvDb/6Lg0/3FZGv8DAgD/AAAA/zs7O8/Nzc1AnJyctQAAAOsAAAD/
|
||||
SDgQ/+WyMf/otTH/57Qx/7+VKf+AZB3/cVga/3FYG/9xWBv/cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/
|
||||
cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/cVgb/3FYG/9xWBv/
|
||||
cVgb/3FYG/9xWBv/cVgb/3FYG/9xWRv/gmYe/8KXKv/otDH/6bUy/+KvMP8+MA7/AAAA/wAAAOeioqKt
|
||||
AAAAkwAAAP8VEAX/sogl/+OuL//hrS7/e18b/w8LA/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/xINBP+EZhz/4q4u/+SvL/+qgiP/
|
||||
EAwE/wAAAP8AAACFAAAAxQAAAP86LAz/0Z8p/+GqLP+ziCT/DAkC/wMDA/8bGxv/Gxsb/xsbG/8bGxv/
|
||||
Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/
|
||||
Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/wMDA/8RDQP/
|
||||
u44l/+CpK//OnCj/MycL/wAAAP8AAAC5AAAA6QAAAP9UPxD/1qEn/92mKP90WBf/AAAA/xsbG///////
|
||||
/////////////////////////////////////////////////v7+////////////////////////////
|
||||
///////////+/v7////////////////////////////+/v7//////////////////v7+////////////
|
||||
/////xsbG/8AAAD/gGEZ/92mKP/Unyf/SjgO/wAAAP8AAADbAAAA7wAAAP9ZQhD/1Z4l/9qhJf9oTRT/
|
||||
AAAA/xsbG//////////////////+/v7/////////////////////////////////////////////////
|
||||
//////////////////////7+/v////////////7+/v////////////7+/v/+/v7///////7+/v//////
|
||||
//////7+/v/+/v7//////xsbG/8AAAD/dFYW/9mgJf/RmyT/TzoO/wAAAP8AAADfAAAA6wAAAP9INQ3/
|
||||
rH4e/6+AHv9UPhH/AAAA/xsbG//+/v7//////8zMzPWHh4f5hISE/4SEhP+FhYX9hYWF/YSEhP+EhIT/
|
||||
hYWF/bKysu3+/v7////////////+/v7///////7+/v/Q0NDPjIyM8YWFhf+EhIT/hISE/4yMjPHp6en5
|
||||
/v7+/////////////v7+//7+/v/+/v7//v7+/xsbG/8AAAD/clMV/9WbI//NliL/TTkN/wAAAP8AAADf
|
||||
AAAAxwAAAP8IBgH/FQ8E/xUPBP8KBwL/AAAA/xwcHPf/////ycnJ+xgYGPsAAAD9AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wwMDPeZmZn3/f39//7+/v///////////9DQ0N0QEBDRAAAA+QAAAP8AAAD/
|
||||
AAAA/wAAAPk4ODj77e3t+/7+/v////////////7+/v///////////xsbG/8AAAD/cFEU/9GWIP/JkR//
|
||||
TDcL/wAAAP8AAADfAAAAyQAAAP8ODg7/IiIh/yIiIv8VFRX/AAAA/xwcHP//////NjY29QAAAP8MDAz/
|
||||
IiIi/yIiIv8UFBT/EhER/yIiIv8iIiL/EBAQ/wAAAP8AAADl9vb2/f///////////////6ioqPkAAAD5
|
||||
BAQE/xwcHP8iIiL/ICAg/wUFBf8AAAD7gICA6////////////////////////////////xsbG/8AAAD/
|
||||
bk8S/8ySHf/FjBz/SjUK/wAAAP8AAADfAAAA5wAAAP9eXl7/39/f/+Li4v+MjIz/AAAA/wQEBP8mJib/
|
||||
BwcH/wAAAP9RUVD/4uLi/+Li4v+GhYX/dHNz/+Li4v/i4uL/cHBw/wICAv8AAAD9JCQk/yYmJv8mJib/
|
||||
JiYm/xgYGP8AAAD/HR0d/7q6uf/i4uL/09PT/yQkJP8AAAD/YWFh+9DQ0P3Q0ND90NDQ/dDQ0P3d3d35
|
||||
/v7+/xsbG/8AAAD/a0wQ/8iNGv/BiBn/STMJ/wAAAP8AAADfAAAA6QAAAP9oaGj/+vr6//7+/v+ZmZn/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP9hYGD///////////+Wlpb/gH9////////+/v7/eXl4/wICAv8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/ICAg/9DQ0P/+/v7/7e3t/ycnJ/8AAAD/AAAA+wAAAPkAAAD5
|
||||
AAAA+QAAAPcZGRnxenp69w0NDfsAAAD/akoP/8WJF/++hBf/SDII/wAAAP8AAADfAAAA6QAAAP9oaGj/
|
||||
+vr6//7+/v/Kycn/d3d3/3l5eP95eXj/eXl4/39/fv/Ozs7///////r6+v96enr/f35+//7+/v/+/v7/
|
||||
wsLB/4mJiP+IiIj/iIiI/4iIiP+IiIj/ioqK/2JiYv8ZGRn/ICAg/9DQ0P/+/v7/7e3t/y4uLv8LCwv/
|
||||
CwsL/wsLC/8LCwv/CwsL/woKCv8BAQH/AAAA/QAAAP8AAAD/aEgO/8KFFv+7gBX/RjAI/wAAAP8AAADf
|
||||
AAAA6QAAAP9oaGj/+vr6///////+/v7//v7+///////+/v7//////////////////f39/6urqv8fHx//
|
||||
gH9////////+/v7//v7+//////////////////////////////////n5+f+ioqH/ISEg/9DPz///////
|
||||
+Pj4/7Cvr/+ioqL/oqKi/6Kiov+ioqL/o6Oj/46Ojv8QEBD/AAAA/wAAAP8AAAD/ZkYN/76BFP+4fRP/
|
||||
RS8H/wAAAP8AAADfAAAA6QAAAP9oaGj/+vr6///////t7e3/0dHR/9LS0f/S0tH/0tLR/9LS0v/p6en/
|
||||
/v7+/9nZ2f9FRUX/gH9////////+/v7/5eXl/83Nzf/Nzc3/zc3N/83Nzf/X19f/+Pf3///////z8/P/
|
||||
QkJB/83Nzf///////v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+/97e3v8aGhr/AAAA/wAAAP8AAAD/
|
||||
ZEML/7t9Ef+0eBD/RC0G/wAAAP8AAADfAAAA6QAAAP9oaGj/+vr6//////+kpKT/HBwc/x0dHf8dHR3/
|
||||
HR0d/x4eHv9qamr//Pz8//7+/v+SkpL/gH9////////+/v7/hIWE/xcXF/8WFhb/FhYW/xUVFf8wLy//
|
||||
ysrK///////5+fn/Y2Nj/8zMzP//////9/f3/56env+Ojo7/j46O/4+Ojv+Pjo7/j46O/319ff8ODg7/
|
||||
AAAA/wAAAP8AAAD/Y0IL/7h6EP+xdQ//QywF/wAAAP8AAADfAAAA6QAAAP9oaGj/+vr6//////+cm5v/
|
||||
BAQE/wQEBP8EBAT/BAQE/wYGBv9OTk7/+vr6//7+/v+goKD/gYGA//7+/v/+/v7/fX18/wcGBv8EBAT/
|
||||
BAQE/wQEBP8eHh7/wsLC///////5+fn/ZGNj/8zMzP//////7e3t/ygoKP8GBgb/BgYG/wYGBv8GBgb/
|
||||
BgYG/wYGBv8BAQH/AAAA/wAAAP8AAAD/YT8K/7R2Df+ucgz/QioE/wAAAP8AAADfAAAA6QAAAP9oaGj/
|
||||
+vr6///////V1dX/k5OT/5WVlP+VlZT/lZSU/5mZmP/MzMz//v7+//////+ZmZn/gICA///////+/v7/
|
||||
ycnI/5WVlP+VlZT/lZWU/5SUlP+xsbH/8fHx///////39/f/SklJ/83MzP/+/v7/9vb2/5qamv+IiIj/
|
||||
iYmJ/4mJif+JiYn/iYmJ/4uLiv8wLy//AAAA/wAAAP8AAAD/Xz4J/7FyDP+rbgz/QCkE/wAAAP8AAADf
|
||||
AAAA6QAAAP9qamr/+/v7///////+/v7//f39//7+/f/+/v3//v39//7+/v/+/v7///////Dw8P9cXFv/
|
||||
gICA//7+/v///////v7+//39/f/+/v3//v79//39/f/+/v7//v7+//r6+v+1tbT/IyMj/9DQ0P/+/v7/
|
||||
/v7+//39/f/9/f3//f39//39/f/9/f3//f39//39/f9YWFj/AAAA/wAAAP8AAAD/XjwH/65vCf+oawn/
|
||||
PygD/wAAAP8AAADfAAAA5wAAAP9SUlL/wMDA/8LCwv/CwsL/wsLC/8LCwv/CwsL/wsLC/8LCwv/DwsL/
|
||||
uLi4/21sbP8ODg7/ZGRk/8LCwv/CwsL/wsLC/8LCwv/CwsL/wsLC/8LCwv/Dw8P/vr29/35+fv8lJSX/
|
||||
GhkZ/6Cgn//CwsL/wsLC/8LCwv/CwsL/wsLC/8LCwv/CwsL/wsLC/8LCwv9ERET/AAAA/wAAAP8AAAD/
|
||||
XToG/6xsB/+maQf/PicC/wAAAP8AAADfAAAAvwAAAP8AAAD/AgIC/wICAv8CAgL/AgIC/wICAv8CAgL/
|
||||
AgIC/wICAv8CAgL/AQEB/wAAAP8AAAD/AQEB/wICAv8CAgL/AgIC/wICAv8CAgL/AgIC/wICAv8CAgL/
|
||||
AgIC/wAAAP8AAAD/AAAA/wEBAf8CAgL/AgIC/wICAv8CAgL/AgIC/wICAv8CAgL/AgIC/wICAv8AAAD/
|
||||
AAAA/wAAAP8AAAD/WzkG/6lpBv+jZQX/PiYB/wAAAP8AAADfAAAAzQAAAP8HBQD/EgsC/xILAv8IBQH/
|
||||
AAAA/wAAAP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/
|
||||
AwMD/wMDA/8DAwP/AwMD/wMDA/sDAwPtAwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/
|
||||
AwMD/wMDA/8DAwP/AwMD9QAAAP0AAAD/WjcF/6dlA/+hYQP/PCQB/wAAAP8AAADfAAAA7wAAAP9CKAH/
|
||||
nV4B/6FgAf9NLwP/AAAA/xsbG////////////////////////v7+/////////////v7+///////+/v7/
|
||||
///////////+/v7///////7+/v/+/v7///////7+/v///////////////////////v7+////////////
|
||||
//////7+/v///////v7+//7+/v/+/v7//////xsbG/8AAAD/WDUD/6RiAP+dXgD/OyQA/wAAAP8AAADf
|
||||
AAAA7QAAAP9FKwn/pWgY/6ttHv9SNhL/AAAA/xsbG////////v7+//7+/v/+/v7/////////////////
|
||||
//////////////////////////////////////7+/v///////v7+///////+/v7/////////////////
|
||||
///////////+/v7///////7+/v////////////7+/v///////////xsbG/8AAAD/VjQD/6JgAP+cXQD/
|
||||
OiMA/wAAAP8AAADfAAAA7QAAAP9MNiL/toFR/7qEU/9YQCj/AAAA/xsbG///////////////////////
|
||||
//////////////////////////////////////////////////////7+/v////////////7+/v//////
|
||||
//////7+/v////////////7+/v////////////7+/v////////////7+/v///////////xsbG/8AAAD/
|
||||
VjMC/6BdAP+aWgD/OiEA/wAAAP8AAADfAAAA7QAAAP9LNSH/tH5N/7iBTv9YPib/AAAA/xsbG///////
|
||||
//////7+/v///////////////////////v7+//7+/v///////////////////////v7+///////+/v7/
|
||||
///////////+/v7//v7+//7+/v///////v7+//7+/v///////////////////////v7+////////////
|
||||
/v7+/xsbG/8AAAD/VDEC/51bAP+XVwD/OSAA/wAAAP8AAADfAAAA7QAAAP9KNCD/sXxM/7V+Tf9WPSb/
|
||||
AAAA/xsbG//////////////////+/v7///////7+/v//////////////////////////////////////
|
||||
//////////////////////////////////////7+/v////////////7+/v////////////7+/v//////
|
||||
/////////////////////xsbG/8AAAD/UzAC/5tZAP+WVQD/OCAA/wAAAP8AAADfAAAA7QAAAP9KMx//
|
||||
sHpK/7R8TP9WPCb/AAAA/xsbG///////////////////////////////////////////////////////
|
||||
//////////////////////7+/v////////////7+/v///////v7+//7+/v////////////7+/v//////
|
||||
//////7+/v////////////7+/v///////////xsbG/8AAAD/UzAF/5pXA/+UVAD/Nx8A/wAAAP8AAADf
|
||||
AAAA7QAAAP9JMh7/rnhJ/7N6S/9VOyX/AAAA/xsbG////////v7+//////////////////7+/v//////
|
||||
/v7+//////////////////7+/v///////v7+/////////////////////////////v7+//7+/v/+/v7/
|
||||
///////////+/v7//v7+///////+/v7//v7+/////////////////xsbG/8AAAD/XkAl/6twNv+bXxz/
|
||||
OCEG/wAAAP8AAADfAAAA7QAAAP9JMh7/rndJ/7J6Sv9VOyX/AAAA/xsbG////////v7+////////////
|
||||
//////////////////////7+/v///////////////////////v7+//7+/v//////////////////////
|
||||
///////////////////////////+/v7//v7+//7+/v////////////7+/v///////////xsbG/8AAAD/
|
||||
X0Iq/7J6S/+qdEf/QCsZ/wAAAP8AAADfAAAA7QAAAP9IMR7/rXZH/7B4Sf9UOiT/AAAA/xsbG//+/v7/
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/v7+//7+/v///////////////////////v7+//7+/v//////////////////////////////////////
|
||||
/////xsbG/8AAAD/X0Eo/7F4Sf+qc0b/QCsa/wAAAP8AAADfAAAA7QAAAP9HMR7/rHRH/693Sf9TOST/
|
||||
AAAA/xsbG/////////////7+/v////////////7+/v////////////7+/v//////////////////////
|
||||
/v7+/////////////////////////////////////////////////////////////v7+///////+/v7/
|
||||
/v7+/////////////////xsbG/8AAAD/XkAo/7B3Sf+pc0b/QCsa/wAAAP8AAADfAAAA7QAAAP9HMB7/
|
||||
qnJH/651SP9TOCT/AAAA/xsbG///////////////////////////////////////////////////////
|
||||
//////////////////////7+/v////////////7+/v////////////7+/v//////////////////////
|
||||
//////7+/v///////////////////////////xsbG/8AAAD/Xj8o/650SP+ocUb/Pyoa/wAAAP8AAADf
|
||||
AAAA7QAAAP9GLx3/qXFG/610R/9TOCP/AAAA/xsbG////////v7+/////////////v7+////////////
|
||||
/v7+/////////////v7+//////////////////////////////////////////////////7+/v//////
|
||||
//////////////////////7+/v///////////////////////////xsbG/8AAAD/XT8n/61zR/+ncEX/
|
||||
Pyoa/wAAAP8AAADfAAAA7QAAAP9GLx3/qHFG/6xzR/9SNyP/AAAA/xsbG///////////////////////
|
||||
//////////////////////7+/v////////////7+/v/////////////////+/v7/////////////////
|
||||
/////////////////v7+//////////////////7+/v///////////////////////////xsbG/8AAAD/
|
||||
XT4n/6xzR/+mb0X/Pioa/wAAAP8AAADfAAAA7QAAAP9GLh3/p29F/6tyR/9SNyP/AAAA/xsbG///////
|
||||
/v7+///////+/v7///////7+/v///////v7+//7+/v/+/v7///////7+/v///////v7+////////////
|
||||
//////7+/v/+/v7///////7+/v///////////////////////v7+///////////////////////+/v7/
|
||||
/////xsbG/8AAAD/Wz4n/6tyR/+lbkT/Pika/wAAAP8AAADfAAAA5wAAAP9BKxv/pm5F/6tyR/9aPCb/
|
||||
AAAA/xsbG////////v7+///////////////////////+/v7////////////////////////////+/v7/
|
||||
//////7+/v////////////7+/v////////////7+/v////////////7+/v////////////7+/v//////
|
||||
//////7+/v///////////xsbG/8AAAD/ZEMq/6tyR/+kbUT/OSYY/wAAAP8AAADbAAAAxQAAAP8rHRL/
|
||||
nmhA/6lwRf+HWjf/CQYE/wMDA/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/
|
||||
Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/
|
||||
Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/wMDA/8NCQX/jV46/6lwRf+aZz7/JhoQ/wAAAP8AAAC5
|
||||
AAAAkwAAAP8PCgb/glc1/6hwRP+nbkP/XD0l/wsIBf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/w4JBv9iQSj/qG9E/6lwRP98UjL/
|
||||
CwgF/wAAAP0AAACDnJycswAAAOsAAAD/MyIV/6VtQ/+ob0T/pm5D/4tcOf9fPyf/WDok/1g6JP9YOiT/
|
||||
WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/
|
||||
WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/WDok/1g6JP9YOiT/YEAn/41dOv+nb0T/
|
||||
qHBE/6NsQv8sHRL/AAAA/wAAAOWjo6OtxcXFRDk5OdcAAAD/AwIB/1U5I/+kbUL/qHBE/6hwRP+qcUX/
|
||||
qnBF/6lwRf+qcEX/qnBF/6lwRf+qcEX/qnBF/6pwRf+pcEX/qnBF/6pwRf+pcEX/qnBF/6pwRf+pcEX/
|
||||
qXBF/6pwRf+qcEX/qnBF/6pwRf+qcEX/qXBF/6pwRf+pcEX/qXBF/6pwRf+qcEX/qXBF/6lwRf+pcEX/
|
||||
qnFF/6lwRP+ocET/o2xC/040IP8CAQD/AAAA/zw8PM3Pz89A////BBwcHCgAAADdAAAA/wMCAf8zIhX/
|
||||
gVY1/51oP/+kbUP/pW5D/6VuQ/+mbkP/pm5D/6ZuQ/+lbkP/pW5D/6VuQ/+lbkP/pm5D/6ZuQ/+mbkP/
|
||||
pW5D/6VuQ/+mbkP/pm5D/6ZuQ/+lbkP/pm5D/6ZuQ/+mbkP/pW5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/
|
||||
pW5D/6ZuQ/+lbkP/pGxC/5xnP/9+VDP/Lh8T/wIBAP8AAAD/AAAA0ykpKRz///8EAAAAAAAAAAAAAABM
|
||||
AAAA3QAAAP8AAAD/DwoG/yocEf8+KRr/RC4c/0QuHf9ELh3/RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/
|
||||
RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/RC4d/0QuHf9ELh3/
|
||||
RC4d/0QuHf9ELh3/RC4d/0QuHf9ELhz/PSkZ/ygbEP8NCQX/AAAA/wAAAP8AAADRAAAAQgAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAGxsbKDo6OtMAAADpAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA5zs7O88lJSUe
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////BMrKykKgoKCvAAAAjwAAAL8AAADjAAAA6wAAAOsAAADr
|
||||
AAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADr
|
||||
AAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA6wAAAOsAAADrAAAA4QAAAL0AAACP
|
||||
oqKirc3NzUD///8EAAAAAAAAAAAAAAAA4AAAAAAHAADgAAAAAAcAAMAAAAAAAwAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAADAADgAAAAAAcAAOAAAAAABwAAKAAAACAAAABAAAAA
|
||||
AQAgAAAAAACAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxcXFNltbW50AAAC/AAAA6QAAAPMAAADz
|
||||
AAAA8wAAAPMAAADzAAAA8wAAAPMAAADzAAAA8wAAAPMAAADzAAAA8wAAAPMAAADzAAAA8wAAAPMAAADz
|
||||
AAAA8wAAAPMAAADzAAAA5wAAAL1eXl6ZysrKNAAAAAAAAAAAAAAAAAAAACQAAAC/AAAA/RYSBf86Lg3/
|
||||
RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP9ENhD/
|
||||
RDYQ/0Q2EP9ENhD/RDYQ/0Q2EP84LQ3/FRAF/wAAAP0AAAC3AAAAIgAAAADExMQ2AAAAvwEBAP9mUhj/
|
||||
1qox/++9Nv/xvzf/8b83//G/N//xvzf/8b83//G/N//xvzf/8b83//G/N//xvzf/8b83//G/N//xvzf/
|
||||
8b83//G/N//xvzf/8b83//G/N//xvzf/8b83/+69Nv/UqTH/YU0X/wAAAP8AAAC3zMzMNFpaWp8AAAD9
|
||||
YkwV/+i1Mv/jsTH/sYsn/5x6I/+ceiT/nHok/5x6JP+ceiT/nHok/5x6JP+ceiT/nHok/5x6JP+ceiT/
|
||||
nHok/5x6JP+ceiT/nHok/5x6JP+ceiT/nHok/5x6JP+ceiT/s4wo/+SyMf/ntDL/WkYU/wAAAP1fX1+X
|
||||
AAAAvxQPBP/ImSn/26cs/0IzDv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/STgQ/9ypLf/Elij/
|
||||
EQ0D/wAAALcAAADrNCcK/9eiKP+jeyD/AAAA/4uLi/+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/
|
||||
vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/4uLi/8AAAD/
|
||||
q4Eh/9WgKP8uIwn/AAAA4wAAAPM8LQr/2J8l/5FrGv8AAAD/vLy8////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
vLy8/wAAAP+Wbxv/0Zsk/zQnCf8AAADpAAAA4Q8LA/83KAr/JRsH/wAAAP2+vr79uLi4/QUFBfUDAwP/
|
||||
AwMD/QMDA/0DAwP/AwMD95SUlPf+/v7///////////9iYmLFAwMD9QMDA/8DAwP9SUlJ9ff39/3/////
|
||||
//////////+8vLz/AAAA/5JqGf/LkyD/MyUI/wAAAOkAAADhGRkZ/1hYWP9DQ0L/AAAA/5CQkP8bGxv7
|
||||
FRUV/1lZWf9BQED/PDw8/1lZWf8eHh7/AAAA876+vv/Dw8P/w8PD/xMTE/kaGhr/WVlZ/0BAP/8BAQH9
|
||||
qqqq9f///////////////7y8vP8AAAD/jmUV/8WMG/8xIwf/AAAA6QAAAPFGRkb//Pz8/7y7u/8AAAD/
|
||||
AAAA/wAAAP8/Pz///////7m5uf+rqqr//v7+/1NTU/8AAAD/AAAA/wAAAP8AAAD/AAAA/0xLS///////
|
||||
tra2/wICAv8iIiL7NTU1+TU1NflHR0fze3t7+wAAAP+KYBL/wIYY/zAhBv8AAADpAAAA8UZGRv/7+/v/
|
||||
5+fn/6WlpP+mpqX/paWl/87Ozv/9/f3/kJCQ/6mpqf/+/v7/ycnJ/7Cwr/+wsK//sLCv/6ysrP9PT0//
|
||||
TEtL//////+9vb3/IiIi/yAgIP8gICD/ICAg/woKCv8AAAD/AAAA/4dcEf+8gBX/LyAF/wAAAOkAAADx
|
||||
RkZG//v7+//39/f/4ODg/+Hh4P/h4OD/6+vr//Dw8P9TU1P/qqqq//7+/v/o6Oj/3d3d/93d3f/i4uL/
|
||||
+/v7//Dw8P9ZWVn///////7+/v/8/Pz//f39//39/f/8/Pz/UVFR/wAAAP8AAAD/g1gO/7Z6Ef8uHwT/
|
||||
AAAA6QAAAPFGRkb/+/v7/8DAwP8TExP/FBQT/xMTE/9DQ0P//Pz8/7m5uf+qqqr//v7+/1xcW/8ODg7/
|
||||
Dg4O/x0dHf/Y2Nf/+/v7/3Z2dv//////0NDQ/2NiYv9iYWH/YmFh/2JhYf8fHx//AAAA/wAAAP+AVAz/
|
||||
sXUO/ywdA/8AAADpAAAA8UZGRv/7+/v/19fW/2ZlZf9mZmb/ZmZm/5SUlP/+/v7/vLy8/6qqqv/+/v7/
|
||||
mZiY/2ZmZv9mZmb/e3t6/+3t7f/6+vr/amlp///////Pz8//XV1d/11dXf9dXV3/XV1d/zU1Nf8AAAD/
|
||||
AAAA/3xQCv+tcAz/KxwD/wAAAOkAAADxRUVF//T09P/19fX/9fX1//X19f/19fX/9fX1//Hx8f9xcXH/
|
||||
paWl//X19f/19fX/9fX1//X19f/19fX/8/Pz/6qqqf9KSkr/9vb1//X19f/09PT/9PT0//T09P/09PT/
|
||||
iouK/wAAAP8AAAD/eU0I/6hrCP8qGgL/AAAA6QAAAN0PDw//NjY2/zc3N/83Nzf/Nzc3/zc3N/83Nzf/
|
||||
KSkp/wMDA/8lJSX/Nzc3/zc3N/83Nzf/Nzc3/zc3N/8tLS3/BQUF/xAQEP83Nzf/Nzc3/zc3N/83Nzf/
|
||||
Nzc3/zc3N/8fHx//AAAA/wAAAP93Sgb/pWcG/ykZAf8AAADpAAAA5RILAP9AJwL/KxoC/wAAAP9AQED/
|
||||
V1dX/1dXV/9XV1f/V1dX/1dXV/9XV1f/V1dX/1dXV/9XV1f/V1dX/1dXV/9aWlr1V1dX/1dXV/9XV1f/
|
||||
V1dX/1dXV/9XV1f/V1dX/1dXV/9CQkL5AAAA/3RGA/+hYQL/KBgA/wAAAOkAAADzLhwE/6RlEf9vRhD/
|
||||
AAAA/7y8vP//////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////7y8vP8AAAD/cUMC/51eAP8nFwD/AAAA6QAAAPMzJBb/
|
||||
tYBQ/3pWNv8AAAD/vLy8////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////vLy8/wAAAP9vQQH/mloA/yYWAP8AAADp
|
||||
AAAA8zIjFf+yfUz/eFQ0/wAAAP+8vLz/////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////+8vLz/AAAA/2w+Af+XVgD/
|
||||
JRUA/wAAAOkAAADzMSIU/7B6Sv92UjP/AAAA/7y8vP//////////////////////////////////////
|
||||
///////////////////////////+/v7//////////////////////////////////////7y8vP8AAAD/
|
||||
b0MP/5ZVBP8lFQD/AAAA6QAAAPMxIRT/rndJ/3VRMv8AAAD/vLy8////////////////////////////
|
||||
//////////////////////////////////////7+/v//////////////////////////////////////
|
||||
vLy8/wAAAP98VjX/qnND/ykbDv8AAADpAAAA8zAhFP+tdUf/dE8x/wAAAP+8vLz/////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////+8vLz/AAAA/3tUM/+rdEf/Kx0R/wAAAOkAAADzMCAU/6tzR/9yTTD/AAAA/7y8vP//////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////7y8vP8AAAD/elIz/6lyRv8qHBH/AAAA6QAAAPMvHxT/qXFG/3JMMP8AAAD/
|
||||
vLy8////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////vLy8/wAAAP95UTL/qHBF/yocEf8AAADpAAAA8y8fE/+ocEb/
|
||||
cUsv/wAAAP+8vLz/////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////+8vLz/AAAA/3dQMv+mb0X/KRwR/wAAAOkAAADp
|
||||
KBoR/6VuRP9+VDT/AAAA/4uLi/+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/
|
||||
vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/7y8vP+8vLz/vLy8/4uLi/8AAAD/hFg3/6RtQ/8jFw7/
|
||||
AAAA4QAAAL8PCgb/lGI8/6NsQv8yIRT/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/
|
||||
AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/zYkFv+kbUP/
|
||||
kWA7/wwIBf8AAAC1W1tbnwAAAP1GLhz/pm5D/6NsQv+AVTT/dE0v/3RNL/90TS//dE0v/3RNL/90TS//
|
||||
dE0v/3RNL/90TS//dE0v/3RNL/90TS//dE0v/3VNL/90TS//dE0v/3RNL/90TS//dE0v/3RNL/+CVjX/
|
||||
pG1C/6ZuQ/9AKxr/AAAA/WBgYJfGxsY2AAAAvQEAAP9GLhz/k2I8/6RtQv+mbkP/pm5D/6ZuQ/+mbkP/
|
||||
pm5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/pm5D/6ZuQ/+mbkP/
|
||||
pm5D/6RtQv+SYTv/Qiwb/wAAAP8AAACzzs7OMgAAAAAAAAAiAAAAvQAAAP0OCQb/JhkQ/y0fE/8uHxP/
|
||||
Lh8T/y4fE/8uHxP/LR8T/y4fE/8uHxP/Lh8T/y4fE/8uHxP/LR8T/y4fE/8uHxP/LR8T/y4fE/8uHxP/
|
||||
Lh8T/y4fE/8uHxP/JRkP/w0JBf8AAAD9AAAAswAAAB4AAAAAAAAAAAAAAADGxsY0XV1dmwAAAL0AAADn
|
||||
AAAA8QAAAPEAAADxAAAA8QAAAPEAAADxAAAA8QAAAPEAAADxAAAA8QAAAPEAAADxAAAA8QAAAPEAAADx
|
||||
AAAA8QAAAPEAAADxAAAA8QAAAPEAAADlAAAAvV9fX5fMzMw0AAAAAAAAAADAAAADgAAAAQAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAABwAAAAygAAAAYAAAA
|
||||
MAAAAAEAIAAAAAAAYAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMTExDE1NTa8AAADVAAAA9QAAAPcAAAD3
|
||||
AAAA9wAAAPcAAAD3AAAA9wAAAPcAAAD3AAAA9wAAAPcAAAD3AAAA9wAAAPcAAAD3AAAA9QAAANNOTk6r
|
||||
PDw8CgAAAAAyMjIMAAAAwxQQBf9+ZB3/qYYn/6uJKP+siSj/rIko/6uJKP+siSj/q4ko/6yJKP+riSj/
|
||||
rIko/6yJKP+riSj/q4ko/6uJKP+siSj/qYYn/3xjHf8SDwT/AAAAvUJCQghMTEyvEw8E/82gLf/hsDH/
|
||||
tY4p/7GLKP+xiyj/sYso/7GLKP+xiyj/sYso/7GLKP+xiyj/sYso/7GLKP+xiyj/sYso/7GLKP+xiyj/
|
||||
to8p/+KxMv/JnSz/EAwD/09PT6kAAADVdFkY/9ajK/8mHQn/DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/
|
||||
DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/yohCv/YpSv/b1QW/wAAAM8AAAD1
|
||||
lnAb/6V7Hv8NDQ3//v7+//7+/v/+/v7//v7+//7+/v/////////////////+/v7////////////+/v7/
|
||||
/v7+/////////////////w0NDf+qfx//j2sa/wAAAO8AAADtRDIM/0k1Df8ODg798fHx/1paWvlCQkL/
|
||||
QkJC/UJCQv9QUFD35eXl/f/////09PT3WFhY40JCQv9DQ0P7w8PD+//////+/v7//////w0NDf+idRv/
|
||||
jGYW/wAAAO8AAADrW1tb/2pqaf8ICAj/WVlZ/RcXF/+CgoL/SEdH/4KCgv8hISD/SEhI95KSkv95eXn9
|
||||
CAgI/Xd2dv9HR0f/Nzc39+fn5/3n5+f99vb2/Q0NDf+bbhb/hl8S/wAAAO8AAADzsbGx/9jY2P88PDz/
|
||||
PDw8/2tra//9/f3/hISD//7+/v9xcXH/RERE/0RERP87Ozv/FhYW/+fn5/+MjIz/BQUF/wUFBfsFBQX7
|
||||
JCQk+QMDA/2WaBP/gloP/wAAAO8AAADzsbGx//r6+v/o6Oj/6Ojo/+7u7v/g4OD/WVlY//7+/v/s7Oz/
|
||||
5ubm/+jo6P/7+/v/fn5+/+bm5v/p6en/0NDQ/9DQ0P/Dw8P/CgoK/wAAAP+RYg//fVQM/wAAAO8AAADz
|
||||
sbGx/8/Pz/8QEBD/ERER/zc3N//9/f3/jY2M//7+/v9ISEf/DQ0N/xoaGv/i4uL/rq6u/+Xl5f+qqqr/
|
||||
SkpK/0pKSv9GRkb/BAQE/wAAAP+MXAz/eU8J/wAAAO8AAADzsrKy//T09P/Jycj/ycnJ/9jY2P/7+/v/
|
||||
fX19//7+/v/W1tb/ycnJ/9DQ0P/6+vr/hoaG/+bm5v/j4+P/w8PD/8PDw//ExMP/IiIh/wAAAP+HVwn/
|
||||
dUsH/wAAAO8AAADpRUVF/2JiYv9iYmL/YmJi/2JiYv9KSUn/HRwc/2JiYv9iYmL/YmJi/2JiYv9PT0//
|
||||
Dw8P/1lZWf9iYmL/YmJi/2JiYv9iYmL/ERER/wAAAP+DUgb/cUcE/wAAAO8AAADvPiUB/0IoAv8HBwf/
|
||||
gYGB/4GBgf+BgYH/gYGB/4GBgf+BgYH/gYGB/4GBgf+BgYH/g4OD+4GBgf+BgYH/gYGB/4GBgf+BgYH/
|
||||
goKC/QcHB/9/TQP/bUIB/wAAAO8AAAD3e1Il/4RZK/8NDQ3///////7+/v/+/v7///////7+/v/+/v7/
|
||||
///////////+/v7////////////+/v7///////7+/v/+/v7//v7+/w0NDf97SQH/az8A/wAAAO8AAAD3
|
||||
f1k2/4deOv8NDQ3/////////////////////////////////////////////////////////////////
|
||||
/////////////////////w0NDf94RQH/ZzsA/wAAAO8AAAD3fFY0/4RbOP8NDQ3/////////////////
|
||||
//////////////////////7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+/w0NDf9+Thn/
|
||||
aD0I/wAAAO8AAAD3e1Qz/4NaN/8NDQ3///////7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7/
|
||||
/v7+//7+/v/+/v7///////7+/v/+/v7//v7+/w0NDf+IXTn/dU8w/wAAAO8AAAD3eVIy/4FXNv8NDQ3/
|
||||
/////////////////////////////////////////////////v7+////////////////////////////
|
||||
/////w0NDf+GWzj/dE4w/wAAAO8AAAD3d1Ay/39VNf8NDQ3///////////////////////7+/v//////
|
||||
/////////////////v7+/////////////v7+/////////////v7+/w0NDf+FWTf/ck0v/wAAAO8AAAD1
|
||||
dU4w/4FWNv8NDQ3//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7/
|
||||
/v7+//7+/v/+/v7//v7+/w0NDf+FWTj/cEsu/wAAAO0AAADVVzkj/6BqQf8dEwz/DQ0N/w0NDf8NDQ3/
|
||||
DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/w0NDf8NDQ3/DQ0N/yAVDf+ia0L/
|
||||
Ujch/wAAAM9NTU2vDQkF/5JhO/+gakH/g1Y1/4FVNP+BVTT/gVU0/4FVNP+BVTT/gVU0/4FVNP+BVTT/
|
||||
gVU0/4FVNP+BVTT/gVU0/4FVNP+BVTT/g1c1/6FrQf+PXzr/CwcE/1BQUKkzMzMMAAAAwQ0JBf9VOSP/
|
||||
c0wv/3VOMP91TjD/dU4w/3VOMP91TjD/dU4w/3VOMP91TjD/dU4w/3VOMP91TjD/dU4w/3VOMP91TjD/
|
||||
c0wv/1Q4Iv8MCAX/AAAAuUdHRwgAAAAAMjIyDE5OTqsAAADTAAAA8wAAAPUAAAD1AAAA9QAAAPUAAAD1
|
||||
AAAA9QAAAPUAAAD1AAAA9QAAAPUAAAD1AAAA9QAAAPUAAAD1AAAA8wAAANNPT0+pQkJCCAAAAACAAAEA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAQAoAAAAEAAAACAAAAABACAAAAAAAEAEAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAACCYmJqUWEQXpIhsI+SIbCPkiGwj5IhsI+SIbCPkiGwj5IhsI+SIbCPkiGwj5
|
||||
IhsI+RURBeknJyahAAAACCYmJqVsVRj/1qkw/8edLf/HnS3/x50t/8edLf/HnS3/x50t/8edLf/HnS3/
|
||||
x50t/8edLf/WqTD/aVIX/ycnJ58TDwTrx5cn/zMvJv9eXl7/Xl5e/15eXv9eXl7/Xl5e/15eXv9eXl7/
|
||||
Xl5e/15eXv9eXl7/NTEn/8iYJ/8RDQPlEw4D9XFTFP9eXl7/sLCw/YGBgf+BgYH/p6en+/7+/v/f39/x
|
||||
goKC/ZOTk/v9/f3//////15eXv+xgh7/GxME9RkZGfOVlJT/JCQk/xwcG/2UlJT/j4+P/xwcHPtgYGD/
|
||||
NTU1/W9vb/8+Pj7/gICA+aCgoPtNTU39p3YX/xkSA/UkJCT39fX1/8PDw//Q0ND/tLS0/9TU1P/Q0M//
|
||||
yMjH/7q6uv+oqKj/tra2/46Ojv9eXl7/AAAA/59sEf8YEAL1JCQk9+Pj4/89PDz/VFRU/9zc3P/U1NT/
|
||||
Wlpa/0NDQ//u7u7/t7e3/5iYmP9fX1//RUVE/wAAAP+XYgz/Fw8B9RYWFvOVlZX/lpaW/5aWlv9jY2P/
|
||||
fn19/5aWlv+Wlpb/c3Nz/2JiYv+Wlpb/lpaW/3V1df8AAAD/j1oH/xUNAPUQCgH1XzsJ/z8/P/+rq6v/
|
||||
q6ur/6urq/+rq6v/q6ur/6ysrP2rq6v/q6ur/6urq/+rq6v/Pz8//YlSAv8UDAD1GRIL+ZZqQf9eXl7/
|
||||
/////////////////////////////////////////////////////15eXv+DTAD/FAsA9RkRCvmSZT7/
|
||||
Xl5e//////////////////////////////////7+/v////////////////9eXl7/i1gj/xQMA/UYEAr5
|
||||
j2E8/15eXv//////////////////////////////////////////////////////Xl5e/5JjPf8WDwn1
|
||||
GBAK+Y1eO/9eXl7//////////////////////////////////////////////////////15eXv+QYDz/
|
||||
FQ4J9Q8KBumWZD3/Lyso/15eXv9eXl7/Xl5e/15eXv9eXl7/Xl5e/15eXv9eXl7/Xl5e/15eXv8wLCj/
|
||||
l2Q+/w0JBeUmJialTTMf/5dkPf+NXTn/jV45/41eOf+NXjn/jV45/41eOf+NXjn/jV45/41eOf+NXjn/
|
||||
l2Q9/0oxHv8nJyefAAAACCYmJqMOCQbpFw8K+RcPCvkXDwr5Fw8K+RcPCvkXDwr5Fw8K+RcPCvkXDwr5
|
||||
Fw8K+Q4JBecnJyefAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
|
@ -0,0 +1,505 @@
|
|||
/*
|
||||
* CellEditKeyEngine - A engine that allows the behaviour of arbitrary keys to be configured
|
||||
*
|
||||
* Author: Phillip Piper
|
||||
* Date: 3-March-2011 10:53 pm
|
||||
*
|
||||
* Change log:
|
||||
* 2012-04-14 JPP - Fixed bug where, on a OLV with only a single editable column, tabbing
|
||||
* to change rows would edit the cell above rather than the cell below
|
||||
* the cell being edited.
|
||||
* 2.5
|
||||
* 2011-03-03 JPP - First version
|
||||
*
|
||||
* Copyright (C) 2011-2012 Phillip Piper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using BrightIdeasSoftware;
|
||||
|
||||
namespace BrightIdeasSoftware {
|
||||
/// <summary>
|
||||
/// Indicates the behavior of a key when a cell "on the edge" is being edited.
|
||||
/// and the normal behavior of that key would exceed the edge. For example,
|
||||
/// for a key that normally moves one column to the left, the "edge" would be
|
||||
/// the left most column, since the normal action of the key cannot be taken
|
||||
/// (since there are no more columns to the left).
|
||||
/// </summary>
|
||||
public enum CellEditAtEdgeBehaviour {
|
||||
/// <summary>
|
||||
/// The key press will be ignored
|
||||
/// </summary>
|
||||
Ignore,
|
||||
|
||||
/// <summary>
|
||||
/// The key press will result in the cell editing wrapping to the
|
||||
/// cell on the opposite edge.
|
||||
/// </summary>
|
||||
Wrap,
|
||||
|
||||
/// <summary>
|
||||
/// The key press will wrap, but the column will be changed to the
|
||||
/// appropiate adjacent column. This only makes sense for keys where
|
||||
/// the normal action is ChangeRow.
|
||||
/// </summary>
|
||||
ChangeColumn,
|
||||
|
||||
/// <summary>
|
||||
/// The key press will wrap, but the row will be changed to the
|
||||
/// appropiate adjacent row. This only makes sense for keys where
|
||||
/// the normal action is ChangeColumn.
|
||||
/// </summary>
|
||||
ChangeRow,
|
||||
|
||||
/// <summary>
|
||||
/// The key will result in the current edit operation being ended.
|
||||
/// </summary>
|
||||
EndEdit
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the normal behaviour of a key when used during a cell edit
|
||||
/// operation.
|
||||
/// </summary>
|
||||
public enum CellEditCharacterBehaviour {
|
||||
/// <summary>
|
||||
/// The key press will be ignored
|
||||
/// </summary>
|
||||
Ignore,
|
||||
|
||||
/// <summary>
|
||||
/// The key press will end the current edit and begin an edit
|
||||
/// operation on the next editable cell to the left.
|
||||
/// </summary>
|
||||
ChangeColumnLeft,
|
||||
|
||||
/// <summary>
|
||||
/// The key press will end the current edit and begin an edit
|
||||
/// operation on the next editable cell to the right.
|
||||
/// </summary>
|
||||
ChangeColumnRight,
|
||||
|
||||
/// <summary>
|
||||
/// The key press will end the current edit and begin an edit
|
||||
/// operation on the row above.
|
||||
/// </summary>
|
||||
ChangeRowUp,
|
||||
|
||||
/// <summary>
|
||||
/// The key press will end the current edit and begin an edit
|
||||
/// operation on the row below
|
||||
/// </summary>
|
||||
ChangeRowDown,
|
||||
|
||||
/// <summary>
|
||||
/// The key press will cancel the current edit
|
||||
/// </summary>
|
||||
CancelEdit,
|
||||
|
||||
/// <summary>
|
||||
/// The key press will finish the current edit operation
|
||||
/// </summary>
|
||||
EndEdit,
|
||||
|
||||
/// <summary>
|
||||
/// Custom verb that can be used for specialized actions.
|
||||
/// </summary>
|
||||
CustomVerb1,
|
||||
|
||||
/// <summary>
|
||||
/// Custom verb that can be used for specialized actions.
|
||||
/// </summary>
|
||||
CustomVerb2,
|
||||
|
||||
/// <summary>
|
||||
/// Custom verb that can be used for specialized actions.
|
||||
/// </summary>
|
||||
CustomVerb3,
|
||||
|
||||
/// <summary>
|
||||
/// Custom verb that can be used for specialized actions.
|
||||
/// </summary>
|
||||
CustomVerb4,
|
||||
|
||||
/// <summary>
|
||||
/// Custom verb that can be used for specialized actions.
|
||||
/// </summary>
|
||||
CustomVerb5,
|
||||
|
||||
/// <summary>
|
||||
/// Custom verb that can be used for specialized actions.
|
||||
/// </summary>
|
||||
CustomVerb6,
|
||||
|
||||
/// <summary>
|
||||
/// Custom verb that can be used for specialized actions.
|
||||
/// </summary>
|
||||
CustomVerb7,
|
||||
|
||||
/// <summary>
|
||||
/// Custom verb that can be used for specialized actions.
|
||||
/// </summary>
|
||||
CustomVerb8,
|
||||
|
||||
/// <summary>
|
||||
/// Custom verb that can be used for specialized actions.
|
||||
/// </summary>
|
||||
CustomVerb9,
|
||||
|
||||
/// <summary>
|
||||
/// Custom verb that can be used for specialized actions.
|
||||
/// </summary>
|
||||
CustomVerb10,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Instances of this class handle key presses during a cell edit operation.
|
||||
/// </summary>
|
||||
public class CellEditKeyEngine {
|
||||
|
||||
#region Public interface
|
||||
|
||||
/// <summary>
|
||||
/// Sets the behaviour of a given key
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="normalBehaviour"></param>
|
||||
/// <param name="atEdgeBehaviour"></param>
|
||||
public virtual void SetKeyBehaviour(Keys key, CellEditCharacterBehaviour normalBehaviour, CellEditAtEdgeBehaviour atEdgeBehaviour) {
|
||||
this.CellEditKeyMap[key] = normalBehaviour;
|
||||
this.CellEditKeyAtEdgeBehaviourMap[key] = atEdgeBehaviour;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a key press
|
||||
/// </summary>
|
||||
/// <param name="olv"></param>
|
||||
/// <param name="keyData"></param>
|
||||
/// <returns>True if the key was completely handled.</returns>
|
||||
public virtual bool HandleKey(ObjectListView olv, Keys keyData) {
|
||||
if (olv == null) throw new ArgumentNullException("olv");
|
||||
|
||||
CellEditCharacterBehaviour behaviour;
|
||||
if (!CellEditKeyMap.TryGetValue(keyData, out behaviour))
|
||||
return false;
|
||||
|
||||
this.ListView = olv;
|
||||
|
||||
switch (behaviour) {
|
||||
case CellEditCharacterBehaviour.Ignore:
|
||||
break;
|
||||
case CellEditCharacterBehaviour.CancelEdit:
|
||||
this.HandleCancelEdit();
|
||||
break;
|
||||
case CellEditCharacterBehaviour.EndEdit:
|
||||
this.HandleEndEdit();
|
||||
break;
|
||||
case CellEditCharacterBehaviour.ChangeColumnLeft:
|
||||
case CellEditCharacterBehaviour.ChangeColumnRight:
|
||||
this.HandleColumnChange(keyData, behaviour);
|
||||
break;
|
||||
case CellEditCharacterBehaviour.ChangeRowDown:
|
||||
case CellEditCharacterBehaviour.ChangeRowUp:
|
||||
this.HandleRowChange(keyData, behaviour);
|
||||
break;
|
||||
default:
|
||||
return this.HandleCustomVerb(keyData, behaviour);
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ObjectListView on which the current key is being handled.
|
||||
/// This cannot be null.
|
||||
/// </summary>
|
||||
protected ObjectListView ListView {
|
||||
get { return listView; }
|
||||
set { listView = value; }
|
||||
}
|
||||
private ObjectListView listView;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the row of the cell that is currently being edited
|
||||
/// </summary>
|
||||
protected OLVListItem ItemBeingEdited {
|
||||
get {
|
||||
return this.ListView.cellEditEventArgs.ListViewItem;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the column of the cell that is being edited
|
||||
/// </summary>
|
||||
protected int SubItemIndexBeingEdited {
|
||||
get {
|
||||
return this.ListView.cellEditEventArgs.SubItemIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the map that remembers the normal behaviour of keys
|
||||
/// </summary>
|
||||
protected IDictionary<Keys, CellEditCharacterBehaviour> CellEditKeyMap {
|
||||
get {
|
||||
if (cellEditKeyMap == null)
|
||||
this.InitializeCellEditKeyMaps();
|
||||
return cellEditKeyMap;
|
||||
}
|
||||
set {
|
||||
cellEditKeyMap = value;
|
||||
}
|
||||
}
|
||||
private IDictionary<Keys, CellEditCharacterBehaviour> cellEditKeyMap;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the map that remembers the desired behaviour of keys
|
||||
/// on edge cases.
|
||||
/// </summary>
|
||||
protected IDictionary<Keys, CellEditAtEdgeBehaviour> CellEditKeyAtEdgeBehaviourMap {
|
||||
get {
|
||||
if (cellEditKeyAtEdgeBehaviourMap == null)
|
||||
this.InitializeCellEditKeyMaps();
|
||||
return cellEditKeyAtEdgeBehaviourMap;
|
||||
}
|
||||
set {
|
||||
cellEditKeyAtEdgeBehaviourMap = value;
|
||||
}
|
||||
}
|
||||
private IDictionary<Keys, CellEditAtEdgeBehaviour> cellEditKeyAtEdgeBehaviourMap;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Initialization
|
||||
|
||||
/// <summary>
|
||||
/// Setup the default key mapping
|
||||
/// </summary>
|
||||
protected virtual void InitializeCellEditKeyMaps() {
|
||||
this.cellEditKeyMap = new Dictionary<Keys, CellEditCharacterBehaviour>();
|
||||
this.cellEditKeyMap[Keys.Escape] = CellEditCharacterBehaviour.CancelEdit;
|
||||
this.cellEditKeyMap[Keys.Return] = CellEditCharacterBehaviour.EndEdit;
|
||||
this.cellEditKeyMap[Keys.Enter] = CellEditCharacterBehaviour.EndEdit;
|
||||
this.cellEditKeyMap[Keys.Tab] = CellEditCharacterBehaviour.ChangeColumnRight;
|
||||
this.cellEditKeyMap[Keys.Tab | Keys.Shift] = CellEditCharacterBehaviour.ChangeColumnLeft;
|
||||
this.cellEditKeyMap[Keys.Left | Keys.Alt] = CellEditCharacterBehaviour.ChangeColumnLeft;
|
||||
this.cellEditKeyMap[Keys.Right | Keys.Alt] = CellEditCharacterBehaviour.ChangeColumnRight;
|
||||
this.cellEditKeyMap[Keys.Up | Keys.Alt] = CellEditCharacterBehaviour.ChangeRowUp;
|
||||
this.cellEditKeyMap[Keys.Down | Keys.Alt] = CellEditCharacterBehaviour.ChangeRowDown;
|
||||
|
||||
this.cellEditKeyAtEdgeBehaviourMap = new Dictionary<Keys, CellEditAtEdgeBehaviour>();
|
||||
this.cellEditKeyAtEdgeBehaviourMap[Keys.Tab] = CellEditAtEdgeBehaviour.Wrap;
|
||||
this.cellEditKeyAtEdgeBehaviourMap[Keys.Tab | Keys.Shift] = CellEditAtEdgeBehaviour.Wrap;
|
||||
this.cellEditKeyAtEdgeBehaviourMap[Keys.Left | Keys.Alt] = CellEditAtEdgeBehaviour.Wrap;
|
||||
this.cellEditKeyAtEdgeBehaviourMap[Keys.Right | Keys.Alt] = CellEditAtEdgeBehaviour.Wrap;
|
||||
this.cellEditKeyAtEdgeBehaviourMap[Keys.Up | Keys.Alt] = CellEditAtEdgeBehaviour.ChangeColumn;
|
||||
this.cellEditKeyAtEdgeBehaviourMap[Keys.Down | Keys.Alt] = CellEditAtEdgeBehaviour.ChangeColumn;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Command handling
|
||||
|
||||
/// <summary>
|
||||
/// Handle the end edit command
|
||||
/// </summary>
|
||||
protected virtual void HandleEndEdit() {
|
||||
this.ListView.PossibleFinishCellEditing();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the cancel edit command
|
||||
/// </summary>
|
||||
protected virtual void HandleCancelEdit() {
|
||||
this.ListView.CancelCellEdit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Placeholder that subclasses can override to handle any custom verbs
|
||||
/// </summary>
|
||||
/// <param name="keyData"></param>
|
||||
/// <param name="behaviour"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual bool HandleCustomVerb(Keys keyData, CellEditCharacterBehaviour behaviour) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a change row command
|
||||
/// </summary>
|
||||
/// <param name="keyData"></param>
|
||||
/// <param name="behaviour"></param>
|
||||
protected virtual void HandleRowChange(Keys keyData, CellEditCharacterBehaviour behaviour) {
|
||||
// If we couldn't finish editing the current cell, don't try to move it
|
||||
if (!this.ListView.PossibleFinishCellEditing())
|
||||
return;
|
||||
|
||||
OLVListItem olvi = this.ItemBeingEdited;
|
||||
int subItemIndex = this.SubItemIndexBeingEdited;
|
||||
bool isGoingUp = behaviour == CellEditCharacterBehaviour.ChangeRowUp;
|
||||
|
||||
// Try to find a row above (or below) the currently edited cell
|
||||
// If we find one, start editing it and we're done.
|
||||
OLVListItem adjacentOlvi = this.GetAdjacentItemOrNull(olvi, isGoingUp);
|
||||
if (adjacentOlvi != null) {
|
||||
this.StartCellEditIfDifferent(adjacentOlvi, subItemIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
// There is no adjacent row in the direction we want, so we must be on an edge.
|
||||
CellEditAtEdgeBehaviour atEdgeBehaviour = CellEditAtEdgeBehaviour.Wrap;
|
||||
this.CellEditKeyAtEdgeBehaviourMap.TryGetValue(keyData, out atEdgeBehaviour);
|
||||
switch (atEdgeBehaviour) {
|
||||
case CellEditAtEdgeBehaviour.Ignore:
|
||||
break;
|
||||
case CellEditAtEdgeBehaviour.EndEdit:
|
||||
this.ListView.PossibleFinishCellEditing();
|
||||
break;
|
||||
case CellEditAtEdgeBehaviour.Wrap:
|
||||
adjacentOlvi = this.GetAdjacentItemOrNull(null, isGoingUp);
|
||||
this.StartCellEditIfDifferent(adjacentOlvi, subItemIndex);
|
||||
break;
|
||||
case CellEditAtEdgeBehaviour.ChangeColumn:
|
||||
// Figure out the next editable column
|
||||
List<OLVColumn> editableColumnsInDisplayOrder = this.EditableColumnsInDisplayOrder;
|
||||
int displayIndex = Math.Max(0, editableColumnsInDisplayOrder.IndexOf(this.ListView.GetColumn(subItemIndex)));
|
||||
if (isGoingUp)
|
||||
displayIndex = (editableColumnsInDisplayOrder.Count + displayIndex - 1) % editableColumnsInDisplayOrder.Count;
|
||||
else
|
||||
displayIndex = (displayIndex + 1) % editableColumnsInDisplayOrder.Count;
|
||||
subItemIndex = editableColumnsInDisplayOrder[displayIndex].Index;
|
||||
|
||||
// Wrap to the next row and start the cell edit
|
||||
adjacentOlvi = this.GetAdjacentItemOrNull(null, isGoingUp);
|
||||
this.StartCellEditIfDifferent(adjacentOlvi, subItemIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a change column command
|
||||
/// </summary>
|
||||
/// <param name="keyData"></param>
|
||||
/// <param name="behaviour"></param>
|
||||
protected virtual void HandleColumnChange(Keys keyData, CellEditCharacterBehaviour behaviour) {
|
||||
// If we couldn't finish editing the current cell, don't try to move it
|
||||
if (!this.ListView.PossibleFinishCellEditing())
|
||||
return;
|
||||
|
||||
// Changing columns only works in details mode
|
||||
if (this.ListView.View != View.Details)
|
||||
return;
|
||||
|
||||
List<OLVColumn> editableColumns = this.EditableColumnsInDisplayOrder;
|
||||
OLVListItem olvi = this.ItemBeingEdited;
|
||||
int displayIndex = Math.Max(0, editableColumns.IndexOf(this.ListView.GetColumn(this.SubItemIndexBeingEdited)));
|
||||
bool isGoingLeft = behaviour == CellEditCharacterBehaviour.ChangeColumnLeft;
|
||||
|
||||
// Are we trying to continue past one of the edges?
|
||||
if ((isGoingLeft && displayIndex == 0) ||
|
||||
(!isGoingLeft && displayIndex == editableColumns.Count - 1)) {
|
||||
// Yes, so figure out our at edge behaviour
|
||||
CellEditAtEdgeBehaviour atEdgeBehaviour = CellEditAtEdgeBehaviour.Wrap;
|
||||
this.CellEditKeyAtEdgeBehaviourMap.TryGetValue(keyData, out atEdgeBehaviour);
|
||||
switch (atEdgeBehaviour) {
|
||||
case CellEditAtEdgeBehaviour.Ignore:
|
||||
return;
|
||||
case CellEditAtEdgeBehaviour.EndEdit:
|
||||
this.HandleEndEdit();
|
||||
return;
|
||||
case CellEditAtEdgeBehaviour.ChangeRow:
|
||||
case CellEditAtEdgeBehaviour.Wrap:
|
||||
if (atEdgeBehaviour == CellEditAtEdgeBehaviour.ChangeRow)
|
||||
olvi = GetAdjacentItem(olvi, isGoingLeft && displayIndex == 0);
|
||||
if (isGoingLeft)
|
||||
displayIndex = editableColumns.Count - 1;
|
||||
else
|
||||
displayIndex = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (isGoingLeft)
|
||||
displayIndex -= 1;
|
||||
else
|
||||
displayIndex += 1;
|
||||
}
|
||||
|
||||
int subItemIndex = editableColumns[displayIndex].Index;
|
||||
this.StartCellEditIfDifferent(olvi, subItemIndex);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utilities
|
||||
|
||||
/// <summary>
|
||||
/// Start editing the indicated cell if that cell is not already being edited
|
||||
/// </summary>
|
||||
/// <param name="olvi">The row to edit</param>
|
||||
/// <param name="subItemIndex">The cell within that row to edit</param>
|
||||
protected void StartCellEditIfDifferent(OLVListItem olvi, int subItemIndex) {
|
||||
if (this.ItemBeingEdited == olvi && this.SubItemIndexBeingEdited == subItemIndex)
|
||||
return;
|
||||
|
||||
this.ListView.EnsureVisible(olvi.Index);
|
||||
this.ListView.StartCellEdit(olvi, subItemIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the adjacent item to the given item in the given direction
|
||||
/// </summary>
|
||||
/// <param name="olvi">The row whose neighbour is sought</param>
|
||||
/// <param name="up">The direction of the adjacentness</param>
|
||||
/// <returns>An OLVListView adjacent to the given item, or null if there are no more items in that direction.</returns>
|
||||
protected OLVListItem GetAdjacentItemOrNull(OLVListItem olvi, bool up) {
|
||||
return up ? this.ListView.GetPreviousItem(olvi) : this.ListView.GetNextItem(olvi);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the adjacent item to the given item in the given direction, wrapping if needed.
|
||||
/// </summary>
|
||||
/// <param name="olvi">The row whose neighbour is sought</param>
|
||||
/// <param name="up">The direction of the adjacentness</param>
|
||||
/// <returns>An OLVListView adjacent to the given item, or null if there are no more items in that direction.</returns>
|
||||
protected OLVListItem GetAdjacentItem(OLVListItem olvi, bool up) {
|
||||
return this.GetAdjacentItemOrNull(olvi, up) ?? this.GetAdjacentItemOrNull(null, up);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of columns that are editable in the order they are shown to the user
|
||||
/// </summary>
|
||||
protected List<OLVColumn> EditableColumnsInDisplayOrder {
|
||||
get {
|
||||
List<OLVColumn> editableColumnsInDisplayOrder = new List<OLVColumn>();
|
||||
foreach (OLVColumn x in this.ListView.ColumnsInDisplayOrder)
|
||||
if (x.IsEditable)
|
||||
editableColumnsInDisplayOrder.Add(x);
|
||||
return editableColumnsInDisplayOrder;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* CellEditors - Several slightly modified controls that are used as celleditors within ObjectListView.
|
||||
*
|
||||
* Author: Phillip Piper
|
||||
* Date: 20/10/2008 5:15 PM
|
||||
*
|
||||
* Change log:
|
||||
* v2.3
|
||||
* 2009-08-13 JPP - Standardized code formatting
|
||||
* v2.2.1
|
||||
* 2008-01-18 JPP - Added special handling for enums
|
||||
* 2008-01-16 JPP - Added EditorRegistry
|
||||
* v2.0.1
|
||||
* 2008-10-20 JPP - Separated from ObjectListView.cs
|
||||
*
|
||||
* Copyright (C) 2006-2012 Phillip Piper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BrightIdeasSoftware
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// These items allow combo boxes to remember a value and its description.
|
||||
/// </summary>
|
||||
internal class ComboBoxItem
|
||||
{
|
||||
public ComboBoxItem(Object key, String description) {
|
||||
this.key = key;
|
||||
this.description = description;
|
||||
}
|
||||
private String description;
|
||||
|
||||
public Object Key {
|
||||
get { return key; }
|
||||
}
|
||||
private Object key;
|
||||
|
||||
public override string ToString() {
|
||||
return this.description;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Cell editors
|
||||
// These classes are simple cell editors that make it easier to get and set
|
||||
// the value that the control is showing.
|
||||
// In many cases, you can intercept the CellEditStarting event to
|
||||
// change the characteristics of the editor. For example, changing
|
||||
// the acceptable range for a numeric editor or changing the strings
|
||||
// that respresent true and false values for a boolean editor.
|
||||
|
||||
/// <summary>
|
||||
/// This editor shows and auto completes values from the given listview column.
|
||||
/// </summary>
|
||||
[ToolboxItem(false)]
|
||||
public class AutoCompleteCellEditor : ComboBox
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an AutoCompleteCellEditor
|
||||
/// </summary>
|
||||
/// <param name="lv"></param>
|
||||
/// <param name="column"></param>
|
||||
public AutoCompleteCellEditor(ObjectListView lv, OLVColumn column) {
|
||||
this.DropDownStyle = ComboBoxStyle.DropDown;
|
||||
|
||||
Dictionary<String, bool> alreadySeen = new Dictionary<string, bool>();
|
||||
for (int i = 0; i < Math.Min(lv.GetItemCount(), 1000); i++) {
|
||||
String str = column.GetStringValue(lv.GetModelObject(i));
|
||||
if (!alreadySeen.ContainsKey(str)) {
|
||||
this.Items.Add(str);
|
||||
alreadySeen[str] = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.Sorted = true;
|
||||
this.AutoCompleteSource = AutoCompleteSource.ListItems;
|
||||
this.AutoCompleteMode = AutoCompleteMode.Append;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This combo box is specialised to allow editing of an enum.
|
||||
/// </summary>
|
||||
internal class EnumCellEditor : ComboBox
|
||||
{
|
||||
public EnumCellEditor(Type type) {
|
||||
this.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
this.ValueMember = "Key";
|
||||
|
||||
ArrayList values = new ArrayList();
|
||||
foreach (object value in Enum.GetValues(type))
|
||||
values.Add(new ComboBoxItem(value, Enum.GetName(type, value)));
|
||||
|
||||
this.DataSource = values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This editor simply shows and edits integer values.
|
||||
/// </summary>
|
||||
internal class IntUpDown : NumericUpDown
|
||||
{
|
||||
public IntUpDown() {
|
||||
this.DecimalPlaces = 0;
|
||||
this.Minimum = -9999999;
|
||||
this.Maximum = 9999999;
|
||||
}
|
||||
|
||||
new public int Value {
|
||||
get { return Decimal.ToInt32(base.Value); }
|
||||
set { base.Value = new Decimal(value); }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This editor simply shows and edits unsigned integer values.
|
||||
/// </summary>
|
||||
internal class UintUpDown : NumericUpDown
|
||||
{
|
||||
public UintUpDown() {
|
||||
this.DecimalPlaces = 0;
|
||||
this.Minimum = 0;
|
||||
this.Maximum = 9999999;
|
||||
}
|
||||
|
||||
new public uint Value {
|
||||
get { return Decimal.ToUInt32(base.Value); }
|
||||
set { base.Value = new Decimal(value); }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This editor simply shows and edits boolean values.
|
||||
/// </summary>
|
||||
internal class BooleanCellEditor : ComboBox
|
||||
{
|
||||
public BooleanCellEditor() {
|
||||
this.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
this.ValueMember = "Key";
|
||||
|
||||
ArrayList values = new ArrayList();
|
||||
values.Add(new ComboBoxItem(false, "False"));
|
||||
values.Add(new ComboBoxItem(true, "True"));
|
||||
|
||||
this.DataSource = values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This editor simply shows and edits boolean values using a checkbox
|
||||
/// </summary>
|
||||
internal class BooleanCellEditor2 : CheckBox
|
||||
{
|
||||
public BooleanCellEditor2() {
|
||||
}
|
||||
|
||||
public bool? Value {
|
||||
get {
|
||||
switch (this.CheckState) {
|
||||
case CheckState.Checked: return true;
|
||||
case CheckState.Indeterminate: return null;
|
||||
case CheckState.Unchecked:
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
set {
|
||||
if (value.HasValue)
|
||||
this.CheckState = value.Value ? CheckState.Checked : CheckState.Unchecked;
|
||||
else
|
||||
this.CheckState = CheckState.Indeterminate;
|
||||
}
|
||||
}
|
||||
|
||||
public new HorizontalAlignment TextAlign {
|
||||
get {
|
||||
switch (this.CheckAlign) {
|
||||
case ContentAlignment.MiddleRight: return HorizontalAlignment.Right;
|
||||
case ContentAlignment.MiddleCenter: return HorizontalAlignment.Center;
|
||||
case ContentAlignment.MiddleLeft:
|
||||
default: return HorizontalAlignment.Left;
|
||||
}
|
||||
}
|
||||
set {
|
||||
switch (value) {
|
||||
case HorizontalAlignment.Left:
|
||||
this.CheckAlign = ContentAlignment.MiddleLeft;
|
||||
break;
|
||||
case HorizontalAlignment.Center:
|
||||
this.CheckAlign = ContentAlignment.MiddleCenter;
|
||||
break;
|
||||
case HorizontalAlignment.Right:
|
||||
this.CheckAlign = ContentAlignment.MiddleRight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This editor simply shows and edits floating point values.
|
||||
/// </summary>
|
||||
/// <remarks>You can intercept the CellEditStarting event if you want
|
||||
/// to change the characteristics of the editor. For example, by increasing
|
||||
/// the number of decimal places.</remarks>
|
||||
internal class FloatCellEditor : NumericUpDown
|
||||
{
|
||||
public FloatCellEditor() {
|
||||
this.DecimalPlaces = 2;
|
||||
this.Minimum = -9999999;
|
||||
this.Maximum = 9999999;
|
||||
}
|
||||
|
||||
new public double Value {
|
||||
get { return Convert.ToDouble(base.Value); }
|
||||
set { base.Value = Convert.ToDecimal(value); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* EditorRegistry - A registry mapping types to cell editors.
|
||||
*
|
||||
* Author: Phillip Piper
|
||||
* Date: 6-March-2011 7:53 am
|
||||
*
|
||||
* Change log:
|
||||
* 2011-03-31 JPP - Use OLVColumn.DataType if the value to be edited is null
|
||||
* 2011-03-06 JPP - Separated from CellEditors.cs
|
||||
*
|
||||
* Copyright (C) 2011-2012 Phillip Piper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BrightIdeasSoftware {
|
||||
|
||||
/// <summary>
|
||||
/// A delegate that creates an editor for the given value
|
||||
/// </summary>
|
||||
/// <param name="model">The model from which that value came</param>
|
||||
/// <param name="column">The column for which the editor is being created</param>
|
||||
/// <param name="value">A representative value of the type to be edited. This value may not be the exact
|
||||
/// value for the column/model combination. It could be simply representative of
|
||||
/// the appropriate type of value.</param>
|
||||
/// <returns>A control which can edit the given value</returns>
|
||||
public delegate Control EditorCreatorDelegate(Object model, OLVColumn column, Object value);
|
||||
|
||||
/// <summary>
|
||||
/// An editor registry gives a way to decide what cell editor should be used to edit
|
||||
/// the value of a cell. Programmers can register non-standard types and the control that
|
||||
/// should be used to edit instances of that type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>All ObjectListViews share the same editor registry.</para>
|
||||
/// </remarks>
|
||||
public class EditorRegistry {
|
||||
#region Initializing
|
||||
|
||||
/// <summary>
|
||||
/// Create an EditorRegistry
|
||||
/// </summary>
|
||||
public EditorRegistry() {
|
||||
this.InitializeStandardTypes();
|
||||
}
|
||||
|
||||
private void InitializeStandardTypes() {
|
||||
this.Register(typeof(Boolean), typeof(BooleanCellEditor));
|
||||
this.Register(typeof(Int16), typeof(IntUpDown));
|
||||
this.Register(typeof(Int32), typeof(IntUpDown));
|
||||
this.Register(typeof(Int64), typeof(IntUpDown));
|
||||
this.Register(typeof(UInt16), typeof(UintUpDown));
|
||||
this.Register(typeof(UInt32), typeof(UintUpDown));
|
||||
this.Register(typeof(UInt64), typeof(UintUpDown));
|
||||
this.Register(typeof(Single), typeof(FloatCellEditor));
|
||||
this.Register(typeof(Double), typeof(FloatCellEditor));
|
||||
this.Register(typeof(DateTime), delegate(Object model, OLVColumn column, Object value) {
|
||||
DateTimePicker c = new DateTimePicker();
|
||||
c.Format = DateTimePickerFormat.Short;
|
||||
return c;
|
||||
});
|
||||
this.Register(typeof(Boolean), delegate(Object model, OLVColumn column, Object value) {
|
||||
CheckBox c = new BooleanCellEditor2();
|
||||
c.ThreeState = column.TriStateCheckBoxes;
|
||||
return c;
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Registering
|
||||
|
||||
/// <summary>
|
||||
/// Register that values of 'type' should be edited by instances of 'controlType'.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of value to be edited</param>
|
||||
/// <param name="controlType">The type of the Control that will edit values of 'type'</param>
|
||||
/// <example>
|
||||
/// ObjectListView.EditorRegistry.Register(typeof(Color), typeof(MySpecialColorEditor));
|
||||
/// </example>
|
||||
public void Register(Type type, Type controlType) {
|
||||
this.Register(type, delegate(Object model, OLVColumn column, Object value) {
|
||||
return controlType.InvokeMember("", BindingFlags.CreateInstance, null, null, null) as Control;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register the given delegate so that it is called to create editors
|
||||
/// for values of the given type
|
||||
/// </summary>
|
||||
/// <param name="type">The type of value to be edited</param>
|
||||
/// <param name="creator">The delegate that will create a control that can edit values of 'type'</param>
|
||||
/// <example>
|
||||
/// ObjectListView.EditorRegistry.Register(typeof(Color), CreateColorEditor);
|
||||
/// ...
|
||||
/// public Control CreateColorEditor(Object model, OLVColumn column, Object value)
|
||||
/// {
|
||||
/// return new MySpecialColorEditor();
|
||||
/// }
|
||||
/// </example>
|
||||
public void Register(Type type, EditorCreatorDelegate creator) {
|
||||
this.creatorMap[type] = creator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a delegate that will be called to create an editor for values
|
||||
/// that have not been handled.
|
||||
/// </summary>
|
||||
/// <param name="creator">The delegate that will create a editor for all other types</param>
|
||||
public void RegisterDefault(EditorCreatorDelegate creator) {
|
||||
this.defaultCreator = creator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a delegate that will be given a chance to create a control
|
||||
/// before any other option is considered.
|
||||
/// </summary>
|
||||
/// <param name="creator">The delegate that will create a control</param>
|
||||
public void RegisterFirstChance(EditorCreatorDelegate creator) {
|
||||
this.firstChanceCreator = creator;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Accessing
|
||||
|
||||
/// <summary>
|
||||
/// Create and return an editor that is appropriate for the given value.
|
||||
/// Return null if no appropriate editor can be found.
|
||||
/// </summary>
|
||||
/// <param name="model">The model involved</param>
|
||||
/// <param name="column">The column to be edited</param>
|
||||
/// <param name="value">The value to be edited. This value may not be the exact
|
||||
/// value for the column/model combination. It could be simply representative of
|
||||
/// the appropriate type of value.</param>
|
||||
/// <returns>A Control that can edit the given type of values</returns>
|
||||
public Control GetEditor(Object model, OLVColumn column, Object value) {
|
||||
Control editor;
|
||||
|
||||
// Give the first chance delegate a chance to decide
|
||||
if (this.firstChanceCreator != null) {
|
||||
editor = this.firstChanceCreator(model, column, value);
|
||||
if (editor != null)
|
||||
return editor;
|
||||
}
|
||||
|
||||
// Try to find a creator based on the type of the value (or the column)
|
||||
Type type = value == null ? column.DataType : value.GetType();
|
||||
if (type != null && this.creatorMap.ContainsKey(type)) {
|
||||
editor = this.creatorMap[type](model, column, value);
|
||||
if (editor != null)
|
||||
return editor;
|
||||
}
|
||||
|
||||
// Enums without other processing get a special editor
|
||||
if (value != null && value.GetType().IsEnum)
|
||||
return this.CreateEnumEditor(value.GetType());
|
||||
|
||||
// Give any default creator a final chance
|
||||
if (this.defaultCreator != null)
|
||||
return this.defaultCreator(model, column, value);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create and return an editor that will edit values of the given type
|
||||
/// </summary>
|
||||
/// <param name="type">A enum type</param>
|
||||
protected Control CreateEnumEditor(Type type) {
|
||||
return new EnumCellEditor(type);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private variables
|
||||
|
||||
private EditorCreatorDelegate firstChanceCreator;
|
||||
private EditorCreatorDelegate defaultCreator;
|
||||
private Dictionary<Type, EditorCreatorDelegate> creatorMap = new Dictionary<Type, EditorCreatorDelegate>();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Dictionary>
|
||||
<Words>
|
||||
<Recognized>
|
||||
<Word>br</Word>
|
||||
<Word>Canceled</Word>
|
||||
<Word>Center</Word>
|
||||
<Word>Color</Word>
|
||||
<Word>Colors</Word>
|
||||
<Word>f</Word>
|
||||
<Word>fmt</Word>
|
||||
<Word>g</Word>
|
||||
<Word>gdi</Word>
|
||||
<Word>hti</Word>
|
||||
<Word>i</Word>
|
||||
<Word>lightbox</Word>
|
||||
<Word>lv</Word>
|
||||
<Word>lvi</Word>
|
||||
<Word>lvsi</Word>
|
||||
<Word>m</Word>
|
||||
<Word>multi</Word>
|
||||
<Word>Munger</Word>
|
||||
<Word>n</Word>
|
||||
<Word>olv</Word>
|
||||
<Word>olvi</Word>
|
||||
<Word>p</Word>
|
||||
<Word>parms</Word>
|
||||
<Word>r</Word>
|
||||
<Word>Renderer</Word>
|
||||
<Word>s</Word>
|
||||
<Word>SubItem</Word>
|
||||
<Word>Unapply</Word>
|
||||
<Word>Unpause</Word>
|
||||
<Word>x</Word>
|
||||
<Word>y</Word>
|
||||
</Recognized>
|
||||
<Deprecated>
|
||||
<Term PreferredAlternate="EnterpriseServices">ComPlus</Term>
|
||||
</Deprecated>
|
||||
</Words>
|
||||
<Acronyms>
|
||||
<CasingExceptions>
|
||||
<Acronym>OLV</Acronym>
|
||||
</CasingExceptions>
|
||||
</Acronyms>
|
||||
</Dictionary>
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* DataListView - A data-bindable listview
|
||||
*
|
||||
* Author: Phillip Piper
|
||||
* Date: 27/09/2008 9:15 AM
|
||||
*
|
||||
* Change log:
|
||||
* 2011-02-27 JPP - Moved most of the logic to DataSourceAdapter (where it
|
||||
* can be used by FastDataListView too)
|
||||
* v2.3
|
||||
* 2009-01-18 JPP - Boolean columns are now handled as checkboxes
|
||||
* - Auto-generated columns would fail if the data source was
|
||||
* reseated, even to the same data source
|
||||
* v2.0.1
|
||||
* 2009-01-07 JPP - Made all public and protected methods virtual
|
||||
* 2008-10-03 JPP - Separated from ObjectListView.cs
|
||||
*
|
||||
* Copyright (C) 2006-2012 Phillip Piper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing.Design;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BrightIdeasSoftware
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// A DataListView is a ListView that can be bound to a datasource (which would normally be a DataTable or DataView).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This listview keeps itself in sync with its source datatable by listening for change events.</para>
|
||||
/// <para>If the listview has no columns when given a data source, it will automatically create columns to show all of the datatables columns.
|
||||
/// This will be only the simplest view of the world, and would look more interesting with a few delegates installed.</para>
|
||||
/// <para>This listview will also automatically generate missing aspect getters to fetch the values from the data view.</para>
|
||||
/// <para>Changing data sources is possible, but error prone. Before changing data sources, the programmer is responsible for modifying/resetting
|
||||
/// the column collection to be valid for the new data source.</para>
|
||||
/// <para>Internally, a CurrencyManager controls keeping the data source in-sync with other users of the data source (as per normal .NET
|
||||
/// behavior). This means that the model objects in the DataListView are DataRowView objects. If you write your own AspectGetters/Setters,
|
||||
/// they will be given DataRowView objects.</para>
|
||||
/// </remarks>
|
||||
public class DataListView : ObjectListView
|
||||
{
|
||||
/// <summary>
|
||||
/// Make a DataListView
|
||||
/// </summary>
|
||||
public DataListView()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the DataSourceAdapter that this control will use.
|
||||
/// </summary>
|
||||
/// <returns>A DataSourceAdapter configured for this list</returns>
|
||||
/// <remarks>Subclasses should overrride this to create their
|
||||
/// own specialized adapters</remarks>
|
||||
protected virtual DataSourceAdapter CreateDataSourceAdapter() {
|
||||
return new DataSourceAdapter(this);
|
||||
}
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the VirtualListDataSource that will be displayed in this list view.
|
||||
/// </summary>
|
||||
/// <remarks>The VirtualListDataSource should implement either <see cref="IList"/>, <see cref="IBindingList"/>,
|
||||
/// or <see cref="IListSource"/>. Some common examples are the following types of objects:
|
||||
/// <list type="unordered">
|
||||
/// <item><description><see cref="DataView"/></description></item>
|
||||
/// <item><description><see cref="DataTable"/></description></item>
|
||||
/// <item><description><see cref="DataSet"/></description></item>
|
||||
/// <item><description><see cref="DataViewManager"/></description></item>
|
||||
/// <item><description><see cref="BindingSource"/></description></item>
|
||||
/// </list>
|
||||
/// <para>When binding to a list container (i.e. one that implements the
|
||||
/// <see cref="IListSource"/> interface, such as <see cref="DataSet"/>)
|
||||
/// you must also set the <see cref="DataMember"/> property in order
|
||||
/// to identify which particular list you would like to display. You
|
||||
/// may also set the <see cref="DataMember"/> property even when
|
||||
/// VirtualListDataSource refers to a list, since <see cref="DataMember"/> can
|
||||
/// also be used to navigate relations between lists.</para>
|
||||
/// </remarks>
|
||||
[Category("Data"),
|
||||
TypeConverter("System.Windows.Forms.Design.DataSourceConverter, System.Design")]
|
||||
public virtual Object DataSource
|
||||
{
|
||||
get { return this.Adapter.DataSource; }
|
||||
set { this.Adapter.DataSource = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the list or table in the data source for which the DataListView is displaying data.
|
||||
/// </summary>
|
||||
/// <remarks>If the data source is not a DataSet or DataViewManager, this property has no effect</remarks>
|
||||
[Category("Data"),
|
||||
Editor("System.Windows.Forms.Design.DataMemberListEditor, System.Design", typeof(UITypeEditor)),
|
||||
DefaultValue("")]
|
||||
public virtual string DataMember
|
||||
{
|
||||
get { return this.Adapter.DataMember; }
|
||||
set { this.Adapter.DataMember = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the DataSourceAdaptor that does the bulk of the work needed
|
||||
/// for data binding.
|
||||
/// </summary>
|
||||
protected DataSourceAdapter Adapter {
|
||||
get {
|
||||
if (adapter == null)
|
||||
adapter = this.CreateDataSourceAdapter();
|
||||
return adapter;
|
||||
}
|
||||
set { adapter = value; }
|
||||
}
|
||||
private DataSourceAdapter adapter;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Object manipulations
|
||||
|
||||
/// <summary>
|
||||
/// Add the given collection of model objects to this control.
|
||||
/// </summary>
|
||||
/// <param name="modelObjects">A collection of model objects</param>
|
||||
/// <remarks>This is a no-op for data lists, since the data
|
||||
/// is controlled by the VirtualListDataSource. Manipulate the data source
|
||||
/// rather than this view of the data source.</remarks>
|
||||
public override void AddObjects(ICollection modelObjects)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove the given collection of model objects from this control.
|
||||
/// </summary>
|
||||
/// <remarks>This is a no-op for data lists, since the data
|
||||
/// is controlled by the VirtualListDataSource. Manipulate the data source
|
||||
/// rather than this view of the data source.</remarks>
|
||||
public override void RemoveObjects(ICollection modelObjects)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Handles parent binding context changes
|
||||
/// </summary>
|
||||
/// <param name="e">Unused EventArgs.</param>
|
||||
protected override void OnParentBindingContextChanged(EventArgs e)
|
||||
{
|
||||
base.OnParentBindingContextChanged(e);
|
||||
|
||||
// BindingContext is an ambient property - by default it simply picks
|
||||
// up the parent control's context (unless something has explicitly
|
||||
// given us our own). So we must respond to changes in our parent's
|
||||
// binding context in the same way we would changes to our own
|
||||
// binding context.
|
||||
|
||||
// THINK: Do we need to forward this to the adapter?
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* DragSource.cs - Add drag source functionality to an ObjectListView
|
||||
*
|
||||
* Author: Phillip Piper
|
||||
* Date: 2009-03-17 5:15 PM
|
||||
*
|
||||
* Change log:
|
||||
* 2011-03-29 JPP - Separate OLVDataObject.cs
|
||||
* v2.3
|
||||
* 2009-07-06 JPP - Make sure Link is acceptable as an drop effect by default
|
||||
* (since MS didn't make it part of the 'All' value)
|
||||
* v2.2
|
||||
* 2009-04-15 JPP - Separated DragSource.cs into DropSink.cs
|
||||
* 2009-03-17 JPP - Initial version
|
||||
*
|
||||
* Copyright (C) 2009-2012 Phillip Piper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
namespace BrightIdeasSoftware
|
||||
{
|
||||
/// <summary>
|
||||
/// An IDragSource controls how drag out from the ObjectListView will behave
|
||||
/// </summary>
|
||||
public interface IDragSource
|
||||
{
|
||||
/// <summary>
|
||||
/// A drag operation is beginning. Return the data object that will be used
|
||||
/// for data transfer. Return null to prevent the drag from starting. The data
|
||||
/// object will normally include all the selected objects.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The returned object is later passed to the GetAllowedEffect() and EndDrag()
|
||||
/// methods.
|
||||
/// </remarks>
|
||||
/// <param name="olv">What ObjectListView is being dragged from.</param>
|
||||
/// <param name="button">Which mouse button is down?</param>
|
||||
/// <param name="item">What item was directly dragged by the user? There may be more than just this
|
||||
/// item selected.</param>
|
||||
/// <returns>The data object that will be used for data transfer. This will often be a subclass
|
||||
/// of DataObject, but does not need to be.</returns>
|
||||
Object StartDrag(ObjectListView olv, MouseButtons button, OLVListItem item);
|
||||
|
||||
/// <summary>
|
||||
/// What operations are possible for this drag? This controls the icon shown during the drag
|
||||
/// </summary>
|
||||
/// <param name="dragObject">The data object returned by StartDrag()</param>
|
||||
/// <returns>A combination of DragDropEffects flags</returns>
|
||||
DragDropEffects GetAllowedEffects(Object dragObject);
|
||||
|
||||
/// <summary>
|
||||
/// The drag operation is complete. Do whatever is necessary to complete the action.
|
||||
/// </summary>
|
||||
/// <param name="dragObject">The data object returned by StartDrag()</param>
|
||||
/// <param name="effect">The value returned from GetAllowedEffects()</param>
|
||||
void EndDrag(Object dragObject, DragDropEffects effect);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A do-nothing implementation of IDragSource that can be safely subclassed.
|
||||
/// </summary>
|
||||
public class AbstractDragSource : IDragSource
|
||||
{
|
||||
#region IDragSource Members
|
||||
|
||||
/// <summary>
|
||||
/// See IDragSource documentation
|
||||
/// </summary>
|
||||
/// <param name="olv"></param>
|
||||
/// <param name="button"></param>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Object StartDrag(ObjectListView olv, MouseButtons button, OLVListItem item) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See IDragSource documentation
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public virtual DragDropEffects GetAllowedEffects(Object data) {
|
||||
return DragDropEffects.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See IDragSource documentation
|
||||
/// </summary>
|
||||
/// <param name="dragObject"></param>
|
||||
/// <param name="effect"></param>
|
||||
public virtual void EndDrag(Object dragObject, DragDropEffects effect) {
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A reasonable implementation of IDragSource that provides normal
|
||||
/// drag source functionality. It creates a data object that supports
|
||||
/// inter-application dragging of text and HTML representation of
|
||||
/// the dragged rows. It can optionally force a refresh of all dragged
|
||||
/// rows when the drag is complete.
|
||||
/// </summary>
|
||||
/// <remarks>Subclasses can override GetDataObject() to add new
|
||||
/// data formats to the data transfer object.</remarks>
|
||||
public class SimpleDragSource : IDragSource
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Construct a SimpleDragSource
|
||||
/// </summary>
|
||||
public SimpleDragSource() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a SimpleDragSource that refreshes the dragged rows when
|
||||
/// the drag is complete
|
||||
/// </summary>
|
||||
/// <param name="refreshAfterDrop"></param>
|
||||
public SimpleDragSource(bool refreshAfterDrop) {
|
||||
this.RefreshAfterDrop = refreshAfterDrop;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the dragged rows should be refreshed when the
|
||||
/// drag operation is complete.
|
||||
/// </summary>
|
||||
public bool RefreshAfterDrop {
|
||||
get { return refreshAfterDrop; }
|
||||
set { refreshAfterDrop = value; }
|
||||
}
|
||||
private bool refreshAfterDrop;
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDragSource Members
|
||||
|
||||
/// <summary>
|
||||
/// Create a DataObject when the user does a left mouse drag operation.
|
||||
/// See IDragSource for further information.
|
||||
/// </summary>
|
||||
/// <param name="olv"></param>
|
||||
/// <param name="button"></param>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Object StartDrag(ObjectListView olv, MouseButtons button, OLVListItem item) {
|
||||
// We only drag on left mouse
|
||||
if (button != MouseButtons.Left)
|
||||
return null;
|
||||
|
||||
return this.CreateDataObject(olv);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Which operations are allowed in the operation? By default, all operations are supported.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns>All opertions are supported</returns>
|
||||
public virtual DragDropEffects GetAllowedEffects(Object data) {
|
||||
return DragDropEffects.All | DragDropEffects.Link; // why didn't MS include 'Link' in 'All'??
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The drag operation is finished. Refreshe the dragged rows if so configured.
|
||||
/// </summary>
|
||||
/// <param name="dragObject"></param>
|
||||
/// <param name="effect"></param>
|
||||
public virtual void EndDrag(Object dragObject, DragDropEffects effect) {
|
||||
OLVDataObject data = dragObject as OLVDataObject;
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
if (this.RefreshAfterDrop)
|
||||
data.ListView.RefreshObjects(data.ModelObjects);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a data object that will be used to as the data object
|
||||
/// for the drag operation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Subclasses can override this method add new formats to the data object.
|
||||
/// </remarks>
|
||||
/// <param name="olv">The ObjectListView that is the source of the drag</param>
|
||||
/// <returns>A data object for the drag</returns>
|
||||
protected virtual object CreateDataObject(ObjectListView olv) {
|
||||
return new OLVDataObject(olv);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* OLVDataObject.cs - An OLE DataObject that knows how to convert rows of an OLV to text and HTML
|
||||
*
|
||||
* Author: Phillip Piper
|
||||
* Date: 2011-03-29 3:34PM
|
||||
*
|
||||
* Change log:
|
||||
* 2011-03-29 JPP - Initial version
|
||||
*
|
||||
* Copyright (C) 2011-2012 Phillip Piper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
namespace BrightIdeasSoftware {
|
||||
|
||||
/// <summary>
|
||||
/// A data transfer object that knows how to transform a list of model
|
||||
/// objects into a text and HTML representation.
|
||||
/// </summary>
|
||||
public class OLVDataObject : DataObject {
|
||||
#region Life and death
|
||||
|
||||
/// <summary>
|
||||
/// Create a data object from the selected objects in the given ObjectListView
|
||||
/// </summary>
|
||||
/// <param name="olv">The source of the data object</param>
|
||||
public OLVDataObject(ObjectListView olv)
|
||||
: this(olv, olv.SelectedObjects) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a data object which operates on the given model objects
|
||||
/// in the given ObjectListView
|
||||
/// </summary>
|
||||
/// <param name="olv">The source of the data object</param>
|
||||
/// <param name="modelObjects">The model objects to be put into the data object</param>
|
||||
public OLVDataObject(ObjectListView olv, IList modelObjects) {
|
||||
this.objectListView = olv;
|
||||
this.modelObjects = modelObjects;
|
||||
this.includeHiddenColumns = olv.IncludeHiddenColumnsInDataTransfer;
|
||||
this.includeColumnHeaders = olv.IncludeColumnHeadersInCopy;
|
||||
this.CreateTextFormats();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether hidden columns will also be included in the text
|
||||
/// and HTML representation. If this is false, only visible columns will
|
||||
/// be included.
|
||||
/// </summary>
|
||||
public bool IncludeHiddenColumns {
|
||||
get { return includeHiddenColumns; }
|
||||
}
|
||||
private bool includeHiddenColumns;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether column headers will also be included in the text
|
||||
/// and HTML representation.
|
||||
/// </summary>
|
||||
public bool IncludeColumnHeaders {
|
||||
get { return includeColumnHeaders; }
|
||||
}
|
||||
private bool includeColumnHeaders;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ObjectListView that is being used as the source of the data
|
||||
/// </summary>
|
||||
public ObjectListView ListView {
|
||||
get { return objectListView; }
|
||||
}
|
||||
private ObjectListView objectListView;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model objects that are to be placed in the data object
|
||||
/// </summary>
|
||||
public IList ModelObjects {
|
||||
get { return modelObjects; }
|
||||
}
|
||||
private IList modelObjects = new ArrayList();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Put a text and HTML representation of our model objects
|
||||
/// into the data object.
|
||||
/// </summary>
|
||||
public void CreateTextFormats() {
|
||||
IList<OLVColumn> columns = this.IncludeHiddenColumns ? this.ListView.AllColumns : this.ListView.ColumnsInDisplayOrder;
|
||||
|
||||
// Build text and html versions of the selection
|
||||
StringBuilder sbText = new StringBuilder();
|
||||
StringBuilder sbHtml = new StringBuilder("<table>");
|
||||
|
||||
// Include column headers
|
||||
if (includeColumnHeaders) {
|
||||
sbHtml.Append("<tr><td>");
|
||||
foreach (OLVColumn col in columns) {
|
||||
if (col != columns[0]) {
|
||||
sbText.Append("\t");
|
||||
sbHtml.Append("</td><td>");
|
||||
}
|
||||
string strValue = col.Text;
|
||||
sbText.Append(strValue);
|
||||
sbHtml.Append(strValue); //TODO: Should encode the string value
|
||||
}
|
||||
sbText.AppendLine();
|
||||
sbHtml.AppendLine("</td></tr>");
|
||||
}
|
||||
|
||||
foreach (object modelObject in this.ModelObjects) {
|
||||
sbHtml.Append("<tr><td>");
|
||||
foreach (OLVColumn col in columns) {
|
||||
if (col != columns[0]) {
|
||||
sbText.Append("\t");
|
||||
sbHtml.Append("</td><td>");
|
||||
}
|
||||
string strValue = col.GetStringValue(modelObject);
|
||||
sbText.Append(strValue);
|
||||
sbHtml.Append(strValue); //TODO: Should encode the string value
|
||||
}
|
||||
sbText.AppendLine();
|
||||
sbHtml.AppendLine("</td></tr>");
|
||||
}
|
||||
sbHtml.AppendLine("</table>");
|
||||
|
||||
// Put both the text and html versions onto the clipboard.
|
||||
// For some reason, SetText() with UnicodeText doesn't set the basic CF_TEXT format,
|
||||
// but using SetData() does.
|
||||
//this.SetText(sbText.ToString(), TextDataFormat.UnicodeText);
|
||||
this.SetData(sbText.ToString());
|
||||
this.SetText(ConvertToHtmlFragment(sbHtml.ToString()), TextDataFormat.Html);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a HTML representation of our model objects
|
||||
/// </summary>
|
||||
public string CreateHtml() {
|
||||
IList<OLVColumn> columns = this.ListView.ColumnsInDisplayOrder;
|
||||
|
||||
// Build html version of the selection
|
||||
StringBuilder sbHtml = new StringBuilder("<table>");
|
||||
|
||||
foreach (object modelObject in this.ModelObjects) {
|
||||
sbHtml.Append("<tr><td>");
|
||||
foreach (OLVColumn col in columns) {
|
||||
if (col != columns[0]) {
|
||||
sbHtml.Append("</td><td>");
|
||||
}
|
||||
string strValue = col.GetStringValue(modelObject);
|
||||
sbHtml.Append(strValue); //TODO: Should encode the string value
|
||||
}
|
||||
sbHtml.AppendLine("</td></tr>");
|
||||
}
|
||||
sbHtml.AppendLine("</table>");
|
||||
|
||||
return sbHtml.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert the fragment of HTML into the Clipboards HTML format.
|
||||
/// </summary>
|
||||
/// <remarks>The HTML format is found here http://msdn2.microsoft.com/en-us/library/aa767917.aspx
|
||||
/// </remarks>
|
||||
/// <param name="fragment">The HTML to put onto the clipboard. It must be valid HTML!</param>
|
||||
/// <returns>A string that can be put onto the clipboard and will be recognized as HTML</returns>
|
||||
private string ConvertToHtmlFragment(string fragment) {
|
||||
// Minimal implementation of HTML clipboard format
|
||||
string source = "http://www.codeproject.com/KB/list/ObjectListView.aspx";
|
||||
|
||||
const String MARKER_BLOCK =
|
||||
"Version:1.0\r\n" +
|
||||
"StartHTML:{0,8}\r\n" +
|
||||
"EndHTML:{1,8}\r\n" +
|
||||
"StartFragment:{2,8}\r\n" +
|
||||
"EndFragment:{3,8}\r\n" +
|
||||
"StartSelection:{2,8}\r\n" +
|
||||
"EndSelection:{3,8}\r\n" +
|
||||
"SourceURL:{4}\r\n" +
|
||||
"{5}";
|
||||
|
||||
int prefixLength = String.Format(MARKER_BLOCK, 0, 0, 0, 0, source, "").Length;
|
||||
|
||||
const String DEFAULT_HTML_BODY =
|
||||
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">" +
|
||||
"<HTML><HEAD></HEAD><BODY><!--StartFragment-->{0}<!--EndFragment--></BODY></HTML>";
|
||||
|
||||
string html = String.Format(DEFAULT_HTML_BODY, fragment);
|
||||
int startFragment = prefixLength + html.IndexOf(fragment);
|
||||
int endFragment = startFragment + fragment.Length;
|
||||
|
||||
return String.Format(MARKER_BLOCK, prefixLength, prefixLength + html.Length, startFragment, endFragment, source, html);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* FastDataListView - A data bindable listview that has the speed of a virtual list
|
||||
*
|
||||
* Author: Phillip Piper
|
||||
* Date: 22/09/2010 8:11 AM
|
||||
*
|
||||
* Change log:
|
||||
* 2010-09-22 JPP - Initial version
|
||||
*
|
||||
* Copyright (C) 2006-2012 Phillip Piper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing.Design;
|
||||
|
||||
namespace BrightIdeasSoftware
|
||||
{
|
||||
/// <summary>
|
||||
/// A FastDataListView virtualizes the display of data from a DataSource. It operates on
|
||||
/// DataSets and DataTables in the same way as a DataListView, but does so much more efficiently.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A FastDataListView still has to load all its data from the DataSource. If you have SQL statement
|
||||
/// that returns 1 million rows, all 1 million rows will still need to read from the database.
|
||||
/// However, once the rows are loaded, the FastDataListView will only build rows as they are displayed.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class FastDataListView : FastObjectListView
|
||||
{
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the VirtualListDataSource that will be displayed in this list view.
|
||||
/// </summary>
|
||||
/// <remarks>The VirtualListDataSource should implement either <see cref="IList"/>, <see cref="IBindingList"/>,
|
||||
/// or <see cref="IListSource"/>. Some common examples are the following types of objects:
|
||||
/// <list type="unordered">
|
||||
/// <item><description><see cref="DataView"/></description></item>
|
||||
/// <item><description><see cref="DataTable"/></description></item>
|
||||
/// <item><description><see cref="DataSet"/></description></item>
|
||||
/// <item><description><see cref="DataViewManager"/></description></item>
|
||||
/// <item><description><see cref="BindingSource"/></description></item>
|
||||
/// </list>
|
||||
/// <para>When binding to a list container (i.e. one that implements the
|
||||
/// <see cref="IListSource"/> interface, such as <see cref="DataSet"/>)
|
||||
/// you must also set the <see cref="DataMember"/> property in order
|
||||
/// to identify which particular list you would like to display. You
|
||||
/// may also set the <see cref="DataMember"/> property even when
|
||||
/// VirtualListDataSource refers to a list, since <see cref="DataMember"/> can
|
||||
/// also be used to navigate relations between lists.</para>
|
||||
/// </remarks>
|
||||
[Category("Data"),
|
||||
TypeConverter("System.Windows.Forms.Design.DataSourceConverter, System.Design")]
|
||||
public virtual Object DataSource {
|
||||
get { return this.Adapter.DataSource; }
|
||||
set { this.Adapter.DataSource = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the list or table in the data source for which the DataListView is displaying data.
|
||||
/// </summary>
|
||||
/// <remarks>If the data source is not a DataSet or DataViewManager, this property has no effect</remarks>
|
||||
[Category("Data"),
|
||||
Editor("System.Windows.Forms.Design.DataMemberListEditor, System.Design", typeof(UITypeEditor)),
|
||||
DefaultValue("")]
|
||||
public virtual string DataMember {
|
||||
get { return this.Adapter.DataMember; }
|
||||
set { this.Adapter.DataMember = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the DataSourceAdaptor that does the bulk of the work needed
|
||||
/// for data binding.
|
||||
/// </summary>
|
||||
protected DataSourceAdapter Adapter {
|
||||
get {
|
||||
if (adapter == null)
|
||||
adapter = this.CreateDataSourceAdapter();
|
||||
return adapter;
|
||||
}
|
||||
set { adapter = value; }
|
||||
}
|
||||
private DataSourceAdapter adapter;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation
|
||||
|
||||
/// <summary>
|
||||
/// Create the DataSourceAdapter that this control will use.
|
||||
/// </summary>
|
||||
/// <returns>A DataSourceAdapter configured for this list</returns>
|
||||
/// <remarks>Subclasses should overrride this to create their
|
||||
/// own specialized adapters</remarks>
|
||||
protected virtual DataSourceAdapter CreateDataSourceAdapter() {
|
||||
return new DataSourceAdapter(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* FastObjectListView - A listview that behaves like an ObjectListView but has the speed of a virtual list
|
||||
*
|
||||
* Author: Phillip Piper
|
||||
* Date: 27/09/2008 9:15 AM
|
||||
*
|
||||
* Change log:
|
||||
* 2011-04-25 JPP - Fixed problem with removing objects from filtered or sorted list
|
||||
* v2.4
|
||||
* 2010-04-05 JPP - Added filtering
|
||||
* v2.3
|
||||
* 2009-08-27 JPP - Added GroupingStrategy
|
||||
* - Added optimized Objects property
|
||||
* v2.2.1
|
||||
* 2009-01-07 JPP - Made all public and protected methods virtual
|
||||
* 2008-09-27 JPP - Separated from ObjectListView.cs
|
||||
*
|
||||
* Copyright (C) 2006-2012 Phillip Piper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BrightIdeasSoftware
|
||||
{
|
||||
/// <summary>
|
||||
/// A FastObjectListView trades function for speed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>On my mid-range laptop, this view builds a list of 10,000 objects in 0.1 seconds,
|
||||
/// as opposed to a normal ObjectListView which takes 10-15 seconds. Lists of up to 50,000 items should be
|
||||
/// able to be handled with sub-second response times even on low end machines.</para>
|
||||
/// <para>
|
||||
/// A FastObjectListView is implemented as a virtual list with many of the virtual modes limits (e.g. no sorting)
|
||||
/// fixed through coding. There are some functions that simply cannot be provided. Specifically, a FastObjectListView cannot:
|
||||
/// <list type="bullet">
|
||||
/// <item><description>use Tile view</description></item>
|
||||
/// <item><description>show groups on XP</description></item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class FastObjectListView : VirtualObjectListView
|
||||
{
|
||||
/// <summary>
|
||||
/// Make a FastObjectListView
|
||||
/// </summary>
|
||||
public FastObjectListView() {
|
||||
this.VirtualListDataSource = new FastObjectListDataSource(this);
|
||||
this.GroupingStrategy = new FastListGroupingStrategy();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the collection of objects that this list will show
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The contents of the control will be updated immediately after setting this property.
|
||||
/// </para>
|
||||
/// <para>This method preserves selection, if possible. Use SetObjects() if
|
||||
/// you do not want to preserve the selection. Preserving selection is the slowest part of this
|
||||
/// code and performance is O(n) where n is the number of selected rows.</para>
|
||||
/// <para>This method is not thread safe.</para>
|
||||
/// </remarks>
|
||||
[Browsable(false),
|
||||
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public override IEnumerable Objects {
|
||||
get {
|
||||
// This is much faster than the base method
|
||||
return ((FastObjectListDataSource)this.VirtualListDataSource).ObjectList;
|
||||
}
|
||||
set { base.Objects = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove any sorting and revert to the given order of the model objects
|
||||
/// </summary>
|
||||
public override void Unsort() {
|
||||
this.ShowGroups = false;
|
||||
this.PrimarySortColumn = null;
|
||||
this.PrimarySortOrder = SortOrder.None;
|
||||
this.SetObjects(this.Objects);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provide a data source for a FastObjectListView
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class isn't intended to be used directly, but it is left as a public
|
||||
/// class just in case someone wants to subclass it.
|
||||
/// </remarks>
|
||||
public class FastObjectListDataSource : AbstractVirtualListDataSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a FastObjectListDataSource
|
||||
/// </summary>
|
||||
/// <param name="listView"></param>
|
||||
public FastObjectListDataSource(FastObjectListView listView)
|
||||
: base(listView) {
|
||||
}
|
||||
|
||||
internal ArrayList ObjectList {
|
||||
get { return fullObjectList; }
|
||||
}
|
||||
|
||||
internal ArrayList FilteredObjectList {
|
||||
get { return filteredObjectList; }
|
||||
}
|
||||
|
||||
#region IVirtualListDataSource Members
|
||||
|
||||
/// <summary>
|
||||
/// Get n'th object
|
||||
/// </summary>
|
||||
/// <param name="n"></param>
|
||||
/// <returns></returns>
|
||||
public override object GetNthObject(int n) {
|
||||
if (n >= 0 && n < this.filteredObjectList.Count)
|
||||
return this.filteredObjectList[n];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// How many items are in the data source
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int GetObjectCount() {
|
||||
return this.filteredObjectList.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the given model
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
public override int GetObjectIndex(object model) {
|
||||
int index;
|
||||
|
||||
if (model != null && this.objectsToIndexMap.TryGetValue(model, out index))
|
||||
return index;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="first"></param>
|
||||
/// <param name="last"></param>
|
||||
/// <param name="column"></param>
|
||||
/// <returns></returns>
|
||||
public override int SearchText(string value, int first, int last, OLVColumn column) {
|
||||
return DefaultSearchText(value, first, last, column, this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="column"></param>
|
||||
/// <param name="sortOrder"></param>
|
||||
public override void Sort(OLVColumn column, SortOrder sortOrder) {
|
||||
if (sortOrder != SortOrder.None) {
|
||||
ModelObjectComparer comparer = new ModelObjectComparer(column, sortOrder, this.listView.SecondarySortColumn, this.listView.SecondarySortOrder);
|
||||
this.fullObjectList.Sort(comparer);
|
||||
this.filteredObjectList.Sort(comparer);
|
||||
}
|
||||
this.RebuildIndexMap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="modelObjects"></param>
|
||||
public override void AddObjects(ICollection modelObjects) {
|
||||
foreach (object modelObject in modelObjects) {
|
||||
if (modelObject != null)
|
||||
this.fullObjectList.Add(modelObject);
|
||||
}
|
||||
this.FilterObjects();
|
||||
this.RebuildIndexMap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove the given collection of models from this source.
|
||||
/// </summary>
|
||||
/// <param name="modelObjects"></param>
|
||||
public override void RemoveObjects(ICollection modelObjects) {
|
||||
List<int> indicesToRemove = new List<int>();
|
||||
foreach (object modelObject in modelObjects) {
|
||||
int i = this.GetObjectIndex(modelObject);
|
||||
if (i >= 0)
|
||||
indicesToRemove.Add(i);
|
||||
|
||||
// Remove the objects from the unfiltered list
|
||||
this.fullObjectList.Remove(modelObject);
|
||||
}
|
||||
|
||||
// Sort the indices from highest to lowest so that we
|
||||
// remove latter ones before earlier ones. In this way, the
|
||||
// indices of the rows doesn't change after the deletes.
|
||||
indicesToRemove.Sort();
|
||||
indicesToRemove.Reverse();
|
||||
|
||||
foreach (int i in indicesToRemove)
|
||||
this.listView.SelectedIndices.Remove(i);
|
||||
|
||||
this.FilterObjects();
|
||||
this.RebuildIndexMap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="collection"></param>
|
||||
public override void SetObjects(IEnumerable collection) {
|
||||
ArrayList newObjects = ObjectListView.EnumerableToArray(collection, true);
|
||||
|
||||
this.fullObjectList = newObjects;
|
||||
this.FilterObjects();
|
||||
this.RebuildIndexMap();
|
||||
}
|
||||
|
||||
private ArrayList fullObjectList = new ArrayList();
|
||||
private ArrayList filteredObjectList = new ArrayList();
|
||||
private IModelFilter modelFilter;
|
||||
private IListFilter listFilter;
|
||||
|
||||
#endregion
|
||||
|
||||
#region IFilterableDataSource Members
|
||||
|
||||
/// <summary>
|
||||
/// Apply the given filters to this data source. One or both may be null.
|
||||
/// </summary>
|
||||
/// <param name="iModelFilter"></param>
|
||||
/// <param name="iListFilter"></param>
|
||||
public override void ApplyFilters(IModelFilter iModelFilter, IListFilter iListFilter) {
|
||||
this.modelFilter = iModelFilter;
|
||||
this.listFilter = iListFilter;
|
||||
this.SetObjects(this.fullObjectList);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Implementation
|
||||
|
||||
/// <summary>
|
||||
/// Rebuild the map that remembers which model object is displayed at which line
|
||||
/// </summary>
|
||||
protected void RebuildIndexMap() {
|
||||
this.objectsToIndexMap.Clear();
|
||||
for (int i = 0; i < this.filteredObjectList.Count; i++)
|
||||
this.objectsToIndexMap[this.filteredObjectList[i]] = i;
|
||||
}
|
||||
readonly Dictionary<Object, int> objectsToIndexMap = new Dictionary<Object, int>();
|
||||
|
||||
/// <summary>
|
||||
/// Build our filtered list from our full list.
|
||||
/// </summary>
|
||||
protected void FilterObjects() {
|
||||
if (!this.listView.UseFiltering || (this.modelFilter == null && this.listFilter == null)) {
|
||||
this.filteredObjectList = new ArrayList(this.fullObjectList);
|
||||
return;
|
||||
}
|
||||
|
||||
IEnumerable objects = (this.listFilter == null) ?
|
||||
this.fullObjectList : this.listFilter.Filter(this.fullObjectList);
|
||||
|
||||
// Apply the object filter if there is one
|
||||
if (this.modelFilter == null) {
|
||||
this.filteredObjectList = ObjectListView.EnumerableToArray(objects, false);
|
||||
} else {
|
||||
this.filteredObjectList = new ArrayList();
|
||||
foreach (object model in objects) {
|
||||
if (this.modelFilter.Filter(model))
|
||||
this.filteredObjectList.Add(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Cluster - Implements a simple cluster
|
||||
*
|
||||
* Author: Phillip Piper
|
||||
* Date: 3-March-2011 10:53 pm
|
||||
*
|
||||
* Change log:
|
||||
* 2011-03-03 JPP - First version
|
||||
*
|
||||
* Copyright (C) 2011-2012 Phillip Piper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BrightIdeasSoftware {
|
||||
|
||||
/// <summary>
|
||||
/// Concrete implementation of the ICluster interface.
|
||||
/// </summary>
|
||||
public class Cluster : ICluster {
|
||||
|
||||
#region Life and death
|
||||
|
||||
/// <summary>
|
||||
/// Create a cluster
|
||||
/// </summary>
|
||||
/// <param name="key">The key for the cluster</param>
|
||||
public Cluster(object key) {
|
||||
this.Count = 1;
|
||||
this.ClusterKey = key;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public overrides
|
||||
|
||||
/// <summary>
|
||||
/// Return a string representation of this cluster
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString() {
|
||||
return this.DisplayLabel ?? "[empty]";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of ICluster
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets how many items belong to this cluster
|
||||
/// </summary>
|
||||
public int Count {
|
||||
get { return count; }
|
||||
set { count = value; }
|
||||
}
|
||||
private int count;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the label that will be shown to the user to represent
|
||||
/// this cluster
|
||||
/// </summary>
|
||||
public string DisplayLabel {
|
||||
get { return displayLabel; }
|
||||
set { displayLabel = value; }
|
||||
}
|
||||
private string displayLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the actual data object that all members of this cluster
|
||||
/// have commonly returned.
|
||||
/// </summary>
|
||||
public object ClusterKey {
|
||||
get { return clusterKey; }
|
||||
set { clusterKey = value; }
|
||||
}
|
||||
private object clusterKey;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IComparable
|
||||
|
||||
/// <summary>
|
||||
/// Return an indication of the ordering between this object and the given one
|
||||
/// </summary>
|
||||
/// <param name="other"></param>
|
||||
/// <returns></returns>
|
||||
public int CompareTo(object other) {
|
||||
if (other == null || other == System.DBNull.Value)
|
||||
return 1;
|
||||
|
||||
ICluster otherCluster = other as ICluster;
|
||||
if (otherCluster == null)
|
||||
return 1;
|
||||
|
||||
string keyAsString = this.ClusterKey as string;
|
||||
if (keyAsString != null)
|
||||
return String.Compare(keyAsString, otherCluster.ClusterKey as string, StringComparison.CurrentCultureIgnoreCase);
|
||||
|
||||
IComparable keyAsComparable = this.ClusterKey as IComparable;
|
||||
if (keyAsComparable != null)
|
||||
return keyAsComparable.CompareTo(otherCluster.ClusterKey);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* ClusteringStrategy - Implements a simple clustering strategy
|
||||
*
|
||||
* Author: Phillip Piper
|
||||
* Date: 3-March-2011 10:53 pm
|
||||
*
|
||||
* Change log:
|
||||
* 2011-03-03 JPP - First version
|
||||
*
|
||||
* Copyright (C) 2011-2012 Phillip Piper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BrightIdeasSoftware {
|
||||
|
||||
/// <summary>
|
||||
/// This class provides a useful base implemention of a clustering
|
||||
/// strategy where the clusters are grouped around the value of a given column.
|
||||
/// </summary>
|
||||
public class ClusteringStrategy : IClusteringStrategy {
|
||||
|
||||
#region Static properties
|
||||
|
||||
/// <summary>
|
||||
/// This field is the text that will be shown to the user when a cluster
|
||||
/// key is null. It is exposed so it can be localized.
|
||||
/// </summary>
|
||||
static public string NULL_LABEL = "[null]";
|
||||
|
||||
/// <summary>
|
||||
/// This field is the text that will be shown to the user when a cluster
|
||||
/// key is empty (i.e. a string of zero length). It is exposed so it can be localized.
|
||||
/// </summary>
|
||||
static public string EMPTY_LABEL = "[empty]";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the format that will be used by default for clusters that only
|
||||
/// contain 1 item. The format string must accept two placeholders:
|
||||
/// - {0} is the cluster key converted to a string
|
||||
/// - {1} is the number of items in the cluster (always 1 in this case)
|
||||
/// </summary>
|
||||
static public string DefaultDisplayLabelFormatSingular {
|
||||
get { return defaultDisplayLabelFormatSingular; }
|
||||
set { defaultDisplayLabelFormatSingular = value; }
|
||||
}
|
||||
static private string defaultDisplayLabelFormatSingular = "{0} ({1} item)";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the format that will be used by default for clusters that
|
||||
/// contain 0 or two or more items. The format string must accept two placeholders:
|
||||
/// - {0} is the cluster key converted to a string
|
||||
/// - {1} is the number of items in the cluster
|
||||
/// </summary>
|
||||
static public string DefaultDisplayLabelFormatPlural {
|
||||
get { return defaultDisplayLabelFormatPural; }
|
||||
set { defaultDisplayLabelFormatPural = value; }
|
||||
}
|
||||
static private string defaultDisplayLabelFormatPural = "{0} ({1} items)";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Life and death
|
||||
|
||||
/// <summary>
|
||||
/// Create a clustering strategy
|
||||
/// </summary>
|
||||
public ClusteringStrategy() {
|
||||
this.DisplayLabelFormatSingular = DefaultDisplayLabelFormatSingular;
|
||||
this.DisplayLabelFormatPlural = DefaultDisplayLabelFormatPlural;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the column upon which this strategy is operating
|
||||
/// </summary>
|
||||
public OLVColumn Column {
|
||||
get { return column; }
|
||||
set { column = value; }
|
||||
}
|
||||
private OLVColumn column;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the format that will be used when the cluster
|
||||
/// contains only 1 item. The format string must accept two placeholders:
|
||||
/// - {0} is the cluster key converted to a string
|
||||
/// - {1} is the number of items in the cluster (always 1 in this case)
|
||||
/// </summary>
|
||||
/// <remarks>If this is not set, the value from
|
||||
/// ClusteringStrategy.DefaultDisplayLabelFormatSingular will be used</remarks>
|
||||
public string DisplayLabelFormatSingular {
|
||||
get { return displayLabelFormatSingular; }
|
||||
set { displayLabelFormatSingular = value; }
|
||||
}
|
||||
private string displayLabelFormatSingular;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the format that will be used when the cluster
|
||||
/// contains 0 or two or more items. The format string must accept two placeholders:
|
||||
/// - {0} is the cluster key converted to a string
|
||||
/// - {1} is the number of items in the cluster
|
||||
/// </summary>
|
||||
/// <remarks>If this is not set, the value from
|
||||
/// ClusteringStrategy.DefaultDisplayLabelFormatPlural will be used</remarks>
|
||||
public string DisplayLabelFormatPlural {
|
||||
get { return displayLabelFormatPural; }
|
||||
set { displayLabelFormatPural = value; }
|
||||
}
|
||||
private string displayLabelFormatPural;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICluster implementation
|
||||
|
||||
/// <summary>
|
||||
/// Get the cluster key by which the given model will be partitioned by this strategy
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
virtual public object GetClusterKey(object model) {
|
||||
return this.Column.GetValue(model);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a cluster to hold the given cluster key
|
||||
/// </summary>
|
||||
/// <param name="clusterKey"></param>
|
||||
/// <returns></returns>
|
||||
virtual public ICluster CreateCluster(object clusterKey) {
|
||||
return new Cluster(clusterKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display label that the given cluster should use
|
||||
/// </summary>
|
||||
/// <param name="cluster"></param>
|
||||
/// <returns></returns>
|
||||
virtual public string GetClusterDisplayLabel(ICluster cluster) {
|
||||
string s = this.Column.ValueToString(cluster.ClusterKey) ?? NULL_LABEL;
|
||||
if (String.IsNullOrEmpty(s))
|
||||
s = EMPTY_LABEL;
|
||||
return this.ApplyDisplayFormat(cluster, s);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a label that combines the string representation of the cluster
|
||||
/// key with a format string that holds an "X [N items in cluster]" type layout.
|
||||
/// </summary>
|
||||
/// <param name="cluster"></param>
|
||||
/// <param name="s"></param>
|
||||
/// <returns></returns>
|
||||
virtual protected string ApplyDisplayFormat(ICluster cluster, string s) {
|
||||
string format = (cluster.Count == 1) ? this.DisplayLabelFormatSingular : this.DisplayLabelFormatPlural;
|
||||
return String.IsNullOrEmpty(format) ? s : String.Format(format, s, cluster.Count);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* ClusteringStrategy - Implements a simple clustering strategy
|
||||
*
|
||||
* Author: Phillip Piper
|
||||
* Date: 1-April-2011 8:12am
|
||||
*
|
||||
* Change log:
|
||||
* 2011-04-01 JPP - First version
|
||||
*
|
||||
* Copyright (C) 2011-2012 Phillip Piper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BrightIdeasSoftware {
|
||||
|
||||
/// <summary>
|
||||
/// This class calculates clusters from the groups that the column uses.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This is the default strategy for all non-date, filterable columns.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This class does not strictly mimic the groups created by the given column.
|
||||
/// In particular, if the programmer changes the default grouping technique
|
||||
/// by listening for grouping events, this class will not mimic that behaviour.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class ClustersFromGroupsStrategy : ClusteringStrategy {
|
||||
|
||||
/// <summary>
|
||||
/// Get the cluster key by which the given model will be partitioned by this strategy
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
public override object GetClusterKey(object model) {
|
||||
return this.Column.GetGroupKey(model);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display label that the given cluster should use
|
||||
/// </summary>
|
||||
/// <param name="cluster"></param>
|
||||
/// <returns></returns>
|
||||
public override string GetClusterDisplayLabel(ICluster cluster) {
|
||||
string s = this.Column.ConvertGroupKeyToTitle(cluster.ClusterKey);
|
||||
if (String.IsNullOrEmpty(s))
|
||||
s = EMPTY_LABEL;
|
||||
return this.ApplyDisplayFormat(cluster, s);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue