diff options
Diffstat (limited to 'mcs/class/Compat.ICSharpCode.SharpZipLib')
45 files changed, 14973 insertions, 0 deletions
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ChangeLog b/mcs/class/Compat.ICSharpCode.SharpZipLib/ChangeLog new file mode 100644 index 00000000000..8e91e21a4c4 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ChangeLog @@ -0,0 +1,17 @@ +2004-11-25 Raja R Harinath <rharinath@novell.com> + + * Makefile (EXTRA_DISTFILES): Add SharpZipLib.pub. + +2004-06-21 Raja R Harinath <rharinath@novell.com> + + * Makefile (LIBRARY_SNK): Sign with SharpZipLib.key. The library + is delay-signed according to ICSharpCode.SharpZipLib/AssemblyInfo.cs. + +2004-06-09 Sebastien Pouliot <sebastien@ximian.com> + + * Makefile: Don't sign this assembly as it is fully signed during + compilation (we have the original private key). Thanks to Jackson. + +2004-05-28 Duncan Mak <duncan@ximian.com> + + * SharpZipLib.pub: Added public key. diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib.dll.sources b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib.dll.sources new file mode 100644 index 00000000000..98de302206b --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib.dll.sources @@ -0,0 +1,38 @@ +./ICSharpCode.SharpZipLib/BZip2/BZip2.cs +./ICSharpCode.SharpZipLib/BZip2/BZip2Constants.cs +./ICSharpCode.SharpZipLib/BZip2/BZip2InputStream.cs +./ICSharpCode.SharpZipLib/BZip2/BZip2OutputStream.cs +./ICSharpCode.SharpZipLib/Checksums/Adler32.cs +./ICSharpCode.SharpZipLib/Checksums/Crc32.cs +./ICSharpCode.SharpZipLib/Checksums/IChecksum.cs +./ICSharpCode.SharpZipLib/Checksums/StrangeCrc.cs +./ICSharpCode.SharpZipLib/GZip/GZipConstants.cs +./ICSharpCode.SharpZipLib/GZip/GZipInputStream.cs +./ICSharpCode.SharpZipLib/GZip/GZipOutputStream.cs +./ICSharpCode.SharpZipLib/Tar/InvalidHeaderException.cs +./ICSharpCode.SharpZipLib/Tar/TarArchive.cs +./ICSharpCode.SharpZipLib/Tar/TarBuffer.cs +./ICSharpCode.SharpZipLib/Tar/TarEntry.cs +./ICSharpCode.SharpZipLib/Tar/TarHeader.cs +./ICSharpCode.SharpZipLib/Tar/TarInputStream.cs +./ICSharpCode.SharpZipLib/Tar/TarOutputStream.cs +./ICSharpCode.SharpZipLib/Zip/Compression/Deflater.cs +./ICSharpCode.SharpZipLib/Zip/Compression/DeflaterConstants.cs +./ICSharpCode.SharpZipLib/Zip/Compression/DeflaterEngine.cs +./ICSharpCode.SharpZipLib/Zip/Compression/DeflaterHuffman.cs +./ICSharpCode.SharpZipLib/Zip/Compression/DeflaterPending.cs +./ICSharpCode.SharpZipLib/Zip/Compression/Inflater.cs +./ICSharpCode.SharpZipLib/Zip/Compression/InflaterDynHeader.cs +./ICSharpCode.SharpZipLib/Zip/Compression/InflaterHuffmanTree.cs +./ICSharpCode.SharpZipLib/Zip/Compression/PendingBuffer.cs +./ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs +./ICSharpCode.SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs +./ICSharpCode.SharpZipLib/Zip/Compression/Streams/OutputWindow.cs +./ICSharpCode.SharpZipLib/Zip/Compression/Streams/StreamManipulator.cs +./ICSharpCode.SharpZipLib/Zip/ZipConstants.cs +./ICSharpCode.SharpZipLib/Zip/ZipEntry.cs +./ICSharpCode.SharpZipLib/Zip/ZipFile.cs +./ICSharpCode.SharpZipLib/Zip/ZipInputStream.cs +./ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs +./ICSharpCode.SharpZipLib/AssemblyInfo.cs +./ICSharpCode.SharpZipLib/ZipException.cs diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/AssemblyInfo.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/AssemblyInfo.cs new file mode 100644 index 00000000000..a7be065d43d --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/AssemblyInfo.cs @@ -0,0 +1,58 @@ +// AssemblyInfo.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.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: CLSCompliant(true)]
+
+[assembly: AssemblyTitle("ICSharpCode.SharpZipLibrary")]
+[assembly: AssemblyDescription("free C# zlib implementation")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("#ZipLibrary")]
+[assembly: AssemblyCopyright("(c) Mike Krueger 2001-2004")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+#if NET_2_0 +[assembly: AssemblyVersion("2.6.0.0")]
+#else +// not worrying about the NET_1_0 profile for now. +[assembly: AssemblyVersion("0.6.0.0")]
+#endif +
+[assembly: AssemblyDelaySign(true)]
+[assembly: AssemblyKeyFile ("SharpZipLib.pub")]
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2.cs new file mode 100644 index 00000000000..fc24db04701 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2.cs @@ -0,0 +1,89 @@ +// BZip2.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.BZip2
+{
+
+ /// <summary>
+ /// Does all the compress and decompress pre-operation stuff.
+ /// Sets up the streams and file header characters.
+ /// Uses multiply overloaded methods to call for the compress/decompress.
+ /// </summary>
+ public sealed class BZip2
+ {
+ public static void Decompress(Stream instream, Stream outstream)
+ {
+ System.IO.Stream bos = outstream;
+ System.IO.Stream bis = instream;
+ BZip2InputStream bzis = new BZip2InputStream(bis);
+ int ch = bzis.ReadByte();
+ while (ch != -1) {
+ bos.WriteByte((byte)ch);
+ ch = bzis.ReadByte();
+ }
+ bos.Flush();
+ }
+
+ public static void Compress(Stream instream, Stream outstream, int blockSize)
+ {
+ System.IO.Stream bos = outstream;
+ System.IO.Stream bis = instream;
+ int ch = bis.ReadByte();
+ BZip2OutputStream bzos = new BZip2OutputStream(bos, blockSize);
+ while(ch != -1) {
+ bzos.WriteByte((byte)ch);
+ ch = bis.ReadByte();
+ }
+ bis.Close();
+ bzos.Close();
+ }
+ }
+}
+/* derived from a file which contained this license :
+ * Copyright (c) 1999-2001 Keiron Liddle, Aftex Software
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+*/
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2Constants.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2Constants.cs new file mode 100644 index 00000000000..a9db486bfa4 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2Constants.cs @@ -0,0 +1,156 @@ +// 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>
+ /// Base class for both the compress and decompress classes.
+ /// Holds common arrays, and static data.
+ /// </summary>
+ public sealed class BZip2Constants
+ {
+ public readonly static int[] rNums = {
+ 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
+ };
+
+ public readonly static int baseBlockSize = 100000;
+
+ public readonly static int MAX_ALPHA_SIZE = 258;
+ public readonly static int MAX_CODE_LEN = 23;
+
+ public readonly static int RUNA = 0;
+ public readonly static int RUNB = 1;
+
+ public readonly static int N_GROUPS = 6;
+ public readonly static int G_SIZE = 50;
+ public readonly static int N_ITERS = 4;
+
+ public readonly static int MAX_SELECTORS = (2 + (900000 / G_SIZE));
+
+ public readonly static int NUM_OVERSHOOT_BYTES = 20;
+ }
+}
+
+/* This file was derived from a file containing under 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
+ */
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2InputStream.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2InputStream.cs new file mode 100644 index 00000000000..454878d8a01 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2InputStream.cs @@ -0,0 +1,958 @@ +// BZip2InputStream.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 ICSharpCode.SharpZipLib.Checksums;
+
+namespace ICSharpCode.SharpZipLib.BZip2
+{
+
+ /// <summary>
+ /// An input stream that decompresses from the BZip2 format (without the file
+ /// header chars) to be read as any other stream.
+ /// </summary>
+ public class BZip2InputStream : Stream
+ {
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanRead {
+ get {
+ return baseStream.CanRead;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanSeek {
+ get {
+ return baseStream.CanSeek;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanWrite {
+ get {
+ return baseStream.CanWrite;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Length {
+ get {
+ return baseStream.Length;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Position {
+ get {
+ return baseStream.Position;
+ }
+ set {
+ baseStream.Position = value;
+ }
+ }
+
+ /// <summary>
+ /// Flushes the baseInputStream
+ /// </summary>
+ public override void Flush()
+ {
+ if (baseStream != null) {
+ baseStream.Flush();
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ return baseStream.Seek(offset, origin);
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override void SetLength(long val)
+ {
+ baseStream.SetLength(val);
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override void Write(byte[] array, int offset, int count)
+ {
+ baseStream.Write(array, offset, count);
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override void WriteByte(byte val)
+ {
+ baseStream.WriteByte(val);
+ }
+
+ public override int Read(byte[] b, int off, int len)
+ {
+ for (int i = 0; i < len; ++i) {
+ int rb = ReadByte();
+ if (rb == -1) {
+ return i;
+ }
+ b[off + i] = (byte)rb;
+ }
+ return len;
+ }
+
+ /// <summary>
+ /// Closes the input stream
+ /// </summary>
+ public override void Close()
+ {
+ if (baseStream != null) {
+ baseStream.Close();
+ }
+ }
+
+ static void Cadvise()
+ {
+ //Console.WriteLine("CRC Error");
+ //throw new CCoruptionError();
+ }
+
+ static void BadBGLengths()
+ {
+ //Console.WriteLine("bad BG lengths");
+ }
+
+ static void BitStreamEOF()
+ {
+ //Console.WriteLine("bit stream eof");
+ }
+
+ static void CompressedStreamEOF()
+ {
+ //Console.WriteLine("compressed stream eof");
+ }
+
+ void MakeMaps()
+ {
+ nInUse = 0;
+ for (int i = 0; i < 256; ++i) {
+ if (inUse[i]) {
+ seqToUnseq[nInUse] = (byte)i;
+ unseqToSeq[i] = (byte)nInUse;
+ nInUse++;
+ }
+ }
+ }
+
+ /*--
+ index of the last char in the block, so
+ the block size == last + 1.
+ --*/
+ int last;
+
+ /*--
+ index in zptr[] of original string after sorting.
+ --*/
+ int origPtr;
+
+ /*--
+ always: in the range 0 .. 9.
+ The current block size is 100000 * this number.
+ --*/
+ int blockSize100k;
+
+ bool blockRandomised;
+
+ // private int bytesIn;
+ // private int bytesOut;
+ int bsBuff;
+ int bsLive;
+ IChecksum mCrc = new StrangeCRC();
+
+ bool[] inUse = new bool[256];
+ int nInUse;
+
+ byte[] seqToUnseq = new byte[256];
+ byte[] unseqToSeq = new byte[256];
+
+ byte[] selector = new byte[BZip2Constants.MAX_SELECTORS];
+ byte[] selectorMtf = new byte[BZip2Constants.MAX_SELECTORS];
+
+ int[] tt;
+ byte[] ll8;
+
+ /*--
+ freq table collected to save a pass over the data
+ during decompression.
+ --*/
+ int[] unzftab = new int[256];
+
+ int[][] limit = new int[BZip2Constants.N_GROUPS][];
+ int[][] baseArray = new int[BZip2Constants.N_GROUPS][];
+ int[][] perm = new int[BZip2Constants.N_GROUPS][];
+ int[] minLens = new int[BZip2Constants.N_GROUPS];
+
+ Stream baseStream;
+ bool streamEnd = false;
+
+ int currentChar = -1;
+
+ const int START_BLOCK_STATE = 1;
+ const int RAND_PART_A_STATE = 2;
+ const int RAND_PART_B_STATE = 3;
+ const int RAND_PART_C_STATE = 4;
+ const int NO_RAND_PART_A_STATE = 5;
+ const int NO_RAND_PART_B_STATE = 6;
+ const int NO_RAND_PART_C_STATE = 7;
+
+ int currentState = START_BLOCK_STATE;
+
+ int storedBlockCRC, storedCombinedCRC;
+ int computedBlockCRC;
+ uint computedCombinedCRC;
+
+ int count, chPrev, ch2;
+ int tPos;
+ int rNToGo = 0;
+ int rTPos = 0;
+ int i2, j2;
+ byte z;
+
+ public BZip2InputStream(Stream zStream)
+ {
+ // init arrays
+ for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {
+ limit[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];
+ baseArray[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];
+ perm[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];
+ }
+
+ ll8 = null;
+ tt = null;
+ BsSetStream(zStream);
+ Initialize();
+ InitBlock();
+ SetupBlock();
+ }
+
+ public override int ReadByte()
+ {
+ if (streamEnd) {
+ return -1; // ok
+ }
+
+ int retChar = currentChar;
+ switch (currentState) {
+ case RAND_PART_B_STATE:
+ SetupRandPartB();
+ break;
+ case RAND_PART_C_STATE:
+ SetupRandPartC();
+ break;
+ case NO_RAND_PART_B_STATE:
+ SetupNoRandPartB();
+ break;
+ case NO_RAND_PART_C_STATE:
+ SetupNoRandPartC();
+ break;
+ case START_BLOCK_STATE:
+ case NO_RAND_PART_A_STATE:
+ case RAND_PART_A_STATE:
+ break;
+ default:
+ break;
+ }
+ return retChar;
+ }
+
+ void Initialize()
+ {
+ // -jr- 18-Nov-2003 magic1 and 2 added here so stream is fully capable on its own
+ char magic1 = BsGetUChar();
+ char magic2 = BsGetUChar();
+
+ char magic3 = BsGetUChar();
+ char magic4 = BsGetUChar();
+
+ if (magic1 != 'B' || magic2 != 'Z' || magic3 != 'h' || magic4 < '1' || magic4 > '9') {
+ streamEnd = true;
+ return;
+ }
+
+ SetDecompressStructureSizes(magic4 - '0');
+ computedCombinedCRC = 0;
+ }
+
+ void InitBlock()
+ {
+ char magic1 = BsGetUChar();
+ char magic2 = BsGetUChar();
+ char magic3 = BsGetUChar();
+ char magic4 = BsGetUChar();
+ char magic5 = BsGetUChar();
+ char magic6 = BsGetUChar();
+
+ if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45 && magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) {
+ Complete();
+ return;
+ }
+
+ if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) {
+ BadBlockHeader();
+ streamEnd = true;
+ return;
+ }
+
+ storedBlockCRC = BsGetInt32();
+
+ blockRandomised = (BsR(1) == 1);
+
+ // currBlockNo++;
+ GetAndMoveToFrontDecode();
+
+ mCrc.Reset();
+ currentState = START_BLOCK_STATE;
+ }
+
+ void EndBlock()
+ {
+ computedBlockCRC = (int)mCrc.Value;
+
+ /*-- A bad CRC is considered a fatal error. --*/
+ if (storedBlockCRC != computedBlockCRC) {
+ CrcError();
+ }
+
+ // 1528150659
+ computedCombinedCRC = ((computedCombinedCRC << 1) & 0xFFFFFFFF) | (computedCombinedCRC >> 31);
+ computedCombinedCRC = computedCombinedCRC ^ (uint)computedBlockCRC;
+ }
+
+ void Complete()
+ {
+ storedCombinedCRC = BsGetInt32();
+ if (storedCombinedCRC != (int)computedCombinedCRC) {
+ CrcError();
+ }
+
+ streamEnd = true;
+ }
+
+ static void BlockOverrun()
+ {
+ //Console.WriteLine("Block overrun");
+ }
+
+ static void BadBlockHeader()
+ {
+ //Console.WriteLine("Bad block header");
+ }
+
+ static void CrcError()
+ {
+ //Console.WriteLine("crc error");
+ }
+
+
+ void BsSetStream(Stream f)
+ {
+ baseStream = f;
+ bsLive = 0;
+ bsBuff = 0;
+ }
+
+ void FillBuffer()
+ {
+ int thech = 0;
+
+ try {
+ thech = baseStream.ReadByte();
+ } catch (Exception) {
+ CompressedStreamEOF();
+ }
+
+ if (thech == -1) {
+ CompressedStreamEOF();
+ }
+
+ bsBuff = (bsBuff << 8) | (thech & 0xFF);
+ bsLive += 8;
+ }
+
+ int BsR(int n)
+ {
+ while (bsLive < n) {
+ FillBuffer();
+ }
+
+ int v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1);
+ bsLive -= n;
+ return v;
+ }
+
+ char BsGetUChar()
+ {
+ return (char)BsR(8);
+ }
+
+ int BsGetint()
+ {
+ int u = 0;
+ u = (u << 8) | BsR(8);
+ u = (u << 8) | BsR(8);
+ u = (u << 8) | BsR(8);
+ u = (u << 8) | BsR(8);
+ return u;
+ }
+
+ int BsGetIntVS(int numBits)
+ {
+ return (int)BsR(numBits);
+ }
+
+ int BsGetInt32()
+ {
+ return (int)BsGetint();
+ }
+
+ void HbCreateDecodeTables(int[] limit, int[] baseArray, int[] perm, char[] length, int minLen, int maxLen, int alphaSize)
+ {
+ int pp = 0;
+
+ for (int i = minLen; i <= maxLen; ++i) {
+ for (int j = 0; j < alphaSize; ++j) {
+ if (length[j] == i) {
+ perm[pp] = j;
+ ++pp;
+ }
+ }
+ }
+
+ for (int i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) {
+ baseArray[i] = 0;
+ }
+
+ for (int i = 0; i < alphaSize; i++) {
+ ++baseArray[length[i] + 1];
+ }
+
+ for (int i = 1; i < BZip2Constants.MAX_CODE_LEN; i++) {
+ baseArray[i] += baseArray[i - 1];
+ }
+
+ for (int i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) {
+ limit[i] = 0;
+ }
+
+ int vec = 0;
+
+ for (int i = minLen; i <= maxLen; i++) {
+ vec += (baseArray[i + 1] - baseArray[i]);
+ limit[i] = vec - 1;
+ vec <<= 1;
+ }
+
+ for (int i = minLen + 1; i <= maxLen; i++) {
+ baseArray[i] = ((limit[i - 1] + 1) << 1) - baseArray[i];
+ }
+ }
+
+ void RecvDecodingTables()
+ {
+ char[][] len = new char[BZip2Constants.N_GROUPS][];
+ for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {
+ len[i] = new char[BZip2Constants.MAX_ALPHA_SIZE];
+ }
+
+ bool[] inUse16 = new bool[16];
+
+ /*--- Receive the mapping table ---*/
+ for (int i = 0; i < 16; i++) {
+ inUse16[i] = (BsR(1) == 1);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ if (inUse16[i]) {
+ for (int j = 0; j < 16; j++) {
+ inUse[i * 16 + j] = (BsR(1) == 1);
+ }
+ } else {
+ for (int j = 0; j < 16; j++) {
+ inUse[i * 16 + j] = false;
+ }
+ }
+ }
+
+ MakeMaps();
+ int alphaSize = nInUse + 2;
+
+ /*--- Now the selectors ---*/
+ int nGroups = BsR(3);
+ int nSelectors = BsR(15);
+
+ for (int i = 0; i < nSelectors; i++) {
+ int j = 0;
+ while (BsR(1) == 1) {
+ j++;
+ }
+ selectorMtf[i] = (byte)j;
+ }
+
+ /*--- Undo the MTF values for the selectors. ---*/
+ byte[] pos = new byte[BZip2Constants.N_GROUPS];
+ for (int v = 0; v < nGroups; v++) {
+ pos[v] = (byte)v;
+ }
+
+ for (int i = 0; i < nSelectors; i++) {
+ int v = selectorMtf[i];
+ byte tmp = pos[v];
+ while (v > 0) {
+ pos[v] = pos[v - 1];
+ v--;
+ }
+ pos[0] = tmp;
+ selector[i] = tmp;
+ }
+
+ /*--- Now the coding tables ---*/
+ for (int t = 0; t < nGroups; t++) {
+ int curr = BsR(5);
+ for (int i = 0; i < alphaSize; i++) {
+ while (BsR(1) == 1) {
+ if (BsR(1) == 0) {
+ curr++;
+ } else {
+ curr--;
+ }
+ }
+ len[t][i] = (char)curr;
+ }
+ }
+
+ /*--- Create the Huffman decoding tables ---*/
+ for (int t = 0; t < nGroups; t++) {
+ int minLen = 32;
+ int maxLen = 0;
+ for (int i = 0; i < alphaSize; i++) {
+ maxLen = Math.Max(maxLen, len[t][i]);
+ minLen = Math.Min(minLen, len[t][i]);
+ }
+ HbCreateDecodeTables(limit[t], baseArray[t], perm[t], len[t], minLen, maxLen, alphaSize);
+ minLens[t] = minLen;
+ }
+ }
+
+ void GetAndMoveToFrontDecode()
+ {
+ byte[] yy = new byte[256];
+ int nextSym;
+
+ int limitLast = BZip2Constants.baseBlockSize * blockSize100k;
+ origPtr = BsGetIntVS(24);
+
+ RecvDecodingTables();
+ int EOB = nInUse+1;
+ int groupNo = -1;
+ int groupPos = 0;
+
+ /*--
+ Setting up the unzftab entries here is not strictly
+ necessary, but it does save having to do it later
+ in a separate pass, and so saves a block's worth of
+ cache misses.
+ --*/
+ for (int i = 0; i <= 255; i++) {
+ unzftab[i] = 0;
+ }
+
+ for (int i = 0; i <= 255; i++) {
+ yy[i] = (byte)i;
+ }
+
+ last = -1;
+
+ if (groupPos == 0) {
+ groupNo++;
+ groupPos = BZip2Constants.G_SIZE;
+ }
+
+ groupPos--;
+ int zt = selector[groupNo];
+ int zn = minLens[zt];
+ int zvec = BsR(zn);
+ int zj;
+
+ while (zvec > limit[zt][zn]) {
+ if (zn > 20) { // the longest code
+ throw new ApplicationException("Bzip data error"); // -jr- 17-Dec-2003 from bzip 1.02 why 20???
+ }
+ zn++;
+ while (bsLive < 1) {
+ FillBuffer();
+ }
+ zj = (bsBuff >> (bsLive-1)) & 1;
+ bsLive--;
+ zvec = (zvec << 1) | zj;
+ }
+ if (zvec - baseArray[zt][zn] < 0 || zvec - baseArray[zt][zn] >= BZip2Constants.MAX_ALPHA_SIZE) {
+ throw new ApplicationException("Bzip data error"); // -jr- 17-Dec-2003 from bzip 1.02
+ }
+ nextSym = perm[zt][zvec - baseArray[zt][zn]];
+
+ while (true) {
+ if (nextSym == EOB) {
+ break;
+ }
+
+ if (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB) {
+ int s = -1;
+ int n = 1;
+ do {
+ if (nextSym == BZip2Constants.RUNA) {
+ s += (0 + 1) * n;
+ } else if (nextSym == BZip2Constants.RUNB) {
+ s += (1 + 1) * n;
+ }
+
+ n <<= 1;
+
+ if (groupPos == 0) {
+ groupNo++;
+ groupPos = BZip2Constants.G_SIZE;
+ }
+
+ groupPos--;
+
+ zt = selector[groupNo];
+ zn = minLens[zt];
+ zvec = BsR(zn);
+
+ while (zvec > limit[zt][zn]) {
+ zn++;
+ while (bsLive < 1) {
+ FillBuffer();
+ }
+ zj = (bsBuff >> (bsLive - 1)) & 1;
+ bsLive--;
+ zvec = (zvec << 1) | zj;
+ }
+ nextSym = perm[zt][zvec - baseArray[zt][zn]];
+ } while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB);
+
+ s++;
+ byte ch = seqToUnseq[yy[0]];
+ unzftab[ch] += s;
+
+ while (s > 0) {
+ last++;
+ ll8[last] = ch;
+ s--;
+ }
+
+ if (last >= limitLast) {
+ BlockOverrun();
+ }
+ continue;
+ } else {
+ last++;
+ if (last >= limitLast) {
+ BlockOverrun();
+ }
+
+ byte tmp = yy[nextSym - 1];
+ unzftab[seqToUnseq[tmp]]++;
+ ll8[last] = seqToUnseq[tmp];
+
+ for (int j = nextSym-1; j > 0; --j) {
+ yy[j] = yy[j - 1];
+ }
+ yy[0] = tmp;
+
+ if (groupPos == 0) {
+ groupNo++;
+ groupPos = BZip2Constants.G_SIZE;
+ }
+
+ groupPos--;
+ zt = selector[groupNo];
+ zn = minLens[zt];
+ zvec = BsR(zn);
+ while (zvec > limit[zt][zn]) {
+ zn++;
+ while (bsLive < 1) {
+ FillBuffer();
+ }
+ zj = (bsBuff >> (bsLive-1)) & 1;
+ bsLive--;
+ zvec = (zvec << 1) | zj;
+ }
+ nextSym = perm[zt][zvec - baseArray[zt][zn]];
+ continue;
+ }
+ }
+ }
+
+ void SetupBlock()
+ {
+ int[] cftab = new int[257];
+
+ cftab[0] = 0;
+ Array.Copy(unzftab, 0, cftab, 1, 256);
+
+ for (int i = 1; i <= 256; i++) {
+ cftab[i] += cftab[i - 1];
+ }
+
+ for (int i = 0; i <= last; i++) {
+ byte ch = ll8[i];
+ tt[cftab[ch]] = i;
+ cftab[ch]++;
+ }
+
+ cftab = null;
+
+ tPos = tt[origPtr];
+
+ count = 0;
+ i2 = 0;
+ ch2 = 256; /*-- not a char and not EOF --*/
+
+ if (blockRandomised) {
+ rNToGo = 0;
+ rTPos = 0;
+ SetupRandPartA();
+ } else {
+ SetupNoRandPartA();
+ }
+ }
+
+ void SetupRandPartA()
+ {
+ if (i2 <= last) {
+ chPrev = ch2;
+ ch2 = ll8[tPos];
+ tPos = tt[tPos];
+ if (rNToGo == 0) {
+ rNToGo = BZip2Constants.rNums[rTPos];
+ rTPos++;
+ if(rTPos == 512) {
+ rTPos = 0;
+ }
+ }
+ rNToGo--;
+ ch2 ^= (int)((rNToGo == 1) ? 1 : 0);
+ i2++;
+
+ currentChar = ch2;
+ currentState = RAND_PART_B_STATE;
+ mCrc.Update(ch2);
+ } else {
+ EndBlock();
+ InitBlock();
+ SetupBlock();
+ }
+ }
+
+ void SetupNoRandPartA()
+ {
+ if (i2 <= last) {
+ chPrev = ch2;
+ ch2 = ll8[tPos];
+ tPos = tt[tPos];
+ i2++;
+
+ currentChar = ch2;
+ currentState = NO_RAND_PART_B_STATE;
+ mCrc.Update(ch2);
+ } else {
+ EndBlock();
+ InitBlock();
+ SetupBlock();
+ }
+ }
+
+ void SetupRandPartB()
+ {
+ if (ch2 != chPrev) {
+ currentState = RAND_PART_A_STATE;
+ count = 1;
+ SetupRandPartA();
+ } else {
+ count++;
+ if (count >= 4) {
+ z = ll8[tPos];
+ tPos = tt[tPos];
+ if (rNToGo == 0) {
+ rNToGo = BZip2Constants.rNums[rTPos];
+ rTPos++;
+ if (rTPos == 512) {
+ rTPos = 0;
+ }
+ }
+ rNToGo--;
+ z ^= (byte)((rNToGo == 1) ? 1 : 0);
+ j2 = 0;
+ currentState = RAND_PART_C_STATE;
+ SetupRandPartC();
+ } else {
+ currentState = RAND_PART_A_STATE;
+ SetupRandPartA();
+ }
+ }
+ }
+
+ void SetupRandPartC()
+ {
+ if (j2 < (int)z) {
+ currentChar = ch2;
+ mCrc.Update(ch2);
+ j2++;
+ } else {
+ currentState = RAND_PART_A_STATE;
+ i2++;
+ count = 0;
+ SetupRandPartA();
+ }
+ }
+
+ void SetupNoRandPartB()
+ {
+ if (ch2 != chPrev) {
+ currentState = NO_RAND_PART_A_STATE;
+ count = 1;
+ SetupNoRandPartA();
+ } else {
+ count++;
+ if (count >= 4) {
+ z = ll8[tPos];
+ tPos = tt[tPos];
+ currentState = NO_RAND_PART_C_STATE;
+ j2 = 0;
+ SetupNoRandPartC();
+ } else {
+ currentState = NO_RAND_PART_A_STATE;
+ SetupNoRandPartA();
+ }
+ }
+ }
+
+ void SetupNoRandPartC()
+ {
+ if (j2 < (int)z) {
+ currentChar = ch2;
+ mCrc.Update(ch2);
+ j2++;
+ } else {
+ currentState = NO_RAND_PART_A_STATE;
+ i2++;
+ count = 0;
+ SetupNoRandPartA();
+ }
+ }
+
+ void SetDecompressStructureSizes(int newSize100k)
+ {
+ if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k && blockSize100k <= 9)) {
+ throw new ApplicationException("Invalid block size");
+ }
+
+ blockSize100k = newSize100k;
+
+ if (newSize100k == 0) {
+ return;
+ }
+
+ int n = BZip2Constants.baseBlockSize * newSize100k;
+ ll8 = new byte[n];
+ tt = new int[n];
+ }
+ }
+}
+/* This file was derived from a file containing under 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
+ */
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2OutputStream.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2OutputStream.cs new file mode 100644 index 00000000000..4f3d91372cc --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2OutputStream.cs @@ -0,0 +1,1776 @@ +// BZip2OutputStream.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 ICSharpCode.SharpZipLib.Checksums;
+
+namespace ICSharpCode.SharpZipLib.BZip2
+{
+
+ /// <summary>
+ /// An output stream that compresses into the BZip2 format (without the file
+ /// header chars) into another stream.
+ /// TODO: Update to BZip2 1.0.1, 1.0.2
+ /// </summary>
+ public class BZip2OutputStream : Stream
+ {
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanRead {
+ get {
+ return baseStream.CanRead;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanSeek {
+ get {
+ return baseStream.CanSeek;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanWrite {
+ get {
+ return baseStream.CanWrite;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Length {
+ get {
+ return baseStream.Length;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Position {
+ get {
+ return baseStream.Position;
+ }
+ set {
+ baseStream.Position = value;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ return baseStream.Seek(offset, origin);
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override void SetLength(long val)
+ {
+ baseStream.SetLength(val);
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override int ReadByte()
+ {
+ return baseStream.ReadByte();
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override int Read(byte[] b, int off, int len)
+ {
+ return baseStream.Read(b, off, len);
+ }
+
+ public override void Write(byte[] buf, int off, int len)
+ {
+ for (int i = 0; i < len; ++i) {
+ WriteByte(buf[off + i]);
+ }
+ }
+
+ readonly static int SETMASK = (1 << 21);
+ readonly static int CLEARMASK = (~SETMASK);
+ readonly static int GREATER_ICOST = 15;
+ readonly static int LESSER_ICOST = 0;
+ readonly static int SMALL_THRESH = 20;
+ readonly static int DEPTH_THRESH = 10;
+
+ /*--
+ If you are ever unlucky/improbable enough
+ to get a stack overflow whilst sorting,
+ increase the following constant and try
+ again. In practice I have never seen the
+ stack go above 27 elems, so the following
+ limit seems very generous.
+ --*/
+ readonly static int QSORT_STACK_SIZE = 1000;
+
+ static void Panic()
+ {
+ //Console.WriteLine("panic");
+ }
+
+ void MakeMaps()
+ {
+ int i;
+ nInUse = 0;
+ for (i = 0; i < 256; i++) {
+ if (inUse[i]) {
+ seqToUnseq[nInUse] = (char)i;
+ unseqToSeq[i] = (char)nInUse;
+ nInUse++;
+ }
+ }
+ }
+
+ static void HbMakeCodeLengths(char[] len, int[] freq, int alphaSize, int maxLen)
+ {
+ /*--
+ Nodes and heap entries run from 1. Entry 0
+ for both the heap and nodes is a sentinel.
+ --*/
+ int nNodes, nHeap, n1, n2, j, k;
+ bool tooLong;
+
+ int[] heap = new int[BZip2Constants.MAX_ALPHA_SIZE + 2];
+ int[] weight = new int[BZip2Constants.MAX_ALPHA_SIZE * 2];
+ int[] parent = new int[BZip2Constants.MAX_ALPHA_SIZE * 2];
+
+ for (int i = 0; i < alphaSize; ++i) {
+ weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+ }
+
+ while (true) {
+ nNodes = alphaSize;
+ nHeap = 0;
+
+ heap[0] = 0;
+ weight[0] = 0;
+ parent[0] = -2;
+
+ for (int i = 1; i <= alphaSize; ++i) {
+ parent[i] = -1;
+ nHeap++;
+ heap[nHeap] = i;
+ int zz = nHeap;
+ int tmp = heap[zz];
+ while (weight[tmp] < weight[heap[zz >> 1]]) {
+ heap[zz] = heap[zz >> 1];
+ zz >>= 1;
+ }
+ heap[zz] = tmp;
+ }
+ if (!(nHeap < (BZip2Constants.MAX_ALPHA_SIZE+2))) {
+ Panic();
+ }
+
+ while (nHeap > 1) {
+ n1 = heap[1];
+ heap[1] = heap[nHeap];
+ nHeap--;
+ int zz = 1;
+ int yy = 0;
+ int tmp = heap[zz];
+ while (true) {
+ yy = zz << 1;
+ if (yy > nHeap) {
+ break;
+ }
+ if (yy < nHeap && weight[heap[yy+1]] < weight[heap[yy]]) {
+ yy++;
+ }
+ if (weight[tmp] < weight[heap[yy]]) {
+ break;
+ }
+
+ heap[zz] = heap[yy];
+ zz = yy;
+ }
+ heap[zz] = tmp;
+ n2 = heap[1];
+ heap[1] = heap[nHeap];
+ nHeap--;
+
+ zz = 1;
+ yy = 0;
+ tmp = heap[zz];
+ while (true) {
+ yy = zz << 1;
+ if (yy > nHeap) {
+ break;
+ }
+ if (yy < nHeap && weight[heap[yy+1]] < weight[heap[yy]]) {
+ yy++;
+ }
+ if (weight[tmp] < weight[heap[yy]]) {
+ break;
+ }
+ heap[zz] = heap[yy];
+ zz = yy;
+ }
+ heap[zz] = tmp;
+ nNodes++;
+ parent[n1] = parent[n2] = nNodes;
+
+ weight[nNodes] = (int)((weight[n1] & 0xffffff00) + (weight[n2] & 0xffffff00)) |
+ (int)(1 + (((weight[n1] & 0x000000ff) > (weight[n2] & 0x000000ff)) ? (weight[n1] & 0x000000ff) : (weight[n2] & 0x000000ff)));
+
+ parent[nNodes] = -1;
+ nHeap++;
+ heap[nHeap] = nNodes;
+
+ zz = nHeap;
+ tmp = heap[zz];
+ while (weight[tmp] < weight[heap[zz >> 1]]) {
+ heap[zz] = heap[zz >> 1];
+ zz >>= 1;
+ }
+ heap[zz] = tmp;
+ }
+ if (!(nNodes < (BZip2Constants.MAX_ALPHA_SIZE * 2))) {
+ Panic();
+ }
+
+ tooLong = false;
+ for (int i = 1; i <= alphaSize; ++i) {
+ j = 0;
+ k = i;
+ while (parent[k] >= 0) {
+ k = parent[k];
+ j++;
+ }
+ len[i - 1] = (char)j;
+ if (j > maxLen) {
+ tooLong = true;
+ }
+ }
+
+ if (!tooLong) {
+ break;
+ }
+
+ for (int i = 1; i < alphaSize; ++i) {
+ j = weight[i] >> 8;
+ j = 1 + (j / 2);
+ weight[i] = j << 8;
+ }
+ }
+ }
+
+ /*--
+ index of the last char in the block, so
+ the block size == last + 1.
+ --*/
+ int last;
+
+ /*--
+ index in zptr[] of original string after sorting.
+ --*/
+ int origPtr;
+
+ /*--
+ always: in the range 0 .. 9.
+ The current block size is 100000 * this number.
+ --*/
+ int blockSize100k;
+
+ bool blockRandomised;
+
+ // int bytesIn;
+ int bytesOut;
+ int bsBuff;
+ int bsLive;
+ IChecksum mCrc = new StrangeCRC();
+
+ bool[] inUse = new bool[256];
+ int nInUse;
+
+ char[] seqToUnseq = new char[256];
+ char[] unseqToSeq = new char[256];
+
+ char[] selector = new char[BZip2Constants.MAX_SELECTORS];
+ char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS];
+
+ byte[] block;
+ int[] quadrant;
+ int[] zptr;
+ short[] szptr;
+ int[] ftab;
+
+ int nMTF;
+
+ int[] mtfFreq = new int[BZip2Constants.MAX_ALPHA_SIZE];
+
+ /*
+ * Used when sorting. If too many long comparisons
+ * happen, we stop sorting, randomise the block
+ * slightly, and try again.
+ */
+ int workFactor;
+ int workDone;
+ int workLimit;
+ bool firstAttempt;
+ int nBlocksRandomised;
+
+ int currentChar = -1;
+ int runLength = 0;
+
+ public BZip2OutputStream(Stream inStream) : this(inStream, 9)
+ {
+ }
+
+ public BZip2OutputStream(Stream inStream, int inBlockSize)
+ {
+ block = null;
+ quadrant = null;
+ zptr = null;
+ ftab = null;
+
+ BsSetStream(inStream);
+
+ workFactor = 50;
+ if(inBlockSize > 9) {
+ inBlockSize = 9;
+ }
+ if(inBlockSize < 1) {
+ inBlockSize = 1;
+ }
+ blockSize100k = inBlockSize;
+ AllocateCompressStructures();
+ Initialize();
+ InitBlock();
+ }
+
+ public override void WriteByte(byte bv)
+ {
+ int b = (256 + bv) % 256;
+ if (currentChar != -1) {
+ if (currentChar == b) {
+ runLength++;
+ if (runLength > 254) {
+ WriteRun();
+ currentChar = -1;
+ runLength = 0;
+ }
+ } else {
+ WriteRun();
+ runLength = 1;
+ currentChar = b;
+ }
+ } else {
+ currentChar = b;
+ runLength++;
+ }
+ }
+
+ void WriteRun()
+ {
+ if (last < allowableBlockSize) {
+ inUse[currentChar] = true;
+ for (int i = 0; i < runLength; i++) {
+ mCrc.Update(currentChar);
+ }
+
+ switch (runLength) {
+ case 1:
+ last++;
+ block[last + 1] = (byte)currentChar;
+ break;
+ case 2:
+ last++;
+ block[last + 1] = (byte)currentChar;
+ last++;
+ block[last + 1] = (byte)currentChar;
+ break;
+ case 3:
+ last++;
+ block[last + 1] = (byte)currentChar;
+ last++;
+ block[last + 1] = (byte)currentChar;
+ last++;
+ block[last + 1] = (byte)currentChar;
+ break;
+ default:
+ inUse[runLength - 4] = true;
+ last++;
+ block[last + 1] = (byte)currentChar;
+ last++;
+ block[last + 1] = (byte)currentChar;
+ last++;
+ block[last + 1] = (byte)currentChar;
+ last++;
+ block[last + 1] = (byte)currentChar;
+ last++;
+ block[last + 1] = (byte)(runLength - 4);
+ break;
+ }
+ } else {
+ EndBlock();
+ InitBlock();
+ WriteRun();
+ }
+ }
+
+ bool closed = false;
+
+ public void Finalize()
+ {
+ Close();
+ }
+
+ public override void Close()
+ {
+ if (closed) {
+ return;
+ }
+
+ if (runLength > 0) {
+ WriteRun();
+ }
+
+ currentChar = -1;
+ EndBlock();
+ EndCompression();
+ closed = true;
+ // super.close();
+ Flush();
+ baseStream.Close();
+ }
+
+ public override void Flush()
+ {
+ // super.flush();
+ baseStream.Flush();
+ }
+
+ uint blockCRC, combinedCRC;
+
+ void Initialize()
+ {
+ // bytesIn = 0;
+ bytesOut = 0;
+ nBlocksRandomised = 0;
+
+ /*--- Write `magic' bytes h indicating file-format == huffmanised,
+ followed by a digit indicating blockSize100k.
+ ---*/
+ BsPutUChar('B'); // -jr- 18-Nov-2003 added to match BZ2 1.02 header already in BZip class but that sux a lot
+ BsPutUChar('Z');
+
+ BsPutUChar('h');
+ BsPutUChar('0' + blockSize100k);
+
+ combinedCRC = 0;
+ }
+
+ int allowableBlockSize;
+
+ void InitBlock()
+ {
+ // blockNo++;
+ mCrc.Reset();
+ last = -1;
+ // ch = 0;
+
+ for (int i = 0; i < 256; i++) {
+ inUse[i] = false;
+ }
+
+ /*--- 20 is just a paranoia constant ---*/
+ allowableBlockSize = BZip2Constants.baseBlockSize * blockSize100k - 20;
+ }
+
+ void EndBlock()
+ {
+ if (last < 0) { //-jr- dont do anything for empty files, (makes empty files compatible with original Bzip)
+ return;
+ }
+
+ blockCRC = (uint)mCrc.Value;
+ combinedCRC = (combinedCRC << 1) | (combinedCRC >> 31);
+ combinedCRC ^= blockCRC;
+
+ /*-- sort the block and establish posn of original string --*/
+ DoReversibleTransformation();
+
+ /*--
+ A 6-byte block header, the value chosen arbitrarily
+ as 0x314159265359 :-). A 32 bit value does not really
+ give a strong enough guarantee that the value will not
+ appear by chance in the compressed datastream. Worst-case
+ probability of this event, for a 900k block, is about
+ 2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits.
+ For a compressed file of size 100Gb -- about 100000 blocks --
+ only a 48-bit marker will do. NB: normal compression/
+ decompression do *not* rely on these statistical properties.
+ They are only important when trying to recover blocks from
+ damaged files.
+ --*/
+ BsPutUChar(0x31);
+ BsPutUChar(0x41);
+ BsPutUChar(0x59);
+ BsPutUChar(0x26);
+ BsPutUChar(0x53);
+ BsPutUChar(0x59);
+
+ /*-- Now the block's CRC, so it is in a known place. --*/
+ BsPutint((int)blockCRC);
+
+ /*-- Now a single bit indicating randomisation. --*/
+ if (blockRandomised) {
+ BsW(1,1);
+ nBlocksRandomised++;
+ } else {
+ BsW(1,0);
+ }
+
+ /*-- Finally, block's contents proper. --*/
+ MoveToFrontCodeAndSend();
+ }
+
+ void EndCompression()
+ {
+ /*--
+ Now another magic 48-bit number, 0x177245385090, to
+ indicate the end of the last block. (sqrt(pi), if
+ you want to know. I did want to use e, but it contains
+ too much repetition -- 27 18 28 18 28 46 -- for me
+ to feel statistically comfortable. Call me paranoid.)
+ --*/
+ BsPutUChar(0x17);
+ BsPutUChar(0x72);
+ BsPutUChar(0x45);
+ BsPutUChar(0x38);
+ BsPutUChar(0x50);
+ BsPutUChar(0x90);
+
+ BsPutint((int)combinedCRC);
+
+ BsFinishedWithStream();
+ }
+
+ void HbAssignCodes (int[] code, char[] length, int minLen, int maxLen, int alphaSize)
+ {
+ int vec = 0;
+ for (int n = minLen; n <= maxLen; ++n) {
+ for (int i = 0; i < alphaSize; ++i) {
+ if (length[i] == n) {
+ code[i] = vec;
+ ++vec;
+ }
+ }
+ vec <<= 1;
+ }
+ }
+
+ void BsSetStream(Stream f)
+ {
+ baseStream = f;
+ bsLive = 0;
+ bsBuff = 0;
+ bytesOut = 0;
+ }
+
+ void BsFinishedWithStream()
+ {
+ while (bsLive > 0)
+ {
+ int ch = (bsBuff >> 24);
+ baseStream.WriteByte((byte)ch); // write 8-bit
+ bsBuff <<= 8;
+ bsLive -= 8;
+ bytesOut++;
+ }
+ }
+
+ void BsW(int n, int v)
+ {
+ while (bsLive >= 8) {
+ int ch = (bsBuff >> 24);
+ baseStream.WriteByte((byte)ch); // write 8-bit
+ bsBuff <<= 8;
+ bsLive -= 8;
+ ++bytesOut;
+ }
+ bsBuff |= (v << (32 - bsLive - n));
+ bsLive += n;
+ }
+
+ void BsPutUChar(int c)
+ {
+ BsW(8, c);
+ }
+
+ void BsPutint(int u)
+ {
+ BsW(8, (u >> 24) & 0xFF);
+ BsW(8, (u >> 16) & 0xFF);
+ BsW(8, (u >> 8) & 0xFF);
+ BsW(8, u & 0xFF);
+ }
+
+ void BsPutIntVS(int numBits, int c)
+ {
+ BsW(numBits, c);
+ }
+
+ void SendMTFValues()
+ {
+ char[][] len = new char[BZip2Constants.N_GROUPS][];
+ for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {
+ len[i] = new char[BZip2Constants.MAX_ALPHA_SIZE];
+ }
+
+ int gs, ge, totc, bt, bc, iter;
+ int nSelectors = 0, alphaSize, minLen, maxLen, selCtr;
+ int nGroups, nBytes;
+
+ alphaSize = nInUse + 2;
+ for (int t = 0; t < BZip2Constants.N_GROUPS; t++) {
+ for (int v = 0; v < alphaSize; v++) {
+ len[t][v] = (char)GREATER_ICOST;
+ }
+ }
+
+ /*--- Decide how many coding tables to use ---*/
+ if (nMTF <= 0) {
+ Panic();
+ }
+
+ if (nMTF < 200) {
+ nGroups = 2;
+ } else if (nMTF < 600) {
+ nGroups = 3;
+ } else if (nMTF < 1200) {
+ nGroups = 4;
+ } else if (nMTF < 2400) {
+ nGroups = 5;
+ } else {
+ nGroups = 6;
+ }
+
+ /*--- Generate an initial set of coding tables ---*/
+ int nPart = nGroups;
+ int remF = nMTF;
+ gs = 0;
+ while (nPart > 0) {
+ int tFreq = remF / nPart;
+ int aFreq = 0;
+ ge = gs - 1;
+ while (aFreq < tFreq && ge < alphaSize - 1) {
+ ge++;
+ aFreq += mtfFreq[ge];
+ }
+
+ if (ge > gs && nPart != nGroups && nPart != 1 && ((nGroups - nPart) % 2 == 1)) {
+ aFreq -= mtfFreq[ge];
+ ge--;
+ }
+
+ for (int v = 0; v < alphaSize; v++) {
+ if (v >= gs && v <= ge) {
+ len[nPart - 1][v] = (char)LESSER_ICOST;
+ } else {
+ len[nPart - 1][v] = (char)GREATER_ICOST;
+ }
+ }
+
+ nPart--;
+ gs = ge + 1;
+ remF -= aFreq;
+ }
+
+ int[][] rfreq = new int[BZip2Constants.N_GROUPS][];
+ for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {
+ rfreq[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];
+ }
+
+ int[] fave = new int[BZip2Constants.N_GROUPS];
+ short[] cost = new short[BZip2Constants.N_GROUPS];
+ /*---
+ Iterate up to N_ITERS times to improve the tables.
+ ---*/
+ for (iter = 0; iter < BZip2Constants.N_ITERS; ++iter) {
+ for (int t = 0; t < nGroups; ++t) {
+ fave[t] = 0;
+ }
+
+ for (int t = 0; t < nGroups; ++t) {
+ for (int v = 0; v < alphaSize; ++v) {
+ rfreq[t][v] = 0;
+ }
+ }
+
+ nSelectors = 0;
+ totc = 0;
+ gs = 0;
+ while (true) {
+ /*--- Set group start & end marks. --*/
+ if (gs >= nMTF) {
+ break;
+ }
+ ge = gs + BZip2Constants.G_SIZE - 1;
+ if (ge >= nMTF) {
+ ge = nMTF - 1;
+ }
+
+ /*--
+ Calculate the cost of this group as coded
+ by each of the coding tables.
+ --*/
+ for (int t = 0; t < nGroups; t++) {
+ cost[t] = 0;
+ }
+
+ if (nGroups == 6) {
+ short cost0, cost1, cost2, cost3, cost4, cost5;
+ cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0;
+ for (int i = gs; i <= ge; ++i) {
+ short icv = szptr[i];
+ cost0 += (short)len[0][icv];
+ cost1 += (short)len[1][icv];
+ cost2 += (short)len[2][icv];
+ cost3 += (short)len[3][icv];
+ cost4 += (short)len[4][icv];
+ cost5 += (short)len[5][icv];
+ }
+ cost[0] = cost0;
+ cost[1] = cost1;
+ cost[2] = cost2;
+ cost[3] = cost3;
+ cost[4] = cost4;
+ cost[5] = cost5;
+ } else {
+ for (int i = gs; i <= ge; ++i) {
+ short icv = szptr[i];
+ for (int t = 0; t < nGroups; t++) {
+ cost[t] += (short)len[t][icv];
+ }
+ }
+ }
+
+ /*--
+ Find the coding table which is best for this group,
+ and record its identity in the selector table.
+ --*/
+ bc = 999999999;
+ bt = -1;
+ for (int t = 0; t < nGroups; ++t) {
+ if (cost[t] < bc) {
+ bc = cost[t];
+ bt = t;
+ }
+ }
+ totc += bc;
+ fave[bt]++;
+ selector[nSelectors] = (char)bt;
+ nSelectors++;
+
+ /*--
+ Increment the symbol frequencies for the selected table.
+ --*/
+ for (int i = gs; i <= ge; ++i) {
+ ++rfreq[bt][szptr[i]];
+ }
+
+ gs = ge+1;
+ }
+
+ /*--
+ Recompute the tables based on the accumulated frequencies.
+ --*/
+ for (int t = 0; t < nGroups; ++t) {
+ HbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20);
+ }
+ }
+
+ rfreq = null;
+ fave = null;
+ cost = null;
+
+ if (!(nGroups < 8)) {
+ Panic();
+ }
+ if (!(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZip2Constants.G_SIZE)))) {
+ Panic();
+ }
+
+ /*--- Compute MTF values for the selectors. ---*/
+ char[] pos = new char[BZip2Constants.N_GROUPS];
+ char ll_i, tmp2, tmp;
+ for (int i = 0; i < nGroups; i++) {
+ pos[i] = (char)i;
+ }
+ for (int i = 0; i < nSelectors; i++) {
+ ll_i = selector[i];
+ int j = 0;
+ tmp = pos[j];
+ while (ll_i != tmp) {
+ j++;
+ tmp2 = tmp;
+ tmp = pos[j];
+ pos[j] = tmp2;
+ }
+ pos[0] = tmp;
+ selectorMtf[i] = (char)j;
+ }
+
+ int[][] code = new int[BZip2Constants.N_GROUPS][];
+
+ for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {
+ code[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];
+ }
+
+ /*--- Assign actual codes for the tables. --*/
+ for (int t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (int i = 0; i < alphaSize; i++) {
+ if (len[t][i] > maxLen) {
+ maxLen = len[t][i];
+ }
+ if (len[t][i] < minLen) {
+ minLen = len[t][i];
+ }
+ }
+ if (maxLen > 20) {
+ Panic();
+ }
+ if (minLen < 1) {
+ Panic();
+ }
+ HbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize);
+ }
+
+ /*--- Transmit the mapping table. ---*/
+ bool[] inUse16 = new bool[16];
+ for (int i = 0; i < 16; ++i) {
+ inUse16[i] = false;
+ for (int j = 0; j < 16; ++j) {
+ if (inUse[i * 16 + j]) {
+ inUse16[i] = true;
+ } // TODO : insert break;
+ }
+ }
+
+ nBytes = bytesOut;
+ for (int i = 0; i < 16; ++i) {
+ if (inUse16[i]) {
+ BsW(1,1);
+ } else {
+ BsW(1,0);
+ }
+ }
+
+ for (int i = 0; i < 16; ++i) {
+ if (inUse16[i]) {
+ for (int j = 0; j < 16; ++j) {
+ if (inUse[i * 16 + j]) {
+ BsW(1,1);
+ } else {
+ BsW(1,0);
+ }
+ }
+ }
+ }
+
+ /*--- Now the selectors. ---*/
+ nBytes = bytesOut;
+ BsW(3, nGroups);
+ BsW(15, nSelectors);
+ for (int i = 0; i < nSelectors; ++i) {
+ for (int j = 0; j < selectorMtf[i]; ++j) {
+ BsW(1,1);
+ }
+ BsW(1,0);
+ }
+
+ /*--- Now the coding tables. ---*/
+ nBytes = bytesOut;
+
+ for (int t = 0; t < nGroups; ++t) {
+ int curr = len[t][0];
+ BsW(5, curr);
+ for (int i = 0; i < alphaSize; ++i) {
+ while (curr < len[t][i]) {
+ BsW(2, 2);
+ curr++; /* 10 */
+ }
+ while (curr > len[t][i]) {
+ BsW(2, 3);
+ curr--; /* 11 */
+ }
+ BsW (1, 0);
+ }
+ }
+
+ /*--- And finally, the block data proper ---*/
+ nBytes = bytesOut;
+ selCtr = 0;
+ gs = 0;
+ while (true) {
+ if (gs >= nMTF) {
+ break;
+ }
+ ge = gs + BZip2Constants.G_SIZE - 1;
+ if (ge >= nMTF) {
+ ge = nMTF - 1;
+ }
+
+ for (int i = gs; i <= ge; i++) {
+ BsW(len[selector[selCtr]][szptr[i]], code[selector[selCtr]][szptr[i]]);
+ }
+
+ gs = ge + 1;
+ ++selCtr;
+ }
+ if (!(selCtr == nSelectors)) {
+ Panic();
+ }
+ }
+
+ void MoveToFrontCodeAndSend ()
+ {
+ BsPutIntVS(24, origPtr);
+ GenerateMTFValues();
+ SendMTFValues();
+ }
+
+ Stream baseStream;
+
+ void SimpleSort(int lo, int hi, int d)
+ {
+ int i, j, h, bigN, hp;
+ int v;
+
+ bigN = hi - lo + 1;
+ if (bigN < 2) {
+ return;
+ }
+
+ hp = 0;
+ while (incs[hp] < bigN) {
+ hp++;
+ }
+ hp--;
+
+ for (; hp >= 0; hp--) {
+ h = incs[hp];
+
+ i = lo + h;
+ while (true) {
+ /*-- copy 1 --*/
+ if (i > hi)
+ break;
+ v = zptr[i];
+ j = i;
+ while (FullGtU(zptr[j-h]+d, v+d)) {
+ zptr[j] = zptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1))
+ break;
+ }
+ zptr[j] = v;
+ i++;
+
+ /*-- copy 2 --*/
+ if (i > hi) {
+ break;
+ }
+ v = zptr[i];
+ j = i;
+ while (FullGtU ( zptr[j-h]+d, v+d )) {
+ zptr[j] = zptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) {
+ break;
+ }
+ }
+ zptr[j] = v;
+ i++;
+
+ /*-- copy 3 --*/
+ if (i > hi) {
+ break;
+ }
+ v = zptr[i];
+ j = i;
+ while (FullGtU ( zptr[j-h]+d, v+d)) {
+ zptr[j] = zptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) {
+ break;
+ }
+ }
+ zptr[j] = v;
+ i++;
+
+ if (workDone > workLimit && firstAttempt) {
+ return;
+ }
+ }
+ }
+ }
+
+ void Vswap(int p1, int p2, int n )
+ {
+ int temp = 0;
+ while (n > 0) {
+ temp = zptr[p1];
+ zptr[p1] = zptr[p2];
+ zptr[p2] = temp;
+ p1++;
+ p2++;
+ n--;
+ }
+ }
+
+ byte Med3(byte a, byte b, byte c )
+ {
+ byte t;
+ if (a > b) {
+ t = a;
+ a = b;
+ b = t;
+ }
+ if (b > c) {
+ t = b;
+ b = c;
+ c = t;
+ }
+ if (a > b) {
+ b = a;
+ }
+ return b;
+ }
+
+ class StackElem
+ {
+ public int ll;
+ public int hh;
+ public int dd;
+ }
+
+ void QSort3(int loSt, int hiSt, int dSt)
+ {
+ int unLo, unHi, ltLo, gtHi, med, n, m;
+ int sp, lo, hi, d;
+ StackElem[] stack = new StackElem[QSORT_STACK_SIZE];
+ for (int count = 0; count < QSORT_STACK_SIZE; count++) {
+ stack[count] = new StackElem();
+ }
+
+ sp = 0;
+
+ stack[sp].ll = loSt;
+ stack[sp].hh = hiSt;
+ stack[sp].dd = dSt;
+ sp++;
+
+ while (sp > 0) {
+ if (sp >= QSORT_STACK_SIZE) {
+ Panic();
+ }
+
+ sp--;
+ lo = stack[sp].ll;
+ hi = stack[sp].hh;
+ d = stack[sp].dd;
+
+ if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) {
+ SimpleSort(lo, hi, d);
+ if (workDone > workLimit && firstAttempt) {
+ return;
+ }
+ continue;
+ }
+
+ med = Med3(block[zptr[lo] + d + 1],
+ block[zptr[hi ] + d + 1],
+ block[zptr[(lo + hi) >> 1] + d + 1]);
+
+ unLo = ltLo = lo;
+ unHi = gtHi = hi;
+
+ while (true) {
+ while (true) {
+ if (unLo > unHi) {
+ break;
+ }
+ n = ((int)block[zptr[unLo]+d + 1]) - med;
+ if (n == 0) {
+ int temp = 0;
+ temp = zptr[unLo];
+ zptr[unLo] = zptr[ltLo];
+ zptr[ltLo] = temp;
+ ltLo++;
+ unLo++;
+ continue;
+ }
+ if (n > 0) {
+ break;
+ }
+ unLo++;
+ }
+ while (true) {
+ if (unLo > unHi) {
+ break;
+ }
+ n = ((int)block[zptr[unHi]+d + 1]) - med;
+ if (n == 0) {
+ int temp = 0;
+ temp = zptr[unHi];
+ zptr[unHi] = zptr[gtHi];
+ zptr[gtHi] = temp;
+ gtHi--;
+ unHi--;
+ continue;
+ }
+ if (n < 0) {
+ break;
+ }
+ unHi--;
+ }
+ if (unLo > unHi) {
+ break;
+ }
+ {
+ int temp = zptr[unLo];
+ zptr[unLo] = zptr[unHi];
+ zptr[unHi] = temp;
+ unLo++;
+ unHi--;
+ }
+ }
+
+ if (gtHi < ltLo) {
+ stack[sp].ll = lo;
+ stack[sp].hh = hi;
+ stack[sp].dd = d+1;
+ sp++;
+ continue;
+ }
+
+ n = ((ltLo-lo) < (unLo-ltLo)) ? (ltLo-lo) : (unLo-ltLo);
+ Vswap(lo, unLo-n, n);
+ m = ((hi-gtHi) < (gtHi-unHi)) ? (hi-gtHi) : (gtHi-unHi);
+ Vswap(unLo, hi-m+1, m);
+
+ n = lo + unLo - ltLo - 1;
+ m = hi - (gtHi - unHi) + 1;
+
+ stack[sp].ll = lo;
+ stack[sp].hh = n;
+ stack[sp].dd = d;
+ sp++;
+
+ stack[sp].ll = n + 1;
+ stack[sp].hh = m - 1;
+ stack[sp].dd = d+1;
+ sp++;
+
+ stack[sp].ll = m;
+ stack[sp].hh = hi;
+ stack[sp].dd = d;
+ sp++;
+ }
+ }
+
+ void MainSort()
+ {
+ int i, j, ss, sb;
+ int[] runningOrder = new int[256];
+ int[] copy = new int[256];
+ bool[] bigDone = new bool[256];
+ int c1, c2;
+ int numQSorted;
+
+ /*--
+ In the various block-sized structures, live data runs
+ from 0 to last+NUM_OVERSHOOT_BYTES inclusive. First,
+ set up the overshoot area for block.
+ --*/
+
+ // if (verbosity >= 4) fprintf ( stderr, " sort initialise ...\n" );
+ for (i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {
+ block[last + i + 2] = block[(i % (last + 1)) + 1];
+ }
+ for (i = 0; i <= last + BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {
+ quadrant[i] = 0;
+ }
+
+ block[0] = (byte)(block[last + 1]);
+
+ if (last < 4000) {
+ /*--
+ Use simpleSort(), since the full sorting mechanism
+ has quite a large constant overhead.
+ --*/
+ for (i = 0; i <= last; i++) {
+ zptr[i] = i;
+ }
+ firstAttempt = false;
+ workDone = workLimit = 0;
+ SimpleSort(0, last, 0);
+ } else {
+ numQSorted = 0;
+ for (i = 0; i <= 255; i++) {
+ bigDone[i] = false;
+ }
+ for (i = 0; i <= 65536; i++) {
+ ftab[i] = 0;
+ }
+
+ c1 = block[0];
+ for (i = 0; i <= last; i++) {
+ c2 = block[i + 1];
+ ftab[(c1 << 8) + c2]++;
+ c1 = c2;
+ }
+
+ for (i = 1; i <= 65536; i++) {
+ ftab[i] += ftab[i - 1];
+ }
+
+ c1 = block[1];
+ for (i = 0; i < last; i++) {
+ c2 = block[i + 2];
+ j = (c1 << 8) + c2;
+ c1 = c2;
+ ftab[j]--;
+ zptr[ftab[j]] = i;
+ }
+
+ j = ((block[last + 1]) << 8) + (block[1]);
+ ftab[j]--;
+ zptr[ftab[j]] = last;
+
+ /*--
+ Now ftab contains the first loc of every small bucket.
+ Calculate the running order, from smallest to largest
+ big bucket.
+ --*/
+
+ for (i = 0; i <= 255; i++) {
+ runningOrder[i] = i;
+ }
+
+ int vv;
+ int h = 1;
+ do {
+ h = 3 * h + 1;
+ } while (h <= 256);
+ do {
+ h = h / 3;
+ for (i = h; i <= 255; i++) {
+ vv = runningOrder[i];
+ j = i;
+ while ((ftab[((runningOrder[j-h])+1) << 8] - ftab[(runningOrder[j-h]) << 8]) > (ftab[((vv)+1) << 8] - ftab[(vv) << 8])) {
+ runningOrder[j] = runningOrder[j-h];
+ j = j - h;
+ if (j <= (h - 1)) {
+ break;
+ }
+ }
+ runningOrder[j] = vv;
+ }
+ } while (h != 1);
+
+ /*--
+ The main sorting loop.
+ --*/
+ for (i = 0; i <= 255; i++) {
+
+ /*--
+ Process big buckets, starting with the least full.
+ --*/
+ ss = runningOrder[i];
+
+ /*--
+ Complete the big bucket [ss] by quicksorting
+ any unsorted small buckets [ss, j]. Hopefully
+ previous pointer-scanning phases have already
+ completed many of the small buckets [ss, j], so
+ we don't have to sort them at all.
+ --*/
+ for (j = 0; j <= 255; j++) {
+ sb = (ss << 8) + j;
+ if(!((ftab[sb] & SETMASK) == SETMASK)) {
+ int lo = ftab[sb] & CLEARMASK;
+ int hi = (ftab[sb+1] & CLEARMASK) - 1;
+ if (hi > lo) {
+ QSort3(lo, hi, 2);
+ numQSorted += (hi - lo + 1);
+ if (workDone > workLimit && firstAttempt) {
+ return;
+ }
+ }
+ ftab[sb] |= SETMASK;
+ }
+ }
+
+ /*--
+ The ss big bucket is now done. Record this fact,
+ and update the quadrant descriptors. Remember to
+ update quadrants in the overshoot area too, if
+ necessary. The "if (i < 255)" test merely skips
+ this updating for the last bucket processed, since
+ updating for the last bucket is pointless.
+ --*/
+ bigDone[ss] = true;
+
+ if (i < 255) {
+ int bbStart = ftab[ss << 8] & CLEARMASK;
+ int bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;
+ int shifts = 0;
+
+ while ((bbSize >> shifts) > 65534) {
+ shifts++;
+ }
+
+ for (j = 0; j < bbSize; j++) {
+ int a2update = zptr[bbStart + j];
+ int qVal = (j >> shifts);
+ quadrant[a2update] = qVal;
+ if (a2update < BZip2Constants.NUM_OVERSHOOT_BYTES) {
+ quadrant[a2update + last + 1] = qVal;
+ }
+ }
+
+ if (!(((bbSize-1) >> shifts) <= 65535)) {
+ Panic();
+ }
+ }
+
+ /*--
+ Now scan this big bucket so as to synthesise the
+ sorted order for small buckets [t, ss] for all t != ss.
+ --*/
+ for (j = 0; j <= 255; j++) {
+ copy[j] = ftab[(j << 8) + ss] & CLEARMASK;
+ }
+
+ for (j = ftab[ss << 8] & CLEARMASK; j < (ftab[(ss+1) << 8] & CLEARMASK); j++) {
+ c1 = block[zptr[j]];
+ if (!bigDone[c1]) {
+ zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1;
+ copy[c1] ++;
+ }
+ }
+
+ for (j = 0; j <= 255; j++) {
+ ftab[(j << 8) + ss] |= SETMASK;
+ }
+ }
+ }
+ }
+
+ void RandomiseBlock()
+ {
+ int i;
+ int rNToGo = 0;
+ int rTPos = 0;
+ for (i = 0; i < 256; i++) {
+ inUse[i] = false;
+ }
+
+ for (i = 0; i <= last; i++) {
+ if (rNToGo == 0) {
+ rNToGo = (int)BZip2Constants.rNums[rTPos];
+ rTPos++;
+ if (rTPos == 512) {
+ rTPos = 0;
+ }
+ }
+ rNToGo--;
+ block[i + 1] ^= (byte)((rNToGo == 1) ? 1 : 0);
+ // handle 16 bit signed numbers
+ block[i + 1] &= 0xFF;
+
+ inUse[block[i + 1]] = true;
+ }
+ }
+
+ void DoReversibleTransformation()
+ {
+ workLimit = workFactor * last;
+ workDone = 0;
+ blockRandomised = false;
+ firstAttempt = true;
+
+ MainSort();
+
+ if (workDone > workLimit && firstAttempt) {
+ RandomiseBlock();
+ workLimit = workDone = 0;
+ blockRandomised = true;
+ firstAttempt = false;
+ MainSort();
+ }
+
+ origPtr = -1;
+ for (int i = 0; i <= last; i++) {
+ if (zptr[i] == 0) {
+ origPtr = i;
+ break;
+ }
+ }
+
+ if (origPtr == -1) {
+ Panic();
+ }
+ }
+
+ bool FullGtU(int i1, int i2)
+ {
+ int k;
+ byte c1, c2;
+ int s1, s2;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ i1++;
+ i2++;
+
+ k = last + 1;
+
+ do {
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return s1 > s2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return s1 > s2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return s1 > s2;
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return c1 > c2;
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return s1 > s2;
+ }
+ i1++;
+ i2++;
+
+ if (i1 > last) {
+ i1 -= last;
+ i1--;
+ }
+ if (i2 > last) {
+ i2 -= last;
+ i2--;
+ }
+
+ k -= 4;
+ ++workDone;
+ } while (k >= 0);
+
+ return false;
+ }
+
+ /*--
+ Knuth's increments seem to work better
+ than Incerpi-Sedgewick here. Possibly
+ because the number of elems to sort is
+ usually small, typically <= 20.
+ --*/
+ readonly int[] incs = new int[] {
+ 1, 4, 13, 40, 121, 364, 1093, 3280,
+ 9841, 29524, 88573, 265720,
+ 797161, 2391484
+ };
+
+ void AllocateCompressStructures()
+ {
+ int n = BZip2Constants.baseBlockSize * blockSize100k;
+ block = new byte[(n + 1 + BZip2Constants.NUM_OVERSHOOT_BYTES)];
+ quadrant = new int[(n + BZip2Constants.NUM_OVERSHOOT_BYTES)];
+ zptr = new int[n];
+ ftab = new int[65537];
+
+ if (block == null || quadrant == null || zptr == null || ftab == null) {
+ // int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537;
+ // compressOutOfMemory ( totalDraw, n );
+ }
+
+ /*
+ The back end needs a place to store the MTF values
+ whilst it calculates the coding tables. We could
+ put them in the zptr array. However, these values
+ will fit in a short, so we overlay szptr at the
+ start of zptr, in the hope of reducing the number
+ of cache misses induced by the multiple traversals
+ of the MTF values when calculating coding tables.
+ Seems to improve compression speed by about 1%.
+ */
+ // szptr = zptr;
+
+
+ szptr = new short[2 * n];
+ }
+
+ void GenerateMTFValues()
+ {
+ char[] yy = new char[256];
+ int i, j;
+ char tmp;
+ char tmp2;
+ int zPend;
+ int wr;
+ int EOB;
+
+ MakeMaps();
+ EOB = nInUse+1;
+
+ for (i = 0; i <= EOB; i++) {
+ mtfFreq[i] = 0;
+ }
+
+ wr = 0;
+ zPend = 0;
+ for (i = 0; i < nInUse; i++) {
+ yy[i] = (char) i;
+ }
+
+
+ for (i = 0; i <= last; i++) {
+ char ll_i;
+
+ ll_i = unseqToSeq[block[zptr[i]]];
+
+ j = 0;
+ tmp = yy[j];
+ while (ll_i != tmp) {
+ j++;
+ tmp2 = tmp;
+ tmp = yy[j];
+ yy[j] = tmp2;
+ }
+ yy[0] = tmp;
+
+ if (j == 0) {
+ zPend++;
+ } else {
+ if (zPend > 0) {
+ zPend--;
+ while (true) {
+ switch (zPend % 2) {
+ case 0:
+ szptr[wr] = (short)BZip2Constants.RUNA;
+ wr++;
+ mtfFreq[BZip2Constants.RUNA]++;
+ break;
+ case 1:
+ szptr[wr] = (short)BZip2Constants.RUNB;
+ wr++;
+ mtfFreq[BZip2Constants.RUNB]++;
+ break;
+ }
+ if (zPend < 2) {
+ break;
+ }
+ zPend = (zPend - 2) / 2;
+ }
+ zPend = 0;
+ }
+ szptr[wr] = (short)(j + 1);
+ wr++;
+ mtfFreq[j + 1]++;
+ }
+ }
+
+ if (zPend > 0) {
+ zPend--;
+ while (true) {
+ switch (zPend % 2) {
+ case 0:
+ szptr[wr] = (short)BZip2Constants.RUNA;
+ wr++;
+ mtfFreq[BZip2Constants.RUNA]++;
+ break;
+ case 1:
+ szptr[wr] = (short)BZip2Constants.RUNB;
+ wr++;
+ mtfFreq[BZip2Constants.RUNB]++;
+ break;
+ }
+ if (zPend < 2) {
+ break;
+ }
+ zPend = (zPend - 2) / 2;
+ }
+ }
+
+ szptr[wr] = (short)EOB;
+ wr++;
+ mtfFreq[EOB]++;
+
+ nMTF = wr;
+ }
+ }
+}
+
+/* This file was derived from a file containing under 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
+ */
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/ChangeLog b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/ChangeLog new file mode 100644 index 00000000000..514b0719bf6 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/ChangeLog @@ -0,0 +1,10 @@ +2004-06-24 Raja R Harinath <rharinath@novell.com> + + * AssemblyInfo.cs (AssemblyVersion): Set different version for the + net_2_0 profile. + +2004-05-28 Duncan Mak <duncan@ximian.com> + + * AssemblyInfo.cs: Use the new SharpZipLib.pub. + * Zip/Compression/DeflaterHuffman.cs (FlushBlock): Add some + parenthesis to help the generics compiler read this source. diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/Adler32.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/Adler32.cs new file mode 100644 index 00000000000..220dcbafa0c --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/Adler32.cs @@ -0,0 +1,200 @@ +// 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>
+ readonly static uint BASE = 65521;
+
+ uint checksum;
+
+ /// <summary>
+ /// Returns the Adler32 data checksum computed so far.
+ /// </summary>
+ public long Value {
+ get {
+ return checksum;
+ }
+ }
+
+ /// <summary>
+ /// Creates a new instance of the <code>Adler32</code> 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; //Initialize to 1
+ }
+
+ /// <summary>
+ /// Updates the checksum with the byte b.
+ /// </summary>
+ /// <param name="bval">
+ /// the data value to add. The high byte of the int is ignored.
+ /// </param>
+ public void Update(int bval)
+ {
+ //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)bval & 0xFF)) % BASE;
+ s2 = (s1 + s2) % BASE;
+
+ checksum = (s2 << 16) + s1;
+ }
+
+ /// <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)
+ {
+ Update(buffer, 0, buffer.Length);
+ }
+
+ /// <summary>
+ /// Updates the checksum with the bytes taken from the array.
+ /// </summary>
+ /// <param name="buf">
+ /// an array of bytes
+ /// </param>
+ /// <param name="off">
+ /// the start of the data used for this update
+ /// </param>
+ /// <param name="len">
+ /// the number of bytes to use for this update
+ /// </param>
+ public void Update(byte[] buf, int off, int len)
+ {
+ if (buf == null) {
+ throw new ArgumentNullException("buf");
+ }
+
+ if (off < 0 || len < 0 || off + len > buf.Length) {
+ throw new ArgumentOutOfRangeException();
+ }
+
+ //(By Per Bothner)
+ uint s1 = checksum & 0xFFFF;
+ uint s2 = checksum >> 16;
+
+ while (len > 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 > len) {
+ n = len;
+ }
+ len -= n;
+ while (--n >= 0) {
+ s1 = s1 + (uint)(buf[off++] & 0xFF);
+ s2 = s2 + s1;
+ }
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+
+ checksum = (s2 << 16) | s1;
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/Crc32.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/Crc32.cs new file mode 100644 index 00000000000..a78ad4c29f6 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/Crc32.cs @@ -0,0 +1,211 @@ +// 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
+ {
+ readonly static 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 bval)
+ {
+ return (uint)(Crc32.CrcTable[(oldCrc ^ bval) & 0xFF] ^ (oldCrc >> 8));
+ }
+
+ /// <summary>
+ /// The crc data checksum so far.
+ /// </summary>
+ uint crc = 0;
+
+ /// <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 = "bval">
+ /// the byte is taken as the lower 8 bits of bval
+ /// </param>
+ public void Update(int bval)
+ {
+ crc ^= CrcSeed;
+ crc = CrcTable[(crc ^ bval) & 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)
+ {
+ Update(buffer, 0, buffer.Length);
+ }
+
+ /// <summary>
+ /// Adds the byte array to the data checksum.
+ /// </summary>
+ /// <param name = "buf">
+ /// the buffer which contains the data
+ /// </param>
+ /// <param name = "off">
+ /// the offset in the buffer where the data starts
+ /// </param>
+ /// <param name = "len">
+ /// the length of the data
+ /// </param>
+ public void Update(byte[] buf, int off, int len)
+ {
+ if (buf == null) {
+ throw new ArgumentNullException("buf");
+ }
+
+ if (off < 0 || len < 0 || off + len > buf.Length) {
+ throw new ArgumentOutOfRangeException();
+ }
+
+ crc ^= CrcSeed;
+
+ while (--len >= 0) {
+ crc = CrcTable[(crc ^ buf[off++]) & 0xFF] ^ (crc >> 8);
+ }
+
+ crc ^= CrcSeed;
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/IChecksum.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/IChecksum.cs new file mode 100644 index 00000000000..98385b316ac --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/IChecksum.cs @@ -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 = "bval">
+ /// the data value to add. The high byte of the int is ignored.
+ /// </param>
+ void Update(int bval);
+
+ /// <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 = "buf">
+ /// the buffer which contains the data
+ /// </param>
+ /// <param name = "off">
+ /// the offset in the buffer where the data starts
+ /// </param>
+ /// <param name = "len">
+ /// the length of the data
+ /// </param>
+ void Update(byte[] buf, int off, int len);
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/StrangeCrc.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/StrangeCrc.cs new file mode 100644 index 00000000000..a2dc10fcf12 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/StrangeCrc.cs @@ -0,0 +1,159 @@ +// StrangeCRC.cs - computes a crc used in the bziplib ... I don't think that
+// this is the 'standard' crc, please correct me, if I'm wrong
+// 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
+{
+
+ 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;
+
+ public StrangeCRC()
+ {
+ Reset();
+ }
+
+ public void Reset()
+ {
+ globalCrc = -1;
+ }
+
+ public long Value {
+ get {
+ return ~globalCrc;
+ }
+ }
+
+ public void Update(int inCh)
+ {
+ int temp = (globalCrc >> 24) ^ inCh;
+ if (temp < 0) {
+ temp = 256 + temp;
+ }
+ globalCrc = (int)((globalCrc << 8) ^ crc32Table[temp]);
+ }
+
+ public void Update(byte[] buf)
+ {
+ Update(buf, 0, buf.Length);
+ }
+
+ public void Update(byte[] buf, int off, int len)
+ {
+ if (buf == null) {
+ throw new ArgumentNullException("buf");
+ }
+
+ if (off < 0 || len < 0 || off + len > buf.Length) {
+ throw new ArgumentOutOfRangeException();
+ }
+
+ for (int i = 0; i < len; ++i) {
+ Update(buf[off++]);
+ }
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipConstants.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipConstants.cs new file mode 100644 index 00000000000..d40ef5a88c8 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipConstants.cs @@ -0,0 +1,68 @@ +// 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>
+ public class GZipConstants
+ {
+ /// <summary>
+ /// Magic number found at start of GZIP header
+ /// </summary>
+ public static readonly 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
+ */
+ public const int FTEXT = 0x1;
+ public const int FHCRC = 0x2;
+ public const int FEXTRA = 0x4;
+ public const int FNAME = 0x8;
+ public const int FCOMMENT = 0x10;
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipInputStream.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipInputStream.cs new file mode 100644 index 00000000000..5a35548e2fb --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipInputStream.cs @@ -0,0 +1,336 @@ +// 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.
+
+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 NZlib.GZip;
+ ///
+ /// class MainClass
+ /// {
+ /// public static void Main(string[] args)
+ /// {
+ /// Stream s = new GZipInputStream(File.OpenRead(args[0]));
+ /// FileStream fs = File.Create(Path.GetFileNameWithoutExtension(args[0]));
+ /// int size = 2048;
+ /// byte[] writeData = new byte[2048];
+ /// while (true) {
+ /// size = s.Read(writeData, 0, size);
+ /// if (size > 0) {
+ /// fs.Write(writeData, 0, size);
+ /// } else {
+ /// break;
+ /// }
+ /// }
+ /// s.Close();
+ /// }
+ /// }
+ /// </code>
+ /// </example>
+ public class GZipInputStream : InflaterInputStream
+ {
+ /// <summary>
+ /// CRC-32 value for uncompressed data
+ /// </summary>
+ protected Crc32 crc = new Crc32();
+
+ /// <summary>
+ /// Indicates end of stream
+ /// </summary>
+ protected bool eos;
+
+ // Have we read the GZIP header yet?
+ bool readGZIPHeader;
+
+ /// <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)
+ {
+ }
+
+ /// <summary>
+ /// Reads uncompressed data into an array of bytes
+ /// </summary>
+ /// <param name="buf">
+ /// the buffer to read uncompressed data into
+ /// </param>
+ /// <param name="offset">
+ /// the offset indicating where the data should be placed
+ /// </param>
+ /// <param name="len">
+ /// the number of uncompressed bytes to be read
+ /// </param>
+ public override int Read(byte[] buf, int offset, int len)
+ {
+ // We first have to slurp baseInputStream the GZIP header, then we feed all the
+ // rest of the data to the superclass.
+ //
+ // As we do that we continually update the CRC32. Once the data is
+ // finished, we check the CRC32
+ //
+ // This means we don't need our own buffer, as everything is done
+ // baseInputStream the superclass.
+ if (!readGZIPHeader) {
+ ReadHeader();
+ }
+
+ if (eos) {
+ return 0;
+ }
+
+ // System.err.println("GZIPIS.read(byte[], off, len ... " + offset + " and len " + len);
+ //We don't have to read the header, so we just grab data from the superclass
+ int numRead = base.Read(buf, offset, len);
+ if (numRead > 0) {
+ crc.Update(buf, offset, numRead);
+ }
+
+ if (inf.IsFinished) {
+ ReadFooter();
+ }
+ return numRead;
+ }
+
+ private void ReadHeader()
+ {
+ /* 1. Check the two magic bytes */
+ Crc32 headCRC = new Crc32();
+ int magic = baseInputStream.ReadByte();
+ if (magic < 0) {
+ eos = true;
+ return;
+ }
+ headCRC.Update(magic);
+ if (magic != (GZipConstants.GZIP_MAGIC >> 8)) {
+ throw new IOException("Error baseInputStream GZIP header, first byte doesn't match");
+ }
+
+ magic = baseInputStream.ReadByte();
+ if (magic != (GZipConstants.GZIP_MAGIC & 0xFF)) {
+ throw new IOException("Error baseInputStream GZIP header, second byte doesn't match");
+ }
+ headCRC.Update(magic);
+
+ /* 2. Check the compression type (must be 8) */
+ int CM = baseInputStream.ReadByte();
+ if (CM != 8) {
+ throw new IOException("Error baseInputStream GZIP header, data not baseInputStream deflate format");
+ }
+ headCRC.Update(CM);
+
+ /* 3. Check the flags */
+ int flags = baseInputStream.ReadByte();
+ if (flags < 0) {
+ throw new Exception("Early EOF baseInputStream 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 & 0xd0) != 0) {
+ throw new IOException("Reserved flag bits baseInputStream GZIP header != 0");
+ }
+
+ /* 4.-6. Skip the modification time, extra flags, and OS type */
+ for (int i=0; i< 6; i++) {
+ int readByte = baseInputStream.ReadByte();
+ if (readByte < 0) {
+ throw new Exception("Early EOF baseInputStream 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 = baseInputStream.ReadByte();
+ if (readByte < 0) {
+ throw new Exception("Early EOF baseInputStream GZIP header");
+ }
+ headCRC.Update(readByte);
+ }
+ if (baseInputStream.ReadByte() < 0 || baseInputStream.ReadByte() < 0) {
+ throw new Exception("Early EOF baseInputStream GZIP header");
+ }
+
+ int len1, len2, extraLen;
+ len1 = baseInputStream.ReadByte();
+ len2 = baseInputStream.ReadByte();
+ if ((len1 < 0) || (len2 < 0)) {
+ throw new Exception("Early EOF baseInputStream GZIP header");
+ }
+ headCRC.Update(len1);
+ headCRC.Update(len2);
+
+ extraLen = (len1 << 8) | len2;
+ for (int i = 0; i < extraLen;i++) {
+ int readByte = baseInputStream.ReadByte();
+ if (readByte < 0)
+ {
+ throw new Exception("Early EOF baseInputStream GZIP header");
+ }
+ headCRC.Update(readByte);
+ }
+ }
+
+ /* 8. Read file name */
+ if ((flags & GZipConstants.FNAME) != 0) {
+ int readByte;
+ while ( (readByte = baseInputStream.ReadByte()) > 0) {
+ headCRC.Update(readByte);
+ }
+ if (readByte < 0) {
+ throw new Exception("Early EOF baseInputStream GZIP file name");
+ }
+ headCRC.Update(readByte);
+ }
+
+ /* 9. Read comment */
+ if ((flags & GZipConstants.FCOMMENT) != 0) {
+ int readByte;
+ while ( (readByte = baseInputStream.ReadByte()) > 0) {
+ headCRC.Update(readByte);
+ }
+
+ if (readByte < 0) {
+ throw new Exception("Early EOF baseInputStream GZIP comment");
+ }
+ headCRC.Update(readByte);
+ }
+
+ /* 10. Read header CRC */
+ if ((flags & GZipConstants.FHCRC) != 0) {
+ int tempByte;
+ int crcval = baseInputStream.ReadByte();
+ if (crcval < 0) {
+ throw new Exception("Early EOF baseInputStream GZIP header");
+ }
+
+ tempByte = baseInputStream.ReadByte();
+ if (tempByte < 0) {
+ throw new Exception("Early EOF baseInputStream GZIP header");
+ }
+
+ crcval = (crcval << 8) | tempByte;
+ if (crcval != ((int) headCRC.Value & 0xffff)) {
+ throw new IOException("Header CRC value mismatch");
+ }
+ }
+
+ readGZIPHeader = true;
+ //System.err.println("Read GZIP header");
+ }
+
+ private void ReadFooter()
+ {
+ byte[] footer = new byte[8];
+ int avail = inf.RemainingInput;
+ if (avail > 8) {
+ avail = 8;
+ }
+ System.Array.Copy(buf, len - inf.RemainingInput, footer, 0, avail);
+ int needed = 8 - avail;
+ while (needed > 0) {
+ int count = baseInputStream.Read(footer, 8-needed, needed);
+ if (count <= 0) {
+ throw new Exception("Early EOF baseInputStream GZIP footer");
+ }
+ needed -= count; //Jewel Jan 16
+ }
+ int crcval = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8) | ((footer[2] & 0xff) << 16) | (footer[3] << 24);
+ if (crcval != (int) crc.Value) {
+ throw new IOException("GZIP crc sum mismatch, theirs \"" + crcval + "\" and ours \"" + (int) crc.Value);
+ }
+ int total = (footer[4] & 0xff) | ((footer[5] & 0xff) << 8) | ((footer[6] & 0xff) << 16) | (footer[7] << 24);
+ if (total != inf.TotalOut) {
+ throw new IOException("Number of bytes mismatch");
+ }
+ /* XXX Should we support multiple members.
+ * Difficult, since there may be some bytes still baseInputStream buf
+ */
+ eos = true;
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipOutputStream.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipOutputStream.cs new file mode 100644 index 00000000000..b150e66d5c2 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipOutputStream.cs @@ -0,0 +1,174 @@ +// 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; // -jr- corrected
+ ///
+ /// class MainClass
+ /// {
+ /// public static void Main(string[] args)
+ /// {
+ /// Stream s = new GZipOutputStream(File.Create(args[0] + ".gz"));
+ /// FileStream fs = File.OpenRead(args[0]);
+ /// byte[] writeData = new byte[fs.Length];
+ /// fs.Read(writeData, 0, (int)fs.Length);
+ /// s.Write(writeData, 0, writeData.Length);
+ /// s.Close();
+ /// }
+ /// }
+ /// </code>
+ /// </example>
+ public class GZipOutputStream : DeflaterOutputStream
+ {
+ //Variables
+
+ /// <summary>
+ /// CRC-32 value for uncompressed data
+ /// </summary>
+ protected Crc32 crc = new Crc32();
+
+ // 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)
+ {
+ WriteHeader();
+ // System.err.println("wrote GZIP header (" + gzipHeader.length + " bytes )");
+ }
+
+ void WriteHeader()
+ {
+ int mod_time = (int)(DateTime.Now.Ticks / 10000L); // Ticks give back 100ns intervals
+ byte[] gzipHeader = {
+ /* The two magic bytes */
+ (byte) (GZipConstants.GZIP_MAGIC >> 8), (byte) GZipConstants.GZIP_MAGIC,
+
+ /* 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);
+ }
+
+ public override void Write(byte[] buf, int off, int len)
+ {
+ crc.Update(buf, off, len);
+ base.Write(buf, off, len);
+ }
+
+ /// <summary>
+ /// Writes remaining compressed output data to the output stream
+ /// and closes it.
+ /// </summary>
+ public override void Close()
+ {
+ Finish();
+ baseOutputStream.Close();
+ }
+
+ public override void Finish()
+ {
+ base.Finish();
+
+ int totalin = def.TotalIn;
+ int crcval = (int) (crc.Value & 0xffffffff);
+
+ // System.err.println("CRC val is " + Integer.toHexString( crcval ) + " and length " + Integer.toHexString(totalin));
+
+ byte[] gzipFooter = {
+ (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);
+ // System.err.println("wrote GZIP trailer (" + gzipFooter.length + " bytes )");
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/InvalidHeaderException.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/InvalidHeaderException.cs new file mode 100644 index 00000000000..3fd5301df30 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/InvalidHeaderException.cs @@ -0,0 +1,72 @@ +// 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;
+using System.IO;
+
+using ICSharpCode.SharpZipLib.Checksums;
+
+namespace ICSharpCode.SharpZipLib.Tar {
+
+ /// <summary>
+ /// This exception is used to indicate that there is a problem
+ /// with a TAR archive header.
+ /// </summary>
+ public class InvalidHeaderException : System.IO.IOException
+ {
+ public InvalidHeaderException()
+ {
+ }
+
+ public InvalidHeaderException(string msg) : base(msg)
+ {
+ }
+ }
+}
+
+/* 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.
+**
+*/
+
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarArchive.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarArchive.cs new file mode 100644 index 00000000000..ffe7b35a402 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarArchive.cs @@ -0,0 +1,696 @@ +// 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 {
+
+ public delegate void ProgressMessageHandler(TarArchive archive, TarEntry entry, string message);
+
+ /// <summary>
+ /// The TarArchive class implements the concept of a
+ /// tar 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. 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.getCurrentRecordNum() and TarBuffer.getCurrentBlockNum()
+ /// methods, this would be rather trvial.
+ /// </summary>
+ public class TarArchive
+ {
+ bool verbose;
+ bool debug;
+ bool keepOldFiles;
+ bool asciiTranslate;
+
+ int userId;
+ string userName;
+ int groupId;
+ string groupName;
+
+ string rootPath;
+ string pathPrefix;
+
+ int recordSize;
+ byte[] recordBuf;
+
+ TarInputStream tarIn;
+ TarOutputStream tarOut;
+
+ public event ProgressMessageHandler ProgressMessageEvent;
+
+ protected virtual void OnProgressMessageEvent(TarEntry entry, string message)
+ {
+ if (ProgressMessageEvent != null) {
+ ProgressMessageEvent(this, entry, message);
+ }
+ }
+
+ protected TarArchive()
+ {
+ }
+
+ /// <summary>
+ /// The InputStream based constructors create a TarArchive for the
+ /// purposes of e'x'tracting or lis't'ing a tar archive. Thus, use
+ /// these constructors when you wish to extract files from or list
+ /// the contents of an existing tar archive.
+ /// </summary>
+ public static TarArchive CreateInputTarArchive(Stream inputStream)
+ {
+ return CreateInputTarArchive(inputStream, TarBuffer.DefaultBlockFactor);
+ }
+
+ public static TarArchive CreateInputTarArchive(Stream inputStream, int blockFactor)
+ {
+ TarArchive archive = new TarArchive();
+ archive.tarIn = new TarInputStream(inputStream, blockFactor);
+ archive.Initialize(blockFactor * TarBuffer.BlockSize);
+ return archive;
+ }
+
+ /// <summary>
+ /// The OutputStream based constructors create a TarArchive for the
+ /// purposes of 'c'reating a tar archive. Thus, use these constructors
+ /// when you wish to create a new tar archive and write files into it.
+ /// </summary>
+ public static TarArchive CreateOutputTarArchive(Stream outputStream)
+ {
+ return CreateOutputTarArchive(outputStream, TarBuffer.DefaultBlockFactor);
+ }
+
+ public static TarArchive CreateOutputTarArchive(Stream outputStream, int blockFactor)
+ {
+ TarArchive archive = new TarArchive();
+ archive.tarOut = new TarOutputStream(outputStream, blockFactor);
+ archive.Initialize(blockFactor * TarBuffer.BlockSize);
+ return archive;
+ }
+
+ /// <summary>
+ /// Common constructor initialization code.
+ /// </summary>
+ void Initialize(int recordSize)
+ {
+ this.recordSize = recordSize;
+ this.rootPath = null;
+ this.pathPrefix = null;
+
+// this.tempPath = System.getProperty( "user.dir" );
+
+ this.userId = 0;
+ this.userName = String.Empty;
+ this.groupId = 0;
+ this.groupName = String.Empty;
+
+ this.debug = false;
+ this.verbose = false;
+ this.keepOldFiles = false;
+
+ this.recordBuf = new byte[RecordSize];
+ }
+
+ ///
+ /// <summary> Set the debugging flag. </summary>
+ ///
+ /// <param name=debugF> The new debug setting. </param>
+
+ public void SetDebug(bool debugF)
+ {
+ this.debug = debugF;
+ if (this.tarIn != null) {
+ this.tarIn.SetDebug(debugF);
+ }
+ if (this.tarOut != null) {
+ this.tarOut.SetDebug(debugF);
+ }
+ }
+
+ /// <summary>
+ /// Get/Set the verbosity setting.
+ /// </summary>
+ public bool IsVerbose {
+ get {
+ return verbose;
+ }
+ set {
+ verbose = value;
+ }
+ }
+
+ /// <summary>
+ /// Set the flag that determines whether existing files are
+ /// kept, or overwritten during extraction.
+ /// </summary>
+ /// <param name="keepOldFiles">
+ /// If true, do not overwrite existing files.
+ /// </param>
+ public void SetKeepOldFiles(bool keepOldFiles)
+ {
+ this.keepOldFiles = keepOldFiles;
+ }
+
+ /// <summary>
+ /// Set the ascii file translation flag. If ascii file translation
+ /// is true, then the MIME file type will be consulted to determine
+ /// if the file is of type 'text/*'. If the MIME type is not found,
+ /// then the TransFileTyper is consulted if it is not null. If
+ /// either of these two checks indicates the file is an 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>
+ /// <param name= "asciiTranslate">
+ /// If true, translate ascii text files.
+ /// </param>
+ public void SetAsciiTranslation(bool asciiTranslate)
+ {
+ this.asciiTranslate = asciiTranslate;
+ }
+
+/*
+ /// <summary>
+ /// Set the object that will determine if a file is of type
+ /// ascii text for translation purposes.
+ /// </summary>
+ /// <param name="transTyper">
+ /// The new TransFileTyper object.
+ /// </param>
+ public void SetTransFileTyper(TarTransFileTyper transTyper)
+ {
+ this.transTyper = transTyper;
+ }
+*/
+
+ /// <summary>
+ /// Set user and group information that will be used to fill in the
+ /// tar archive's entry headers. Since Java currently provides no means
+ /// of determining a user name, user id, group name, or group id for
+ /// a given File, TarArchive allows the programmer to specify values
+ /// to be used in their place.
+ /// </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)
+ {
+ this.userId = userId;
+ this.userName = userName;
+ this.groupId = groupId;
+ this.groupName = groupName;
+ }
+
+ /// <summary>
+ /// Get the user id being used for archive entry headers.
+ /// </summary>
+ /// <returns>
+ /// The current user id.
+ /// </returns>
+ public int UserId {
+ get {
+ return this.userId;
+ }
+ }
+
+ /// <summary>
+ /// Get the user name being used for archive entry headers.
+ /// </summary>
+ /// <returns>
+ /// The current user name.
+ /// </returns>
+ public string UserName {
+ get {
+ return this.userName;
+ }
+ }
+
+ /// <summary>
+ /// Get the group id being used for archive entry headers.
+ /// </summary>
+ /// <returns>
+ /// The current group id.
+ /// </returns>
+ public int GroupId {
+ get {
+ return this.groupId;
+ }
+ }
+
+ /// <summary>
+ /// Get the group name being used for archive entry headers.
+ /// </summary>
+ /// <returns>
+ /// The current group name.
+ /// </returns>
+ public string GroupName {
+ get {
+ return this.groupName;
+ }
+ }
+
+ /// <summary>
+ /// Get the archive's record size. Because of its history, tar
+ /// supports the concept of buffered IO consisting of RECORDS of
+ /// BLOCKS. This allowed tar to match the IO characteristics of
+ /// the physical device being used. Of course, in the Java world,
+ /// this makes no sense, WITH ONE EXCEPTION - archives are expected
+ /// to be properly "blocked". Thus, all of the horrible TarBuffer
+ /// support boils down to simply getting the "boundaries" correct.
+ /// </summary>
+ /// <returns>
+ /// The record size this archive is using.
+ /// </returns>
+ public int RecordSize {
+ get {
+ if (this.tarIn != null) {
+ return this.tarIn.GetRecordSize();
+ }
+ else if (this.tarOut != null) {
+ return this.tarOut.GetRecordSize();
+ }
+ return TarBuffer.DefaultRecordSize;
+ }
+ }
+
+ /// <summary>
+ /// Close the archive. This simply calls the underlying
+ /// tar stream's close() method.
+ /// </summary>
+ public void CloseArchive()
+ {
+ if (this.tarIn != null) {
+ this.tarIn.Close();
+ }
+ else if (this.tarOut != null) {
+ this.tarOut.Flush();
+ this.tarOut.Close();
+ }
+ }
+
+ /// <summary>
+ /// Perform the "list" command and list the contents of the archive.
+ ///
+ /// NOTE That this method uses the progress display to actually list
+ /// the conents. If the progress display is not set, nothing will be
+ /// listed!
+ /// </summary>
+ public void ListContents()
+ {
+ while (true) {
+ TarEntry entry = this.tarIn.GetNextEntry();
+
+ if (entry == null) {
+ if (this.debug) {
+ Console.Error.WriteLine("READ EOF BLOCK");
+ }
+ break;
+ }
+ OnProgressMessageEvent(entry, null);
+ }
+ }
+
+ /// <summary>
+ /// Perform the "extract" command and extract the contents of the archive.
+ /// </summary>
+ /// <param name="destDir">
+ /// The destination directory into which to extract.
+ /// </param>
+ public void ExtractContents(string destDir)
+ {
+ while (true) {
+ TarEntry entry = this.tarIn.GetNextEntry();
+
+ if (entry == null) {
+ if (this.debug) {
+ Console.Error.WriteLine("READ EOF BLOCK");
+ }
+ break;
+ }
+
+ this.ExtractEntry(destDir, entry);
+ }
+ }
+
+ void EnsureDirectoryExists(string directoryName)
+ {
+ if (!Directory.Exists(directoryName)) {
+ try {
+ Directory.CreateDirectory(directoryName);
+ }
+ catch (Exception e) {
+ throw new IOException("error making directory path '" + directoryName + "', " + e.Message);
+ }
+ }
+ }
+
+ // TODO -jr- No longer reads entire file into memory but is still a weak test!
+ bool IsBinary(string filename)
+ {
+ FileStream fs = File.OpenRead(filename);
+
+ int sampleSize = System.Math.Min(4096, (int)fs.Length);
+ byte[] content = new byte[sampleSize];
+
+ fs.Read(content, 0, sampleSize);
+ fs.Close();
+
+ // assume that ascii 0 or
+ // ascii 255 are only found in non text files.
+ // and that all non text files contain 0 and 255
+ foreach (byte b in content) {
+ if (b == 0 || b == 255) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /// <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)
+ {
+ if (this.verbose) {
+ OnProgressMessageEvent(entry, null);
+ }
+
+ string name = entry.Name;
+ name = name.Replace('/', Path.DirectorySeparatorChar);
+
+ if (!destDir.EndsWith(Path.DirectorySeparatorChar.ToString())) {
+ destDir += Path.DirectorySeparatorChar;
+ }
+
+ string destFile = destDir + name;
+
+ if (entry.IsDirectory) {
+ EnsureDirectoryExists(destFile);
+ }
+ else {
+ string parentDirectory = Path.GetDirectoryName(destFile);
+ EnsureDirectoryExists(parentDirectory);
+
+ if (this.keepOldFiles && File.Exists(destFile)) {
+ if (this.verbose) {
+ OnProgressMessageEvent(entry, "Destination file already exists");
+ }
+ }
+ else {
+ bool asciiTrans = false;
+ Stream outputStream = File.Create(destFile);
+ if (this.asciiTranslate) {
+ asciiTrans = !IsBinary(destFile);
+// original java sourcecode :
+// MimeType mime = null;
+// string contentType = null;
+// try {
+// contentType = FileTypeMap.getDefaultFileTypeMap().getContentType( destFile );
+//
+// mime = new MimeType(contentType);
+//
+// if (mime.getPrimaryType().equalsIgnoreCase( "text" )) {
+// asciiTrans = true;
+// } else if ( this.transTyper != null ) {
+// if ( this.transTyper.isAsciiFile( entry.getName() ) ) {
+// asciiTrans = true;
+// }
+// }
+// } catch (MimeTypeParseException ex) {
+// }
+//
+// if (this.debug) {
+// Console.Error.WriteLine(("EXTRACT TRANS? '" + asciiTrans + "' ContentType='" + contentType + "' PrimaryType='" + mime.getPrimaryType() + "'" );
+// }
+ }
+
+ StreamWriter outw = null;
+ if (asciiTrans) {
+ outw = new StreamWriter(outputStream);
+ }
+
+ byte[] rdbuf = new byte[32 * 1024];
+
+ while (true) {
+ int numRead = this.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="entry">
+ /// 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 entry, bool recurse)
+ {
+ bool asciiTrans = false;
+
+ string tempFileName = null;
+ string eFile = entry.File;
+
+ // Work on a copy of the entry so we can manipulate it.
+ // Note that we must distinguish how the entry was constructed.
+ //
+ if (eFile == null || eFile.Length == 0) {
+ entry = TarEntry.CreateTarEntry(entry.Name);
+ }
+ else {
+ //
+ // The user may have explicitly set the entry's name to
+ // something other than the file's path, so we must save
+ // and restore it. This should work even when the name
+ // was set from the File's name.
+ //
+ string saveName = entry.Name;
+ entry = TarEntry.CreateEntryFromFile(eFile);
+ entry.Name = saveName;
+ }
+
+ if (this.verbose) {
+ OnProgressMessageEvent(entry, null);
+ }
+
+ if (this.asciiTranslate && !entry.IsDirectory) {
+ asciiTrans = !IsBinary(eFile);
+
+// original java source :
+// MimeType mime = null;
+// string contentType = null;
+//
+// try {
+// contentType = FileTypeMap.getDefaultFileTypeMap(). getContentType( eFile );
+//
+// mime = new MimeType( contentType );
+//
+// if ( mime.getPrimaryType().
+// equalsIgnoreCase( "text" ) )
+// {
+// asciiTrans = true;
+// }
+// else if ( this.transTyper != null )
+// {
+// if ( this.transTyper.isAsciiFile( eFile ) )
+// {
+// asciiTrans = true;
+// }
+// }
+// } catch ( MimeTypeParseException ex )
+// {
+// // IGNORE THIS ERROR...
+// }
+//
+// if (this.debug) {
+// Console.Error.WriteLine("CREATE TRANS? '" + asciiTrans + "' ContentType='" + contentType + "' PrimaryType='" + mime.getPrimaryType()+ "'" );
+// }
+
+ if (asciiTrans) {
+ tempFileName = Path.GetTempFileName();
+
+ StreamReader inStream = File.OpenText(eFile);
+ Stream outStream = new BufferedStream(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');
+ }
+
+ inStream.Close();
+
+ outStream.Flush();
+ outStream.Close();
+
+ entry.Size = new FileInfo(tempFileName).Length;
+
+ eFile = tempFileName;
+ }
+ }
+
+ string newName = null;
+
+ if (this.rootPath != null) {
+ if (entry.Name.StartsWith(this.rootPath)) {
+ newName = entry.Name.Substring(this.rootPath.Length + 1 );
+ }
+ }
+
+ if (this.pathPrefix != null) {
+ newName = (newName == null) ? this.pathPrefix + "/" + entry.Name : this.pathPrefix + "/" + newName;
+ }
+
+ if (newName != null) {
+ entry.Name = newName;
+ }
+
+ this.tarOut.PutNextEntry(entry);
+
+ if (entry.IsDirectory) {
+ if (recurse) {
+ TarEntry[] list = entry.GetDirectoryEntries();
+ for (int i = 0; i < list.Length; ++i) {
+ this.WriteEntry(list[i], recurse);
+ }
+ }
+ }
+ else {
+ Stream inputStream = File.OpenRead(eFile);
+ int numWritten = 0;
+ byte[] eBuf = new byte[32 * 1024];
+ while (true) {
+ int numRead = inputStream.Read(eBuf, 0, eBuf.Length);
+
+ if (numRead <=0) {
+ break;
+ }
+
+ this.tarOut.Write(eBuf, 0, numRead);
+ numWritten += numRead;
+ }
+
+// Console.WriteLine("written " + numWritten + " bytes");
+
+ inputStream.Close();
+
+ if (tempFileName != null && tempFileName.Length > 0) {
+ File.Delete(tempFileName);
+ }
+
+ this.tarOut.CloseEntry();
+ }
+ }
+ }
+}
+/* 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.
+ **
+ */
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarBuffer.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarBuffer.cs new file mode 100644 index 00000000000..b53b713e26d --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarBuffer.cs @@ -0,0 +1,510 @@ +// 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;
+using System.Text;
+
+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 (where N is set by the `--blocking-factor=512-SIZE'
+(`-b 512-SIZE') option to `tar') 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.
+*/
+
+// public static readonly int DEFAULT_RCDSIZE = 512;
+// public const int DEFAULT_BLOCKFACTOR = 20;
+// public static readonly int DEFAULT_BLKSIZE = DEFAULT_RCDSIZE * DEFAULT_BLOCKFACTOR;
+
+ public static readonly int BlockSize = 512;
+ public static readonly int DefaultBlockFactor = 20;
+ public static readonly int DefaultRecordSize = BlockSize * DefaultBlockFactor;
+
+ Stream inputStream;
+ Stream outputStream;
+
+ byte[] recordBuffer;
+ int currentBlockIndex;
+ int currentRecordIndex;
+
+ int recordSize = DefaultRecordSize;
+ public int RecordSize
+ {
+ get { return recordSize; }
+ }
+
+ int blockFactor = DefaultBlockFactor;
+
+ public int BlockFactor
+ {
+ get { return blockFactor; }
+ }
+
+ bool debug = false;
+
+ /// <summary>
+ /// Set the debugging flag for the buffer.
+ /// </summary>
+ public void SetDebug(bool debug)
+ {
+ this.debug = debug;
+ }
+
+
+ protected TarBuffer()
+ {
+ }
+
+ public static TarBuffer CreateInputTarBuffer(Stream inputStream)
+ {
+ return CreateInputTarBuffer(inputStream, TarBuffer.DefaultBlockFactor);
+ }
+
+ public static TarBuffer CreateInputTarBuffer(Stream inputStream, int blockFactor)
+ {
+ TarBuffer tarBuffer = new TarBuffer();
+ tarBuffer.inputStream = inputStream;
+ tarBuffer.outputStream = null;
+ tarBuffer.Initialize(blockFactor);
+
+ return tarBuffer;
+ }
+
+ public static TarBuffer CreateOutputTarBuffer(Stream outputStream)
+ {
+ return CreateOutputTarBuffer(outputStream, TarBuffer.DefaultBlockFactor);
+ }
+
+ public static TarBuffer CreateOutputTarBuffer(Stream outputStream, int blockFactor)
+ {
+ 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 blockFactor)
+ {
+ this.debug = false;
+ this.blockFactor = blockFactor;
+ this.recordSize = blockFactor * BlockSize;
+
+ this.recordBuffer = new byte[RecordSize];
+
+ if (inputStream != null)
+ {
+ this.currentRecordIndex = -1;
+ this.currentBlockIndex = BlockFactor;
+ }
+ else
+ {
+ this.currentRecordIndex = 0;
+ this.currentBlockIndex = 0;
+ }
+ }
+
+ /// <summary>
+ /// Get the TAR Buffer's block factor
+ /// </summary>
+ public int GetBlockFactor()
+ {
+ return this.blockFactor;
+ }
+
+ /// <summary>
+ /// Get the TAR Buffer's record size.
+ /// </summary>
+ public int GetRecordSize()
+ {
+ return this.recordSize;
+ }
+
+ /// <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 block data to check.
+ /// </param>
+ public bool IsEOFBlock(byte[] block)
+ {
+ for (int i = 0, sz = BlockSize; i < sz; ++i)
+ {
+ if (block[i] != 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Skip over a block on the input stream.
+ /// </summary>
+ public void SkipBlock()
+ {
+ if (this.debug)
+ {
+ //Console.WriteLine.WriteLine("SkipBlock: recIdx = " + this.currentRecordIndex + " blkIdx = " + this.currentBlockIndex);
+ }
+
+ if (this.inputStream == null)
+ {
+ throw new System.IO.IOException("no input stream defined");
+ }
+
+ if (this.currentBlockIndex >= this.BlockFactor)
+ {
+ if (!this.ReadRecord())
+ {
+ return; // UNDONE
+ }
+ }
+
+ this.currentBlockIndex++;
+ }
+
+ /// <summary>
+ /// Read a block from the input stream and return the data.
+ /// </summary>
+ /// <returns>
+ /// The block data.
+ /// </returns>
+ public byte[] ReadBlock()
+ {
+ if (this.debug)
+ {
+ //Console.WriteLine.WriteLine( "ReadBlock: blockIndex = " + this.currentBlockIndex + " recordIndex = " + this.currentRecordIndex );
+ }
+
+ if (this.inputStream == null)
+ {
+ throw new ApplicationException("TarBuffer.ReadBlock - no input stream defined");
+ }
+
+ if (this.currentBlockIndex >= this.BlockFactor)
+ {
+ if (!this.ReadRecord())
+ {
+ return null;
+ }
+ }
+
+ byte[] result = new byte[BlockSize];
+
+ Array.Copy(this.recordBuffer, (this.currentBlockIndex * BlockSize), result, 0, BlockSize );
+ this.currentBlockIndex++;
+ return result;
+ }
+
+ /// <returns>
+ /// false if End-Of-File, else true
+ /// </returns>
+ bool ReadRecord()
+ {
+ if (this.debug)
+ {
+ //Console.WriteLine.WriteLine("ReadRecord: recordIndex = " + this.currentRecordIndex);
+ }
+
+ if (this.inputStream == null)
+ {
+ throw new System.IO.IOException("no input stream stream defined");
+ }
+
+ this.currentBlockIndex = 0;
+
+ int offset = 0;
+ int bytesNeeded = RecordSize;
+
+ while (bytesNeeded > 0)
+ {
+ long numBytes = this.inputStream.Read(this.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;
+ if (numBytes != RecordSize)
+ {
+ if (this.debug)
+ {
+ //Console.WriteLine.WriteLine("ReadRecord: INCOMPLETE READ " + numBytes + " of " + this.blockSize + " bytes read.");
+ }
+ }
+ }
+
+ this.currentRecordIndex++;
+ return true;
+ }
+
+ /// <summary>
+ /// Get the current block number, within the current record, zero based.
+ /// </summary>
+ /// <returns>
+ /// The current zero based block number.
+ /// </returns>
+ public int GetCurrentBlockNum()
+ {
+ return this.currentBlockIndex;
+ }
+
+ /// <summary>
+ /// Get the current record number
+ /// Absolute block number in file = (currentRecordNum * block factor) + currentBlockNum.
+ /// </summary>
+ /// <returns>
+ /// The current zero based record number.
+ /// </returns>
+ public int GetCurrentRecordNum()
+ {
+ return this.currentRecordIndex;
+ }
+
+ /// <summary>
+ /// Write an archive block to the archive.
+ /// </summary>
+ /// <param name="block">
+ /// The data to write to the archive.
+ /// </param>
+ ///
+ public void WriteBlock(byte[] block)
+ {
+ if (this.debug)
+ {
+ //Console.WriteLine.WriteLine("WriteRecord: recIdx = " + this.currentRecordIndex + " blkIdx = " + this.currentBlockIndex );
+ }
+
+ if (this.outputStream == null)
+ {
+ throw new ApplicationException("TarBuffer.WriteBlock - no output stream defined");
+ }
+
+ if (block.Length != BlockSize)
+ {
+ throw new ApplicationException("TarBuffer.WriteBlock - block to write has length '" + block.Length + "' which is not the block size of '" + BlockSize + "'" );
+ }
+
+ if (this.currentBlockIndex >= BlockFactor)
+ {
+ this.WriteRecord();
+ }
+
+ Array.Copy(block, 0, this.recordBuffer, (this.currentBlockIndex * BlockSize), BlockSize);
+ this.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="buf">
+ /// The buffer containing the record data to write.
+ /// </param>
+ /// <param name="offset">
+ /// The offset of the record data within buf.
+ /// </param>
+ public void WriteBlock(byte[] buf, int offset)
+ {
+ if (this.debug)
+ {
+ //Console.WriteLine.WriteLine("WriteBlock: recIdx = " + this.currentRecordIndex + " blkIdx = " + this.currentBlockIndex );
+ }
+
+ if (this.outputStream == null)
+ {
+ throw new ApplicationException("TarBuffer.WriteBlock - no output stream stream defined");
+ }
+
+ if ((offset + BlockSize) > buf.Length)
+ {
+ throw new ApplicationException("TarBuffer.WriteBlock - record has length '" + buf.Length + "' with offset '" + offset + "' which is less than the record size of '" + this.recordSize + "'" );
+ }
+
+ if (this.currentBlockIndex >= this.BlockFactor)
+ {
+ this.WriteRecord();
+ }
+
+ Array.Copy(buf, offset, this.recordBuffer, (this.currentBlockIndex * BlockSize), BlockSize);
+
+ this.currentBlockIndex++;
+ }
+
+ /// <summary>
+ /// Write a TarBuffer record to the archive.
+ /// </summary>
+ void WriteRecord()
+ {
+ if (this.debug)
+ {
+ //Console.WriteLine.WriteLine("Writerecord: record index = " + this.currentRecordIndex);
+ }
+
+ if (this.outputStream == null)
+ {
+ throw new ApplicationException("TarBuffer.WriteRecord no output stream defined");
+ }
+
+ this.outputStream.Write(this.recordBuffer, 0, RecordSize);
+ this.outputStream.Flush();
+
+ this.currentBlockIndex = 0;
+ this.currentRecordIndex++;
+ }
+
+ /// <summary>
+ /// Flush the current data block if it has any data in it.
+ /// </summary>
+ void Flush()
+ {
+ if (this.debug)
+ {
+ //Console.WriteLine.WriteLine("TarBuffer.FlushBlock() called.");
+ }
+
+ if (this.outputStream == null)
+ {
+ throw new ApplicationException("TarBuffer.Flush no output stream defined");
+ }
+
+ if (this.currentBlockIndex > 0)
+ {
+ this.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 (this.debug)
+ {
+ //Console.WriteLine.WriteLine("TarBuffer.Close().");
+ }
+
+ if (outputStream != null)
+ {
+ Flush();
+
+ outputStream.Close();
+ outputStream = null;
+ }
+ else if (inputStream != null)
+ {
+ inputStream.Close();
+ inputStream = null;
+ }
+ }
+ }
+}
+
+/* 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.
+ **
+ */
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarEntry.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarEntry.cs new file mode 100644 index 00000000000..a2c958fbf1d --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarEntry.cs @@ -0,0 +1,567 @@ +// 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;
+using System.Text;
+
+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 TarEntry( File )
+ /// 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
+ {
+ /// <summary>
+ /// If this entry represents a File, this references it.
+ /// </summary>
+ string file;
+
+ /// <summary>
+ /// This is the entry's header information.
+ /// </summary>
+ TarHeader header;
+
+ /// <summary>
+ /// Only Create Entries with the static CreateXYZ methods or a headerBuffer.
+ /// </summary>
+ private TarEntry()
+ {
+ }
+
+ /// <summary>
+ /// Construct an entry from an archive's header bytes. File is set
+ /// to null.
+ /// </summary>
+ /// <param name = "headerBuf">
+ /// The header bytes from a tar archive entry.
+ /// </param>
+ public TarEntry(byte[] headerBuf)
+ {
+ this.Initialize();
+ this.header.ParseBuffer(headerBuf);
+ }
+
+
+ public TarEntry(TarHeader header)
+ {
+ file = null;
+ this.header = header;
+ }
+
+ /// <summary>
+ /// Construct an entry with only a name. This allows the programmer
+ /// to construct the entry's header "by hand". File is set to null.
+ /// </summary>
+ public static TarEntry CreateTarEntry(string name)
+ {
+ TarEntry entry = new TarEntry();
+ entry.Initialize();
+ entry.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 that the entry represents.
+ /// </param>
+ public static TarEntry CreateEntryFromFile(string fileName)
+ {
+ TarEntry entry = new TarEntry();
+ entry.Initialize();
+ entry.GetFileTarHeader(entry.header, fileName);
+ return entry;
+ }
+
+ /// <summary>
+ /// Initialization code common to all pseudo constructors.
+ /// </summary>
+ void Initialize()
+ {
+ this.file = null;
+ this.header = new TarHeader();
+ }
+
+ /// <summary>
+ /// Determine if the two entries are equal. Equality is determined
+ /// by the header names being equal.
+ /// </summary>
+ /// <returns>
+ /// True if the entries are equal.
+ /// </returns>
+ public override bool Equals(object it)
+ {
+ if (!(it is TarEntry))
+ {
+ return false;
+ }
+ return this.header.name.ToString().Equals(((TarEntry)it).header.name.ToString());
+ }
+
+ /// <summary>
+ /// Must be overridden when you override Equals.
+ /// </summary>
+ public override int GetHashCode()
+ {
+ return this.header.name.ToString().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 = "desc">
+ /// Entry to be checked as a descendent of this.
+ /// </param>
+ /// <returns>
+ /// True if entry is a descendant of this.
+ /// </returns>
+ public bool IsDescendent(TarEntry desc)
+ {
+ return desc.header.name.ToString().StartsWith(this.header.name.ToString());
+ }
+
+ /// <summary>
+ /// Get this entry's header.
+ /// </summary>
+ /// <returns>
+ /// This entry's TarHeader.
+ /// </returns>
+ public TarHeader TarHeader
+ {
+ get
+ {
+ return this.header;
+ }
+ }
+
+ /// <summary>
+ /// Get/Set this entry's name.
+ /// </summary>
+ public string Name
+ {
+ get
+ {
+ return this.header.name.ToString();
+ }
+ set
+ {
+ this.header.name = new StringBuilder(value);
+ }
+ }
+
+ /// <summary>
+ /// Get/set this entry's user id.
+ /// </summary>
+ public int UserId
+ {
+ get
+ {
+ return this.header.userId;
+ }
+ set
+ {
+ this.header.userId = value;
+ }
+ }
+
+ /// <summary>
+ /// Get/set this entry's group id.
+ /// </summary>
+ public int GroupId
+ {
+ get
+ {
+ return this.header.groupId;
+ }
+ set
+ {
+ this.header.groupId = value;
+ }
+ }
+
+ /// <summary>
+ /// Get/set this entry's user name.
+ /// </summary>
+ public string UserName
+ {
+ get
+ {
+ return this.header.userName.ToString();
+ }
+ set
+ {
+ this.header.userName = new StringBuilder(value);
+ }
+ }
+
+ /// <summary>
+ /// Get/set this entry's group name.
+ /// </summary>
+ public string GroupName
+ {
+ get
+ {
+ return this.header.groupName.ToString();
+ }
+ set
+ {
+ this.header.groupName = new StringBuilder(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;
+ }
+
+ // TODO :
+ // /**
+ // * Set this entry's modification time. The parameter passed
+ // * to this method is in "Java time".
+ // *
+ // * @param time This entry's new modification time.
+ // */
+ // public void setModTime( long time )
+ // {
+ // this.header.modTime = time / 1000;
+ // }
+
+ /// Convert time to DateTimes
+ /**
+ * Get/Set this entry's modification time.
+ *
+ * @param time This entry's new modification time.
+ */
+ public DateTime ModTime
+ {
+ get
+ {
+ return this.header.modTime;
+ }
+ set
+ {
+ this.header.modTime = value;
+ }
+ }
+
+ /// <summary>
+ /// Get this entry's file.
+ /// </summary>
+ /// <returns>
+ /// This entry's file.
+ /// </returns>
+ public string File
+ {
+ get
+ {
+ return this.file;
+ }
+ }
+
+ /// <summary>
+ /// Get/set this entry's file size.
+ /// </summary>
+ public long Size
+ {
+ get
+ {
+ return this.header.size;
+ }
+ set
+ {
+ this.header.size = value;
+ }
+ }
+
+ /// <summary>
+ /// Convenience method that will modify an entry's name directly
+ /// in place in an entry header buffer byte array.
+ /// </summary>
+ /// <param name="outbuf">
+ /// The buffer containing the entry header to modify.
+ /// </param>
+ /// <param name="newName">
+ /// The new name to place into the header buffer.
+ /// </param>
+ public void AdjustEntryName(byte[] outbuf, string newName)
+ {
+ int offset = 0;
+ offset = TarHeader.GetNameBytes(new StringBuilder(newName), outbuf, offset, TarHeader.NAMELEN);
+ }
+
+ /// <summary>
+ /// Return whether or not this entry represents a directory.
+ /// </summary>
+ /// <returns>
+ /// True if this entry is a directory.
+ /// </returns>
+ public bool IsDirectory
+ {
+ get
+ {
+ if (this.file != null)
+ {
+ return Directory.Exists(file);
+ }
+
+ if (this.header != null)
+ {
+ if (this.header.typeFlag == TarHeader.LF_DIR || this.header.name.ToString().EndsWith( "/" ))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Fill in a TarHeader with information from a File.
+ /// </summary>
+ /// <param name="hdr">
+ /// The TarHeader to fill in.
+ /// </param>
+ /// <param name="file">
+ /// The file from which to get the header information.
+ /// </param>
+ public void GetFileTarHeader(TarHeader hdr, string file)
+ {
+ this.file = file;
+
+ // bugfix from torhovl from #D forum:
+ string name = file;
+
+ // -jr- 23-Jan-2004 HAK HAK HAK, GnuTar allows device names in path where the name is not local to the current directory
+ if (Environment.CurrentDirectory == Path.GetDirectoryName(name))
+ {
+ name = Path.GetFileName(name);
+ }
+/*
+ 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, '/').ToLower();
+
+ // 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);
+ }
+
+ hdr.linkName = new StringBuilder(String.Empty);
+ hdr.name = new StringBuilder(name);
+
+ if (Directory.Exists(file)) {
+ hdr.mode = 1003; // 01753 -jr- no octal constants!! 040755; // Magic number for security access for a UNIX filesystem
+ hdr.typeFlag = TarHeader.LF_DIR;
+ if (hdr.name.Length == 0 || hdr.name[hdr.name.Length - 1] != '/') {
+ hdr.name.Append("/");
+ }
+
+ hdr.size = 0;
+ } else {
+ hdr.mode = 33216; // 0100700 -jr- // 0100644; // Magic number for security access for a UNIX filesystem
+ hdr.typeFlag = TarHeader.LF_NORMAL;
+ hdr.size = new FileInfo(file.Replace('/', Path.DirectorySeparatorChar)).Length;
+ }
+
+ // UNDONE When File lets us get the userName, use it!
+ hdr.modTime = System.IO.File.GetLastWriteTimeUtc(file.Replace('/', Path.DirectorySeparatorChar)); // -jr- Unix times are in UTC
+ hdr.checkSum = 0;
+ hdr.devMajor = 0;
+ hdr.devMinor = 0;
+ }
+
+ /// <summary>
+ /// If this entry represents a file, and the file is a directory, return
+ /// an array of TarEntries for this entry's children.
+ /// </summary>
+ /// <returns>
+ /// An array of TarEntry's for this entry's children.
+ /// </returns>
+ public TarEntry[] GetDirectoryEntries()
+ {
+ if (this.file == null || !Directory.Exists(this.file))
+ {
+ return new TarEntry[0];
+ }
+
+ string[] list = Directory.GetFileSystemEntries(this.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 = "outbuf">
+ /// The tar entry header buffer to fill in.
+ /// </param>
+ public void WriteEntryHeader(byte[] outbuf)
+ {
+ this.header.WriteHeader(outbuf);
+ }
+
+ /// <summary>
+ /// Fill in a TarHeader given only the entry's name.
+ /// </summary>
+ /// <param name="hdr">
+ /// The TarHeader to fill in.
+ /// </param>
+ /// <param name="name">
+ /// The tar entry name.
+ /// </param>
+ public void NameTarHeader(TarHeader hdr, string name)
+ {
+ bool isDir = name.EndsWith("/"); // -jr- this is true for BSD tar but not all others I think?
+
+ hdr.checkSum = 0;
+
+ hdr.name = new StringBuilder(name);
+// hdr.mode = isDir ? 040755 : 0100644; // TODO : I think I've seen these magics before ...
+ hdr.mode = isDir ? 1003 : 33216;
+ hdr.userId = 0;
+ hdr.groupId = 0;
+ hdr.size = 0;
+ hdr.checkSum = 0;
+
+ hdr.modTime = DateTime.UtcNow; // -jr- 24-Jan-2004 Unix times are in utc!
+// hdr.modTime = DateTime.Now; // (new java.util.Date()).getTime() / 1000;
+
+ hdr.typeFlag = isDir ? TarHeader.LF_DIR : TarHeader.LF_NORMAL;
+
+ hdr.linkName = new StringBuilder(String.Empty);
+ hdr.userName = new StringBuilder(String.Empty);
+ hdr.groupName = new StringBuilder(String.Empty);
+
+ hdr.devMajor = 0;
+ hdr.devMinor = 0;
+ }
+ }
+}
+
+
+
+/* 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.
+ **
+ */
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarHeader.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarHeader.cs new file mode 100644 index 00000000000..eb542452bcd --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarHeader.cs @@ -0,0 +1,753 @@ +// TarHeader.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.
+
+
+/* The tar format and its POSIX successor PAX have a long history which makes for compatability
+ issues when creating and reading files...
+
+This is the ustar (Posix 1003.1) header.
+
+struct header
+{
+ char t_name[100]; // 0 Filename
+ char t_mode[8]; // 100 Permissions
+ char t_uid[8]; // 108 Numerical User ID
+ char t_gid[8]; // 116 Numerical Group ID
+ char t_size[12]; // 124 Filesize
+ char t_mtime[12]; // 136 st_mtime
+ char t_chksum[8]; // 148 Checksum
+ char t_typeflag; // 156 Type of File
+ char t_linkname[100]; // 157 Target of Links
+ char t_magic[6]; // 257 "ustar"
+ char t_version[2]; // 263 Version fixed to 00
+ char t_uname[32]; // 265 User Name
+ char t_gname[32]; // 297 Group Name
+ char t_devmajor[8]; // 329 Major for devices
+ char t_devminor[8]; // 337 Minor for devices
+ char t_prefix[155]; // 345 Prefix for t_name
+ // 500 End
+ char t_mfill[12]; // 500 Filler up to 512
+};
+
+*/
+
+using System;
+using System.Text;
+
+namespace ICSharpCode.SharpZipLib.Tar
+{
+
+
+ /// <summary>
+ /// This class encapsulates the Tar Entry Header used in Tar Archives.
+ /// The class also holds a number of tar constants, used mostly in headers.
+ /// </summary>
+ public class TarHeader : ICloneable
+ {
+ /// <summary>
+ /// The length of the name field in a header buffer.
+ /// </summary>
+ public readonly static int NAMELEN = 100;
+
+ /// <summary>
+ /// The length of the mode field in a header buffer.
+ /// </summary>
+ public readonly static int MODELEN = 8;
+
+ /// <summary>
+ /// The length of the user id field in a header buffer.
+ /// </summary>
+ public readonly static int UIDLEN = 8;
+
+ /// <summary>
+ /// The length of the group id field in a header buffer.
+ /// </summary>
+ public readonly static int GIDLEN = 8;
+
+ /// <summary>
+ /// The length of the checksum field in a header buffer.
+ /// </summary>
+ public readonly static int CHKSUMLEN = 8;
+
+ /// <summary>
+ /// The length of the size field in a header buffer.
+ /// </summary>
+ public readonly static int SIZELEN = 12;
+
+ /// <summary>
+ /// The length of the magic field in a header buffer.
+ /// </summary>
+ public readonly static int MAGICLEN = 6;
+
+ /// <summary>
+ /// The length of the version field in a header buffer.
+ /// </summary>
+ public readonly static int VERSIONLEN = 2;
+
+ /// <summary>
+ /// The length of the modification time field in a header buffer.
+ /// </summary>
+ public readonly static int MODTIMELEN = 12;
+
+ /// <summary>
+ /// The length of the user name field in a header buffer.
+ /// </summary>
+ public readonly static int UNAMELEN = 32;
+
+ /// <summary>
+ /// The length of the group name field in a header buffer.
+ /// </summary>
+ public readonly static int GNAMELEN = 32;
+
+ /// <summary>
+ /// The length of the devices field in a header buffer.
+ /// </summary>
+ public readonly static int DEVLEN = 8;
+
+ /// <summary>
+ /// LF_ constants represents the "type" of an entry
+ /// </summary>
+ ///
+
+ /// <summary>
+ /// This is the "old way" of indicating a normal file.
+ /// </summary>
+ public const byte LF_OLDNORM = 0;
+
+ /// <summary>
+ /// Normal file type.
+ /// </summary>
+ public const byte LF_NORMAL = (byte) '0';
+
+ /// <summary>
+ /// Link file type.
+ /// </summary>
+ public const byte LF_LINK = (byte) '1';
+
+ /// <summary>
+ /// Symbolic link file type.
+ /// </summary>
+ public const byte LF_SYMLINK = (byte) '2';
+
+ /// <summary>
+ /// Character device file type.
+ /// </summary>
+ public const byte LF_CHR = (byte) '3';
+
+ /// <summary>
+ /// Block device file type.
+ /// </summary>
+ public const byte LF_BLK = (byte) '4';
+
+ /// <summary>
+ /// Directory file type.
+ /// </summary>
+ public const byte LF_DIR = (byte) '5';
+
+ /// <summary>
+ /// FIFO (pipe) file type.
+ /// </summary>
+ public const byte LF_FIFO = (byte) '6';
+
+ /// <summary>
+ /// Contiguous file type.
+ /// </summary>
+ public const byte LF_CONTIG = (byte) '7';
+
+ /// <summary>
+ /// Posix.1 2001 global extended header
+ /// </summary>
+ ///
+ public const byte LF_GHDR = (byte) 'g';
+
+ /// <summary>
+ /// Posix.1 2001 extended header
+ /// </summary>
+ public readonly static byte LF_XHDR = (byte) 'x';
+
+
+
+
+ // POSIX allows for upper case ascii type as extensions
+
+ // Solaris access control list
+ public const byte LF_ACL = (byte) 'A';
+
+ // This is a dir entry that contains the names of files that were in the
+ // dir at the time the dump was made
+ public const byte LF_GNU_DUMPDIR = (byte) 'D';
+
+ // Solaris Extended Attribute File
+ public const byte LF_EXTATTR = (byte) 'E' ;
+
+ // Inode (metadata only) no file content
+ public const byte LF_META = (byte) 'I';
+
+ // Identifies the next file on the tape as having a long link name
+ public const byte LF_GNU_LONGLINK = (byte) 'K';
+
+ // Identifies the next file on the tape as having a long name
+ public const byte LF_GNU_LONGNAME = (byte) 'L';
+
+ // Continuation of a file that began on another volume
+ public const byte LF_GNU_MULTIVOL = (byte) 'M';
+
+ // For storing filenames that dont fit in the main header (old GNU)
+ public const byte LF_GNU_NAMES = (byte) 'N';
+
+ // Sparse file
+ public const byte LF_GNU_SPARSE = (byte) 'S';
+
+ // Tape/volume header ignore on extraction
+ public const byte LF_GNU_VOLHDR = (byte) 'V';
+
+ /// <summary>
+ /// The magic tag representing a POSIX tar archive. (includes trailing NULL)
+ /// </summary>
+ public readonly static string TMAGIC = "ustar ";
+
+ /// <summary>
+ /// The magic tag representing an old GNU tar archive where version is included in magic and overwrites it
+ /// </summary>
+ public readonly static string GNU_TMAGIC = "ustar ";
+
+ /// <summary>
+ /// The entry's name.
+ /// </summary>
+ public StringBuilder name;
+
+ /// <summary>
+ /// The entry's permission mode.
+ /// </summary>
+ public int mode;
+
+ /// <summary>
+ /// The entry's user id.
+ /// </summary>
+ public int userId;
+
+ /// <summary>
+ /// The entry's group id.
+ /// </summary>
+ public int groupId;
+
+ /// <summary>
+ /// The entry's size.
+ /// </summary>
+ public long size;
+
+ /// <summary>
+ /// The entry's modification time.
+ /// </summary>
+ public DateTime modTime;
+
+ /// <summary>
+ /// The entry's checksum.
+ /// </summary>
+ public int checkSum;
+
+ /// <summary>
+ /// The entry's type flag.
+ /// </summary>
+ public byte typeFlag;
+
+ /// <summary>
+ /// The entry's link name.
+ /// </summary>
+ public StringBuilder linkName;
+
+ /// <summary>
+ /// The entry's magic tag.
+ /// </summary>
+ public StringBuilder magic;
+
+ /// <summary>
+ /// The entry's version.
+ /// </summary>
+ public StringBuilder version;
+
+ /// <summary>
+ /// The entry's user name.
+ /// </summary>
+ public StringBuilder userName;
+
+ /// <summary>
+ /// The entry's group name.
+ /// </summary>
+ public StringBuilder groupName;
+
+ /// <summary>
+ /// The entry's major device number.
+ /// </summary>
+ public int devMajor;
+
+ /// <summary>
+ /// The entry's minor device number.
+ /// </summary>
+ public int devMinor;
+
+ public TarHeader()
+ {
+ this.magic = new StringBuilder(TarHeader.TMAGIC);
+ this.version = new StringBuilder(" ");
+
+ this.name = new StringBuilder();
+ this.linkName = new StringBuilder();
+
+ string user = Environment.UserName;
+ // string user = "PocketPC";
+ // string user = "Everyone";
+
+ if (user.Length > 31) {
+ user = user.Substring(0, 31);
+ }
+
+ this.userId = 1003; // -jr- was 0
+ this.groupId = 513; // -jr- was 0
+ this.userName = new StringBuilder(user);
+// -jr-
+// this.groupName = new StringBuilder(String.Empty);
+// this.groupName = new StringBuilder("Everyone"); Attempt2
+ this.groupName = new StringBuilder("None"); // Gnu compatible
+ this.size = 0;
+ }
+
+ /// <summary>
+ /// TarHeaders can be cloned.
+ /// </summary>
+ public object Clone()
+ {
+ TarHeader hdr = new TarHeader();
+
+ hdr.name = (this.name == null) ? null : new StringBuilder(this.name.ToString());
+ hdr.mode = this.mode;
+ hdr.userId = this.userId;
+ hdr.groupId = this.groupId;
+ hdr.size = this.size;
+ hdr.modTime = this.modTime;
+ hdr.checkSum = this.checkSum;
+ hdr.typeFlag = this.typeFlag;
+ hdr.linkName = (this.linkName == null) ? null : new StringBuilder(this.linkName.ToString());
+ hdr.magic = (this.magic == null) ? null : new StringBuilder(this.magic.ToString());
+ hdr.version = (this.version == null) ? null : new StringBuilder(this.version.ToString());
+ hdr.userName = (this.userName == null) ? null : new StringBuilder(this.userName.ToString());
+ hdr.groupName = (this.groupName == null) ? null : new StringBuilder(this.groupName.ToString());
+ hdr.devMajor = this.devMajor;
+ hdr.devMinor = this.devMinor;
+
+ return hdr;
+ }
+
+ /// <summary>
+ /// Get the name of this entry.
+ /// </summary>
+ /// <returns>
+ /// The entry's name.
+ /// </returns>
+ public string GetName()
+ {
+ return this.name.ToString();
+ }
+
+ /// <summary>
+ /// Parse an octal string from a header buffer. This is used for the
+ /// file permission mode value.
+ /// </summary>
+ /// <param name = "header">
+ /// The header buffer from which to parse.
+ /// </param>
+ /// <param name = "offset">
+ /// The offset into the buffer from which to parse.
+ /// </param>
+ /// <param name = "length">
+ /// The number of header bytes to parse.
+ /// </param>
+ /// <returns>
+ /// The long value of the octal string.
+ /// </returns>
+ public static long ParseOctal(byte[] header, int offset, int length)
+ {
+ long result = 0;
+ bool stillPadding = true;
+
+ int end = offset + length;
+ for (int i = offset; i < end ; ++i)
+ {
+ if (header[i] == 0)
+ {
+ break;
+ }
+
+ if (header[i] == (byte)' ' || header[i] == '0')
+ {
+ if (stillPadding)
+ {
+ continue;
+ }
+
+ if (header[i] == (byte)' ')
+ {
+ break;
+ }
+ }
+
+ stillPadding = false;
+
+ result = (result << 3) + (header[i] - '0');
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Parse an entry name from a header buffer.
+ /// </summary>
+ /// <param name="header">
+ /// The header buffer from which to parse.
+ /// </param>
+ /// <param name="offset">
+ /// The offset into the buffer from which to parse.
+ /// </param>
+ /// <param name="length">
+ /// The number of header bytes to parse.
+ /// </param>
+ /// <returns>
+ /// The header's entry name.
+ /// </returns>
+ public static StringBuilder ParseName(byte[] header, int offset, int length)
+ {
+ StringBuilder result = new StringBuilder(length);
+
+ for (int i = offset; i < offset + length; ++i)
+ {
+ if (header[i] == 0)
+ {
+ break;
+ }
+ result.Append((char)header[i]);
+ }
+
+ return result;
+ }
+
+ public static int GetNameBytes(StringBuilder name, int nameOffset, byte[] buf, int bufferOffset, int length)
+ {
+ int i;
+
+ for (i = 0 ; i < length && nameOffset + i < name.Length; ++i)
+ {
+ buf[bufferOffset + i] = (byte)name[nameOffset + i];
+ }
+
+ for (; i < length ; ++i)
+ {
+ buf[bufferOffset + i] = 0;
+ }
+
+ return bufferOffset + length;
+ }
+
+ /// <summary>
+ /// Determine the number of bytes in an entry name.
+ /// </summary>
+ /// <param name="name">
+ /// </param>
+ /// <param name="buf">
+ /// The header buffer from which to parse.
+ /// </param>
+ /// <param name="offset">
+ /// The offset into the buffer from which to parse.
+ /// </param>
+ /// <param name="length">
+ /// The number of header bytes to parse.
+ /// </param>
+ /// <returns>
+ /// The number of bytes in a header's entry name.
+ /// </returns>
+ public static int GetNameBytes(StringBuilder name, byte[] buf, int offset, int length)
+ {
+ return GetNameBytes(name, 0, buf, offset, length);
+ }
+
+ /// <summary>
+ /// Parse an octal integer from a header buffer.
+ /// </summary>
+ /// <param name = "val">
+ /// </param>
+ /// <param name = "buf">
+ /// The header buffer from which to parse.
+ /// </param>
+ /// <param name = "offset">
+ /// The offset into the buffer from which to parse.
+ /// </param>
+ /// <param name = "length">
+ /// The number of header bytes to parse.
+ /// </param>
+ /// <returns>
+ /// The integer value of the octal bytes.
+ /// </returns>
+ public static int GetOctalBytes(long val, byte[] buf, int offset, int length)
+ {
+ // TODO check for values too large...
+
+ int idx = length - 1;
+
+ // Either a space or null is valid here. We use NULL as per GNUTar
+ buf[offset + idx] = 0;
+ --idx;
+
+ if (val > 0)
+ {
+ for (long v = val; idx >= 0 && v > 0; --idx)
+ {
+ buf[offset + idx] = (byte)((byte)'0' + (byte)(v & 7));
+ v >>= 3;
+ }
+ }
+
+ for (; idx >= 0; --idx)
+ {
+ buf[offset + idx] = (byte)'0';
+ }
+
+ return offset + length;
+ }
+
+ /// <summary>
+ /// Parse an octal long integer from a header buffer.
+ /// </summary>
+ /// <param name = "val">
+ /// </param>
+ /// <param name = "buf">
+ /// The header buffer from which to parse.
+ /// </param>
+ /// <param name = "offset">
+ /// The offset into the buffer from which to parse.
+ /// </param>
+ /// <param name = "length">
+ /// The number of header bytes to parse.
+ /// </param>
+ /// <returns>
+ /// The long value of the octal bytes.
+ /// </returns>
+ public static int GetLongOctalBytes(long val, byte[] buf, int offset, int length)
+ {
+ return GetOctalBytes(val, buf, offset, length);
+ }
+
+ /// <summary>
+ /// Add the checksum octal integer to header buffer.
+ /// </summary>
+ /// <param name = "val">
+ /// </param>
+ /// <param name = "buf">
+ /// The header buffer to set the checksum for
+ /// </param>
+ /// <param name = "offset">
+ /// The offset into the buffer for the checksum
+ /// </param>
+ /// <param name = "length">
+ /// The number of header bytes to update.
+ /// It's formatted differently from the other fields: it has 6 digits, a
+ /// null, then a space -- rather than digits, a space, then a null.
+ /// The final space is already there, from checksumming
+
+ /// </param>
+ /// <returns>
+ /// The modified buffer offset
+ /// </returns>
+ private static int GetCheckSumOctalBytes(long val, byte[] buf, int offset, int length)
+ {
+ TarHeader.GetOctalBytes(val, buf, offset, length - 1);
+// buf[offset + length - 1] = (byte)' '; -jr- 23-Jan-2004 this causes failure!!!
+// buf[offset + length - 2] = 0;
+ return offset + length;
+ }
+
+ /// <summary>
+ /// Compute the checksum for a tar entry header.
+ /// The checksum field must be all spaces prior to this happening
+ /// </summary>
+ /// <param name = "buf">
+ /// The tar entry's header buffer.
+ /// </param>
+ /// <returns>
+ /// The computed checksum.
+ /// </returns>
+ private static long ComputeCheckSum(byte[] buf)
+ {
+ long sum = 0;
+ for (int i = 0; i < buf.Length; ++i)
+ {
+ sum += buf[i];
+ }
+ return sum;
+ }
+
+ readonly static long timeConversionFactor = 10000000L; // -jr- 1 tick == 100 nanoseconds
+ readonly static DateTime datetTime1970 = new DateTime(1970, 1, 1, 0, 0, 0, 0);
+// readonly static DateTime datetTime1970 = new DateTime(1970, 1, 1, 0, 0, 0, 0).ToUniversalTime(); // -jr- Should be UTC? doesnt match Gnutar if this is so though, why?
+
+ static int GetCTime(System.DateTime dateTime)
+ {
+ return (int)((dateTime.Ticks - datetTime1970.Ticks) / timeConversionFactor);
+ }
+
+ static DateTime GetDateTimeFromCTime(long ticks)
+ {
+ return new DateTime(datetTime1970.Ticks + ticks * timeConversionFactor);
+ }
+
+ /// <summary>
+ /// Parse TarHeader information from a header buffer.
+ /// </summary>
+ /// <param name = "header">
+ /// The tar entry header buffer to get information from.
+ /// </param>
+ public void ParseBuffer(byte[] header)
+ {
+ int offset = 0;
+
+ name = TarHeader.ParseName(header, offset, TarHeader.NAMELEN);
+ offset += TarHeader.NAMELEN;
+
+ mode = (int)TarHeader.ParseOctal(header, offset, TarHeader.MODELEN);
+ offset += TarHeader.MODELEN;
+
+ userId = (int)TarHeader.ParseOctal(header, offset, TarHeader.UIDLEN);
+ offset += TarHeader.UIDLEN;
+
+ groupId = (int)TarHeader.ParseOctal(header, offset, TarHeader.GIDLEN);
+ offset += TarHeader.GIDLEN;
+
+ size = TarHeader.ParseOctal(header, offset, TarHeader.SIZELEN);
+ offset += TarHeader.SIZELEN;
+
+ modTime = GetDateTimeFromCTime(TarHeader.ParseOctal(header, offset, TarHeader.MODTIMELEN));
+ offset += TarHeader.MODTIMELEN;
+
+ checkSum = (int)TarHeader.ParseOctal(header, offset, TarHeader.CHKSUMLEN);
+ offset += TarHeader.CHKSUMLEN;
+
+ typeFlag = header[ offset++ ];
+
+ linkName = TarHeader.ParseName(header, offset, TarHeader.NAMELEN);
+ offset += TarHeader.NAMELEN;
+
+ magic = TarHeader.ParseName(header, offset, TarHeader.MAGICLEN);
+ offset += TarHeader.MAGICLEN;
+
+ version = TarHeader.ParseName(header, offset, TarHeader.VERSIONLEN);
+ offset += TarHeader.VERSIONLEN;
+
+ userName = TarHeader.ParseName(header, offset, TarHeader.UNAMELEN);
+ offset += TarHeader.UNAMELEN;
+
+ groupName = TarHeader.ParseName(header, offset, TarHeader.GNAMELEN);
+ offset += TarHeader.GNAMELEN;
+
+ devMajor = (int)TarHeader.ParseOctal(header, offset, TarHeader.DEVLEN);
+ offset += TarHeader.DEVLEN;
+
+ devMinor = (int)TarHeader.ParseOctal(header, offset, TarHeader.DEVLEN);
+
+ // Fields past this point not currently parsed or used...
+ }
+
+ /// <summary>
+ /// 'Write' header information to buffer provided
+ /// </summary>
+ /// <param name="outbuf">output buffer for header information</param>
+ public void WriteHeader(byte[] outbuf)
+ {
+ int offset = 0;
+
+ offset = GetNameBytes(this.name, outbuf, offset, TarHeader.NAMELEN);
+ offset = GetOctalBytes(this.mode, outbuf, offset, TarHeader.MODELEN);
+ offset = GetOctalBytes(this.userId, outbuf, offset, TarHeader.UIDLEN);
+ offset = GetOctalBytes(this.groupId, outbuf, offset, TarHeader.GIDLEN);
+
+ long size = this.size;
+
+ offset = GetLongOctalBytes(size, outbuf, offset, TarHeader.SIZELEN);
+ offset = GetLongOctalBytes(GetCTime(this.modTime), outbuf, offset, TarHeader.MODTIMELEN);
+
+ int csOffset = offset;
+ for (int c = 0; c < TarHeader.CHKSUMLEN; ++c)
+ {
+ outbuf[offset++] = (byte)' ';
+ }
+
+ outbuf[offset++] = this.typeFlag;
+
+ offset = GetNameBytes(this.linkName, outbuf, offset, NAMELEN);
+ offset = GetNameBytes(this.magic, outbuf, offset, MAGICLEN);
+ offset = GetNameBytes(this.version, outbuf, offset, VERSIONLEN);
+ offset = GetNameBytes(this.userName, outbuf, offset, UNAMELEN);
+ offset = GetNameBytes(this.groupName, outbuf, offset, GNAMELEN);
+
+ if (this.typeFlag == LF_CHR || this.typeFlag == LF_BLK)
+ {
+ offset = GetOctalBytes(this.devMajor, outbuf, offset, DEVLEN);
+ offset = GetOctalBytes(this.devMinor, outbuf, offset, DEVLEN);
+ }
+
+ for ( ; offset < outbuf.Length; )
+ {
+ outbuf[offset++] = 0;
+ }
+
+ long checkSum = ComputeCheckSum(outbuf);
+
+ GetCheckSumOctalBytes(checkSum, outbuf, csOffset, CHKSUMLEN);
+ }
+ }
+}
+
+/* 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.
+**
+*/
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarInputStream.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarInputStream.cs new file mode 100644 index 00000000000..4ba1de45ea2 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarInputStream.cs @@ -0,0 +1,646 @@ +// 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
+ {
+ protected bool debug;
+ protected bool hasHitEOF;
+
+ protected int entrySize;
+ protected int entryOffset;
+
+ protected byte[] readBuf;
+
+ protected TarBuffer buffer;
+ protected TarEntry currEntry;
+ protected IEntryFactory eFactory;
+
+ Stream inputStream;
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanRead
+ {
+ get
+ {
+ return inputStream.CanRead;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanSeek
+ {
+ // TODO is this valid? should it return false?
+ get
+ {
+ return inputStream.CanSeek;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanWrite
+ {
+ get
+ {
+ return inputStream.CanWrite;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Length
+ {
+ get
+ {
+ return inputStream.Length;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Position
+ {
+ get
+ {
+ return inputStream.Position;
+ }
+ set
+ {
+ inputStream.Position = value;
+ }
+ }
+
+ /// <summary>
+ /// Flushes the baseInputStream
+ /// </summary>
+ public override void Flush()
+ {
+ inputStream.Flush();
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ // TODO allow this?
+ return inputStream.Seek(offset, origin);
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override void SetLength(long val)
+ {
+ inputStream.SetLength(val);
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override void Write(byte[] array, int offset, int count)
+ {
+ inputStream.Write(array, offset, count);
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override void WriteByte(byte val)
+ {
+ inputStream.WriteByte(val);
+ }
+
+
+ public TarInputStream(Stream inputStream) : this(inputStream, TarBuffer.DefaultBlockFactor)
+ {
+ }
+
+ public TarInputStream(Stream inputStream, int blockFactor)
+ {
+ this.inputStream = inputStream;
+ this.buffer = TarBuffer.CreateInputTarBuffer(inputStream, blockFactor);
+
+ this.readBuf = null;
+ this.debug = false;
+ this.hasHitEOF = false;
+ this.eFactory = null;
+ }
+
+ public void SetDebug(bool debugFlag)
+ {
+ this.debug = debugFlag;
+ SetBufferDebug(debugFlag);
+ }
+
+ public void SetBufferDebug(bool debug)
+ {
+ this.buffer.SetDebug(debug);
+ }
+
+
+
+ public void SetEntryFactory(IEntryFactory factory)
+ {
+ this.eFactory = factory;
+ }
+
+ /// <summary>
+ /// Closes this stream. Calls the TarBuffer's close() method.
+ /// The underlying stream is closed by the TarBuffer.
+ /// </summary>
+ public override void Close()
+ {
+ this.buffer.Close();
+ }
+
+ /// <summary>
+ /// Get the record size being used by this stream's TarBuffer.
+ /// </summary>
+ /// <returns>
+ /// TarBuffer record size.
+ /// </returns>
+ public int GetRecordSize()
+ {
+ return this.buffer.GetRecordSize();
+ }
+
+ /// <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 int Available
+ {
+ get
+ {
+ return this.entrySize - this.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="numToSkip">
+ /// The number of bytes to skip.
+ /// </param>
+ public void Skip(int numToSkip)
+ {
+ // TODO REVIEW
+ // This is horribly inefficient, but it ensures that we
+ // properly skip over bytes via the TarBuffer...
+ //
+ byte[] skipBuf = new byte[8 * 1024];
+
+ for (int num = numToSkip; num > 0;)
+ {
+ int numRead = this.Read(skipBuf, 0, (num > skipBuf.Length ? skipBuf.Length : num));
+
+ if (numRead == -1)
+ {
+ break;
+ }
+
+ num -= numRead;
+ }
+ }
+
+ /// <summary>
+ /// Since we do not support marking just yet, we return false.
+ /// </summary>
+ 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()
+ {
+ }
+
+ void SkipToNextEntry()
+ {
+ int numToSkip = this.entrySize - this.entryOffset;
+
+ if (this.debug)
+ {
+ //Console.WriteLine.WriteLine("TarInputStream: SKIP currENTRY '" + this.currEntry.Name + "' SZ " + this.entrySize + " OFF " + this.entryOffset + " skipping " + numToSkip + " bytes");
+ }
+
+ if (numToSkip > 0)
+ {
+ this.Skip(numToSkip);
+ }
+
+ this.readBuf = null;
+ }
+
+ /// <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 (this.hasHitEOF)
+ {
+ return null;
+ }
+
+ if (this.currEntry != null)
+ {
+ SkipToNextEntry();
+ }
+
+ byte[] headerBuf = this.buffer.ReadBlock();
+
+ if (headerBuf == null)
+ {
+ if (this.debug)
+ {
+ //Console.WriteLine.WriteLine("READ NULL BLOCK");
+ }
+
+ this.hasHitEOF = true;
+ }
+ else if (this.buffer.IsEOFBlock(headerBuf))
+ {
+ if (this.debug)
+ {
+ //Console.WriteLine.WriteLine( "READ EOF BLOCK" );
+ }
+
+ this.hasHitEOF = true;
+ }
+
+ if (this.hasHitEOF)
+ {
+ this.currEntry = null;
+ }
+ else
+ {
+ try
+ {
+ TarHeader header = new TarHeader();
+ header.ParseBuffer(headerBuf);
+ this.entryOffset = 0;
+ this.entrySize = (int)header.size;
+
+ StringBuilder longName = null;
+
+ if (header.typeFlag == TarHeader.LF_GNU_LONGNAME)
+ {
+ Console.WriteLine("TarInputStream: Long name found '" + header.name + "' size = " + header.size); // DEBUG
+
+ byte[] nameBuffer = new byte[TarBuffer.BlockSize];
+
+ int numToRead = this.entrySize;
+
+ longName = new StringBuilder();
+
+ while (numToRead > 0)
+ {
+ int numRead = this.Read(nameBuffer, 0, (numToRead > nameBuffer.Length ? nameBuffer.Length : numToRead));
+
+ if (numRead == -1)
+ {
+ throw new InvalidHeaderException("Failed to read long name entry");
+ }
+
+ longName.Append(TarHeader.ParseName(nameBuffer, 0, numRead).ToString());
+ numToRead -= numRead;
+ }
+
+ Console.WriteLine("TarInputStream: Long name is '" + longName.ToString()); // DEBUG
+
+ SkipToNextEntry();
+ headerBuf = this.buffer.ReadBlock();
+ }
+ else if (header.typeFlag == TarHeader.LF_GHDR) // POSIX global extended header
+ {
+ // Ignore things we dont understand completely for now
+ SkipToNextEntry();
+ headerBuf = this.buffer.ReadBlock();
+ }
+ else if (header.typeFlag == TarHeader.LF_XHDR) // POSIX extended header
+ {
+ // Ignore things we dont understand completely for now
+ SkipToNextEntry();
+ headerBuf = this.buffer.ReadBlock();
+ }
+ else if (header.typeFlag == TarHeader.LF_GNU_VOLHDR)
+ {
+ // TODO could show volume name when verbose?
+ SkipToNextEntry();
+ headerBuf = this.buffer.ReadBlock();
+ }
+ else if (header.typeFlag != TarHeader.LF_NORMAL
+ && header.typeFlag != TarHeader.LF_OLDNORM)
+ {
+ // Ignore things we dont understand completely for now
+ SkipToNextEntry();
+ headerBuf = this.buffer.ReadBlock();
+ }
+
+ if (this.eFactory == null)
+ {
+ this.currEntry = new TarEntry(headerBuf);
+ if (longName != null)
+ {
+ this.currEntry.TarHeader.name.Length = 0;
+ this.currEntry.TarHeader.name.Append(longName.ToString());
+ }
+ }
+ else
+ {
+ this.currEntry = this.eFactory.CreateEntry(headerBuf);
+ }
+
+ // TODO -jr- ustar is not the only magic possible by any means
+ // tar, xtar, ...
+ if (!(headerBuf[257] == 'u' && headerBuf[258] == 's' && headerBuf[259] == 't' && headerBuf[260] == 'a' && headerBuf[261] == 'r'))
+ {
+ throw new InvalidHeaderException("header magic is not 'ustar', but '" + headerBuf[257] + headerBuf[258] + headerBuf[259] + headerBuf[260] + headerBuf[261] +
+ "', or (dec) " + ((int)headerBuf[257]) + ", " + ((int)headerBuf[258]) + ", " + ((int)headerBuf[259]) + ", " + ((int)headerBuf[260]) + ", " + ((int)headerBuf[261]));
+ }
+
+ if (this.debug)
+ {
+ //Console.WriteLine.WriteLine("TarInputStream: SET CURRENTRY '" + this.currEntry.Name + "' size = " + this.currEntry.Size);
+ }
+
+ this.entryOffset = 0;
+
+ // TODO REVIEW How do we resolve this discrepancy?!
+ this.entrySize = (int) this.currEntry.Size;
+ }
+ catch (InvalidHeaderException ex)
+ {
+ this.entrySize = 0;
+ this.entryOffset = 0;
+ this.currEntry = null;
+ throw new InvalidHeaderException("bad header in record " + this.buffer.GetCurrentBlockNum() + " block " + this.buffer.GetCurrentBlockNum() + ", " + ex.Message);
+ }
+ }
+ return this.currEntry;
+ }
+
+ /// <summary>
+ /// Reads a byte from the current tar archive entry.
+ /// This method simply calls read(byte[], int, int).
+ /// </summary>
+ public override int ReadByte()
+ {
+ byte[] oneByteBuffer = new byte[1];
+ int num = this.Read(oneByteBuffer, 0, 1);
+ if (num <= 0) // return -1 to indicate that no byte was read.
+ {
+ return -1;
+ }
+ return (int)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="outputBuffer">
+ /// The buffer into which to place bytes read.
+ /// </param>
+ /// <param name="offset">
+ /// The offset at which to place bytes read.
+ /// </param>
+ /// <param name="numToRead">
+ /// 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[] outputBuffer, int offset, int numToRead)
+ {
+ int totalRead = 0;
+
+ if (this.entryOffset >= this.entrySize)
+ {
+ return 0;
+ }
+
+ if ((numToRead + this.entryOffset) > this.entrySize)
+ {
+ numToRead = this.entrySize - this.entryOffset;
+ }
+
+ if (this.readBuf != null)
+ {
+ int sz = (numToRead > this.readBuf.Length) ? this.readBuf.Length : numToRead;
+
+ Array.Copy(this.readBuf, 0, outputBuffer, offset, sz);
+
+ if (sz >= this.readBuf.Length)
+ {
+ this.readBuf = null;
+ }
+ else
+ {
+ int newLen = this.readBuf.Length - sz;
+ byte[] newBuf = new byte[newLen];
+ Array.Copy(this.readBuf, sz, newBuf, 0, newLen);
+ this.readBuf = newBuf;
+ }
+
+ totalRead += sz;
+ numToRead -= sz;
+ offset += sz;
+ }
+
+ while (numToRead > 0)
+ {
+ byte[] rec = this.buffer.ReadBlock();
+ if (rec == null)
+ {
+ // Unexpected EOF!
+ throw new IOException("unexpected EOF with " + numToRead + " bytes unread");
+ }
+
+ int sz = numToRead;
+ int recLen = rec.Length;
+
+ if (recLen > sz)
+ {
+ Array.Copy(rec, 0, outputBuffer, offset, sz);
+ this.readBuf = new byte[recLen - sz];
+ Array.Copy(rec, sz, this.readBuf, 0, recLen - sz);
+ }
+ else
+ {
+ sz = recLen;
+ Array.Copy(rec, 0, outputBuffer, offset, recLen);
+ }
+
+ totalRead += sz;
+ numToRead -= sz;
+ offset += sz;
+ }
+
+ this.entryOffset += totalRead;
+
+ return totalRead;
+ }
+
+ /// <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[] buf = new byte[32 * 1024];
+
+ while (true)
+ {
+ int numRead = this.Read(buf, 0, buf.Length);
+ if (numRead <= 0)
+ {
+ break;
+ }
+ outputStream.Write(buf, 0, numRead);
+ }
+ }
+
+ /// <summary>
+ /// This interface is provided, with the method setEntryFactory(), to allow
+ /// the programmer to have their own TarEntry subclass instantiated for the
+ /// entries return from getNextEntry().
+ /// </summary>
+ public interface IEntryFactory
+ {
+ TarEntry CreateEntry(string name);
+
+ TarEntry CreateEntryFromFile(string fileName);
+
+ TarEntry CreateEntry(byte[] headerBuf);
+ }
+
+ public class EntryFactoryAdapter : IEntryFactory
+ {
+ public TarEntry CreateEntry(string name)
+ {
+ return TarEntry.CreateTarEntry(name);
+ }
+
+ public TarEntry CreateEntryFromFile(string fileName)
+ {
+ return TarEntry.CreateEntryFromFile(fileName);
+ }
+
+ public TarEntry CreateEntry(byte[] headerBuf)
+ {
+ return new TarEntry(headerBuf);
+ }
+ }
+ }
+
+
+}
+
+/* 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.
+ **
+ */
+
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarOutputStream.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarOutputStream.cs new file mode 100644 index 00000000000..632bed33adc --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarOutputStream.cs @@ -0,0 +1,422 @@ +// TarOutputStream.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 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
+ {
+ protected bool debug;
+ protected int currSize;
+ protected int currBytes;
+ protected byte[] blockBuf;
+ protected int assemLen;
+ protected byte[] assemBuf;
+
+ protected TarBuffer buffer;
+ protected Stream outputStream;
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanRead
+ {
+ get
+ {
+ return outputStream.CanRead;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanSeek
+ {
+ get
+ {
+ return outputStream.CanSeek; // -jr- Should be false?
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanWrite
+ {
+ get
+ {
+ return outputStream.CanWrite;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Length
+ {
+ get
+ {
+ return outputStream.Length;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Position
+ {
+ get
+ {
+ return outputStream.Position;
+ }
+ set
+ {
+ outputStream.Position = value;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ return outputStream.Seek(offset, origin);
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override void SetLength(long val)
+ {
+ outputStream.SetLength(val);
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override int ReadByte()
+ {
+ return outputStream.ReadByte();
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override int Read(byte[] b, int off, int len)
+ {
+ return outputStream.Read(b, off, len);
+ }
+
+ public override void Flush()
+ {
+ outputStream.Flush();
+ }
+
+ public TarOutputStream(Stream outputStream) : this(outputStream, TarBuffer.DefaultBlockFactor)
+ {
+ }
+
+ public TarOutputStream(Stream outputStream, int blockFactor)
+ {
+ this.outputStream = outputStream;
+ this.buffer = TarBuffer.CreateOutputTarBuffer(outputStream, blockFactor);
+
+ this.debug = false;
+ this.assemLen = 0;
+ this.assemBuf = new byte[TarBuffer.BlockSize];
+ this.blockBuf = new byte[TarBuffer.BlockSize];
+ }
+
+ /// <summary>
+ /// Sets the debugging flag.
+ /// </summary>
+ /// <param name = "debugFlag">
+ /// True to turn on debugging.
+ /// </param>
+ public void SetDebug(bool debugFlag)
+ {
+ this.debug = debugFlag;
+ SetBufferDebug(debugFlag);
+ }
+
+ public void SetBufferDebug(bool debug)
+ {
+ this.buffer.SetDebug(debug);
+ }
+
+ /// <summary>
+ /// Ends the TAR archive without closing the underlying OutputStream.
+ /// The result is that the EOF record of nulls is written.
+ /// </summary>
+ public void Finish()
+ {
+ this.WriteEOFRecord();
+ }
+
+ /// <summary>
+ /// Ends the TAR archive and closes the underlying OutputStream.
+ /// This means that finish() is called followed by calling the
+ /// TarBuffer's close().
+ /// </summary>
+ public override void Close()
+ {
+ this.Finish();
+ this.buffer.Close();
+ }
+
+ /// <summary>
+ /// Get the record size being used by this stream's TarBuffer.
+ /// </summary>
+ /// <returns>
+ /// The TarBuffer record size.
+ /// </returns>
+ public int GetRecordSize()
+ {
+ return this.buffer.GetRecordSize();
+ }
+
+ /// <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.TarHeader.name.Length > TarHeader.NAMELEN)
+ {
+ TarHeader longHeader = new TarHeader();
+ longHeader.typeFlag = TarHeader.LF_GNU_LONGNAME;
+ longHeader.name.Append("././@LongLink");
+ longHeader.userId = 0;
+ longHeader.groupId = 0;
+ longHeader.groupName.Length = 0;
+ longHeader.userName.Length = 0;
+ longHeader.linkName.Length = 0;
+
+ longHeader.size = entry.TarHeader.name.Length;
+
+ Console.WriteLine("TarOutputStream: PutNext entry Long name found size = " + longHeader.size); // DEBUG
+
+ longHeader.WriteHeader(this.blockBuf);
+ this.buffer.WriteBlock(this.blockBuf); // Add special long filename header block
+
+ int nameCharIndex = 0;
+
+ while (nameCharIndex < entry.TarHeader.name.Length)
+ {
+ TarHeader.GetNameBytes(entry.TarHeader.name, nameCharIndex, this.blockBuf, 0, TarBuffer.BlockSize);
+ nameCharIndex += TarBuffer.BlockSize;
+ this.buffer.WriteBlock(this.blockBuf);
+ }
+ }
+
+ entry.WriteEntryHeader(this.blockBuf);
+ this.buffer.WriteBlock(this.blockBuf);
+
+ this.currBytes = 0;
+
+ this.currSize = entry.IsDirectory ? 0 : (int)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 (this.assemLen > 0)
+ {
+ for (int i = this.assemLen; i < this.assemBuf.Length; ++i)
+ {
+ this.assemBuf[i] = 0;
+ }
+
+ this.buffer.WriteBlock(this.assemBuf);
+
+ this.currBytes += this.assemLen;
+ this.assemLen = 0;
+ }
+
+ if (this.currBytes < this.currSize)
+ {
+ throw new IOException("entry closed at '" + this.currBytes + "' before the '" + this.currSize + "' bytes specified in the header were written");
+ }
+ }
+
+ /// <summary>
+ /// Writes a byte to the current tar archive entry.
+ /// This method simply calls Write(byte[], int, int).
+ /// </summary>
+ /// <param name="b">
+ /// The byte written.
+ /// </param>
+ public override void WriteByte(byte b)
+ {
+ this.Write(new byte[] { b }, 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 = "wBuf">
+ /// The buffer to write to the archive.
+ /// </param>
+ /// <param name = "wOffset">
+ /// The offset in the buffer from which to get bytes.
+ /// </param>
+ /// <param name = "numToWrite">
+ /// The number of bytes to write.
+ /// </param>
+ public override void Write(byte[] wBuf, int wOffset, int numToWrite)
+ {
+ if ((this.currBytes + numToWrite) > this.currSize)
+ {
+ throw new IOException("request to write '" + numToWrite + "' bytes exceeds size in header of '" + this.currSize + "' bytes");
+ }
+
+ //
+ // We have to deal with assembly!!!
+ // The programmer can be writing little 32 byte chunks for all
+ // we know, and we must assemble complete records for writing.
+ // REVIEW Maybe this should be in TarBuffer? Could that help to
+ // eliminate some of the buffer copying.
+ //
+ if (this.assemLen > 0)
+ {
+ if ((this.assemLen + numToWrite ) >= this.blockBuf.Length)
+ {
+ int aLen = this.blockBuf.Length - this.assemLen;
+
+ Array.Copy(this.assemBuf, 0, this.blockBuf, 0, this.assemLen);
+
+ Array.Copy(wBuf, wOffset, this.blockBuf, this.assemLen, aLen);
+
+ this.buffer.WriteBlock(this.blockBuf);
+
+ this.currBytes += this.blockBuf.Length;
+
+ wOffset += aLen;
+ numToWrite -= aLen;
+
+ this.assemLen = 0;
+ }
+ else
+ {// ( (this.assemLen + numToWrite ) < this.blockBuf.length )
+ Array.Copy(wBuf, wOffset, this.assemBuf, this.assemLen, numToWrite);
+ wOffset += numToWrite;
+ this.assemLen += numToWrite;
+ numToWrite -= numToWrite;
+ }
+ }
+
+ //
+ // When we get here we have EITHER:
+ // o An empty "assemble" buffer.
+ // o No bytes to write (numToWrite == 0)
+ //
+ while (numToWrite > 0)
+ {
+ if (numToWrite < this.blockBuf.Length)
+ {
+ Array.Copy(wBuf, wOffset, this.assemBuf, this.assemLen, numToWrite);
+ this.assemLen += numToWrite;
+ break;
+ }
+
+ this.buffer.WriteBlock(wBuf, wOffset);
+
+ int num = this.blockBuf.Length;
+ this.currBytes += num;
+ numToWrite -= num;
+ wOffset += num;
+ }
+ }
+
+ /// <summary>
+ /// Write an EOF (end of archive) record to the tar archive.
+ /// An EOF record consists of a record of all zeros.
+ /// </summary>
+ void WriteEOFRecord()
+ {
+ for (int i = 0; i < this.blockBuf.Length; ++i)
+ {
+ this.blockBuf[i] = 0;
+ }
+ this.buffer.WriteBlock(this.blockBuf);
+ }
+ }
+}
+
+/* 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.
+ **
+ */
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Deflater.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Deflater.cs new file mode 100644 index 00000000000..bb8d4cc3ca8 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Deflater.cs @@ -0,0 +1,542 @@ +// Deflater.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
+{
+
+ /// <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
+ {
+ /// <summary>
+ /// The best and slowest compression level. This tries to find very
+ /// long and distant string repetitions.
+ /// </summary>
+ public static int BEST_COMPRESSION = 9;
+
+ /// <summary>
+ /// The worst but fastest compression level.
+ /// </summary>
+ public static int BEST_SPEED = 1;
+
+ /// <summary>
+ /// The default compression level.
+ /// </summary>
+ public static int DEFAULT_COMPRESSION = -1;
+
+ /// <summary>
+ /// This level won't compress at all but output uncompressed blocks.
+ /// </summary>
+ public static 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 static int DEFLATED = 8;
+
+ /*
+ * 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)
+ *
+ */
+
+ private static int IS_SETDICT = 0x01;
+ private static int IS_FLUSHING = 0x04;
+ private static int IS_FINISHING = 0x08;
+
+ private static int INIT_STATE = 0x00;
+ private static int SETDICT_STATE = 0x01;
+ // private static int INIT_FINISHING_STATE = 0x08;
+ // private static int SETDICT_FINISHING_STATE = 0x09;
+ private static int BUSY_STATE = 0x10;
+ private static int FLUSHING_STATE = 0x14;
+ private static int FINISHING_STATE = 0x1c;
+ private static int FINISHED_STATE = 0x1e;
+ private static int CLOSED_STATE = 0x7f;
+
+ /// <summary>
+ /// Compression level.
+ /// </summary>
+ private int level;
+
+ /// <summary>
+ /// should we include a header.
+ /// </summary>
+ private bool noHeader;
+
+ // /// <summary>
+ // /// Compression strategy.
+ // /// </summary>
+ // private int strategy;
+
+ /// <summary>
+ /// The current state.
+ /// </summary>
+ private int state;
+
+ /// <summary>
+ /// The total bytes of output written.
+ /// </summary>
+ private int totalOut;
+
+ /// <summary>
+ /// The pending output.
+ /// </summary>
+ private DeflaterPending pending;
+
+ /// <summary>
+ /// The deflater engine.
+ /// </summary>
+ private DeflaterEngine engine;
+
+ /// <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="lvl">
+ /// 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 lvl) : this(lvl, false)
+ {
+
+ }
+
+ /// <summary>
+ /// Creates a new deflater with given compression level.
+ /// </summary>
+ /// <param name="lvl">
+ /// the compression level, a value between NO_COMPRESSION
+ /// and BEST_COMPRESSION.
+ /// </param>
+ /// <param name="nowrap">
+ /// true, if we should suppress the deflate header at the
+ /// beginning and the adler checksum at the end of the output. This is
+ /// useful for the GZIP format.
+ /// </param>
+ /// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>
+ public Deflater(int lvl, bool nowrap)
+ {
+ if (lvl == DEFAULT_COMPRESSION) {
+ lvl = 6;
+ } else if (lvl < NO_COMPRESSION || lvl > BEST_COMPRESSION) {
+ throw new ArgumentOutOfRangeException("lvl");
+ }
+
+ pending = new DeflaterPending();
+ engine = new DeflaterEngine(pending);
+ this.noHeader = nowrap;
+ SetStrategy(DeflateStrategy.Default);
+ SetLevel(lvl);
+ Reset();
+ }
+
+
+ /// <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 = (noHeader ? 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 int TotalIn {
+ get {
+ return engine.TotalIn;
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of output bytes so far.
+ /// </summary>
+ public int 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="off">
+ /// the start of the data.
+ /// </param>
+ /// <param name="len">
+ /// the length of the data.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// if the buffer was finished() or ended() or if previous input is still pending.
+ /// </exception>
+ public void SetInput(byte[] input, int off, int len)
+ {
+ if ((state & IS_FINISHING) != 0) {
+ throw new InvalidOperationException("finish()/end() already called");
+ }
+ engine.SetInput(input, off, len);
+ }
+
+ /// <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="lvl">
+ /// the new compression level.
+ /// </param>
+ public void SetLevel(int lvl)
+ {
+ if (lvl == DEFAULT_COMPRESSION) {
+ lvl = 6;
+ } else if (lvl < NO_COMPRESSION || lvl > BEST_COMPRESSION) {
+ throw new ArgumentOutOfRangeException("lvl");
+ }
+
+ if (level != lvl) {
+ level = lvl;
+ engine.SetLevel(lvl);
+ }
+ }
+
+ /// <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="stgy">
+ /// the new compression strategy.
+ /// </param>
+ public void SetStrategy(DeflateStrategy stgy)
+ {
+ engine.Strategy = stgy;
+ }
+
+ /// <summary>
+ /// Deflates the current input block to the given array. It returns
+ /// the number of bytes compressed, or 0 if either
+ /// needsInput() or finished() returns true or length is zero.
+ /// </summary>
+ /// <param name="output">
+ /// the buffer where to write the compressed data.
+ /// </param>
+ public int Deflate(byte[] output)
+ {
+ return Deflate(output, 0, output.Length);
+ }
+
+ /// <summary>
+ /// Deflates the current input block to the given array. It returns
+ /// the number of bytes compressed, or 0 if either
+ /// needsInput() or finished() returns true or length is zero.
+ /// </summary>
+ /// <param name="output">
+ /// the buffer where to write the compressed data.
+ /// </param>
+ /// <param name="offset">
+ /// the offset into the output array.
+ /// </param>
+ /// <param name="length">
+ /// the maximum number of bytes that may be written.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// if end() was called.
+ /// </exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// if offset and/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
+ * are 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();
+ /* We have completed the stream */
+ if (!noHeader) {
+ 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="dict">
+ /// 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[] dict)
+ {
+ SetDictionary(dict, 0, dict.Length);
+ }
+
+ /// <summary>
+ /// Sets the dictionary which should be used in the deflate process.
+ /// The dictionary should be 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="dict">
+ /// the dictionary.
+ /// </param>
+ /// <param name="offset">
+ /// an offset into the dictionary.
+ /// </param>
+ /// <param name="length">
+ /// the length of 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[] dict, int offset, int length)
+ {
+ if (state != INIT_STATE) {
+ throw new InvalidOperationException();
+ }
+
+ state = SETDICT_STATE;
+ engine.SetDictionary(dict, offset, length);
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/DeflaterConstants.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/DeflaterConstants.cs new file mode 100644 index 00000000000..8e2be6e21ca --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/DeflaterConstants.cs @@ -0,0 +1,85 @@ +// DeflaterConstants.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
+{
+
+ /// <summary>
+ /// This class contains constants used for the deflater.
+ /// </summary>
+ public class DeflaterConstants
+ {
+ public const bool DEBUGGING = false;
+
+ public const int STORED_BLOCK = 0;
+ public const int STATIC_TREES = 1;
+ public const int DYN_TREES = 2;
+ public const int PRESET_DICT = 0x20;
+
+ public const int DEFAULT_MEM_LEVEL = 8;
+
+ public const int MAX_MATCH = 258;
+ public const int MIN_MATCH = 3;
+
+ public const int MAX_WBITS = 15;
+ public const int WSIZE = 1 << MAX_WBITS;
+ public const int WMASK = WSIZE - 1;
+
+ public const int HASH_BITS = DEFAULT_MEM_LEVEL + 7;
+ public const int HASH_SIZE = 1 << HASH_BITS;
+ public const int HASH_MASK = HASH_SIZE - 1;
+ public const int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH;
+
+ public const int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;
+ public const int MAX_DIST = WSIZE - MIN_LOOKAHEAD;
+
+ public const int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8);
+ public static int MAX_BLOCK_SIZE = Math.Min(65535, PENDING_BUF_SIZE-5);
+
+ public const int DEFLATE_STORED = 0;
+ public const int DEFLATE_FAST = 1;
+ public const int DEFLATE_SLOW = 2;
+
+ public static int[] GOOD_LENGTH = { 0, 4, 4, 4, 4, 8, 8, 8, 32, 32 };
+ public static int[] MAX_LAZY = { 0, 4, 5, 6, 4,16, 16, 32, 128, 258 };
+ public static int[] NICE_LENGTH = { 0, 8,16,32,16,32,128,128, 258, 258 };
+ public static int[] MAX_CHAIN = { 0, 4, 8,32,16,32,128,256,1024,4096 };
+ public static int[] COMPR_FUNC = { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2 };
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/DeflaterEngine.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/DeflaterEngine.cs new file mode 100644 index 00000000000..c543f850980 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/DeflaterEngine.cs @@ -0,0 +1,653 @@ +// DeflaterEngine.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.Checksums;
+
+namespace ICSharpCode.SharpZipLib.Zip.Compression
+{
+
+ public enum DeflateStrategy
+ {
+ // The default strategy.
+ Default = 0,
+
+ // This strategy will only allow longer string repetitions. It is
+ // useful for random data with a small character set.
+ Filtered = 1,
+
+ // 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.
+ HuffmanOnly = 2
+ }
+
+ public class DeflaterEngine : DeflaterConstants
+ {
+ static int TOO_FAR = 4096;
+
+ int ins_h;
+ // private byte[] buffer;
+ short[] head;
+ short[] prev;
+
+ int matchStart, matchLen;
+ bool prevAvailable;
+ int blockStart;
+ int strstart, lookahead;
+ byte[] window;
+
+ DeflateStrategy strategy;
+ int max_chain, max_lazy, niceLength, goodLength;
+
+ /// <summary>
+ /// The current compression function.
+ /// </summary>
+ int comprFunc;
+
+ /// <summary>
+ /// The input data for compression.
+ /// </summary>
+ byte[] inputBuf;
+
+ /// <summary>
+ /// The total bytes of input read.
+ /// </summary>
+ int 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;
+
+ 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 a implementation deficiency, that
+ * we cannot build a repeat pattern at index 0.
+ */
+ blockStart = strstart = 1;
+ }
+
+ 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;
+ }
+ }
+
+ public void ResetAdler()
+ {
+ adler.Reset();
+ }
+
+ public int Adler {
+ get {
+ return (int)adler.Value;
+ }
+ }
+
+ public int TotalIn {
+ get {
+ return totalIn;
+ }
+ }
+
+ public DeflateStrategy Strategy {
+ get {
+ return strategy;
+ }
+ set {
+ strategy = value;
+ }
+ }
+
+ public void SetLevel(int lvl)
+ {
+ goodLength = DeflaterConstants.GOOD_LENGTH[lvl];
+ max_lazy = DeflaterConstants.MAX_LAZY[lvl];
+ niceLength = DeflaterConstants.NICE_LENGTH[lvl];
+ max_chain = DeflaterConstants.MAX_CHAIN[lvl];
+
+ if (DeflaterConstants.COMPR_FUNC[lvl] != comprFunc) {
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("Change from "+comprFunc +" to "
+ // + DeflaterConstants.COMPR_FUNC[lvl]);
+ // }
+ switch (comprFunc) {
+ 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;
+ }
+ comprFunc = COMPR_FUNC[lvl];
+ }
+ }
+
+ void UpdateHash()
+ {
+ // if (DEBUGGING) {
+ // //Console.WriteLine("updateHash: "+strstart);
+ // }
+ ins_h = (window[strstart] << HASH_SHIFT) ^ window[strstart + 1];
+ }
+
+ int InsertString()
+ {
+ short match;
+ int hash = ((ins_h << HASH_SHIFT) ^ window[strstart + (MIN_MATCH -1)]) & HASH_MASK;
+
+ // if (DEBUGGING) {
+ // if (hash != (((window[strstart] << (2*HASH_SHIFT)) ^
+ // (window[strstart + 1] << HASH_SHIFT) ^
+ // (window[strstart + 2])) & HASH_MASK)) {
+ // throw new Exception("hash inconsistent: "+hash+"/"
+ // +window[strstart]+","
+ // +window[strstart+1]+","
+ // +window[strstart+2]+","+HASH_SHIFT);
+ // }
+ // }
+
+ prev[strstart & WMASK] = match = head[hash];
+ head[hash] = (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);
+ }
+ }
+
+ 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();
+ }
+ }
+
+ 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 (DeflaterConstants.DEBUGGING && strstart > 2 * WSIZE - MIN_LOOKAHEAD) {
+ throw new InvalidOperationException("need lookahead");
+ }
+
+ do {
+ if (DeflaterConstants.DEBUGGING && curMatch >= strstart) {
+ throw new InvalidOperationException("future match");
+ }
+ 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) ;
+
+ if (scan > best_end) {
+ // if (DeflaterConstants.DEBUGGING && ins_h == 0)
+ // System.err.println("Found match: "+curMatch+"-"+(scan-strstart));
+ 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;
+ }
+
+ public void SetDictionary(byte[] buffer, int offset, int length)
+ {
+ if (DeflaterConstants.DEBUGGING && strstart != 1) {
+ throw new InvalidOperationException("strstart not 1");
+ }
+ 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;
+ }
+
+ bool DeflateStored(bool flush, bool finish)
+ {
+ if (!flush && lookahead == 0) {
+ return false;
+ }
+
+ strstart += lookahead;
+ lookahead = 0;
+
+ int storedLen = strstart - blockStart;
+
+ if ((storedLen >= DeflaterConstants.MAX_BLOCK_SIZE) || /* Block is full */
+ (blockStart < WSIZE && storedLen >= MAX_DIST) || /* Block may move out of window */
+ flush) {
+ bool lastBlock = finish;
+ if (storedLen > DeflaterConstants.MAX_BLOCK_SIZE) {
+ storedLen = DeflaterConstants.MAX_BLOCK_SIZE;
+ lastBlock = false;
+ }
+
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("storedBlock["+storedLen+","+lastBlock+"]");
+ // }
+
+ huffman.FlushStoredBlock(window, blockStart, storedLen, lastBlock);
+ blockStart += storedLen;
+ return !lastBlock;
+ }
+ return true;
+ }
+
+ private 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 need 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 (DeflaterConstants.DEBUGGING) {
+ // for (int i = 0 ; i < matchLen; i++) {
+ // if (window[strstart+i] != window[matchStart + i]) {
+ // throw new Exception();
+ // }
+ // }
+ // }
+
+ // -jr- Hak hak hak this stops problems with fast/low compression and index out of range
+ if (huffman.TallyDist(strstart - matchStart, matchLen)) {
+ bool lastBlock = finish && lookahead == 0;
+ huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock);
+ blockStart = strstart;
+ }
+
+ 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;
+ 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 (DeflaterConstants.DEBUGGING && !flush) {
+ throw new Exception("Not flushing, but no lookahead");
+ }
+ huffman.FlushBlock(window, blockStart, strstart - blockStart,
+ finish);
+ blockStart = strstart;
+ return false;
+ }
+
+ if (strstart >= 2 * WSIZE - MIN_LOOKAHEAD) {
+ /* slide window, as findLongestMatch need 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 > TOO_FAR))) {
+ matchLen = MIN_MATCH - 1;
+ }
+ }
+ }
+
+ /* previous match was better */
+ if (prevLen >= MIN_MATCH && matchLen <= prevLen) {
+ // if (DeflaterConstants.DEBUGGING) {
+ // for (int i = 0 ; i < matchLen; i++) {
+ // if (window[strstart-1+i] != window[prevMatch + i])
+ // throw new Exception();
+ // }
+ // }
+ 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;
+ }
+
+ public bool Deflate(bool flush, bool finish)
+ {
+ bool progress;
+ do {
+ FillWindow();
+ bool canFlush = flush && inputOff == inputEnd;
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("window: ["+blockStart+","+strstart+","
+ // +lookahead+"], "+comprFunc+","+canFlush);
+ // }
+ switch (comprFunc) {
+ 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 comprFunc");
+ }
+ } while (pending.IsFlushed && progress); /* repeat while we have no pending output and progress was made */
+ return progress;
+ }
+
+ public void SetInput(byte[] buf, int off, int len)
+ {
+ if (inputOff < inputEnd) {
+ throw new InvalidOperationException("Old input was not completely processed");
+ }
+
+ int end = off + len;
+
+ /* We want to throw an ArrayIndexOutOfBoundsException early. The
+ * check is very tricky: it also handles integer wrap around.
+ */
+ if (0 > off || off > end || end > buf.Length) {
+ throw new ArgumentOutOfRangeException();
+ }
+
+ inputBuf = buf;
+ inputOff = off;
+ inputEnd = end;
+ }
+
+ public bool NeedsInput()
+ {
+ return inputEnd == inputOff;
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/DeflaterHuffman.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/DeflaterHuffman.cs new file mode 100644 index 00000000000..ebf9beade37 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/DeflaterHuffman.cs @@ -0,0 +1,780 @@ +// DeflaterHuffman.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
+{
+
+ /// <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
+ {
+ private static int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6);
+ private static int LITERAL_NUM = 286;
+ private static int DIST_NUM = 30;
+ private static int BITLEN_NUM = 19;
+ private static int REP_3_6 = 16;
+ private static int REP_3_10 = 17;
+ private static int REP_11_138 = 18;
+ private static int EOF_SYMBOL = 256;
+ private static int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+
+ private static byte[] bit4Reverse = {
+ 0,
+ 8,
+ 4,
+ 12,
+ 2,
+ 10,
+ 6,
+ 14,
+ 1,
+ 9,
+ 5,
+ 13,
+ 3,
+ 11,
+ 7,
+ 15
+ };
+
+ public class Tree
+ {
+ public short[] freqs;
+ public byte[] length;
+ public int minNumCodes, numCodes;
+
+ short[] codes;
+ int[] bl_counts;
+ int maxLength;
+ DeflaterHuffman dh;
+
+ 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];
+ }
+
+ 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]);
+ }
+
+ 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 Exception();
+ }
+ //Console.WriteLine("checkEmpty suceeded!");
+ }
+
+ public void SetStaticCodes(short[] stCodes, byte[] stLength)
+ {
+ codes = stCodes;
+ length = stLength;
+ }
+
+ 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); // HACK : Integer.toHexString(
+ // }
+ }
+ if (DeflaterConstants.DEBUGGING && code != 65536) {
+ throw new Exception("Inconsistent bl_counts!");
+ }
+
+ 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]+")," // HACK : Integer.toHexString(
+ // +bits);
+ // }
+ codes[i] = BitReverse(nextCode[bits-1]);
+ nextCode[bits-1] += 1 << (16 - bits);
+ }
+ }
+ }
+
+ 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
+ * amount 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]]);
+ // }
+ // }
+ }
+
+ 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 Exception("Weird!");
+ }
+ BuildLength(childs);
+ }
+
+ public int GetEncodedLength()
+ {
+ int len = 0;
+ for (int i = 0; i < freqs.Length; i++) {
+ len += freqs[i] * length[i];
+ }
+ return len;
+ }
+
+ 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]++;
+ }
+ }
+ }
+
+ 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);
+ }
+ }
+ }
+ }
+
+ public DeflaterPending pending;
+ private Tree literalTree, distTree, blTree;
+
+ private short[] d_buf;
+ private byte[] l_buf;
+ private int last_lit;
+ private int extra_bits;
+
+ private static short[] staticLCodes;
+ private static byte[] staticLLength;
+ private static short[] staticDCodes;
+ private static byte[] staticDLength;
+
+ /// <summary>
+ /// Reverse the bits of a 16 bit value.
+ /// </summary>
+ public static short BitReverse(int value)
+ {
+ return (short) (bit4Reverse[value & 0xF] << 12 |
+ bit4Reverse[(value >> 4) & 0xF] << 8 |
+ bit4Reverse[(value >> 8) & 0xF] << 4 |
+ bit4Reverse[value >> 12]);
+ }
+
+
+ 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;
+ }
+
+ /* Distant 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;
+ }
+ }
+
+ 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];
+ }
+
+ public void Reset()
+ {
+ last_lit = 0;
+ extra_bits = 0;
+ literalTree.Reset();
+ distTree.Reset();
+ blTree.Reset();
+ }
+
+ int Lcode(int len)
+ {
+ if (len == 255) {
+ return 285;
+ }
+
+ int code = 257;
+ while (len >= 8) {
+ code += 4;
+ len >>= 1;
+ }
+ return code + len;
+ }
+
+ int Dcode(int distance)
+ {
+ int code = 0;
+ while (distance >= 4) {
+ code += 2;
+ distance >>= 1;
+ }
+ return code + distance;
+ }
+
+ 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 (DeflaterConstants.DEBUGGING) {
+ // blTree.CheckEmpty();
+ // }
+ }
+
+ 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 (DeflaterConstants.DEBUGGING) {
+ // Console.Write("EOF: ");
+ // }
+ literalTree.WriteSymbol(EOF_SYMBOL);
+ // if (DeflaterConstants.DEBUGGING) {
+ // literalTree.CheckEmpty();
+ // distTree.CheckEmpty();
+ // }
+ }
+
+ public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
+ {
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("Flushing stored block "+ storedLength);
+ // }
+ pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3);
+ pending.AlignToByte();
+ pending.WriteShort(storedLength);
+ pending.WriteShort(~storedLength);
+ pending.WriteBlock(stored, storedOffset, storedLength);
+ Reset();
+ }
+
+ 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();
+ }
+ }
+
+ public bool IsFull()
+ {
+// return last_lit + 16 >= BUFSIZE; // HACK: This was == 'last_lit == BUFSIZE', but errors occured with DeflateFast
+ return last_lit >= BUFSIZE; // -jr- This is the correct form!
+ }
+
+ public bool TallyLit(int lit)
+ {
+ // 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)lit;
+ literalTree.freqs[lit]++;
+ return IsFull();
+ }
+
+ public bool TallyDist(int dist, int len)
+ {
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("["+dist+","+len+"]");
+ // }
+
+ d_buf[last_lit] = (short)dist;
+ l_buf[last_lit++] = (byte)(len - 3);
+
+ int lc = Lcode(len - 3);
+ literalTree.freqs[lc]++;
+ if (lc >= 265 && lc < 285) {
+ extra_bits += (lc - 261) / 4;
+ }
+
+ int dc = Dcode(dist - 1);
+ distTree.freqs[dc]++;
+ if (dc >= 4) {
+ extra_bits += dc / 2 - 1;
+ }
+ return IsFull();
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/DeflaterPending.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/DeflaterPending.cs new file mode 100644 index 00000000000..8144ff35e61 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/DeflaterPending.cs @@ -0,0 +1,52 @@ +// DeflaterPending.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.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
+ {
+ public DeflaterPending() : base(DeflaterConstants.PENDING_BUF_SIZE)
+ {
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Inflater.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Inflater.cs new file mode 100644 index 00000000000..b915c8ffe7d --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Inflater.cs @@ -0,0 +1,782 @@ +// Inflater.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.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 rfc1950.
+ ///
+ /// 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>needsInput() returns true because the input buffer is empty.
+ /// You have to provide more input with <code>setInput()</code>.
+ /// NOTE: needsInput() also returns true when, the stream is finished.
+ /// </li>
+ /// <li>needsDictionary() returns true, you have to provide a preset
+ /// dictionary with <code>setDictionary()</code>.</li>
+ /// <li>finished() 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
+ {
+ /// <summary>
+ /// Copy lengths for literal codes 257..285
+ /// </summary>
+ private static 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>
+ private static 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>
+ private static 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>
+ private static 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>
+ /// This are the state in which the inflater can be.
+ /// </summary>
+ private const int DECODE_HEADER = 0;
+ private const int DECODE_DICT = 1;
+ private const int DECODE_BLOCKS = 2;
+ private const int DECODE_STORED_LEN1 = 3;
+ private const int DECODE_STORED_LEN2 = 4;
+ private const int DECODE_STORED = 5;
+ private const int DECODE_DYN_HEADER = 6;
+ private const int DECODE_HUFFMAN = 7;
+ private const int DECODE_HUFFMAN_LENBITS = 8;
+ private const int DECODE_HUFFMAN_DIST = 9;
+ private const int DECODE_HUFFMAN_DISTBITS = 10;
+ private const int DECODE_CHKSUM = 11;
+ private const int FINISHED = 12;
+
+ /// <summary>
+ /// This variable contains the current state.
+ /// </summary>
+ private 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>
+ private 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>
+ private int neededBits;
+ private int repLength, repDist;
+ private 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>
+ private bool isLastBlock;
+
+ /// <summary>
+ /// The total number of inflated bytes.
+ /// </summary>
+ private int totalOut;
+
+ /// <summary>
+ /// The total number of bytes set with setInput(). This is not the
+ /// value returned by getTotalIn(), since this also includes the
+ /// unprocessed input.
+ /// </summary>
+ private int totalIn;
+
+ /// <summary>
+ /// This variable stores the nowrap flag that was given to the constructor.
+ /// True means, that the inflated stream doesn't contain a header nor the
+ /// checksum in the footer.
+ /// </summary>
+ private bool nowrap;
+
+ private StreamManipulator input;
+ private OutputWindow outputWindow;
+ private InflaterDynHeader dynHeader;
+ private InflaterHuffmanTree litlenTree, distTree;
+ private Adler32 adler;
+
+ /// <summary>
+ /// Creates a new inflater.
+ /// </summary>
+ public Inflater() : this(false)
+ {
+ }
+
+ /// <summary>
+ /// Creates a new inflater.
+ /// </summary>
+ /// <param name="nowrap">
+ /// true if no header and checksum field appears in the
+ /// stream. This is used for GZIPed input. For compatibility with
+ /// Sun JDK you should provide one byte of input more than needed in
+ /// this case.
+ /// </param>
+ public Inflater(bool nowrap)
+ {
+ this.nowrap = nowrap;
+ this.adler = new Adler32();
+ input = new StreamManipulator();
+ outputWindow = new OutputWindow();
+ mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER;
+ }
+
+ /// <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 = nowrap ? DECODE_BLOCKS : DECODE_HEADER;
+ totalIn = totalOut = 0;
+ input.Reset();
+ outputWindow.Reset();
+ dynHeader = null;
+ litlenTree = null;
+ distTree = null;
+ isLastBlock = false;
+ adler.Reset();
+ }
+
+ /// <summary>
+ /// Decodes the deflate header.
+ /// </summary>
+ /// <returns>
+ /// false if more input is needed.
+ /// </returns>
+ /// <exception cref="System.FormatException">
+ /// if 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 FormatException("Header checksum illegal");
+ }
+
+ if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) {
+ throw new FormatException("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="System.FormatException">
+ /// 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 FormatException("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 FormatException("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 FormatException();
+ }
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Decodes the adler checksum after the deflate stream.
+ /// </summary>
+ /// <returns>
+ /// false if more input is needed.
+ /// </returns>
+ /// <exception cref="System.FormatException">
+ /// DataFormatException, 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 FormatException("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="System.FormatException">
+ /// DataFormatException, 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 (nowrap) {
+ 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 FormatException("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 FormatException("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 FormatException();
+ }
+ }
+
+ /// <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>
+ /// <exception cref="System.InvalidOperationException">
+ /// if no dictionary is needed.
+ /// </exception>
+ /// <exception cref="System.ArgumentException">
+ /// if the dictionary checksum is wrong.
+ /// </exception>
+ 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="off">
+ /// the offset into buffer where the dictionary starts.
+ /// </param>
+ /// <param name="len">
+ /// the length of the dictionary.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// if no dictionary is needed.
+ /// </exception>
+ /// <exception cref="System.ArgumentException">
+ /// if the dictionary checksum is wrong.
+ /// </exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// if the off and/or len are wrong.
+ /// </exception>
+ public void SetDictionary(byte[] buffer, int off, int len)
+ {
+ if (!IsNeedingDictionary) {
+ throw new InvalidOperationException();
+ }
+
+ adler.Update(buffer, off, len);
+ if ((int)adler.Value != readAdler) {
+ throw new ArgumentException("Wrong adler checksum");
+ }
+ adler.Reset();
+ outputWindow.CopyDict(buffer, off, len);
+ mode = DECODE_BLOCKS;
+ }
+
+ /// <summary>
+ /// Sets the input. This should only be called, if needsInput()
+ /// returns true.
+ /// </summary>
+ /// <param name="buf">
+ /// the input.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// if no input is needed.
+ /// </exception>
+ public void SetInput(byte[] buf)
+ {
+ SetInput(buf, 0, buf.Length);
+ }
+
+ /// <summary>
+ /// Sets the input. This should only be called, if needsInput()
+ /// returns true.
+ /// </summary>
+ /// <param name="buf">
+ /// the input.
+ /// </param>
+ /// <param name="off">
+ /// the offset into buffer where the input starts.
+ /// </param>
+ /// <param name="len">
+ /// the length of the input.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// if no input is needed.
+ /// </exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// if the off and/or len are wrong.
+ /// </exception>
+ public void SetInput(byte[] buf, int off, int len)
+ {
+ input.SetInput(buf, off, len);
+ totalIn += len;
+ }
+
+ /// <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 = "buf">
+ /// 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 buf has length 0.
+ /// </exception>
+ /// <exception cref="System.FormatException">
+ /// if deflated stream is invalid.
+ /// </exception>
+ public int Inflate(byte[] buf)
+ {
+ return Inflate(buf, 0, buf.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 = "buf">
+ /// the output buffer.
+ /// </param>
+ /// <param name = "off">
+ /// the offset into buffer where the output should start.
+ /// </param>
+ /// <param name = "len">
+ /// the maximum length of the 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 len is <= 0.
+ /// </exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// if the off and/or len are wrong.
+ /// </exception>
+ /// <exception cref="System.FormatException">
+ /// if deflated stream is invalid.
+ /// </exception>
+ public int Inflate(byte[] buf, int off, int len)
+ {
+ if (len < 0) {
+ throw new ArgumentOutOfRangeException("len < 0");
+ }
+ // Special case: len may be zero
+ if (len == 0) {
+ if (IsFinished == false) {// -jr- 08-Nov-2003 INFLATE_BUG fix..
+ Decode();
+ }
+ return 0;
+ }
+ /* // Check for correct buff, off, len triple
+ if (off < 0 || off + len >= buf.Length) {
+ throw new ArgumentException("off/len outside buf bounds");
+ }*/
+ int count = 0;
+ int more;
+ 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:
+ * needsInput() and not finished()
+ * implies more output can be produced.
+ */
+ more = outputWindow.CopyOutput(buf, off, len);
+ adler.Update(buf, off, more);
+ off += more;
+ count += more;
+ totalOut += more;
+ len -= more;
+ if (len == 0) {
+ return count;
+ }
+ }
+ } while (Decode() || (outputWindow.GetAvailable() > 0 && mode != DECODE_CHKSUM));
+ return count;
+ }
+
+ /// <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 int 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 int TotalIn {
+ get {
+ return totalIn - RemainingInput;
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of unprocessed input. 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 were not processed.
+ /// </returns>
+ public int RemainingInput {
+ get {
+ return input.AvailableBytes;
+ }
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/InflaterDynHeader.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/InflaterDynHeader.cs new file mode 100644 index 00000000000..653c7847cea --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/InflaterDynHeader.cs @@ -0,0 +1,207 @@ +// 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
+ {
+ 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 };
+
+ byte[] blLens;
+ byte[] litdistLens;
+
+ InflaterHuffmanTree blTree;
+
+ int mode;
+ int lnum, dnum, blnum, num;
+ int repSymbol;
+ byte lastLen;
+ int ptr;
+
+ static readonly int[] BL_ORDER =
+ { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+
+ public InflaterDynHeader()
+ {
+ }
+
+ 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 Exception();
+ }
+ }
+ 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 Exception();
+ }
+ 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);
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/InflaterHuffmanTree.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/InflaterHuffmanTree.cs new file mode 100644 index 00000000000..02beb60a34c --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/InflaterHuffmanTree.cs @@ -0,0 +1,213 @@ +// 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
+{
+
+ public class InflaterHuffmanTree
+ {
+ private static int MAX_BITLEN = 15;
+ private short[] tree;
+
+ public static InflaterHuffmanTree defLitLenTree, 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 ApplicationException("InflaterHuffmanTree: static tree length illegal");
+ }
+ }
+
+ /// <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);
+ }
+
+ private 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 Exception("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;
+ }
+ }
+ }
+ }
+}
+
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/PendingBuffer.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/PendingBuffer.cs new file mode 100644 index 00000000000..e0bc96b9192 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/PendingBuffer.cs @@ -0,0 +1,210 @@ +// PendingBuffer.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
+{
+
+ /// <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
+ {
+ protected byte[] buf;
+ int start;
+ int end;
+
+ uint bits;
+ int bitCount;
+
+ public PendingBuffer() : this( 4096 )
+ {
+
+ }
+
+ public PendingBuffer(int bufsize)
+ {
+ buf = new byte[bufsize];
+ }
+
+ public void Reset()
+ {
+ start = end = bitCount = 0;
+ }
+
+ public void WriteByte(int b)
+ {
+ if (DeflaterConstants.DEBUGGING && start != 0) {
+ throw new Exception();
+ }
+ buf[end++] = (byte) b;
+ }
+
+ public void WriteShort(int s)
+ {
+ if (DeflaterConstants.DEBUGGING && start != 0) {
+ throw new Exception();
+ }
+ buf[end++] = (byte) s;
+ buf[end++] = (byte) (s >> 8);
+ }
+
+ public void WriteInt(int s)
+ {
+ if (DeflaterConstants.DEBUGGING && start != 0) {
+ throw new Exception();
+ }
+ buf[end++] = (byte) s;
+ buf[end++] = (byte) (s >> 8);
+ buf[end++] = (byte) (s >> 16);
+ buf[end++] = (byte) (s >> 24);
+ }
+
+ public void WriteBlock(byte[] block, int offset, int len)
+ {
+ if (DeflaterConstants.DEBUGGING && start != 0) {
+ throw new Exception();
+ }
+ System.Array.Copy(block, offset, buf, end, len);
+ end += len;
+ }
+
+ public int BitCount {
+ get {
+ return bitCount;
+ }
+ }
+
+ public void AlignToByte()
+ {
+ if (DeflaterConstants.DEBUGGING && start != 0) {
+ throw new Exception();
+ }
+ if (bitCount > 0) {
+ buf[end++] = (byte) bits;
+ if (bitCount > 8) {
+ buf[end++] = (byte) (bits >> 8);
+ }
+ }
+ bits = 0;
+ bitCount = 0;
+ }
+
+ public void WriteBits(int b, int count)
+ {
+ if (DeflaterConstants.DEBUGGING && start != 0) {
+ throw new Exception();
+ }
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("writeBits("+b+","+count+")");
+ // }
+ bits |= (uint)(b << bitCount);
+ bitCount += count;
+ if (bitCount >= 16) {
+ buf[end++] = (byte) bits;
+ buf[end++] = (byte) (bits >> 8);
+ bits >>= 16;
+ bitCount -= 16;
+ }
+ }
+
+ public void WriteShortMSB(int s)
+ {
+ if (DeflaterConstants.DEBUGGING && start != 0) {
+ throw new Exception();
+ }
+ buf[end++] = (byte) (s >> 8);
+ buf[end++] = (byte) s;
+ }
+
+ 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">
+ /// length the maximum number of bytes to store;
+ /// </param>
+ /// <exception name="ArgumentOutOfRangeException">
+ /// IndexOutOfBoundsException if offset or length are invalid.
+ /// </exception>
+ public int Flush(byte[] output, int offset, int length)
+ {
+ if (bitCount >= 8) {
+ buf[end++] = (byte) bits;
+ bits >>= 8;
+ bitCount -= 8;
+ }
+ if (length > end - start) {
+ length = end - start;
+ System.Array.Copy(buf, start, output, offset, length);
+ start = 0;
+ end = 0;
+ } else {
+ System.Array.Copy(buf, start, output, offset, length);
+ start += length;
+ }
+ return length;
+ }
+
+ public byte[] ToByteArray()
+ {
+ byte[] ret = new byte[end - start];
+ System.Array.Copy(buf, start, ret, 0, ret.Length);
+ start = 0;
+ end = 0;
+ return ret;
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs new file mode 100644 index 00000000000..dd8c658e843 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs @@ -0,0 +1,379 @@ +// 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.
+
+using System;
+using System.IO;
+using ICSharpCode.SharpZipLib.Checksums;
+using ICSharpCode.SharpZipLib.Zip.Compression;
+
+namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
+{
+
+ /// <summary>
+ /// This is a special FilterOutputStream deflating the bytes that are
+ /// written through it. It uses the Deflater for deflating.
+ ///
+ /// authors of the original java version : Tom Tromey, Jochen Hoenicke
+ /// </summary>
+ public class DeflaterOutputStream : Stream
+ {
+ /// <summary>
+ /// This buffer is used temporarily to retrieve the bytes from the
+ /// deflater and write them to the underlying output stream.
+ /// </summary>
+ protected byte[] buf;
+
+ /// <summary>
+ /// The deflater which is used to deflate the stream.
+ /// </summary>
+ protected Deflater def;
+
+ /// <summary>
+ /// base stream the deflater depends on.
+ /// </summary>
+ protected Stream baseOutputStream;
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanRead {
+ get {
+ return baseOutputStream.CanRead;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanSeek {
+ get {
+ return false;
+// return baseOutputStream.CanSeek;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanWrite {
+ get {
+ return baseOutputStream.CanWrite;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Length {
+ get {
+ return baseOutputStream.Length;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Position {
+ get {
+ return baseOutputStream.Position;
+ }
+ set {
+ baseOutputStream.Position = value;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException("Seek not supported"); // -jr- 01-Dec-2003
+// return baseOutputStream.Seek(offset, origin);
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override void SetLength(long val)
+ {
+ baseOutputStream.SetLength(val);
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override int ReadByte()
+ {
+ return baseOutputStream.ReadByte();
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override int Read(byte[] b, int off, int len)
+ {
+ return baseOutputStream.Read(b, off, len);
+ }
+ // -jr- 01-Dec-2003
+ public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+ {
+ throw new NotSupportedException("Asynch read not currently supported");
+ }
+
+ // -jr- 01-Dec-2003
+ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+ {
+ throw new NotSupportedException("Asynch write not currently supported");
+ }
+
+ /// <summary>
+ /// Deflates everything in the def's input buffers. This will call
+ /// <code>def.deflate()</code> until all bytes from the input buffers
+ /// are processed.
+ /// </summary>
+ protected void Deflate()
+ {
+ while (!def.IsNeedingInput) {
+ int len = def.Deflate(buf, 0, buf.Length);
+
+ // System.err.println("DOS deflated " + len + " baseOutputStream of " + buf.length);
+ if (len <= 0) {
+ break;
+ }
+ baseOutputStream.Write(buf, 0, len);
+ }
+
+ if (!def.IsNeedingInput) {
+ throw new ApplicationException("Can't deflate all input?");
+ }
+ }
+
+ /// <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="defl">
+ /// the underlying deflater.
+ /// </param>
+ public DeflaterOutputStream(Stream baseOutputStream, Deflater defl) :this(baseOutputStream, defl, 512)
+ {
+ }
+
+ /// <summary>
+ /// Creates a new DeflaterOutputStream with the given Deflater and
+ /// buffer size.
+ /// </summary>
+ /// <param name="baseOutputStream">
+ /// the output stream where deflated output should be written.
+ /// </param>
+ /// <param name="defl">
+ /// the underlying deflater.
+ /// </param>
+ /// <param name="bufsize">
+ /// the buffer size.
+ /// </param>
+ /// <exception cref="System.InvalidOperationException">
+ /// if bufsize isn't positive.
+ /// </exception>
+ public DeflaterOutputStream(Stream baseOutputStream, Deflater defl, int bufsize)
+ {
+ this.baseOutputStream = baseOutputStream;
+ if (bufsize <= 0) {
+ throw new InvalidOperationException("bufsize <= 0");
+ }
+ buf = new byte[bufsize];
+ def = defl;
+ }
+
+ /// <summary>
+ /// Flushes the stream by calling flush() on the deflater and then
+ /// on the underlying stream. This ensures that all bytes are
+ /// flushed.
+ /// </summary>
+ public override void Flush()
+ {
+ def.Flush();
+ Deflate();
+ baseOutputStream.Flush();
+ }
+
+ /// <summary>
+ /// Finishes the stream by calling finish() on the deflater.
+ /// </summary>
+ public virtual void Finish()
+ {
+ def.Finish();
+ while (!def.IsFinished) {
+ int len = def.Deflate(buf, 0, buf.Length);
+ if (len <= 0) {
+ break;
+ }
+
+ // kidnthrain encryption alteration
+ if (this.Password != null) {
+ // plain data has been deflated. Now encrypt result
+ this.EncryptBlock(buf, 0, len);
+ }
+
+ baseOutputStream.Write(buf, 0, len);
+ }
+ if (!def.IsFinished) {
+ throw new ApplicationException("Can't deflate all input?");
+ }
+ baseOutputStream.Flush();
+ }
+
+ /// <summary>
+ /// Calls finish () and closes the stream.
+ /// </summary>
+ public override void Close()
+ {
+ Finish();
+ baseOutputStream.Close();
+ }
+
+ /// <summary>
+ /// Writes a single byte to the compressed output stream.
+ /// </summary>
+ /// <param name="bval">
+ /// the byte value.
+ /// </param>
+ public override void WriteByte(byte bval)
+ {
+ byte[] b = new byte[1];
+ b[0] = (byte) bval;
+ Write(b, 0, 1);
+ }
+
+ /// <summary>
+ /// Writes a len bytes from an array to the compressed stream.
+ /// </summary>
+ /// <param name="buf">
+ /// the byte array.
+ /// </param>
+ /// <param name="off">
+ /// the offset into the byte array where to start.
+ /// </param>
+ /// <param name="len">
+ /// the number of bytes to write.
+ /// </param>
+ public override void Write(byte[] buf, int off, int len)
+ {
+ // System.err.println("DOS with off " + off + " and len " + len);
+ def.SetInput(buf, off, len);
+ Deflate();
+ }
+
+ #region Encryption
+ string password = null;
+ uint[] keys = null;
+
+ public string Password {
+ get {
+ return password;
+ }
+ set {
+ password = value;
+ }
+ }
+
+
+ //The beauty of xor-ing bits is that
+ //plain ^ key = enc
+ //and enc ^ key = plain
+ //accordingly, this is the exact same as the decrypt byte
+ //function in InflaterInputStream
+ protected byte EncryptByte()
+ {
+ uint temp = ((keys[2] & 0xFFFF) | 2);
+ return (byte)((temp * (temp ^ 1)) >> 8);
+ }
+
+
+ /// <summary>
+ /// Takes a buffer of data and uses the keys
+ /// that have been previously initialized from a
+ /// password and then updated via a random encryption header
+ /// to encrypt that data
+ /// </summary>
+ protected void EncryptBlock(byte[] buf, int off, int len)
+ {
+ for (int i = off; i < off + len; ++i) {
+ byte oldbyte = buf[i];
+ buf[i] ^= EncryptByte();
+ UpdateKeys(oldbyte);
+ }
+ }
+
+ /// <summary>
+ /// Initializes our encryption keys using a given password
+ /// </summary>
+ protected void InitializePassword(string password) {
+ keys = new uint[] {
+ 0x12345678,
+ 0x23456789,
+ 0x34567890
+ };
+
+ for (int i = 0; i < password.Length; ++i) {
+ UpdateKeys((byte)password[i]);
+ }
+ }
+
+ 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));
+ }
+ #endregion
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs new file mode 100644 index 00000000000..9317e5e185d --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs @@ -0,0 +1,386 @@ +// InflaterInputStream.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.Zip.Compression;
+using ICSharpCode.SharpZipLib.Checksums;
+
+namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
+{
+
+ /// <summary>
+ /// This filter stream is used to decompress data compressed baseInputStream the "deflate"
+ /// format. The "deflate" format is described baseInputStream RFC 1951.
+ ///
+ /// This stream may form the basis for other decompression filters, such
+ /// as the <code>GzipInputStream</code>.
+ ///
+ /// author of the original java version : John Leuner
+ /// </summary>
+ public class InflaterInputStream : Stream
+ {
+ //Variables
+
+ /// <summary>
+ /// Decompressor for this filter
+ /// </summary>
+ protected Inflater inf;
+
+ /// <summary>
+ /// Byte array used as a buffer
+ /// </summary>
+ protected byte[] buf;
+
+ /// <summary>
+ /// Size of buffer
+ /// </summary>
+ protected int len;
+
+ //We just use this if we are decoding one byte at a time with the read() call
+ private byte[] onebytebuffer = new byte[1];
+
+ /// <summary>
+ /// base stream the inflater depends on.
+ /// </summary>
+ protected Stream baseInputStream;
+
+ protected long csize;
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanRead {
+ get {
+ return baseInputStream.CanRead;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanSeek {
+ get {
+ return false;
+ // return baseInputStream.CanSeek;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override bool CanWrite {
+ get {
+ return baseInputStream.CanWrite;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Length {
+ get {
+ return len;
+ }
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Position {
+ get {
+ return baseInputStream.Position;
+ }
+ set {
+ baseInputStream.Position = value;
+ }
+ }
+
+ /// <summary>
+ /// Flushes the baseInputStream
+ /// </summary>
+ public override void Flush()
+ {
+ baseInputStream.Flush();
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException("Seek not supported"); // -jr- 01-Dec-2003
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override void SetLength(long val)
+ {
+ baseInputStream.SetLength(val);
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override void Write(byte[] array, int offset, int count)
+ {
+ baseInputStream.Write(array, offset, count);
+ }
+
+ /// <summary>
+ /// I needed to implement the abstract member.
+ /// </summary>
+ public override void WriteByte(byte val)
+ {
+ baseInputStream.WriteByte(val);
+ }
+
+ // -jr- 01-Dec-2003 This may be flawed for some base streams? Depends on implementation of BeginWrite
+ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+ {
+ throw new NotSupportedException("Asynch write not currently supported");
+ }
+
+ //Constructors
+
+ /// <summary>
+ /// Create an InflaterInputStream with the default decompresseor
+ /// and a default buffer size.
+ /// </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 decompresseor
+ /// and a default buffer size.
+ /// </summary>
+ /// <param name = "baseInputStream">
+ /// the InputStream to read bytes from
+ /// </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 decompresseor
+ /// and a specified buffer size.
+ /// </summary>
+ /// <param name = "baseInputStream">
+ /// the InputStream to read bytes from
+ /// </param>
+ /// <param name = "inf">
+ /// the decompressor used to decompress data read from baseInputStream
+ /// </param>
+ /// <param name = "size">
+ /// size of the buffer to use
+ /// </param>
+ public InflaterInputStream(Stream baseInputStream, Inflater inf, int size)
+ {
+ this.baseInputStream = baseInputStream;
+ this.inf = inf;
+ try {
+ this.len = (int)baseInputStream.Length;
+ } catch (Exception) {
+ // the stream may not support .Length
+ this.len = 0;
+ }
+
+ if (size <= 0) {
+ throw new ArgumentOutOfRangeException("size <= 0");
+ }
+
+ buf = new byte[size]; //Create the buffer
+ }
+
+ //Methods
+
+ /// <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>
+ /// Closes the input stream
+ /// </summary>
+ public override void Close()
+ {
+ baseInputStream.Close();
+ }
+
+ /// <summary>
+ /// Fills the buffer with more data to decompress.
+ /// </summary>
+ protected void Fill()
+ {
+ len = baseInputStream.Read(buf, 0, buf.Length);
+ // decrypting crypted data
+ if (cryptbuffer != null) {
+ DecryptBlock(buf, 0, System.Math.Min((int)(csize - inf.TotalIn), buf.Length));
+ }
+
+ if (len <= 0) {
+ throw new ApplicationException("Deflated stream ends early.");
+ }
+ inf.SetInput(buf, 0, len);
+ }
+
+ /// <summary>
+ /// Reads one byte of decompressed data.
+ ///
+ /// The byte is baseInputStream the lower 8 bits of the int.
+ /// </summary>
+ public override int ReadByte()
+ {
+ int nread = Read(onebytebuffer, 0, 1); //read one byte
+ if (nread > 0) {
+ return onebytebuffer[0] & 0xff;
+ }
+ return -1; // ok
+ }
+
+ /// <summary>
+ /// Decompresses data into the byte array
+ /// </summary>
+ /// <param name ="b">
+ /// the array to read and decompress data into
+ /// </param>
+ /// <param name ="off">
+ /// the offset indicating where the data should be placed
+ /// </param>
+ /// <param name ="len">
+ /// the number of bytes to decompress
+ /// </param>
+ public override int Read(byte[] b, int off, int len)
+ {
+ for (;;) {
+ int count;
+ try {
+ count = inf.Inflate(b, off, len);
+ } catch (Exception e) {
+ throw new ZipException(e.ToString());
+ }
+
+ if (count > 0) {
+ return count;
+ }
+
+ if (inf.IsNeedingDictionary) {
+ throw new ZipException("Need a dictionary");
+ } else if (inf.IsFinished) {
+ return 0;
+ } else if (inf.IsNeedingInput) {
+ Fill();
+ } else {
+ throw new InvalidOperationException("Don't know what to do");
+ }
+ }
+ }
+
+ /// <summary>
+ /// Skip specified number of bytes of uncompressed data
+ /// </summary>
+ /// <param name ="n">
+ /// number of bytes to skip
+ /// </param>
+ public long Skip(long n)
+ {
+ if (n < 0) {
+ throw new ArgumentOutOfRangeException("n");
+ }
+ int len = 2048;
+ if (n < len) {
+ len = (int) n;
+ }
+ byte[] tmp = new byte[len];
+ return (long)baseInputStream.Read(tmp, 0, tmp.Length);
+ }
+
+ #region Encryption stuff
+ protected byte[] cryptbuffer = null;
+
+ uint[] keys = null;
+ protected byte DecryptByte()
+ {
+ uint temp = ((keys[2] & 0xFFFF) | 2);
+ return (byte)((temp * (temp ^ 1)) >> 8);
+ }
+
+ protected void DecryptBlock(byte[] buf, int off, int len)
+ {
+ for (int i = off; i < off + len; ++i) {
+ buf[i] ^= DecryptByte();
+ UpdateKeys(buf[i]);
+ }
+ }
+
+ protected void InitializePassword(string password)
+ {
+ keys = new uint[] {
+ 0x12345678,
+ 0x23456789,
+ 0x34567890
+ };
+ for (int i = 0; i < password.Length; ++i) {
+ UpdateKeys((byte)password[i]);
+ }
+ }
+
+ 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));
+ }
+ #endregion
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Streams/OutputWindow.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Streams/OutputWindow.cs new file mode 100644 index 00000000000..426c1f752d3 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Streams/OutputWindow.cs @@ -0,0 +1,176 @@ +// 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.
+ ///
+ /// author of the original java version : John Leuner
+ /// </summary>
+ public class OutputWindow
+ {
+ private static int WINDOW_SIZE = 1 << 15;
+ private static int WINDOW_MASK = WINDOW_SIZE - 1;
+
+ private byte[] window = new byte[WINDOW_SIZE]; //The window is 2^15 bytes
+ private int windowEnd = 0;
+ private int windowFilled = 0;
+
+ public void Write(int abyte)
+ {
+ if (windowFilled++ == WINDOW_SIZE) {
+ throw new InvalidOperationException("Window full");
+ }
+ window[windowEnd++] = (byte) abyte;
+ windowEnd &= WINDOW_MASK;
+ }
+
+
+ private void SlowRepeat(int repStart, int len, int dist)
+ {
+ while (len-- > 0) {
+ window[windowEnd++] = window[repStart++];
+ windowEnd &= WINDOW_MASK;
+ repStart &= WINDOW_MASK;
+ }
+ }
+
+ public void Repeat(int len, int dist)
+ {
+ if ((windowFilled += len) > WINDOW_SIZE) {
+ throw new InvalidOperationException("Window full");
+ }
+
+ int rep_start = (windowEnd - dist) & WINDOW_MASK;
+ int border = WINDOW_SIZE - len;
+ if (rep_start <= border && windowEnd < border) {
+ if (len <= dist) {
+ System.Array.Copy(window, rep_start, window, windowEnd, len);
+ windowEnd += len;
+ } else {
+ /* We have to copy manually, since the repeat pattern overlaps.
+ */
+ while (len-- > 0) {
+ window[windowEnd++] = window[rep_start++];
+ }
+ }
+ } else {
+ SlowRepeat(rep_start, len, dist);
+ }
+ }
+
+ public int CopyStored(StreamManipulator input, int len)
+ {
+ len = Math.Min(Math.Min(len, WINDOW_SIZE - windowFilled), input.AvailableBytes);
+ int copied;
+
+ int tailLen = WINDOW_SIZE - windowEnd;
+ if (len > tailLen) {
+ copied = input.CopyBytes(window, windowEnd, tailLen);
+ if (copied == tailLen) {
+ copied += input.CopyBytes(window, 0, len - tailLen);
+ }
+ } else {
+ copied = input.CopyBytes(window, windowEnd, len);
+ }
+
+ windowEnd = (windowEnd + copied) & WINDOW_MASK;
+ windowFilled += copied;
+ return copied;
+ }
+
+ public void CopyDict(byte[] dict, int offset, int len)
+ {
+ if (windowFilled > 0) {
+ throw new InvalidOperationException();
+ }
+
+ if (len > WINDOW_SIZE) {
+ offset += len - WINDOW_SIZE;
+ len = WINDOW_SIZE;
+ }
+ System.Array.Copy(dict, offset, window, 0, len);
+ windowEnd = len & WINDOW_MASK;
+ }
+
+ public int GetFreeSpace()
+ {
+ return WINDOW_SIZE - windowFilled;
+ }
+
+ public int GetAvailable()
+ {
+ return windowFilled;
+ }
+
+ public int CopyOutput(byte[] output, int offset, int len)
+ {
+ int copy_end = windowEnd;
+ if (len > windowFilled) {
+ len = windowFilled;
+ } else {
+ copy_end = (windowEnd - windowFilled + len) & WINDOW_MASK;
+ }
+
+ int copied = len;
+ int tailLen = len - copy_end;
+
+ if (tailLen > 0) {
+ System.Array.Copy(window, WINDOW_SIZE - tailLen, output, offset, tailLen);
+ offset += tailLen;
+ len = copy_end;
+ }
+ System.Array.Copy(window, copy_end - len, output, offset, len);
+ windowFilled -= copied;
+ if (windowFilled < 0) {
+ throw new InvalidOperationException();
+ }
+ return copied;
+ }
+
+ public void Reset()
+ {
+ windowFilled = windowEnd = 0;
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Streams/StreamManipulator.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Streams/StreamManipulator.cs new file mode 100644 index 00000000000..35f98cc4f76 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/Compression/Streams/StreamManipulator.cs @@ -0,0 +1,245 @@ +// 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 amount 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 then 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
+ {
+ private byte[] window;
+ private int window_start = 0;
+ private int window_end = 0;
+
+ private uint buffer = 0;
+ private int bits_in_buffer = 0;
+
+ /// <summary>
+ /// Get the next n bits but don't increase input pointer. n must be
+ /// less or equal 16 and if you if this call succeeds, you must drop
+ /// at least n-8 bits in the next call.
+ /// </summary>
+ /// <returns>
+ /// the value of the bits, or -1 if not enough bits available. */
+ /// </returns>
+ public int PeekBits(int n)
+ {
+ if (bits_in_buffer < n) {
+ if (window_start == window_end) {
+ return -1; // ok
+ }
+ buffer |= (uint)((window[window_start++] & 0xff |
+ (window[window_start++] & 0xff) << 8) << bits_in_buffer);
+ bits_in_buffer += 16;
+ }
+ return (int)(buffer & ((1 << n) - 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>
+ public void DropBits(int n)
+ {
+ buffer >>= n;
+ bits_in_buffer -= n;
+ }
+
+ /// <summary>
+ /// Gets the next n bits and increases input pointer. This is equivalent
+ /// to peekBits followed by dropBits, except for correct error handling.
+ /// </summary>
+ /// <returns>
+ /// the value of the bits, or -1 if not enough bits available.
+ /// </returns>
+ public int GetBits(int n)
+ {
+ int bits = PeekBits(n);
+ if (bits >= 0) {
+ DropBits(n);
+ }
+ 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 bits_in_buffer;
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of bytes available.
+ /// </summary>
+ /// <returns>
+ /// the number of bytes available.
+ /// </returns>
+ public int AvailableBytes {
+ get {
+ return window_end - window_start + (bits_in_buffer >> 3);
+ }
+ }
+
+ /// <summary>
+ /// Skips to the next byte boundary.
+ /// </summary>
+ public void SkipToByteBoundary()
+ {
+ buffer >>= (bits_in_buffer & 7);
+ bits_in_buffer &= ~7;
+ }
+
+ public bool IsNeedingInput {
+ get {
+ return window_start == window_end;
+ }
+ }
+
+ /// <summary>
+ /// Copies length 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.
+ /// </param>
+ /// <param name="offset">
+ /// the offset in the buffer.
+ /// </param>
+ /// <param name="length">
+ /// the length to copy, 0 is allowed.
+ /// </param>
+ /// <returns>
+ /// the number of bytes copied, 0 if no byte is available.
+ /// </returns>
+ public int CopyBytes(byte[] output, int offset, int length)
+ {
+ if (length < 0) {
+ throw new ArgumentOutOfRangeException("length negative");
+ }
+ if ((bits_in_buffer & 7) != 0) {
+ /* bits_in_buffer may only be 0 or 8 */
+ throw new InvalidOperationException("Bit buffer is not aligned!");
+ }
+
+ int count = 0;
+ while (bits_in_buffer > 0 && length > 0) {
+ output[offset++] = (byte) buffer;
+ buffer >>= 8;
+ bits_in_buffer -= 8;
+ length--;
+ count++;
+ }
+ if (length == 0) {
+ return count;
+ }
+
+ int avail = window_end - window_start;
+ if (length > avail) {
+ length = avail;
+ }
+ System.Array.Copy(window, window_start, output, offset, length);
+ window_start += length;
+
+ if (((window_start - window_end) & 1) != 0) {
+ /* We always want an even number of bytes in input, see peekBits */
+ buffer = (uint)(window[window_start++] & 0xff);
+ bits_in_buffer = 8;
+ }
+ return count + length;
+ }
+
+ public StreamManipulator()
+ {
+ }
+
+ public void Reset()
+ {
+ buffer = (uint)(window_start = window_end = bits_in_buffer = 0);
+ }
+
+ public void SetInput(byte[] buf, int off, int len)
+ {
+ if (window_start < window_end) {
+ throw new InvalidOperationException("Old input was not completely processed");
+ }
+
+ int end = off + len;
+
+ /* We want to throw an ArrayIndexOutOfBoundsException early. The
+ * check is very tricky: it also handles integer wrap around.
+ */
+ if (0 > off || off > end || end > buf.Length) {
+ throw new ArgumentOutOfRangeException();
+ }
+
+ if ((len & 1) != 0) {
+ /* We always want an even number of bytes in input, see peekBits */
+ buffer |= (uint)((buf[off++] & 0xff) << bits_in_buffer);
+ bits_in_buffer += 8;
+ }
+
+ window = buf;
+ window_start = off;
+ window_end = end;
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipConstants.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipConstants.cs new file mode 100644 index 00000000000..8a56d71d708 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipConstants.cs @@ -0,0 +1,146 @@ +// ZipConstants.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.Text;
+
+namespace ICSharpCode.SharpZipLib.Zip
+{
+
+ /// <summary>
+ /// This class contains constants used for zip.
+ /// </summary>
+ public sealed class ZipConstants
+ {
+ /* The local file header */
+ public const int LOCHDR = 30;
+ public const int LOCSIG = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);
+
+ public const int LOCVER = 4;
+ public const int LOCFLG = 6;
+ public const int LOCHOW = 8;
+ public const int LOCTIM = 10;
+ public const int LOCCRC = 14;
+ public const int LOCSIZ = 18;
+ public const int LOCLEN = 22;
+ public const int LOCNAM = 26;
+ public const int LOCEXT = 28;
+
+ public const int SPANNINGSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
+ public const int SPANTEMPSIG = 'P' | ('K' << 8) | ('0' << 16) | ('0' << 24);
+
+ /* The Data descriptor */
+ public const int EXTSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
+ public const int EXTHDR = 16;
+
+ public const int EXTCRC = 4;
+ public const int EXTSIZ = 8;
+ public const int EXTLEN = 12;
+
+ /* The central directory file header */
+ public const int CENSIG = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);
+
+ /* The central directory file header for 64bit ZIP*/
+ public const int CENSIG64 = 'P' | ('K' << 8) | (6 << 16) | (6 << 24);
+
+ public const int CENHDR = 46;
+
+ public const int CENVEM = 4;
+ public const int CENVER = 6;
+ public const int CENFLG = 8;
+ public const int CENHOW = 10;
+ public const int CENTIM = 12;
+ public const int CENCRC = 16;
+ public const int CENSIZ = 20;
+ public const int CENLEN = 24;
+ public const int CENNAM = 28;
+ public const int CENEXT = 30;
+ public const int CENCOM = 32;
+ public const int CENDSK = 34;
+ public const int CENATT = 36;
+ public const int CENATX = 38;
+ public const int CENOFF = 42;
+
+ /* The entries in the end of central directory */
+ public const int ENDSIG = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);
+ public const int ENDHDR = 22;
+
+ public const int HDRDIGITALSIG = 'P' | ('K' << 8) | (5 << 16) | (5 << 24);
+ public const int CENDIGITALSIG = 'P' | ('K' << 8) | (5 << 16) | (5 << 24);
+
+ /* The following two fields are missing in SUN JDK */
+ public const int ENDNRD = 4;
+ public const int ENDDCD = 6;
+
+ public const int ENDSUB = 8;
+ public const int ENDTOT = 10;
+ public const int ENDSIZ = 12;
+ public const int ENDOFF = 16;
+ public const int ENDCOM = 20;
+
+
+ static int defaultCodePage = 0; // 0 gives default code page, set it to whatever you like or alternatively alter it via property at runtime for more flexibility
+ // Some care for compatability purposes is required as you can specify unicode code pages here.... if this way of working seems ok
+ // then some protection may be added to make the interface a bit more robust perhaps.
+
+ public static int DefaultCodePage {
+ get {
+ return defaultCodePage;
+ }
+ set {
+ defaultCodePage = value;
+ }
+ }
+
+ public static string ConvertToString(byte[] data)
+ {
+#if COMACT_FRAMEWORK
+ return Encoding.ASCII.GetString(data,0, data.Length);
+#else
+ return Encoding.GetEncoding(DefaultCodePage).GetString(data, 0, data.Length);
+#endif
+ }
+
+ public static byte[] ConvertToArray(string str)
+ {
+#if COMACT_FRAMEWORK
+ return Encoding.ASCII.GetBytes(str);
+#else
+ return Encoding.GetEncoding(DefaultCodePage).GetBytes(str);
+#endif
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs new file mode 100644 index 00000000000..1cb65df10a5 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs @@ -0,0 +1,428 @@ +// ZipEntry.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
+{
+
+ public enum CompressionMethod
+ {
+ Stored = 0,
+ Deflated = 8,
+ }
+
+ /// <summary>
+ /// This class represents a member of a zip archive. ZipFile and
+ /// ZipInputStream will give you instances of this class as information
+ /// about the members in an archive. On the other hand ZipOutputStream
+ /// needs an instance of this class to create a new member.
+ ///
+ /// author of the original java version : Jochen Hoenicke
+ /// </summary>
+ public class ZipEntry : ICloneable
+ {
+ static int KNOWN_SIZE = 1;
+ static int KNOWN_CSIZE = 2;
+ static int KNOWN_CRC = 4;
+ static int KNOWN_TIME = 8;
+
+ string name;
+ uint size;
+ ushort version;
+ uint compressedSize;
+ uint crc;
+ uint dosTime;
+
+ ushort known = 0;
+ CompressionMethod method = CompressionMethod.Deflated;
+ byte[] extra = null;
+ string comment = null;
+ bool isCrypted;
+
+ int zipFileIndex = -1; /* used by ZipFile */
+ int flags; /* used by ZipOutputStream */
+ int offset; /* used by ZipFile and ZipOutputStream */
+
+ public bool IsEncrypted {
+ get {
+ return (flags & 1) != 0;
+ }
+ set {
+ if (value) {
+ flags |= 1;
+ } else {
+ flags &= ~1;
+ }
+ }
+ }
+
+ public int ZipFileIndex {
+ get {
+ return zipFileIndex;
+ }
+ set {
+ zipFileIndex = value;
+ }
+ }
+
+ public int Offset {
+ get {
+ return offset;
+ }
+ set {
+ offset = value;
+ }
+ }
+
+ public int Flags { // Stops having two things represent same concept in class (flag isCrypted removed)
+ get {
+ return flags;
+ }
+ set {
+ flags = value;
+ }
+ }
+
+
+ /// <summary>
+ /// Creates a zip entry with the given name.
+ /// </summary>
+ /// <param name="name">
+ /// the name. May include directory components separated by '/'.
+ /// </param>
+ public ZipEntry(string name)
+ {
+ if (name == null) {
+ throw new System.ArgumentNullException("name");
+ }
+ this.DateTime = System.DateTime.Now;
+ this.name = name;
+ }
+
+ /// <summary>
+ /// Creates a copy of the given zip entry.
+ /// </summary>
+ /// <param name="e">
+ /// the entry to copy.
+ /// </param>
+ public ZipEntry(ZipEntry e)
+ {
+ name = e.name;
+ known = e.known;
+ size = e.size;
+ compressedSize = e.compressedSize;
+ crc = e.crc;
+ dosTime = e.dosTime;
+ method = e.method;
+ extra = e.extra;
+ comment = e.comment;
+ }
+
+ public int Version {
+ get {
+ return version;
+ }
+ set {
+ version = (ushort)value;
+ }
+ }
+
+ public long DosTime {
+ get {
+ if ((known & KNOWN_TIME) == 0) {
+ return 0;
+ } else {
+ return dosTime;
+ }
+ }
+ set {
+ this.dosTime = (uint)value;
+ known |= (ushort)KNOWN_TIME;
+ }
+ }
+
+
+ /// <summary>
+ /// Gets/Sets the time of last modification of the entry.
+ /// </summary>
+ public DateTime DateTime {
+ get {
+ uint sec = 2 * (dosTime & 0x1f);
+ uint min = (dosTime >> 5) & 0x3f;
+ uint hrs = (dosTime >> 11) & 0x1f;
+ uint day = (dosTime >> 16) & 0x1f;
+ uint mon = ((dosTime >> 21) & 0xf);
+ uint year = ((dosTime >> 25) & 0x7f) + 1980; /* since 1900 */
+ return new System.DateTime((int)year, (int)mon, (int)day, (int)hrs, (int)min, (int)sec);
+ }
+ set {
+ DosTime = ((uint)value.Year - 1980 & 0x7f) << 25 |
+ ((uint)value.Month) << 21 |
+ ((uint)value.Day) << 16 |
+ ((uint)value.Hour) << 11 |
+ ((uint)value.Minute) << 5 |
+ ((uint)value.Second) >> 1;
+ }
+ }
+
+ /// <summary>
+ /// Returns the entry name. The path components in the entry are
+ /// always separated by slashes ('/').
+ /// </summary>
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ // /// <summary>
+ // /// Gets/Sets the time of last modification of the entry.
+ // /// </summary>
+ // /// <returns>
+ // /// the time of last modification of the entry, or -1 if unknown.
+ // /// </returns>
+ // public long Time {
+ // get {
+ // return (known & KNOWN_TIME) != 0 ? time * 1000L : -1;
+ // }
+ // set {
+ // this.time = (int) (value / 1000L);
+ // this.known |= (ushort)KNOWN_TIME;
+ // }
+ // }
+
+ /// <summary>
+ /// Gets/Sets the size of the uncompressed data.
+ /// </summary>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// if size is not in 0..0xffffffffL
+ /// </exception>
+ /// <returns>
+ /// the size or -1 if unknown.
+ /// </returns>
+ public long Size {
+ get {
+ return (known & KNOWN_SIZE) != 0 ? (long)size : -1L;
+ }
+ set {
+ if (((ulong)value & 0xFFFFFFFF00000000L) != 0) {
+ throw new ArgumentOutOfRangeException("size");
+ }
+ this.size = (uint)value;
+ this.known |= (ushort)KNOWN_SIZE;
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the size of the compressed data.
+ /// </summary>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// if csize is not in 0..0xffffffffL
+ /// </exception>
+ /// <returns>
+ /// the size or -1 if unknown.
+ /// </returns>
+ public long CompressedSize {
+ get {
+ return (known & KNOWN_CSIZE) != 0 ? (long)compressedSize : -1L;
+ }
+ set {
+ if (((ulong)value & 0xffffffff00000000L) != 0) {
+ throw new ArgumentOutOfRangeException();
+ }
+ this.compressedSize = (uint)value;
+ this.known |= (ushort)KNOWN_CSIZE;
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the crc of the uncompressed data.
+ /// </summary>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// if crc is not in 0..0xffffffffL
+ /// </exception>
+ /// <returns>
+ /// the crc or -1 if unknown.
+ /// </returns>
+ public long Crc {
+ get {
+ return (known & KNOWN_CRC) != 0 ? crc & 0xffffffffL : -1L;
+ }
+ set {
+ if (((ulong)crc & 0xffffffff00000000L) != 0)
+ {
+ throw new Exception();
+ }
+ this.crc = (uint)value;
+ this.known |= (ushort)KNOWN_CRC;
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the compression method. Only DEFLATED and STORED are supported.
+ /// </summary>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// if method is not supported.
+ /// </exception>
+ /// <returns>
+ /// the compression method or -1 if unknown.
+ /// </returns>
+ /// <see cref="ZipOutputStream.DEFLATED"/>
+ /// <see cref="ZipOutputStream.STORED"/>
+ public CompressionMethod CompressionMethod {
+ get {
+ return method;
+ }
+ set {
+ this.method = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the extra data.
+ /// </summary>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// if extra is longer than 0xffff bytes.
+ /// </exception>
+ /// <returns>
+ /// the extra data or null if not set.
+ /// </returns>
+ public byte[] ExtraData {
+ get {
+ return extra;
+ }
+ set {
+ if (value == null) {
+ this.extra = null;
+ return;
+ }
+
+ if (value.Length > 0xffff) {
+ throw new System.ArgumentOutOfRangeException();
+ }
+ this.extra = value;
+ try {
+ int pos = 0;
+ while (pos < extra.Length) {
+ int sig = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8;
+ int len = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8;
+ if (sig == 0x5455) {
+ /* extended time stamp, unix format by Rainer Prem <Rainer@Prem.de> */
+ int flags = extra[pos];
+ if ((flags & 1) != 0) {
+ int iTime = ((extra[pos+1] & 0xff) |
+ (extra[pos+2] & 0xff) << 8 |
+ (extra[pos+3] & 0xff) << 16 |
+ (extra[pos+4] & 0xff) << 24);
+
+ DateTime = (new DateTime ( 1970, 1, 1, 0, 0, 0 ) + new TimeSpan ( 0, 0, 0, iTime, 0 )).ToLocalTime ();
+ known |= (ushort)KNOWN_TIME;
+ }
+ }
+ pos += len;
+ }
+ } catch (Exception) {
+ /* be lenient */
+ return;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the entry comment.
+ /// </summary>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// if comment is longer than 0xffff.
+ /// </exception>
+ /// <returns>
+ /// the comment or null if not set.
+ /// </returns>
+ public string Comment {
+ get {
+ return comment;
+ }
+ set {
+ if (value.Length > 0xffff)
+ {
+ throw new ArgumentOutOfRangeException();
+ }
+ this.comment = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets true, if the entry is a directory. This is solely
+ /// determined by the name, a trailing slash '/' marks a directory.
+ /// </summary>
+ public bool IsDirectory {
+ get {
+ int nlen = name.Length;
+ return nlen > 0 && name[nlen - 1] == '/';
+ }
+ }
+
+ /// <value>
+ /// True, if the entry is encrypted.
+ /// </value>
+ public bool IsCrypted {
+ get {
+ return isCrypted;
+ }
+ set {
+ isCrypted = value;
+ }
+ }
+
+ /// <summary>
+ /// Creates a copy of this zip entry.
+ /// </summary>
+ public object Clone()
+ {
+ return this.MemberwiseClone();
+ }
+
+ /// <summary>
+ /// Gets the string representation of this ZipEntry. This is just
+ /// the name as returned by getName().
+ /// </summary>
+ public override string ToString()
+ {
+ return name;
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipFile.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipFile.cs new file mode 100644 index 00000000000..3e3b2a18ef5 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipFile.cs @@ -0,0 +1,540 @@ +// ZipFile.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.Collections;
+using System.IO;
+using System.Text;
+
+using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
+using ICSharpCode.SharpZipLib.Zip.Compression;
+
+namespace ICSharpCode.SharpZipLib.Zip
+{
+
+ /// <summary>
+ /// This class represents a Zip archive. You can ask for the contained
+ /// entries, or get an input stream for a file entry. The entry is
+ /// automatically decompressed.
+ ///
+ /// This class is thread safe: You can open input streams for arbitrary
+ /// entries in different threads.
+ ///
+ /// author of the original java version : Jochen Hoenicke
+ /// </summary>
+ /// <example>
+ /// using System;
+ /// using System.Text;
+ /// using System.Collections;
+ /// using System.IO;
+ ///
+ /// using NZlib.Zip;
+ ///
+ /// class MainClass
+ /// {
+ /// static public void Main(string[] args)
+ /// {
+ /// ZipFile zFile = new ZipFile(args[0]);
+ /// //Console.WriteLine("Listing of : " + zFile.Name);
+ /// //Console.WriteLine("");
+ /// //Console.WriteLine("Raw Size Size Date Time Name");
+ /// //Console.WriteLine("-------- -------- -------- ------ ---------");
+ /// foreach (ZipEntry e in zFile) {
+ /// DateTime d = e.DateTime;
+ /// //Console.WriteLine("{0, -10}{1, -10}{2} {3} {4}", e.Size, e.CompressedSize,
+ /// d.ToString("dd-MM-yy"), d.ToString("t"),
+ /// e.Name);
+ /// }
+ /// }
+ /// }
+ /// </example>
+ public class ZipFile : IEnumerable
+ {
+ string name;
+ string comment;
+ Stream baseStream;
+ ZipEntry[] entries;
+
+ /// <summary>
+ /// Opens a Zip file with the given name for reading.
+ /// </summary>
+ /// <exception name="System.IO.IOException">
+ /// IOException if a i/o error occured.
+ /// </exception>
+ /// <exception name="ICSharpCode.SharpZipLib.ZipException">
+ /// if the file doesn't contain a valid zip archive.
+ /// </exception>
+ public ZipFile(string name) : this(File.OpenRead(name))
+ {
+ }
+
+ /// <summary>
+ /// Opens a Zip file reading the given FileStream
+ /// </summary>
+ /// <exception name="System.IO.IOException">
+ /// IOException if a i/o error occured.
+ /// </exception>
+ /// <exception name="ICSharpCode.SharpZipLib.ZipException">
+ /// if the file doesn't contain a valid zip archive.
+ /// </exception>
+ public ZipFile(FileStream file)
+ {
+ this.baseStream = file;
+ this.name = file.Name;
+ ReadEntries();
+ }
+
+ /// <summary>
+ /// Opens a Zip file reading the given Stream
+ /// </summary>
+ /// <exception name="System.IO.IOException">
+ /// IOException if a i/o error occured.
+ /// </exception>
+ /// <exception name="ICSharpCode.SharpZipLib.ZipException">
+ /// if the file doesn't contain a valid zip archive.
+ /// </exception>
+ public ZipFile(Stream baseStream)
+ {
+ this.baseStream = baseStream;
+ this.name = null;
+ ReadEntries();
+ }
+
+
+ /// <summary>
+ /// Read an unsigned short in little endian byte order.
+ /// </summary>
+ /// <exception name="System.IO.IOException">
+ /// if a i/o error occured.
+ /// </exception>
+ /// <exception name="System.IO.EndOfStreamException">
+ /// if the file ends prematurely
+ /// </exception>
+ int ReadLeShort()
+ {
+ return baseStream.ReadByte() | baseStream.ReadByte() << 8;
+ }
+
+ /// <summary>
+ /// Read an int in little endian byte order.
+ /// </summary>
+ /// <exception name="System.IO.IOException">
+ /// if a i/o error occured.
+ /// </exception>
+ /// <exception name="System.IO.EndOfStreamException">
+ /// if the file ends prematurely
+ /// </exception>
+ int ReadLeInt()
+ {
+ return ReadLeShort() | ReadLeShort() << 16;
+ }
+
+ /// <summary>
+ /// Read the central directory of a zip file and fill the entries
+ /// array. This is called exactly once by the constructors.
+ /// </summary>
+ /// <exception name="System.IO.IOException">
+ /// if a i/o error occured.
+ /// </exception>
+ /// <exception name="ICSharpCode.SharpZipLib.ZipException">
+ /// if the central directory is malformed
+ /// </exception>
+ void ReadEntries()
+ {
+ /* Search for the End Of Central Directory. When a zip comment is
+ * present the directory may start earlier.
+ * FIXME: This searches the whole file in a very slow manner if the
+ * file isn't a zip file.
+ */
+ long pos = baseStream.Length - ZipConstants.ENDHDR;
+ do {
+ if (pos < 0) {
+ throw new ZipException("central directory not found, probably not a zip file");
+ }
+ baseStream.Seek(pos--, SeekOrigin.Begin);
+ } while (ReadLeInt() != ZipConstants.ENDSIG);
+
+ long oldPos = baseStream.Position;
+ baseStream.Position += ZipConstants.ENDTOT - ZipConstants.ENDNRD;
+
+ if (baseStream.Position - oldPos != ZipConstants.ENDTOT - ZipConstants.ENDNRD) {
+ throw new EndOfStreamException();
+ }
+ int count = ReadLeShort();
+
+ oldPos = baseStream.Position;
+ baseStream.Position += ZipConstants.ENDOFF - ZipConstants.ENDSIZ;
+
+ if (baseStream.Position - oldPos != ZipConstants.ENDOFF - ZipConstants.ENDSIZ) {
+ throw new EndOfStreamException();
+ }
+
+ int centralOffset = ReadLeInt();
+
+ // GET COMMENT SIZE (COMES AFTER CENTRALOFFSET)
+ int commentSize = ReadLeShort();
+ byte[] zipComment = new byte[commentSize];
+ baseStream.Read(zipComment, 0, zipComment.Length);
+ comment = ZipConstants.ConvertToString(zipComment);
+
+ entries = new ZipEntry[count];
+ baseStream.Seek(centralOffset, SeekOrigin.Begin);
+ for (int i = 0; i < count; i++) {
+ if (ReadLeInt() != ZipConstants.CENSIG) {
+ throw new ZipException("Wrong Central Directory signature");
+ }
+
+ oldPos = baseStream.Position;
+ baseStream.Position += ZipConstants.CENHOW - ZipConstants.CENVEM;
+
+ if (baseStream.Position - oldPos != ZipConstants.CENHOW - ZipConstants.CENVEM) {
+ throw new EndOfStreamException();
+ }
+ int method = ReadLeShort();
+ int dostime = ReadLeInt();
+ int crc = ReadLeInt();
+ int csize = ReadLeInt();
+ int size = ReadLeInt();
+ int nameLen = ReadLeShort();
+ int extraLen = ReadLeShort();
+ int commentLen = ReadLeShort();
+
+ oldPos = baseStream.Position;
+ baseStream.Position += ZipConstants.CENOFF - ZipConstants.CENDSK;
+ if (baseStream.Position - oldPos != ZipConstants.CENOFF - ZipConstants.CENDSK) {
+ throw new EndOfStreamException();
+ }
+ int offset = ReadLeInt();
+
+ byte[] buffer = new byte[Math.Max(nameLen, commentLen)];
+
+ baseStream.Read(buffer, 0, nameLen);
+ string name = ZipConstants.ConvertToString(buffer);
+
+ ZipEntry entry = new ZipEntry(name);
+ entry.CompressionMethod = (CompressionMethod)method;
+ entry.Crc = crc & 0xffffffffL;
+ entry.Size = size & 0xffffffffL;
+ entry.CompressedSize = csize & 0xffffffffL;
+ entry.DosTime = (uint)dostime;
+ if (extraLen > 0) {
+ byte[] extra = new byte[extraLen];
+ baseStream.Read(extra, 0, extraLen);
+ entry.ExtraData = extra;
+ }
+ if (commentLen > 0) {
+ baseStream.Read(buffer, 0, commentLen);
+ entry.Comment = ZipConstants.ConvertToString(buffer);
+ }
+ entry.ZipFileIndex = i;
+ entry.Offset = offset;
+ entries[i] = entry;
+ }
+ }
+
+ /// <summary>
+ /// Closes the ZipFile. This also closes all input streams given by
+ /// this class. After this is called, no further method should be
+ /// called.
+ /// </summary>
+ /// <exception name="System.IO.IOException">
+ /// if a i/o error occured.
+ /// </exception>
+ public void Close()
+ {
+ entries = null;
+ lock(baseStream) {
+ baseStream.Close();
+ }
+ }
+
+ /// <summary>
+ /// Returns an IEnumerator of all Zip entries in this Zip file.
+ /// </summary>
+ public IEnumerator GetEnumerator()
+ {
+ if (entries == null) {
+ throw new InvalidOperationException("ZipFile has closed");
+ }
+
+ return new ZipEntryEnumeration(entries);
+ }
+
+ int GetEntryIndex(string name)
+ {
+ for (int i = 0; i < entries.Length; i++) {
+ if (name.Equals(entries[i].Name)) {
+ return i;
+ }
+ }
+ return -1; // ok
+ }
+
+ /// <summary>
+ /// Searches for a zip entry in this archive with the given name.
+ /// </summary>
+ /// <param name="name">
+ /// the name. May contain directory components separated by slashes ('/').
+ /// </param>
+ /// <returns>
+ /// the zip entry, or null if no entry with that name exists.
+ /// </returns>
+ public ZipEntry GetEntry(string name)
+ {
+ if (entries == null) {
+ throw new InvalidOperationException("ZipFile has closed");
+ }
+ int index = GetEntryIndex(name);
+ return index >= 0 ? (ZipEntry) entries[index].Clone() : null;
+ }
+
+ /// <summary>
+ /// Checks, if the local header of the entry at index i matches the
+ /// central directory, and returns the offset to the data.
+ /// </summary>
+ /// <returns>
+ /// the start offset of the (compressed) data.
+ /// </returns>
+ /// <exception name="System.IO.IOException">
+ /// if a i/o error occured.
+ /// </exception>
+ /// <exception name="ICSharpCode.SharpZipLib.ZipException">
+ /// if the local header doesn't match the central directory header
+ /// </exception>
+ long CheckLocalHeader(ZipEntry entry)
+ {
+ lock(baseStream) {
+ baseStream.Seek(entry.Offset, SeekOrigin.Begin);
+ if (ReadLeInt() != ZipConstants.LOCSIG) {
+ throw new ZipException("Wrong Local header signature");
+ }
+
+ /* skip version and flags */
+ long oldPos = baseStream.Position;
+ baseStream.Position += ZipConstants.LOCHOW - ZipConstants.LOCVER;
+ if (baseStream.Position - oldPos != ZipConstants.LOCHOW - ZipConstants.LOCVER) {
+ throw new EndOfStreamException();
+ }
+
+ if (entry.CompressionMethod != (CompressionMethod)ReadLeShort()) {
+ throw new ZipException("Compression method mismatch");
+ }
+
+ /* Skip time, crc, size and csize */
+ oldPos = baseStream.Position;
+ baseStream.Position += ZipConstants.LOCNAM - ZipConstants.LOCTIM;
+
+ if (baseStream.Position - oldPos != ZipConstants.LOCNAM - ZipConstants.LOCTIM) {
+ throw new EndOfStreamException();
+ }
+
+ if (entry.Name.Length != ReadLeShort()) {
+ throw new ZipException("file name length mismatch");
+ }
+
+ int extraLen = entry.Name.Length + ReadLeShort();
+ return entry.Offset + ZipConstants.LOCHDR + extraLen;
+ }
+ }
+
+ /// <summary>
+ /// Creates an input stream reading the given zip entry as
+ /// uncompressed data. Normally zip entry should be an entry
+ /// returned by GetEntry().
+ /// </summary>
+ /// <returns>
+ /// the input stream.
+ /// </returns>
+ /// <exception name="System.IO.IOException">
+ /// if a i/o error occured.
+ /// </exception>
+ /// <exception name="ICSharpCode.SharpZipLib.ZipException">
+ /// if the Zip archive is malformed.
+ /// </exception>
+ public Stream GetInputStream(ZipEntry entry)
+ {
+ if (entries == null) {
+ throw new InvalidOperationException("ZipFile has closed");
+ }
+
+ int index = entry.ZipFileIndex;
+ if (index < 0 || index >= entries.Length || entries[index].Name != entry.Name) {
+ index = GetEntryIndex(entry.Name);
+ if (index < 0) {
+ throw new IndexOutOfRangeException();
+ }
+ }
+
+ long start = CheckLocalHeader(entries[index]);
+ CompressionMethod method = entries[index].CompressionMethod;
+ Stream istr = new PartialInputStream(baseStream, start, entries[index].CompressedSize);
+ switch (method) {
+ case CompressionMethod.Stored:
+ return istr;
+ case CompressionMethod.Deflated:
+ return new InflaterInputStream(istr, new Inflater(true));
+ default:
+ throw new ZipException("Unknown compression method " + method);
+ }
+ }
+
+ /// <summary>
+ /// The comment for the whole zip file.
+ /// </summary>
+ public string ZipFileComment {
+ get {
+ return comment;
+ }
+ }
+
+ /// <summary>
+ /// Returns the name of this zip file.
+ /// </summary>
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ /// <summary>
+ /// Returns the number of entries in this zip file.
+ /// </summary>
+ public int Size {
+ get {
+ try {
+ return entries.Length;
+ } catch (Exception) {
+ throw new InvalidOperationException("ZipFile has closed");
+ }
+ }
+ }
+
+ class ZipEntryEnumeration : IEnumerator
+ {
+ ZipEntry[] array;
+ int ptr = -1;
+
+ public ZipEntryEnumeration(ZipEntry[] arr)
+ {
+ array = arr;
+ }
+
+ public object Current {
+ get {
+ return array[ptr];
+ }
+ }
+
+ public void Reset()
+ {
+ ptr = -1;
+ }
+
+ public bool MoveNext()
+ {
+ return (++ptr < array.Length);
+ }
+ }
+
+ class PartialInputStream : InflaterInputStream
+ {
+ Stream baseStream;
+ long filepos, end;
+
+ public PartialInputStream(Stream baseStream, long start, long len) : base(baseStream)
+ {
+ this.baseStream = baseStream;
+ filepos = start;
+ end = start + len;
+ }
+
+ public override int Available
+ {
+ get {
+ long amount = end - filepos;
+ if (amount > Int32.MaxValue) {
+ return Int32.MaxValue;
+ }
+
+ return (int) amount;
+ }
+ }
+
+ public override int ReadByte()
+ {
+ if (filepos == end) {
+ return -1; //ok
+ }
+
+ lock(baseStream) {
+ baseStream.Seek(filepos++, SeekOrigin.Begin);
+ return baseStream.ReadByte();
+ }
+ }
+
+ public override int Read(byte[] b, int off, int len)
+ {
+ if (len > end - filepos) {
+ len = (int) (end - filepos);
+ if (len == 0) {
+ return 0;
+ }
+ }
+ lock(baseStream) {
+ baseStream.Seek(filepos, SeekOrigin.Begin);
+ int count = baseStream.Read(b, off, len);
+ if (count > 0) {
+ filepos += len;
+ }
+ return count;
+ }
+ }
+
+ public long SkipBytes(long amount)
+ {
+ if (amount < 0) {
+ throw new ArgumentOutOfRangeException();
+ }
+ if (amount > end - filepos) {
+ amount = end - filepos;
+ }
+ filepos += amount;
+ return amount;
+ }
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipInputStream.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipInputStream.cs new file mode 100644 index 00000000000..ceae2444672 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipInputStream.cs @@ -0,0 +1,488 @@ +// ZipInputStream.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.Text;
+using System.IO;
+
+using ICSharpCode.SharpZipLib.Checksums;
+using ICSharpCode.SharpZipLib.Zip.Compression;
+using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
+
+namespace ICSharpCode.SharpZipLib.Zip
+{
+ /// <summary>
+ /// This is a FilterInputStream 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.
+ ///
+ /// 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 NZlib.Zip;
+ ///
+ /// class MainClass
+ /// {
+ /// public static void Main(string[] args)
+ /// {
+ /// ZipInputStream s = new ZipInputStream(File.OpenRead(args[0]));
+ ///
+ /// ZipEntry theEntry;
+ /// while ((theEntry = s.GetNextEntry()) != null) {
+ /// int size = 2048;
+ /// byte[] data = new byte[2048];
+ ///
+ /// 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;
+ /// }
+ /// }
+ /// }
+ /// }
+ /// s.Close();
+ /// }
+ /// }
+ /// </code>
+ /// </example>
+ public class ZipInputStream : InflaterInputStream
+ {
+ Crc32 crc = new Crc32();
+ ZipEntry entry = null;
+
+ long size;
+ int method;
+ int flags;
+ long avail;
+ string password = null;
+
+ public string Password {
+ get {
+ return password;
+ }
+ set {
+ password = value;
+ }
+ }
+
+ /// <summary>
+ /// Creates a new Zip input stream, reading a zip archive.
+ /// </summary>
+ public ZipInputStream(Stream baseInputStream) : base(baseInputStream, new Inflater(true))
+ {
+ }
+
+ void FillBuf()
+ {
+ avail = len = baseInputStream.Read(buf, 0, buf.Length);
+ }
+
+ int ReadBuf(byte[] outBuf, int offset, int length)
+ {
+ if (avail <= 0) {
+ FillBuf();
+ if (avail <= 0) {
+ return 0;
+ }
+ }
+ if (length > avail) {
+ length = (int)avail;
+ }
+ System.Array.Copy(buf, len - (int)avail, outBuf, offset, length);
+ avail -= length;
+ return length;
+ }
+
+ void ReadFully(byte[] outBuf)
+ {
+ int off = 0;
+ int len = outBuf.Length;
+ while (len > 0) {
+ int count = ReadBuf(outBuf, off, len);
+ if (count == -1) {
+ throw new Exception();
+ }
+ off += count;
+ len -= count;
+ }
+ }
+
+ int ReadLeByte()
+ {
+ if (avail <= 0) {
+ FillBuf();
+ if (avail <= 0) {
+ throw new ZipException("EOF in header");
+ }
+ }
+ return buf[len - avail--] & 0xff;
+ }
+
+ /// <summary>
+ /// Read an unsigned short baseInputStream little endian byte order.
+ /// </summary>
+ int ReadLeShort()
+ {
+ return ReadLeByte() | (ReadLeByte() << 8);
+ }
+
+ /// <summary>
+ /// Read an int baseInputStream little endian byte order.
+ /// </summary>
+ int ReadLeInt()
+ {
+ return ReadLeShort() | (ReadLeShort() << 16);
+ }
+
+ /// <summary>
+ /// Read an int baseInputStream little endian byte order.
+ /// </summary>
+ long ReadLeLong()
+ {
+ return ReadLeInt() | (ReadLeInt() << 32);
+ }
+
+ /// <summary>
+ /// Open the next entry from the zip archive, and return its description.
+ /// If the previous entry wasn't closed, this method will close it.
+ /// </summary>
+ public ZipEntry GetNextEntry()
+ {
+ if (crc == null) {
+ throw new InvalidOperationException("Closed.");
+ }
+ if (entry != null) {
+ CloseEntry();
+ }
+
+ if (this.cryptbuffer != null) {
+ if (avail == 0 && inf.RemainingInput != 0) {
+ avail = inf.RemainingInput - 16;
+ inf.Reset();
+ }
+ baseInputStream.Position -= this.len;
+ baseInputStream.Read(this.buf, 0, this.len);
+ }
+
+ int header = ReadLeInt();
+
+ // -jr- added end sig for empty zip files, Zip64 end sig and digital sig for files that have them...
+ if (header == ZipConstants.CENSIG ||
+ header == ZipConstants.ENDSIG ||
+ header == ZipConstants.CENDIGITALSIG ||
+ header == ZipConstants.CENSIG64) {
+ // Central Header reached or end of empty zip file
+ Close();
+ return null;
+ }
+ // -jr- 07-Dec-2003 ignore spanning temporary signatures if found
+ // SPANNINGSIG is same as descriptor signature and is untested as yet.
+ if (header == ZipConstants.SPANTEMPSIG || header == ZipConstants.SPANNINGSIG) {
+ header = ReadLeInt();
+ }
+
+ if (header != ZipConstants.LOCSIG) {
+ throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header));
+ }
+
+ short version = (short)ReadLeShort();
+
+ flags = ReadLeShort();
+ method = ReadLeShort();
+ uint dostime = (uint)ReadLeInt();
+ int crc2 = ReadLeInt();
+ csize = ReadLeInt();
+ size = ReadLeInt();
+ int nameLen = ReadLeShort();
+ int extraLen = ReadLeShort();
+ bool isCrypted = (flags & 1) == 1;
+ if (method == ZipOutputStream.STORED && (!isCrypted && csize != size || (isCrypted && csize - 12 != size))) {
+ throw new ZipException("Stored, but compressed != uncompressed");
+ }
+
+ byte[] buffer = new byte[nameLen];
+ ReadFully(buffer);
+
+ string name = ZipConstants.ConvertToString(buffer);
+
+ entry = new ZipEntry(name);
+ entry.IsCrypted = isCrypted;
+ entry.Version = (ushort)version;
+ if (method != 0 && method != 8) {
+ throw new ZipException("unknown compression method " + method);
+ }
+ entry.CompressionMethod = (CompressionMethod)method;
+
+ if ((flags & 8) == 0) {
+ entry.Crc = crc2 & 0xFFFFFFFFL;
+ entry.Size = size & 0xFFFFFFFFL;
+ entry.CompressedSize = csize & 0xFFFFFFFFL;
+ }
+
+ entry.DosTime = dostime;
+
+ if (extraLen > 0) {
+ byte[] extra = new byte[extraLen];
+ ReadFully(extra);
+ entry.ExtraData = extra;
+ }
+
+ // test for encryption
+ if (isCrypted) {
+ if (password == null) {
+ throw new ZipException("No password set.");
+ }
+ InitializePassword(password);
+ cryptbuffer = new byte[12];
+ ReadFully(cryptbuffer);
+ DecryptBlock(cryptbuffer, 0, cryptbuffer.Length);
+ if ((flags & 8) == 0) {// -jr- 10-Feb-2004 Dont yet know correct size here....
+ csize -= 12;
+ }
+ } else {
+ cryptbuffer = null;
+ }
+
+ if (method == ZipOutputStream.DEFLATED && avail > 0) {
+ System.Array.Copy(buf, len - (int)avail, buf, 0, (int)avail);
+ len = (int)avail;
+ avail = 0;
+ if (isCrypted) {
+ DecryptBlock(buf, 0, Math.Min((int)csize, len));
+ }
+ inf.SetInput(buf, 0, len);
+ }
+
+ return entry;
+ }
+ private void ReadDataDescr()
+ {
+ if (ReadLeInt() != ZipConstants.EXTSIG) {
+ throw new ZipException("Data descriptor signature not found");
+ }
+ entry.Crc = ReadLeInt() & 0xFFFFFFFFL;
+ csize = ReadLeInt();
+ size = ReadLeInt();
+ entry.Size = size & 0xFFFFFFFFL;
+ entry.CompressedSize = csize & 0xFFFFFFFFL;
+ }
+
+ /// <summary>
+ /// Closes the current zip entry and moves to the next one.
+ /// </summary>
+ public void CloseEntry()
+ {
+ if (crc == null) {
+ throw new InvalidOperationException("Closed.");
+ }
+
+ if (entry == null) {
+ return;
+ }
+
+ if (method == ZipOutputStream.DEFLATED) {
+ if ((flags & 8) != 0) {
+ /* We don't know how much we must skip, read until end. */
+ byte[] tmp = new byte[2048];
+ while (Read(tmp, 0, tmp.Length) > 0)
+ ;
+ /* read will close this entry */
+ return;
+ }
+ csize -= inf.TotalIn;
+ avail = inf.RemainingInput;
+ }
+ if (avail > csize && csize >= 0) {
+ avail -= csize;
+ } else {
+ csize -= avail;
+ avail = 0;
+ while (csize != 0) {
+ int skipped = (int)base.Skip(csize & 0xFFFFFFFFL);
+
+ if (skipped <= 0) {
+ throw new ZipException("zip archive ends early.");
+ }
+
+ csize -= skipped;
+ }
+ }
+
+ size = 0;
+ crc.Reset();
+ if (method == ZipOutputStream.DEFLATED) {
+ inf.Reset();
+ }
+ entry = null;
+ }
+
+ public override int Available {
+ get {
+ return entry != null ? 1 : 0;
+ }
+ }
+
+ /// <summary>
+ /// Reads a byte from the current zip entry.
+ /// </summary>
+ /// <returns>
+ /// the byte or -1 on EOF.
+ /// </returns>
+ /// <exception name="System.IO.IOException">
+ /// IOException if a i/o error occured.
+ /// </exception>
+ /// <exception name="ICSharpCode.SharpZipLib.ZipException">
+ /// ZipException if the deflated stream is corrupted.
+ /// </exception>
+ public override int ReadByte()
+ {
+ byte[] b = new byte[1];
+ if (Read(b, 0, 1) <= 0) {
+ return -1; // ok
+ }
+ return b[0] & 0xff;
+ }
+
+ /// <summary>
+ /// Reads a block of bytes from the current zip entry.
+ /// </summary>
+ /// <returns>
+ /// the number of bytes read (may be smaller, even before EOF), or -1 on EOF.
+ /// </returns>
+ /// <exception name="Exception">
+ /// IOException if a i/o error occured.
+ /// ZipException if the deflated stream is corrupted.
+ /// </exception>
+ public override int Read(byte[] b, int off, int len)
+ {
+ if (crc == null) {
+ throw new InvalidOperationException("Closed.");
+ }
+
+ if (entry == null) {
+ return 0;
+ }
+ bool finished = false;
+
+ switch (method) {
+ case ZipOutputStream.DEFLATED:
+ len = base.Read(b, off, len);
+ if (len <= 0) { // TODO BUG1 -jr- Check this was < 0 but avail was not adjusted causing failure in later calls
+ if (!inf.IsFinished) {
+ throw new ZipException("Inflater not finished!?");
+ }
+ avail = inf.RemainingInput;
+
+ // BUG1 -jr- With bit 3 set you dont yet know the size
+ if ((flags & 8) == 0 && (inf.TotalIn != csize || inf.TotalOut != size)) {
+ throw new ZipException("size mismatch: " + csize + ";" + size + " <-> " + inf.TotalIn + ";" + inf.TotalOut);
+ }
+ inf.Reset();
+ finished = true;
+ }
+ break;
+
+ case ZipOutputStream.STORED:
+ if (len > csize && csize >= 0) {
+ len = (int)csize;
+ }
+ len = ReadBuf(b, off, len);
+ if (len > 0) {
+ csize -= len;
+ size -= len;
+ }
+
+ if (csize == 0) {
+ finished = true;
+ } else {
+ if (len < 0) {
+ throw new ZipException("EOF in stored block");
+ }
+ }
+
+ // decrypting crypted data
+ if (cryptbuffer != null) {
+ DecryptBlock(b, off, len);
+ }
+
+ break;
+ }
+
+ if (len > 0) {
+ crc.Update(b, off, len);
+ }
+
+ if (finished) {
+ if ((flags & 8) != 0) {
+ ReadDataDescr();
+ }
+
+ if ((crc.Value & 0xFFFFFFFFL) != entry.Crc && entry.Crc != -1) {
+ throw new ZipException("CRC mismatch");
+ }
+ crc.Reset();
+ entry = null;
+ }
+ return len;
+ }
+
+ /// <summary>
+ /// Closes the zip file.
+ /// </summary>
+ /// <exception name="Exception">
+ /// if a i/o error occured.
+ /// </exception>
+ public override void Close()
+ {
+ base.Close();
+ crc = null;
+ entry = null;
+ }
+
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs new file mode 100644 index 00000000000..37d285196b3 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs @@ -0,0 +1,550 @@ +// ZipOutputStream.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 System.Collections;
+using System.Text;
+
+using ICSharpCode.SharpZipLib.Checksums;
+using ICSharpCode.SharpZipLib.Zip.Compression;
+using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
+
+namespace ICSharpCode.SharpZipLib.Zip
+{
+ /// <summary>
+ /// This is a FilterOutputStream 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.
+ ///
+ /// 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 NZlib.Zip;
+ ///
+ /// class MainClass
+ /// {
+ /// public static void Main(string[] args)
+ /// {
+ /// string[] filenames = Directory.GetFiles(args[0]);
+ ///
+ /// ZipOutputStream s = new ZipOutputStream(File.Create(args[1]));
+ ///
+ /// s.SetLevel(5); // 0 - store only to 9 - means best compression
+ ///
+ /// foreach (string file in filenames) {
+ /// FileStream fs = File.OpenRead(file);
+ ///
+ /// byte[] buffer = new byte[fs.Length];
+ /// fs.Read(buffer, 0, buffer.Length);
+ ///
+ /// ZipEntry entry = new ZipEntry(file);
+ ///
+ /// s.PutNextEntry(entry);
+ ///
+ /// s.Write(buffer, 0, buffer.Length);
+ ///
+ /// }
+ ///
+ /// s.Finish();
+ /// s.Close();
+ /// }
+ /// }
+ /// </code>
+ /// </example>
+ public class ZipOutputStream : DeflaterOutputStream
+ {
+ private ArrayList entries = new ArrayList();
+ private Crc32 crc = new Crc32();
+ private ZipEntry curEntry = null;
+
+ private CompressionMethod curMethod;
+ private int size;
+ private int offset = 0;
+
+ private byte[] zipComment = new byte[0];
+ private int defaultMethod = DEFLATED;
+
+ /// <summary>
+ /// Our Zip version is hard coded to 1.0 resp. 2.0
+ /// </summary>
+ private const int ZIP_STORED_VERSION = 10;
+ private const int ZIP_DEFLATED_VERSION = 20;
+
+ /// <summary>
+ /// Compression method. This method doesn't compress at all.
+ /// </summary>
+ public const int STORED = 0;
+
+ /// <summary>
+ /// Compression method. This method uses the Deflater.
+ /// </summary>
+ public const int DEFLATED = 8;
+
+ /// <summary>
+ /// Creates a new Zip output stream, writing a zip archive.
+ /// </summary>
+ /// <param name="baseOutputStream">
+ /// the output stream to which the zip archive is written.
+ /// </param>
+ public ZipOutputStream(Stream baseOutputStream) : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true))
+ {
+ }
+
+ /// <summary>
+ /// Set the zip file comment.
+ /// </summary>
+ /// <param name="comment">
+ /// the comment.
+ /// </param>
+ /// <exception name ="ArgumentException">
+ /// if UTF8 encoding of comment is longer than 0xffff bytes.
+ /// </exception>
+ public void SetComment(string comment)
+ {
+ byte[] commentBytes = ZipConstants.ConvertToArray(comment);
+ if (commentBytes.Length > 0xffff) {
+ throw new ArgumentException("Comment too long.");
+ }
+ zipComment = commentBytes;
+ }
+
+ /// <summary>
+ /// Sets default compression method. If the Zip entry specifies
+ /// another method its method takes precedence.
+ /// </summary>
+ /// <param name = "method">
+ /// the method.
+ /// </param>
+ /// <exception name = "ArgumentException">
+ /// if method is not supported.
+ /// </exception>
+ public void SetMethod(int method)
+ {
+ if (method != STORED && method != DEFLATED) {
+ throw new ArgumentException("Method not supported.");
+ }
+ defaultMethod = method;
+ }
+
+ /// <summary>
+ /// Sets default compression level. The new level will be activated
+ /// immediately.
+ /// </summary>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// if level is not supported.
+ /// </exception>
+ /// <see cref="Deflater"/>
+ public void SetLevel(int level)
+ {
+ def.SetLevel(level);
+ }
+
+ /// <summary>
+ /// Write an unsigned short in little endian byte order.
+ /// </summary>
+ private void WriteLeShort(int value)
+ {
+ baseOutputStream.WriteByte((byte)value);
+ baseOutputStream.WriteByte((byte)(value >> 8));
+ }
+
+ /// <summary>
+ /// Write an int in little endian byte order.
+ /// </summary>
+ private void WriteLeInt(int value)
+ {
+ WriteLeShort(value);
+ WriteLeShort(value >> 16);
+ }
+
+ /// <summary>
+ /// Write an int in little endian byte order.
+ /// </summary>
+ private void WriteLeLong(long value)
+ {
+ WriteLeInt((int)value);
+ WriteLeInt((int)(value >> 32));
+ }
+
+
+ bool shouldWriteBack = false;
+ // -jr- Having a hard coded flag for seek capability requires this so users can determine
+ // if the entries will be patched or not.
+ public bool CanPatchEntries {
+ get {
+ return baseOutputStream.CanSeek;
+ }
+ }
+
+ long seekPos = -1;
+ /// <summary>
+ /// Starts a new Zip entry. It automatically closes the previous
+ /// entry if present. If the compression method is stored, the entry
+ /// must have a valid size and crc, otherwise all elements (except
+ /// name) are optional, but must be correct if present. If the time
+ /// is not set in the entry, the current time is used.
+ /// </summary>
+ /// <param name="entry">
+ /// the entry.
+ /// </param>
+ /// <exception cref="System.IO.IOException">
+ /// if an I/O error occured.
+ /// </exception>
+ /// <exception cref="System.InvalidOperationException">
+ /// if stream was finished
+ /// </exception>
+ public void PutNextEntry(ZipEntry entry)
+ {
+ if (entries == null) {
+ throw new InvalidOperationException("ZipOutputStream was finished");
+ }
+
+ CompressionMethod method = entry.CompressionMethod;
+ int flags = 0;
+ entry.IsCrypted = Password != null;
+ switch (method) {
+ case CompressionMethod.Stored:
+ if (entry.CompressedSize >= 0) {
+ if (entry.Size < 0) {
+ entry.Size = entry.CompressedSize;
+ } else if (entry.Size != entry.CompressedSize) {
+ throw new ZipException("Method STORED, but compressed size != size");
+ }
+ } else {
+ entry.CompressedSize = entry.Size;
+ }
+
+ if (entry.IsCrypted) {
+ entry.CompressedSize += 12;
+ }
+
+ if (entry.Size < 0) {
+ throw new ZipException("Method STORED, but size not set");
+ } else if (entry.Crc < 0) {
+ throw new ZipException("Method STORED, but crc not set");
+ }
+ break;
+ case CompressionMethod.Deflated:
+ if (entry.CompressedSize < 0 || entry.Size < 0 || entry.Crc < 0) {
+ flags |= 8;
+ }
+ break;
+ }
+
+ if (curEntry != null) {
+ CloseEntry();
+ }
+
+ // if (entry.DosTime < 0) {
+ // entry.Time = System.Environment.TickCount;
+ // }
+ if (entry.IsCrypted) {
+ flags |= 1;
+ }
+ entry.Flags = flags;
+ entry.Offset = offset;
+ entry.CompressionMethod = (CompressionMethod)method;
+
+ curMethod = method;
+ // Write the local file header
+ WriteLeInt(ZipConstants.LOCSIG);
+
+ // write ZIP version
+ WriteLeShort(method == CompressionMethod.Stored ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION);
+ if ((flags & 8) == 0) {
+ WriteLeShort(flags);
+ WriteLeShort((byte)method);
+ WriteLeInt((int)entry.DosTime);
+ WriteLeInt((int)entry.Crc);
+ WriteLeInt((int)entry.CompressedSize);
+ WriteLeInt((int)entry.Size);
+ } else {
+ if (baseOutputStream.CanSeek) {
+ shouldWriteBack = true;
+ WriteLeShort((short)(flags & ~8));
+ } else {
+ shouldWriteBack = false;
+ WriteLeShort(flags);
+ }
+ WriteLeShort((byte)method);
+ WriteLeInt((int)entry.DosTime);
+ if (baseOutputStream.CanSeek) {
+ seekPos = baseOutputStream.Position;
+ }
+ WriteLeInt(0);
+ WriteLeInt(0);
+ WriteLeInt(0);
+ }
+ byte[] name = ZipConstants.ConvertToArray(entry.Name);
+
+ if (name.Length > 0xFFFF) {
+ throw new ZipException("Name too long.");
+ }
+ byte[] extra = entry.ExtraData;
+ if (extra == null) {
+ extra = new byte[0];
+ }
+ if (extra.Length > 0xFFFF) {
+ throw new ZipException("Extra data too long.");
+ }
+
+ WriteLeShort(name.Length);
+ WriteLeShort(extra.Length);
+ baseOutputStream.Write(name, 0, name.Length);
+ baseOutputStream.Write(extra, 0, extra.Length);
+
+ if (Password != null) {
+ InitializePassword(Password);
+ byte[] cryptbuffer = new byte[12];
+ Random rnd = new Random();
+ for (int i = 0; i < cryptbuffer.Length; ++i) {
+ cryptbuffer[i] = (byte)rnd.Next();
+ }
+ EncryptBlock(cryptbuffer, 0, cryptbuffer.Length);
+ baseOutputStream.Write(cryptbuffer, 0, cryptbuffer.Length);
+ }
+ offset += ZipConstants.LOCHDR + name.Length + extra.Length;
+
+ /* Activate the entry. */
+ curEntry = entry;
+ crc.Reset();
+ if (method == CompressionMethod.Deflated) {
+ def.Reset();
+ }
+ size = 0;
+ }
+
+ /// <summary>
+ /// Closes the current entry.
+ /// </summary>
+ /// <exception cref="System.IO.IOException">
+ /// if an I/O error occured.
+ /// </exception>
+ /// <exception cref="System.InvalidOperationException">
+ /// if no entry is active.
+ /// </exception>
+ public void CloseEntry()
+ {
+ if (curEntry == null) {
+ throw new InvalidOperationException("No open entry");
+ }
+
+ /* First finish the deflater, if appropriate */
+ if (curMethod == CompressionMethod.Deflated) {
+ base.Finish();
+ }
+
+ int csize = curMethod == CompressionMethod.Deflated ? def.TotalOut : size;
+
+ 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.IsCrypted) {
+ csize += 12;
+ }
+
+ 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;
+
+ /* Now write the data descriptor entry if needed. */
+ if (curMethod == CompressionMethod.Deflated && (curEntry.Flags & 8) != 0) {
+ if (shouldWriteBack) {
+ curEntry.Flags &= ~8;
+ long curPos = baseOutputStream.Position;
+ baseOutputStream.Seek(seekPos, SeekOrigin.Begin);
+ WriteLeInt((int)curEntry.Crc);
+ WriteLeInt((int)curEntry.CompressedSize);
+ WriteLeInt((int)curEntry.Size);
+ baseOutputStream.Seek(curPos, SeekOrigin.Begin);
+ shouldWriteBack = false;
+ } else {
+ WriteLeInt(ZipConstants.EXTSIG);
+ WriteLeInt((int)curEntry.Crc);
+ WriteLeInt((int)curEntry.CompressedSize);
+ WriteLeInt((int)curEntry.Size);
+ offset += ZipConstants.EXTHDR;
+ }
+ }
+
+ entries.Add(curEntry);
+ curEntry = null;
+ }
+
+ /// <summary>
+ /// Writes the given buffer to the current entry.
+ /// </summary>
+ /// <exception cref="System.IO.IOException">
+ /// if an I/O error occured.
+ /// </exception>
+ /// <exception cref="System.InvalidOperationException">
+ /// if no entry is active.
+ /// </exception>
+ public override void Write(byte[] b, int off, int len)
+ {
+ if (curEntry == null) {
+ throw new InvalidOperationException("No open entry.");
+ }
+
+ switch (curMethod) {
+ case CompressionMethod.Deflated:
+ base.Write(b, off, len);
+ break;
+ case CompressionMethod.Stored:
+ if (Password != null) {
+ byte[] buf = new byte[len];
+ Array.Copy(b, off, buf, 0, len);
+ EncryptBlock(buf, 0, len);
+ baseOutputStream.Write(buf, off, len);
+ } else {
+ baseOutputStream.Write(b, off, len);
+ }
+ break;
+ }
+ crc.Update(b, off, len);
+
+ size += len;
+ }
+
+ /// <summary>
+ /// Finishes the stream. This will write the central directory at the
+ /// end of the zip file and flush the stream.
+ /// </summary>
+ /// <exception cref="System.IO.IOException">
+ /// if an I/O error occured.
+ /// </exception>
+ public override void Finish()
+ {
+ if (entries == null) {
+ return;
+ }
+
+ if (curEntry != null) {
+ CloseEntry();
+ }
+
+ int numEntries = 0;
+ int sizeEntries = 0;
+
+ foreach (ZipEntry entry in entries) {
+ // TODO : check the appnote file for compilance with the central directory standard
+ CompressionMethod method = entry.CompressionMethod;
+ WriteLeInt(ZipConstants.CENSIG);
+ WriteLeShort(method == CompressionMethod.Stored ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION);
+ WriteLeShort(method == CompressionMethod.Stored ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION);
+
+ WriteLeShort(entry.Flags);
+ WriteLeShort((short)method);
+ WriteLeInt((int)entry.DosTime);
+ WriteLeInt((int)entry.Crc);
+ WriteLeInt((int)entry.CompressedSize);
+ WriteLeInt((int)entry.Size);
+
+ byte[] name = ZipConstants.ConvertToArray(entry.Name);
+
+ if (name.Length > 0xffff) {
+ throw new ZipException("Name too long.");
+ }
+
+ byte[] extra = entry.ExtraData;
+ if (extra == null) {
+ extra = new byte[0];
+ }
+
+ string strComment = entry.Comment;
+ byte[] comment = strComment != null ? ZipConstants.ConvertToArray(strComment) : new byte[0];
+ if (comment.Length > 0xffff) {
+ throw new ZipException("Comment too long.");
+ }
+
+ WriteLeShort(name.Length);
+ WriteLeShort(extra.Length);
+ WriteLeShort(comment.Length);
+ WriteLeShort(0); // disk number
+ WriteLeShort(0); // internal file attr
+ if (entry.IsDirectory) { // -jr- 17-12-2003 mark entry as directory (from nikolam.AT.perfectinfo.com)
+ WriteLeInt(16);
+ } else {
+ WriteLeInt(0); // external file attr
+ }
+ WriteLeInt(entry.Offset);
+
+ baseOutputStream.Write(name, 0, name.Length);
+ baseOutputStream.Write(extra, 0, extra.Length);
+ baseOutputStream.Write(comment, 0, comment.Length);
+ ++numEntries;
+ sizeEntries += ZipConstants.CENHDR + name.Length + extra.Length + comment.Length;
+ }
+
+ WriteLeInt(ZipConstants.ENDSIG);
+ WriteLeShort(0); // disk number
+ WriteLeShort(0); // disk with start of central dir
+ WriteLeShort(numEntries);
+ WriteLeShort(numEntries);
+ WriteLeInt(sizeEntries);
+ WriteLeInt(offset);
+ WriteLeShort(zipComment.Length);
+ baseOutputStream.Write(zipComment, 0, zipComment.Length);
+ baseOutputStream.Flush();
+ entries = null;
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/ZipException.cs b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/ZipException.cs new file mode 100644 index 00000000000..b342592569a --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/ZipException.cs @@ -0,0 +1,62 @@ +// 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;
+
+namespace ICSharpCode.SharpZipLib
+{
+
+ /// <summary>
+ /// Is thrown during the creation or input of a zip file.
+ /// </summary>
+ public class ZipException : Exception
+ {
+ /// <summary>
+ /// Initializes a new instance of the ZipException class with default properties.
+ /// </summary>
+ public ZipException()
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the ZipException class with a specified error message.
+ /// </summary>
+ public ZipException(string msg) : base(msg)
+ {
+ }
+ }
+}
diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/Makefile b/mcs/class/Compat.ICSharpCode.SharpZipLib/Makefile new file mode 100644 index 00000000000..fe5ae55972c --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/Makefile @@ -0,0 +1,12 @@ +thisdir = class/ICSharpCode.SharpZipLib +SUBDIRS = +include ../../build/rules.make + +LIBRARY = ICSharpCode.SharpZipLib.dll +LIBRARY_SNK = SharpZipLib.key + +LIB_MCS_FLAGS = /r:$(corlib) /r:System.dll /r:System.Xml.dll +NO_TEST = yes +EXTRA_DISTFILES = SharpZipLib.pub $(LIBRARY_SNK) + +include ../../build/library.make diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/README b/mcs/class/Compat.ICSharpCode.SharpZipLib/README new file mode 100644 index 00000000000..e38911920ac --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/README @@ -0,0 +1,28 @@ +I imported the 0.6 version of the library. The only changes from the origional were +the case of some of the file names -- I changed them to match the names in cvs. + +Ben Maurer. May, 2004. + +-------------------- + +This directory contains a local copy of the Zip library from the NZipLib project. + +I have added this as a temporary measure to simplify the building and development +of the Mono Documentation browser, but ideally it should use the real +library. Do not fix bugs here, fix it on the original, and incorporate them +here. + +This code is released under this license, from: + + http://www.icsharpcode.net/OpenSource/SharpZipLib/Default.aspx + +Here it is: + +The library is released under the GPL with the following exception: + +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. + + +Miguel. Jan, 2003 diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/SharpZipLib.key b/mcs/class/Compat.ICSharpCode.SharpZipLib/SharpZipLib.key Binary files differnew file mode 100755 index 00000000000..58cf194dfdb --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/SharpZipLib.key diff --git a/mcs/class/Compat.ICSharpCode.SharpZipLib/SharpZipLib.pub b/mcs/class/Compat.ICSharpCode.SharpZipLib/SharpZipLib.pub Binary files differnew file mode 100644 index 00000000000..c74794f1332 --- /dev/null +++ b/mcs/class/Compat.ICSharpCode.SharpZipLib/SharpZipLib.pub |