Add SharpZiplib
authorMiguel de Icaza <miguel@gnome.org>
Thu, 6 Mar 2003 01:17:10 +0000 (01:17 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Thu, 6 Mar 2003 01:17:10 +0000 (01:17 -0000)
svn path=/trunk/mcs/; revision=12238

29 files changed:
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/AssemblyInfo.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2Constants.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2InputStream.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2OutputStream.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/Adler32.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/Crc32.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/IChecksum.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/StrangeCrc.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipConstants.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipInputStream.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipOutputStream.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/InvalidHeaderException.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarArchive.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarBuffer.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarEntry.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarHeader.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarInputStream.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarOutputStream.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipConstants.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipFile.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipInputStream.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/ZipException.cs [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/README [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/SharpZipLib.build [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/list [new file with mode: 0644]
mcs/class/ICSharpCode.SharpZipLib/makefile.gnu [new file with mode: 0644]

diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/AssemblyInfo.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..ee1a4bd
--- /dev/null
@@ -0,0 +1,50 @@
+// AssemblyInfo.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System.Reflection;\r
+using System.Runtime.CompilerServices;\r
+\r
+[assembly: AssemblyTitle("SharpZipLibrary")]\r
+[assembly: AssemblyDescription("free C# zlib implementation")]\r
+[assembly: AssemblyConfiguration("")]\r
+[assembly: AssemblyCompany("")]\r
+[assembly: AssemblyProduct("#ZipLibrary")]\r
+[assembly: AssemblyCopyright("(c) Mike Krueger 2001-2002")]\r
+[assembly: AssemblyTrademark("")]\r
+[assembly: AssemblyCulture("")]\r
+\r
+[assembly: AssemblyVersion("0.31.0.0")]\r
+\r
+[assembly: AssemblyDelaySign(false)]\r
+[assembly: AssemblyKeyFile("SharpZipLib.key")]\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2.cs
new file mode 100644 (file)
index 0000000..8cb27a4
--- /dev/null
@@ -0,0 +1,98 @@
+// BZip2.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.IO;\r
+\r
+namespace ICSharpCode.SharpZipLib.BZip2 {\r
+       \r
+       /// <summary>\r
+       /// Does all the compress and decompress pre-operation stuff.\r
+       /// Sets up the streams and file header characters.\r
+       /// Uses multiply overloaded methods to call for the compress/decompress.\r
+       /// </summary>\r
+       public sealed class BZip2\r
+       {\r
+               public static void Decompress(Stream instream, Stream outstream) \r
+               {\r
+                       BufferedStream bos = new BufferedStream(outstream);\r
+                       BufferedStream bis = new BufferedStream(instream);\r
+                       int b = bis.ReadByte();\r
+                       if (b != 'B') {\r
+                               return;\r
+                       }\r
+                       b = bis.ReadByte();\r
+                       if (b != 'Z') {\r
+                               return;\r
+                       }\r
+                       BZip2InputStream bzis = new BZip2InputStream(bis);\r
+                       int ch = bzis.ReadByte();\r
+                       while (ch != -1) {\r
+                               bos.WriteByte((byte)ch);\r
+                               ch = bzis.ReadByte();\r
+                       }\r
+                       bos.Flush();\r
+               }\r
+               \r
+               public static void Compress(Stream instream, Stream outstream, int blockSize) \r
+               {\r
+                       BufferedStream bos = new BufferedStream(outstream);\r
+                       bos.WriteByte((byte)'B');\r
+                       bos.WriteByte((byte)'Z');\r
+                       BufferedStream bis = new BufferedStream(instream);\r
+                       int ch = bis.ReadByte();\r
+                       BZip2OutputStream bzos = new BZip2OutputStream(bos);\r
+                       while(ch != -1) {\r
+                               bzos.WriteByte((byte)ch);\r
+                               ch = bis.ReadByte();\r
+                       }\r
+                       bis.Close();\r
+                       bzos.Close();\r
+               }\r
+       }\r
+}\r
+/* derived from a file which contained this license :\r
+ * Copyright (c) 1999-2001 Keiron Liddle, Aftex Software\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ *\r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ *\r
+*/\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2Constants.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2Constants.cs
new file mode 100644 (file)
index 0000000..d6fa589
--- /dev/null
@@ -0,0 +1,155 @@
+// BZip2Constants.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+namespace ICSharpCode.SharpZipLib.BZip2 {\r
+       \r
+       /// <summary>\r
+       /// Base class for both the compress and decompress classes.\r
+       /// Holds common arrays, and static data.\r
+       /// </summary>\r
+       public sealed class BZip2Constants\r
+       {\r
+               public readonly static int[] rNums = {\r
+                       619, 720, 127, 481, 931, 816, 813, 233, 566, 247,\r
+                       985, 724, 205, 454, 863, 491, 741, 242, 949, 214,\r
+                       733, 859, 335, 708, 621, 574, 73, 654, 730, 472,\r
+                       419, 436, 278, 496, 867, 210, 399, 680, 480, 51,\r
+                       878, 465, 811, 169, 869, 675, 611, 697, 867, 561,\r
+                       862, 687, 507, 283, 482, 129, 807, 591, 733, 623,\r
+                       150, 238, 59, 379, 684, 877, 625, 169, 643, 105,\r
+                       170, 607, 520, 932, 727, 476, 693, 425, 174, 647,\r
+                       73, 122, 335, 530, 442, 853, 695, 249, 445, 515,\r
+                       909, 545, 703, 919, 874, 474, 882, 500, 594, 612,\r
+                       641, 801, 220, 162, 819, 984, 589, 513, 495, 799,\r
+                       161, 604, 958, 533, 221, 400, 386, 867, 600, 782,\r
+                       382, 596, 414, 171, 516, 375, 682, 485, 911, 276,\r
+                       98, 553, 163, 354, 666, 933, 424, 341, 533, 870,\r
+                       227, 730, 475, 186, 263, 647, 537, 686, 600, 224,\r
+                       469, 68, 770, 919, 190, 373, 294, 822, 808, 206,\r
+                       184, 943, 795, 384, 383, 461, 404, 758, 839, 887,\r
+                       715, 67, 618, 276, 204, 918, 873, 777, 604, 560,\r
+                       951, 160, 578, 722, 79, 804, 96, 409, 713, 940,\r
+                       652, 934, 970, 447, 318, 353, 859, 672, 112, 785,\r
+                       645, 863, 803, 350, 139, 93, 354, 99, 820, 908,\r
+                       609, 772, 154, 274, 580, 184, 79, 626, 630, 742,\r
+                       653, 282, 762, 623, 680, 81, 927, 626, 789, 125,\r
+                       411, 521, 938, 300, 821, 78, 343, 175, 128, 250,\r
+                       170, 774, 972, 275, 999, 639, 495, 78, 352, 126,\r
+                       857, 956, 358, 619, 580, 124, 737, 594, 701, 612,\r
+                       669, 112, 134, 694, 363, 992, 809, 743, 168, 974,\r
+                       944, 375, 748, 52, 600, 747, 642, 182, 862, 81,\r
+                       344, 805, 988, 739, 511, 655, 814, 334, 249, 515,\r
+                       897, 955, 664, 981, 649, 113, 974, 459, 893, 228,\r
+                       433, 837, 553, 268, 926, 240, 102, 654, 459, 51,\r
+                       686, 754, 806, 760, 493, 403, 415, 394, 687, 700,\r
+                       946, 670, 656, 610, 738, 392, 760, 799, 887, 653,\r
+                       978, 321, 576, 617, 626, 502, 894, 679, 243, 440,\r
+                       680, 879, 194, 572, 640, 724, 926, 56, 204, 700,\r
+                       707, 151, 457, 449, 797, 195, 791, 558, 945, 679,\r
+                       297, 59, 87, 824, 713, 663, 412, 693, 342, 606,\r
+                       134, 108, 571, 364, 631, 212, 174, 643, 304, 329,\r
+                       343, 97, 430, 751, 497, 314, 983, 374, 822, 928,\r
+                       140, 206, 73, 263, 980, 736, 876, 478, 430, 305,\r
+                       170, 514, 364, 692, 829, 82, 855, 953, 676, 246,\r
+                       369, 970, 294, 750, 807, 827, 150, 790, 288, 923,\r
+                       804, 378, 215, 828, 592, 281, 565, 555, 710, 82,\r
+                       896, 831, 547, 261, 524, 462, 293, 465, 502, 56,\r
+                       661, 821, 976, 991, 658, 869, 905, 758, 745, 193,\r
+                       768, 550, 608, 933, 378, 286, 215, 979, 792, 961,\r
+                       61, 688, 793, 644, 986, 403, 106, 366, 905, 644,\r
+                       372, 567, 466, 434, 645, 210, 389, 550, 919, 135,\r
+                       780, 773, 635, 389, 707, 100, 626, 958, 165, 504,\r
+                       920, 176, 193, 713, 857, 265, 203, 50, 668, 108,\r
+                       645, 990, 626, 197, 510, 357, 358, 850, 858, 364,\r
+                       936, 638\r
+               };\r
+               \r
+               public readonly static int baseBlockSize = 100000;\r
+               \r
+               public readonly static int MAX_ALPHA_SIZE = 258;\r
+               public readonly static int MAX_CODE_LEN = 23;\r
+               \r
+               public readonly static int RUNA = 0;\r
+               public readonly static int RUNB = 1;\r
+               \r
+               public readonly static int N_GROUPS = 6;\r
+               public readonly static int G_SIZE = 50;\r
+               public readonly static int N_ITERS = 4;\r
+               \r
+               public readonly static int MAX_SELECTORS = (2 + (900000 / G_SIZE));\r
+               \r
+               public readonly static int NUM_OVERSHOOT_BYTES = 20;\r
+       }\r
+}\r
+       \r
+/* This file was derived from a file containing under this license:\r
+ * \r
+ * This file is a part of bzip2 and/or libbzip2, a program and\r
+ * library for lossless, block-sorting data compression.\r
+ * \r
+ * Copyright (C) 1996-1998 Julian R Seward.  All rights reserved.\r
+ * \r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * \r
+ * 1. Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * \r
+ * 2. The origin of this software must not be misrepresented; you must \r
+ * not claim that you wrote the original software.  If you use this \r
+ * software in a product, an acknowledgment in the product \r
+ * documentation would be appreciated but is not required.\r
+ * \r
+ * 3. Altered source versions must be plainly marked as such, and must\r
+ * not be misrepresented as being the original software.\r
+ * \r
+ * 4. The name of the author may not be used to endorse or promote \r
+ * products derived from this software without specific prior written \r
+ * permission.\r
+ * \r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\r
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\r
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\r
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ * \r
+ * Java version ported by Keiron Liddle, Aftex Software <keiron@aftexsw.com> 1999-2001\r
+ */\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2InputStream.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2InputStream.cs
new file mode 100644 (file)
index 0000000..c4e2109
--- /dev/null
@@ -0,0 +1,945 @@
+// BZip2InputStream.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.IO;\r
+\r
+using ICSharpCode.SharpZipLib.Checksums;\r
+\r
+namespace ICSharpCode.SharpZipLib.BZip2 {\r
+       \r
+       /// <summary>\r
+       /// An input stream that decompresses from the BZip2 format (without the file\r
+       /// header chars) to be read as any other stream.\r
+       /// </summary>\r
+       public class BZip2InputStream : Stream\r
+       {\r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override bool CanRead {\r
+                       get {\r
+                               return baseStream.CanRead;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override bool CanSeek {\r
+                       get {\r
+                               return baseStream.CanSeek;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override bool CanWrite {\r
+                       get {\r
+                               return baseStream.CanWrite;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override long Length {\r
+                       get {\r
+                               return baseStream.Length;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override long Position {\r
+                       get {\r
+                               return baseStream.Position;\r
+                       }\r
+                       set {\r
+                               baseStream.Position = value;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Flushes the baseInputStream\r
+               /// </summary>\r
+               public override void Flush()\r
+               {\r
+                       if (baseStream != null) {\r
+                               baseStream.Flush();\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override long Seek(long offset, SeekOrigin origin)\r
+               {\r
+                       return baseStream.Seek(offset, origin);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override void SetLength(long val)\r
+               {\r
+                       baseStream.SetLength(val);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override void Write(byte[] array, int offset, int count)\r
+               {\r
+                       baseStream.Write(array, offset, count);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override void WriteByte(byte val)\r
+               {\r
+                       baseStream.WriteByte(val);\r
+               }\r
+               \r
+               public override int Read(byte[] b, int off, int len)\r
+               {\r
+                       for (int i = 0; i < len; ++i) {\r
+                               int rb = ReadByte();\r
+                               if (rb == -1) {\r
+                                       return i;\r
+                               }\r
+                               b[off + i] = (byte)rb;\r
+                       }\r
+                       return len;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Closes the input stream\r
+               /// </summary>\r
+               public override void Close()\r
+               {\r
+                       if (baseStream != null) {\r
+                               baseStream.Close();\r
+                       }\r
+               }\r
+               \r
+               static void Cadvise()\r
+               {\r
+                       Console.WriteLine("CRC Error");\r
+                       //throw new CCoruptionError();\r
+               }\r
+               \r
+               static void BadBGLengths() \r
+               {\r
+                       Console.WriteLine("bad BG lengths");\r
+               }\r
+               \r
+               static void bitStreamEOF() \r
+               {\r
+                       Console.WriteLine("bit stream eof");\r
+               }\r
+               \r
+               static void CompressedStreamEOF() \r
+               {\r
+                       Console.WriteLine("compressed stream eof");\r
+               }\r
+               \r
+               void MakeMaps() \r
+               {\r
+                       nInUse = 0;\r
+                       for (int i = 0; i < 256; ++i) {\r
+                               if (inUse[i]) {\r
+                                       seqToUnseq[nInUse] = (byte)i;\r
+                                       unseqToSeq[i] = (byte)nInUse;\r
+                                       nInUse++;\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               /*--\r
+               index of the last char in the block, so\r
+               the block size == last + 1.\r
+               --*/\r
+               int last;\r
+               \r
+               /*--\r
+               index in zptr[] of original string after sorting.\r
+               --*/\r
+               int origPtr;\r
+               \r
+               /*--\r
+               always: in the range 0 .. 9.\r
+               The current block size is 100000 * this number.\r
+               --*/\r
+               int blockSize100k;\r
+               \r
+               bool blockRandomised;\r
+               \r
+//             private int bytesIn;\r
+//             private int bytesOut;\r
+               int bsBuff;\r
+               int bsLive;\r
+               IChecksum mCrc = new StrangeCRC();\r
+               \r
+               bool[] inUse = new bool[256];\r
+               int    nInUse;\r
+               \r
+               byte[] seqToUnseq = new byte[256];\r
+               byte[] unseqToSeq = new byte[256];\r
+               \r
+               byte[] selector    = new byte[BZip2Constants.MAX_SELECTORS];\r
+               byte[] selectorMtf = new byte[BZip2Constants.MAX_SELECTORS];\r
+               \r
+               int[] tt;\r
+               byte[] ll8;\r
+               \r
+               /*--\r
+               freq table collected to save a pass over the data\r
+               during decompression.\r
+               --*/\r
+               int[] unzftab = new int[256];\r
+               \r
+               int[][] limit     = new int[BZip2Constants.N_GROUPS][];\r
+               int[][] baseArray = new int[BZip2Constants.N_GROUPS][];\r
+               int[][] perm      = new int[BZip2Constants.N_GROUPS][];\r
+               int[] minLens     = new int[BZip2Constants.N_GROUPS];\r
+               \r
+               Stream baseStream;\r
+               bool   streamEnd = false;\r
+               \r
+               int currentChar = -1;\r
+               \r
+               const int START_BLOCK_STATE = 1;\r
+               const int RAND_PART_A_STATE = 2;\r
+               const int RAND_PART_B_STATE = 3;\r
+               const int RAND_PART_C_STATE = 4;\r
+               const int NO_RAND_PART_A_STATE = 5;\r
+               const int NO_RAND_PART_B_STATE = 6;\r
+               const int NO_RAND_PART_C_STATE = 7;\r
+               \r
+               int currentState = START_BLOCK_STATE;\r
+               \r
+               int storedBlockCRC, storedCombinedCRC;\r
+               int computedBlockCRC;\r
+               uint computedCombinedCRC;\r
+               \r
+               int count, chPrev, ch2;\r
+               int tPos;\r
+               int rNToGo = 0;\r
+               int rTPos  = 0;\r
+               int i2, j2;\r
+               byte z;\r
+               \r
+               public BZip2InputStream(Stream zStream) \r
+               {\r
+                       // init arrays\r
+                       for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {\r
+                               limit[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];\r
+                               baseArray[i]  = new int[BZip2Constants.MAX_ALPHA_SIZE];\r
+                               perm[i]  = new int[BZip2Constants.MAX_ALPHA_SIZE];\r
+                       }\r
+                       \r
+                       ll8 = null;\r
+                       tt  = null;\r
+                       BsSetStream(zStream);\r
+                       Initialize();\r
+                       InitBlock();\r
+                       SetupBlock();\r
+               }\r
+               \r
+               public override int ReadByte()\r
+               {\r
+                       if (streamEnd) {\r
+                               return -1;\r
+                       }\r
+                       \r
+                       int retChar = currentChar;\r
+                       switch (currentState) {\r
+                               case RAND_PART_B_STATE:\r
+                                       SetupRandPartB();\r
+                                       break;\r
+                               case RAND_PART_C_STATE:\r
+                                       SetupRandPartC();\r
+                                       break;\r
+                               case NO_RAND_PART_B_STATE:\r
+                                       SetupNoRandPartB();\r
+                                       break;\r
+                               case NO_RAND_PART_C_STATE:\r
+                                       SetupNoRandPartC();\r
+                                       break;\r
+                               case START_BLOCK_STATE:\r
+                               case NO_RAND_PART_A_STATE:\r
+                               case RAND_PART_A_STATE:\r
+                                       break;\r
+                               default:\r
+                                       break;\r
+                       }\r
+                       return retChar;\r
+               }\r
+               \r
+               void Initialize() \r
+               {\r
+                       char magic3 = BsGetUChar();\r
+                       char magic4 = BsGetUChar();\r
+                       \r
+                       if (magic3 != 'h' || magic4 < '1' || magic4 > '9') {\r
+                               streamEnd = true;\r
+                               return;\r
+                       }\r
+                       \r
+                       SetDecompressStructureSizes(magic4 - '0');\r
+                       computedCombinedCRC = 0;\r
+               }\r
+               \r
+               void InitBlock() \r
+               {\r
+                       char magic1 = BsGetUChar();\r
+                       char magic2 = BsGetUChar();\r
+                       char magic3 = BsGetUChar();\r
+                       char magic4 = BsGetUChar();\r
+                       char magic5 = BsGetUChar();\r
+                       char magic6 = BsGetUChar();\r
+                       \r
+                       if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45 && magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) {\r
+                               Complete();\r
+                               return;\r
+                       }\r
+                       \r
+                       if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) {\r
+                               BadBlockHeader();\r
+                               streamEnd = true;\r
+                               return;\r
+                       }\r
+                       \r
+                       storedBlockCRC  = BsGetInt32();\r
+                       \r
+                       blockRandomised = (BsR(1) == 1);\r
+                       \r
+                       //              currBlockNo++;\r
+                       GetAndMoveToFrontDecode();\r
+                       \r
+                       mCrc.Reset();\r
+                       currentState = START_BLOCK_STATE;\r
+               }\r
+               \r
+               void EndBlock() \r
+               {\r
+                       computedBlockCRC = (int)mCrc.Value;\r
+                       \r
+                       /*-- A bad CRC is considered a fatal error. --*/\r
+                       if (storedBlockCRC != computedBlockCRC) {\r
+                               CrcError();\r
+                       }\r
+                       \r
+                        // 1528150659\r
+                       computedCombinedCRC = ((computedCombinedCRC << 1) & 0xFFFFFFFF) | (computedCombinedCRC >> 31);\r
+                       computedCombinedCRC = computedCombinedCRC ^ (uint)computedBlockCRC;\r
+               }\r
+               \r
+               void Complete() \r
+               {\r
+                       storedCombinedCRC = BsGetInt32();\r
+                       if (storedCombinedCRC != (int)computedCombinedCRC) {\r
+                               CrcError();\r
+                       }\r
+                       \r
+                       streamEnd = true;\r
+               }\r
+               \r
+               static void BlockOverrun() \r
+               {\r
+                       Console.WriteLine("Block overrun");\r
+               }\r
+               \r
+               static void BadBlockHeader() \r
+               {\r
+                       Console.WriteLine("Bad block header");\r
+               }\r
+               \r
+               static void CrcError() \r
+               {\r
+                       Console.WriteLine("crc error");\r
+               }\r
+               \r
+               \r
+               void BsSetStream(Stream f) \r
+               {\r
+                       baseStream = f;\r
+                       bsLive = 0;\r
+                       bsBuff = 0;\r
+               }\r
+               \r
+               void FillBuffer()\r
+               {\r
+                       int thech = 0;\r
+                       \r
+                       try {\r
+                               thech = baseStream.ReadByte();\r
+                       } catch (Exception) {\r
+                               CompressedStreamEOF();\r
+                       }\r
+                       \r
+                       if (thech == -1) {\r
+                               CompressedStreamEOF();\r
+                       }\r
+                       \r
+                       bsBuff = (bsBuff << 8) | (thech & 0xFF);\r
+                       bsLive += 8;\r
+               }\r
+               \r
+               int BsR(int n) \r
+               {\r
+                       while (bsLive < n) {\r
+                               FillBuffer();\r
+                       }\r
+                       \r
+                       int v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1);\r
+                       bsLive -= n;\r
+                       return v;\r
+               }\r
+               \r
+               char BsGetUChar() \r
+               {\r
+                       return (char)BsR(8);\r
+               }\r
+               \r
+               int BsGetint() \r
+               {\r
+                       int u = 0;\r
+                       u = (u << 8) | BsR(8);\r
+                       u = (u << 8) | BsR(8);\r
+                       u = (u << 8) | BsR(8);\r
+                       u = (u << 8) | BsR(8);\r
+                       return u;\r
+               }\r
+               \r
+               int BsGetIntVS(int numBits) \r
+               {\r
+                       return (int)BsR(numBits);\r
+               }\r
+               \r
+               int BsGetInt32() \r
+               {\r
+                       return (int)BsGetint();\r
+               }\r
+               \r
+               void HbCreateDecodeTables(int[] limit, int[] baseArray, int[] perm, char[] length, int minLen, int maxLen, int alphaSize) \r
+               {\r
+                       int pp = 0;\r
+                       \r
+                       for (int i = minLen; i <= maxLen; ++i) {\r
+                               for (int j = 0; j < alphaSize; ++j) {\r
+                                       if (length[j] == i) {\r
+                                               perm[pp] = j;\r
+                                               ++pp;\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       for (int i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) {\r
+                               baseArray[i] = 0;\r
+                       }\r
+                       \r
+                       for (int i = 0; i < alphaSize; i++) {\r
+                               ++baseArray[length[i] + 1];\r
+                       }\r
+                       \r
+                       for (int i = 1; i < BZip2Constants.MAX_CODE_LEN; i++) {\r
+                               baseArray[i] += baseArray[i - 1];\r
+                       }\r
+                       \r
+                       for (int i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) {\r
+                               limit[i] = 0;\r
+                       }\r
+                       \r
+                       int vec = 0;\r
+                       \r
+                       for (int i = minLen; i <= maxLen; i++) {\r
+                               vec += (baseArray[i + 1] - baseArray[i]);\r
+                               limit[i] = vec - 1;\r
+                               vec <<= 1;\r
+                       }\r
+                       \r
+                       for (int i = minLen + 1; i <= maxLen; i++) {\r
+                               baseArray[i] = ((limit[i - 1] + 1) << 1) - baseArray[i];\r
+                       }\r
+               }\r
+               \r
+               void RecvDecodingTables() \r
+               {\r
+                       char[][] len = new char[BZip2Constants.N_GROUPS][];\r
+                       for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {\r
+                               len[i] = new char[BZip2Constants.MAX_ALPHA_SIZE];\r
+                       }\r
+                       \r
+                       bool[] inUse16 = new bool[16];\r
+                       \r
+                       /*--- Receive the mapping table ---*/\r
+                       for (int i = 0; i < 16; i++) {\r
+                               inUse16[i] = (BsR(1) == 1);\r
+                       } \r
+                       \r
+                       for (int i = 0; i < 16; i++) {\r
+                               if (inUse16[i]) {\r
+                                       for (int j = 0; j < 16; j++) {\r
+                                               inUse[i * 16 + j] = (BsR(1) == 1);\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       MakeMaps();\r
+                       int alphaSize = nInUse + 2;\r
+                       \r
+                       /*--- Now the selectors ---*/\r
+                       int nGroups    = BsR(3);\r
+                       int nSelectors = BsR(15);\r
+                       \r
+                       for (int i = 0; i < nSelectors; i++) {\r
+                               int j = 0;\r
+                               while (BsR(1) == 1) {\r
+                                       j++;\r
+                               }\r
+                               selectorMtf[i] = (byte)j;\r
+                       }\r
+                       \r
+                       /*--- Undo the MTF values for the selectors. ---*/\r
+                       byte[] pos = new byte[BZip2Constants.N_GROUPS];\r
+                       for (int v = 0; v < nGroups; v++) {\r
+                               pos[v] = (byte)v;\r
+                       }\r
+                       \r
+                       for (int i = 0; i < nSelectors; i++) {\r
+                               int  v   = selectorMtf[i];\r
+                               byte tmp = pos[v];\r
+                               while (v > 0) {\r
+                                       pos[v] = pos[v - 1];\r
+                                       v--;\r
+                               }\r
+                               pos[0]      = tmp;\r
+                               selector[i] = tmp;\r
+                       }\r
+                       \r
+                       /*--- Now the coding tables ---*/\r
+                       for (int t = 0; t < nGroups; t++) {\r
+                               int curr = BsR(5);\r
+                               for (int i = 0; i < alphaSize; i++) {\r
+                                       while (BsR(1) == 1) {\r
+                                               if (BsR(1) == 0) {\r
+                                                       curr++;\r
+                                               } else {\r
+                                                       curr--;\r
+                                               }\r
+                                       }\r
+                                       len[t][i] = (char)curr;\r
+                               }\r
+                       }\r
+                       \r
+                       /*--- Create the Huffman decoding tables ---*/\r
+                       for (int t = 0; t < nGroups; t++) {\r
+                               int minLen = 32;\r
+                               int maxLen = 0;\r
+                               for (int i = 0; i < alphaSize; i++) {\r
+                                       maxLen = Math.Max(maxLen, len[t][i]);\r
+                                       minLen = Math.Min(minLen, len[t][i]);\r
+                               }\r
+                               HbCreateDecodeTables(limit[t], baseArray[t], perm[t], len[t], minLen, maxLen, alphaSize);\r
+                               minLens[t] = minLen;\r
+                       }\r
+               }\r
+               \r
+               void GetAndMoveToFrontDecode() \r
+               {\r
+                       byte[] yy = new byte[256];\r
+                       int nextSym;\r
+                       \r
+                       int limitLast = BZip2Constants.baseBlockSize * blockSize100k;\r
+                       origPtr = BsGetIntVS(24);\r
+                       \r
+                       RecvDecodingTables();\r
+                       int EOB = nInUse+1;\r
+                       int groupNo = -1;\r
+                       int groupPos = 0;\r
+                       \r
+                       /*--\r
+                       Setting up the unzftab entries here is not strictly\r
+                       necessary, but it does save having to do it later\r
+                       in a separate pass, and so saves a block's worth of\r
+                       cache misses.\r
+                       --*/\r
+                       for (int i = 0; i <= 255; i++) {\r
+                               unzftab[i] = 0;\r
+                       }\r
+                       \r
+                       for (int i = 0; i <= 255; i++) {\r
+                               yy[i] = (byte)i;\r
+                       }\r
+                       \r
+                       last = -1;\r
+                       \r
+                       if (groupPos == 0) {\r
+                               groupNo++;\r
+                               groupPos = BZip2Constants.G_SIZE;\r
+                       }\r
+                       \r
+                       groupPos--;\r
+                       int zt = selector[groupNo];\r
+                       int zn = minLens[zt];\r
+                       int zvec = BsR(zn);\r
+                       int zj;\r
+                       \r
+                       while (zvec > limit[zt][zn]) {\r
+                               zn++;\r
+                               while (bsLive < 1) {\r
+                                       FillBuffer();\r
+                               }\r
+                               zj = (bsBuff >> (bsLive-1)) & 1;\r
+                               bsLive--;\r
+                               zvec = (zvec << 1) | zj;\r
+                       }\r
+                       nextSym = perm[zt][zvec - baseArray[zt][zn]];\r
+                       \r
+                       while (true) {\r
+                               \r
+                               if (nextSym == EOB) {\r
+                                       break;\r
+                               }\r
+                               \r
+                               if (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB) {\r
+                                       int s = -1;\r
+                                       int n = 1;\r
+                                       do {\r
+                                               if (nextSym == BZip2Constants.RUNA) {\r
+                                                       s += (0+1) * n;\r
+                                               } else if (nextSym == BZip2Constants.RUNB) {\r
+                                                       s += (1+1) * n;\r
+                                               }\r
+\r
+                                               n <<= 1;\r
+                                               \r
+                                               if (groupPos == 0) {\r
+                                                       groupNo++;\r
+                                                       groupPos = BZip2Constants.G_SIZE;\r
+                                               }\r
+                                               \r
+                                               groupPos--;\r
+                                               \r
+                                               zt = selector[groupNo];\r
+                                               zn = minLens[zt];\r
+                                               zvec = BsR(zn);\r
+                                               \r
+                                               while (zvec > limit[zt][zn]) {\r
+                                                       zn++;\r
+                                                       while (bsLive < 1) {\r
+                                                               FillBuffer();\r
+                                                       }\r
+                                                       zj = (bsBuff >> (bsLive - 1)) & 1;\r
+                                                       bsLive--;\r
+                                                       zvec = (zvec << 1) | zj;\r
+                                               }\r
+                                               nextSym = perm[zt][zvec - baseArray[zt][zn]];\r
+                                       } while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB);\r
+                                       \r
+                                       s++;\r
+                                       byte ch = seqToUnseq[yy[0]];\r
+                                       unzftab[ch] += s;\r
+                                       \r
+                                       while (s > 0) {\r
+                                               last++;\r
+                                               ll8[last] = ch;\r
+                                               s--;\r
+                                       }\r
+                                       \r
+                                       if (last >= limitLast) {\r
+                                               BlockOverrun();\r
+                                       }\r
+                                       continue;\r
+                               } else {\r
+                                       last++;\r
+                                       if (last >= limitLast) {\r
+                                               BlockOverrun();\r
+                                       }\r
+                                       \r
+                                       byte tmp = yy[nextSym - 1];\r
+                                       unzftab[seqToUnseq[tmp]]++;\r
+                                       ll8[last] = seqToUnseq[tmp];\r
+                                       \r
+                                       for (int j = nextSym-1; j > 0; --j) {\r
+                                               yy[j] = yy[j - 1];\r
+                                       }\r
+                                       yy[0] = tmp;\r
+                                       \r
+                                       if (groupPos == 0) {\r
+                                               groupNo++;\r
+                                               groupPos = BZip2Constants.G_SIZE;\r
+                                       }\r
+                                       \r
+                                       groupPos--;\r
+                                       zt = selector[groupNo];\r
+                                       zn = minLens[zt];\r
+                                       zvec = BsR(zn);\r
+                                       while (zvec > limit[zt][zn]) {\r
+                                               zn++;\r
+                                               while (bsLive < 1) {\r
+                                                       FillBuffer();\r
+                                               }\r
+                                               zj = (bsBuff >> (bsLive-1)) & 1;\r
+                                               bsLive--;\r
+                                               zvec = (zvec << 1) | zj;\r
+                                       }\r
+                                       nextSym = perm[zt][zvec - baseArray[zt][zn]];\r
+                                       continue;\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               void SetupBlock() \r
+               {\r
+                       int[] cftab = new int[257];\r
+                       \r
+                       cftab[0] = 0;\r
+                       Array.Copy(unzftab, 0, cftab, 1, 256);\r
+                       \r
+                       for (int i = 1; i <= 256; i++) {\r
+                               cftab[i] += cftab[i - 1];\r
+                       }\r
+                       \r
+                       for (int i = 0; i <= last; i++) {\r
+                               byte ch = ll8[i];\r
+                               tt[cftab[ch]] = i;\r
+                               cftab[ch]++;\r
+                       }\r
+                       \r
+                       cftab = null;\r
+                       \r
+                       tPos = tt[origPtr];\r
+                       \r
+                       count = 0;\r
+                       i2    = 0;\r
+                       ch2   = 256;   /*-- not a char and not EOF --*/\r
+                       \r
+                       if (blockRandomised) {\r
+                               rNToGo = 0;\r
+                               rTPos = 0;\r
+                               SetupRandPartA();\r
+                       } else {\r
+                               SetupNoRandPartA();\r
+                       }\r
+               }\r
+               \r
+               void SetupRandPartA() \r
+               {\r
+                       if(i2 <= last) {\r
+                               chPrev = ch2;\r
+                               ch2  = ll8[tPos];\r
+                               tPos = tt[tPos];\r
+                               if (rNToGo == 0) {\r
+                                       rNToGo = BZip2Constants.rNums[rTPos];\r
+                                       rTPos++;\r
+                                       if(rTPos == 512) {\r
+                                               rTPos = 0;\r
+                                       }\r
+                               }\r
+                               rNToGo--;\r
+                               ch2 ^= (int)((rNToGo == 1) ? 1 : 0);\r
+                               i2++;\r
+                               \r
+                               currentChar  = ch2;\r
+                               currentState = RAND_PART_B_STATE;\r
+                               mCrc.Update(ch2);\r
+                       } else {\r
+                               EndBlock();\r
+                               InitBlock();\r
+                               SetupBlock();\r
+                       }\r
+               }\r
+               \r
+               void SetupNoRandPartA() \r
+               {\r
+                       if (i2 <= last) {\r
+                               chPrev = ch2;\r
+                               ch2  = ll8[tPos];\r
+                               tPos = tt[tPos];\r
+                               i2++;\r
+                               \r
+                               currentChar = ch2;\r
+                               currentState = NO_RAND_PART_B_STATE;\r
+                               mCrc.Update(ch2);\r
+                       } else {\r
+                               EndBlock();\r
+                               InitBlock();\r
+                               SetupBlock();\r
+                       }\r
+               }\r
+               \r
+               void SetupRandPartB() \r
+               {\r
+                       if (ch2 != chPrev) {\r
+                               currentState = RAND_PART_A_STATE;\r
+                               count = 1;\r
+                               SetupRandPartA();\r
+                       } else {\r
+                               count++;\r
+                               if (count >= 4) {\r
+                                       z = ll8[tPos];\r
+                                       tPos = tt[tPos];\r
+                                       if (rNToGo == 0) {\r
+                                               rNToGo = BZip2Constants.rNums[rTPos];\r
+                                               rTPos++;\r
+                                               if (rTPos == 512) {\r
+                                                       rTPos = 0;\r
+                                               }\r
+                                       }\r
+                                       rNToGo--;\r
+                                       z ^= (byte)((rNToGo == 1) ? 1 : 0);\r
+                                       j2 = 0;\r
+                                       currentState = RAND_PART_C_STATE;\r
+                                       SetupRandPartC();\r
+                               } else {\r
+                                       currentState = RAND_PART_A_STATE;\r
+                                       SetupRandPartA();\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               void SetupRandPartC() \r
+               {\r
+                       if (j2 < (int)z) {\r
+                               currentChar = ch2;\r
+                               mCrc.Update(ch2);\r
+                               j2++;\r
+                       } else {\r
+                               currentState = RAND_PART_A_STATE;\r
+                               i2++;\r
+                               count = 0;\r
+                               SetupRandPartA();\r
+                       }\r
+               }\r
+               \r
+               void SetupNoRandPartB() \r
+               {\r
+                       if (ch2 != chPrev) {\r
+                               currentState = NO_RAND_PART_A_STATE;\r
+                               count = 1;\r
+                               SetupNoRandPartA();\r
+                       } else {\r
+                               count++;\r
+                               if (count >= 4) {\r
+                                       z = ll8[tPos];\r
+                                       tPos = tt[tPos];\r
+                                       currentState = NO_RAND_PART_C_STATE;\r
+                                       j2 = 0;\r
+                                       SetupNoRandPartC();\r
+                               } else {\r
+                                       currentState = NO_RAND_PART_A_STATE;\r
+                                       SetupNoRandPartA();\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               void SetupNoRandPartC() \r
+               {\r
+                       if (j2 < (int)z) {\r
+                               currentChar = ch2;\r
+                               mCrc.Update(ch2);\r
+                               j2++;\r
+                       } else {\r
+                               currentState = NO_RAND_PART_A_STATE;\r
+                               i2++;\r
+                               count = 0;\r
+                               SetupNoRandPartA();\r
+                       }\r
+               }\r
+               \r
+               void SetDecompressStructureSizes(int newSize100k) \r
+               {\r
+                       if (!(0 <= newSize100k   && newSize100k <= 9 && \r
+                             0 <= blockSize100k && blockSize100k <= 9)) {\r
+                               throw new ApplicationException("Invalid block size");\r
+                       }\r
+                              \r
+                       blockSize100k = newSize100k;\r
+                       \r
+                       if (newSize100k == 0) {\r
+                               return;\r
+                       }\r
+                       \r
+                       int n = BZip2Constants.baseBlockSize * newSize100k;\r
+                       ll8 = new byte[n];\r
+                       tt  = new int[n];\r
+               }\r
+       }\r
+}\r
+/* This file was derived from a file containing under this license:\r
+ * \r
+ * This file is a part of bzip2 and/or libbzip2, a program and\r
+ * library for lossless, block-sorting data compression.\r
+ * \r
+ * Copyright (C) 1996-1998 Julian R Seward.  All rights reserved.\r
+ * \r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * \r
+ * 1. Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * \r
+ * 2. The origin of this software must not be misrepresented; you must \r
+ * not claim that you wrote the original software.  If you use this \r
+ * software in a product, an acknowledgment in the product \r
+ * documentation would be appreciated but is not required.\r
+ * \r
+ * 3. Altered source versions must be plainly marked as such, and must\r
+ * not be misrepresented as being the original software.\r
+ * \r
+ * 4. The name of the author may not be used to endorse or promote \r
+ * products derived from this software without specific prior written \r
+ * permission.\r
+ * \r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\r
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\r
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\r
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ * \r
+ * Java version ported by Keiron Liddle, Aftex Software <keiron@aftexsw.com> 1999-2001\r
+ */\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2OutputStream.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/BZip2/BZip2OutputStream.cs
new file mode 100644 (file)
index 0000000..403b441
--- /dev/null
@@ -0,0 +1,1746 @@
+// BZip2OutputStream.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.IO;\r
+\r
+using ICSharpCode.SharpZipLib.Checksums;\r
+\r
+namespace ICSharpCode.SharpZipLib.BZip2 {\r
+       \r
+       /// <summary>\r
+       /// An output stream that compresses into the BZip2 format (without the file\r
+       /// header chars) into another stream.\r
+       /// TODO: Update to BZip2 1.0.1, 1.0.2\r
+       /// </summary>\r
+       public class BZip2OutputStream : Stream\r
+       {\r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override bool CanRead {\r
+                       get {\r
+                               return baseStream.CanRead;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override bool CanSeek {\r
+                       get {\r
+                               return baseStream.CanSeek;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override bool CanWrite {\r
+                       get {\r
+                               return baseStream.CanWrite;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override long Length {\r
+                       get {\r
+                               return baseStream.Length;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override long Position {\r
+                       get {\r
+                               return baseStream.Position;\r
+                       }\r
+                       set {\r
+                               baseStream.Position = value;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override long Seek(long offset, SeekOrigin origin)\r
+               {\r
+                       return baseStream.Seek(offset, origin);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override void SetLength(long val)\r
+               {\r
+                       baseStream.SetLength(val);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override int ReadByte()\r
+               {\r
+                       return baseStream.ReadByte();\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override int Read(byte[] b, int off, int len)\r
+               {\r
+                       return baseStream.Read(b, off, len);\r
+               }\r
+               \r
+               public override void Write(byte[] buf, int off, int len)\r
+               {\r
+                       for (int i = 0; i < len; ++i) {\r
+                               WriteByte(buf[off + i]);\r
+                       }\r
+               }\r
+               \r
+               readonly static int SETMASK       = (1 << 21);\r
+               readonly static int CLEARMASK     = (~SETMASK);\r
+               readonly static int GREATER_ICOST = 15;\r
+               readonly static int LESSER_ICOST  = 0;\r
+               readonly static int SMALL_THRESH  = 20;\r
+               readonly static int DEPTH_THRESH  = 10;\r
+               \r
+               /*--\r
+               If you are ever unlucky/improbable enough\r
+               to get a stack overflow whilst sorting,\r
+               increase the following constant and try\r
+               again.  In practice I have never seen the\r
+               stack go above 27 elems, so the following\r
+               limit seems very generous.\r
+               --*/\r
+               readonly static int QSORT_STACK_SIZE = 1000;\r
+               \r
+               static void Panic() \r
+               {\r
+                       Console.WriteLine("panic");\r
+               }\r
+               \r
+               void MakeMaps() \r
+               {\r
+                       int i;\r
+                       nInUse = 0;\r
+                       for (i = 0; i < 256; i++) {\r
+                               if (inUse[i]) {\r
+                                       seqToUnseq[nInUse] = (char)i;\r
+                                       unseqToSeq[i] = (char)nInUse;\r
+                                       nInUse++;\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               static void HbMakeCodeLengths(char[] len, int[] freq, int alphaSize, int maxLen) \r
+               {\r
+                       /*--\r
+                       Nodes and heap entries run from 1.  Entry 0\r
+                       for both the heap and nodes is a sentinel.\r
+                       --*/\r
+                       int nNodes, nHeap, n1, n2, j, k;\r
+                       bool  tooLong;\r
+                       \r
+                       int[] heap   = new int[BZip2Constants.MAX_ALPHA_SIZE + 2];\r
+                       int[] weight = new int[BZip2Constants.MAX_ALPHA_SIZE * 2];\r
+                       int[] parent = new int[BZip2Constants.MAX_ALPHA_SIZE * 2];\r
+                       \r
+                       for (int i = 0; i < alphaSize; ++i) {\r
+                               weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;\r
+                       }\r
+                       \r
+                       while (true) {\r
+                               nNodes = alphaSize;\r
+                               nHeap = 0;\r
+                               \r
+                               heap[0] = 0;\r
+                               weight[0] = 0;\r
+                               parent[0] = -2;\r
+                               \r
+                               for (int i = 1; i <= alphaSize; ++i) {\r
+                                       parent[i] = -1;\r
+                                       nHeap++;\r
+                                       heap[nHeap] = i;\r
+                                       int zz = nHeap;\r
+                                       int tmp = heap[zz];\r
+                                       while (weight[tmp] < weight[heap[zz >> 1]]) {\r
+                                               heap[zz] = heap[zz >> 1];\r
+                                               zz >>= 1;\r
+                                       }\r
+                                       heap[zz] = tmp;\r
+                               }\r
+                               if (!(nHeap < (BZip2Constants.MAX_ALPHA_SIZE+2))) {\r
+                                       Panic();\r
+                               }\r
+                               \r
+                               while (nHeap > 1) {\r
+                                       n1 = heap[1];\r
+                                       heap[1] = heap[nHeap];\r
+                                       nHeap--;\r
+                                       int zz = 1;\r
+                                       int yy = 0;\r
+                                       int tmp = heap[zz];\r
+                                       while (true) {\r
+                                               yy = zz << 1;\r
+                                               if (yy > nHeap) {\r
+                                                       break;\r
+                                               }\r
+                                               if (yy < nHeap &&  weight[heap[yy+1]] < weight[heap[yy]]) {\r
+                                                   yy++;\r
+                                               }\r
+                                               if (weight[tmp] < weight[heap[yy]]) {\r
+                                                       break;\r
+                                               }\r
+                                               \r
+                                               heap[zz] = heap[yy];\r
+                                               zz = yy;\r
+                                       }\r
+                                       heap[zz] = tmp;\r
+                                       n2 = heap[1];\r
+                                       heap[1] = heap[nHeap];\r
+                                       nHeap--;\r
+                                       \r
+                                       zz = 1;\r
+                                       yy = 0;\r
+                                       tmp = heap[zz];\r
+                                       while (true) {\r
+                                               yy = zz << 1;\r
+                                               if (yy > nHeap)\r
+                                                       break;\r
+                                               if (yy < nHeap &&\r
+                                                   weight[heap[yy+1]] < weight[heap[yy]])\r
+                                                   yy++;\r
+                                               if (weight[tmp] < weight[heap[yy]])\r
+                                                       break;\r
+                                               heap[zz] = heap[yy];\r
+                                               zz = yy;\r
+                                       }\r
+                                       heap[zz] = tmp;\r
+                                       nNodes++;\r
+                                       parent[n1] = parent[n2] = nNodes;\r
+                                       \r
+                                       weight[nNodes] = (int)((weight[n1] & 0xffffff00) + (weight[n2] & 0xffffff00)) |\r
+                                                        (int)(1 + (((weight[n1] & 0x000000ff) > (weight[n2] & 0x000000ff)) ? (weight[n1] & 0x000000ff) : (weight[n2] & 0x000000ff)));\r
+                                       \r
+                                       parent[nNodes] = -1;\r
+                                       nHeap++;\r
+                                       heap[nHeap] = nNodes;\r
+                                       \r
+                                       zz  = nHeap;\r
+                                       tmp = heap[zz];\r
+                                       while (weight[tmp] < weight[heap[zz >> 1]]) {\r
+                                               heap[zz] = heap[zz >> 1];\r
+                                               zz >>= 1;\r
+                                       }\r
+                                       heap[zz] = tmp;\r
+                               }\r
+                               if (!(nNodes < (BZip2Constants.MAX_ALPHA_SIZE * 2))) {\r
+                                       Panic();\r
+                               }\r
+                               \r
+                               tooLong = false;\r
+                               for (int i = 1; i <= alphaSize; ++i) {\r
+                                       j = 0;\r
+                                       k = i;\r
+                                       while (parent[k] >= 0) {\r
+                                               k = parent[k];\r
+                                               j++;\r
+                                       }\r
+                                       len[i - 1] = (char)j;\r
+                                       if (j > maxLen) {\r
+                                               tooLong = true;\r
+                                       }\r
+                               }\r
+                               \r
+                               if (!tooLong) {\r
+                                       break;\r
+                               }\r
+                               \r
+                               for (int i = 1; i < alphaSize; ++i) {\r
+                                       j = weight[i] >> 8;\r
+                                       j = 1 + (j / 2);\r
+                                       weight[i] = j << 8;\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               /*--\r
+               index of the last char in the block, so\r
+               the block size == last + 1.\r
+               --*/\r
+               int last;\r
+               \r
+               /*--\r
+               index in zptr[] of original string after sorting.\r
+               --*/\r
+               int origPtr;\r
+               \r
+               /*--\r
+               always: in the range 0 .. 9.\r
+               The current block size is 100000 * this number.\r
+               --*/\r
+               int blockSize100k;\r
+               \r
+               bool blockRandomised;\r
+               \r
+//             int bytesIn;\r
+               int bytesOut;\r
+               int bsBuff;\r
+               int bsLive;\r
+               IChecksum mCrc = new StrangeCRC();\r
+               \r
+               bool[] inUse = new bool[256];\r
+               int nInUse;\r
+               \r
+               char[] seqToUnseq = new char[256];\r
+               char[] unseqToSeq = new char[256];\r
+               \r
+               char[] selector = new char[BZip2Constants.MAX_SELECTORS];\r
+               char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS];\r
+               \r
+               byte[]  block;\r
+               int[]   quadrant;\r
+               int[]   zptr;\r
+               short[] szptr;\r
+               int[]   ftab;\r
+               \r
+               int nMTF;\r
+               \r
+               int[] mtfFreq = new int[BZip2Constants.MAX_ALPHA_SIZE];\r
+               \r
+               /*\r
+               * Used when sorting.  If too many long comparisons\r
+               * happen, we stop sorting, randomise the block\r
+               * slightly, and try again.\r
+               */\r
+               int workFactor;\r
+               int workDone;\r
+               int workLimit;\r
+               bool firstAttempt;\r
+               int nBlocksRandomised;\r
+               \r
+               int currentChar = -1;\r
+               int runLength = 0;\r
+               \r
+               public BZip2OutputStream(Stream inStream) : this(inStream, 9)\r
+               {\r
+               }\r
+               \r
+               public BZip2OutputStream(Stream inStream, int inBlockSize)\r
+               {\r
+                       block    = null;\r
+                       quadrant = null;\r
+                       zptr     = null;\r
+                       ftab     = null;\r
+                       \r
+                       BsSetStream(inStream);\r
+                       \r
+                       workFactor = 50;\r
+                       if(inBlockSize > 9) {\r
+                               inBlockSize = 9;\r
+                       }\r
+                       if(inBlockSize < 1) {\r
+                               inBlockSize = 1;\r
+                       }\r
+                       blockSize100k = inBlockSize;\r
+                       AllocateCompressStructures();\r
+                       Initialize();\r
+                       InitBlock();\r
+               }\r
+               \r
+               public override void WriteByte(byte bv)\r
+               {\r
+                       int b = (256 + bv) % 256;\r
+                       if (currentChar != -1) {\r
+                               if (currentChar == b) {\r
+                                       runLength++;\r
+                                       if (runLength > 254) {\r
+                                               WriteRun();\r
+                                               currentChar = -1;\r
+                                               runLength = 0;\r
+                                       }\r
+                               } else {\r
+                                       WriteRun();\r
+                                       runLength = 1;\r
+                                       currentChar = b;\r
+                               }\r
+                       } else {\r
+                               currentChar = b;\r
+                               runLength++;\r
+                       }\r
+               }\r
+               \r
+               void WriteRun()\r
+               {\r
+                       if (last < allowableBlockSize) {\r
+                               inUse[currentChar] = true;\r
+                               for (int i = 0; i < runLength; i++) {\r
+                                       mCrc.Update(currentChar);\r
+                               }\r
+                               \r
+                               switch (runLength) {\r
+                                       case 1:\r
+                                               last++;\r
+                                               block[last + 1] = (byte)currentChar;\r
+                                               break;\r
+                                       case 2:\r
+                                               last++;\r
+                                               block[last + 1] = (byte)currentChar;\r
+                                               last++;\r
+                                               block[last + 1] = (byte)currentChar;\r
+                                               break;\r
+                                       case 3:\r
+                                               last++;\r
+                                               block[last + 1] = (byte)currentChar;\r
+                                               last++;\r
+                                               block[last + 1] = (byte)currentChar;\r
+                                               last++;\r
+                                               block[last + 1] = (byte)currentChar;\r
+                                               break;\r
+                                       default:\r
+                                               inUse[runLength - 4] = true;\r
+                                               last++;\r
+                                               block[last + 1] = (byte)currentChar;\r
+                                               last++;\r
+                                               block[last + 1] = (byte)currentChar;\r
+                                               last++;\r
+                                               block[last + 1] = (byte)currentChar;\r
+                                               last++;\r
+                                               block[last + 1] = (byte)currentChar;\r
+                                               last++;\r
+                                               block[last + 1] = (byte)(runLength - 4);\r
+                                               break;\r
+                               }\r
+                       } else {\r
+                               EndBlock();\r
+                               InitBlock();\r
+                               WriteRun();\r
+                       }\r
+               }\r
+               \r
+               bool closed = false;\r
+               \r
+               public void Finalize()\r
+               {\r
+                       Close();\r
+               }\r
+               \r
+               public override void Close()\r
+               {\r
+                       if (closed) {\r
+                               return;\r
+                       }\r
+                       \r
+                       if (runLength > 0) {\r
+                               WriteRun();\r
+                       }\r
+                       \r
+                       currentChar = -1;\r
+                       EndBlock();\r
+                       EndCompression();\r
+                       closed = true;\r
+//                     super.close();\r
+                       Flush();\r
+                       baseStream.Close();\r
+               }\r
+               \r
+               public override void Flush()\r
+               {\r
+//                     super.flush();\r
+                       baseStream.Flush();\r
+               }\r
+               \r
+               uint blockCRC, combinedCRC;\r
+               \r
+               void Initialize()\r
+               {\r
+//                     bytesIn = 0;\r
+                       bytesOut = 0;\r
+                       nBlocksRandomised = 0;\r
+                       \r
+                       /*--- Write `magic' bytes h indicating file-format == huffmanised,\r
+                       followed by a digit indicating blockSize100k.\r
+                       ---*/\r
+                       BsPutUChar('h');\r
+                       BsPutUChar('0' + blockSize100k);\r
+                       \r
+                       combinedCRC = 0;\r
+               }\r
+               \r
+               int allowableBlockSize;\r
+               \r
+               void InitBlock() \r
+               {\r
+                       //              blockNo++;\r
+                       mCrc.Reset();\r
+                       last = -1;\r
+                       //              ch = 0;\r
+                       \r
+                       for (int i = 0; i < 256; i++) {\r
+                               inUse[i] = false;\r
+                       }\r
+                       \r
+                       /*--- 20 is just a paranoia constant ---*/\r
+                       allowableBlockSize = BZip2Constants.baseBlockSize * blockSize100k - 20;\r
+               }\r
+               \r
+               void EndBlock()\r
+               {\r
+                       blockCRC = (uint)mCrc.Value;\r
+                       combinedCRC = (combinedCRC << 1) | (combinedCRC >> 31);\r
+                       combinedCRC ^= blockCRC;\r
+                       \r
+                       /*-- sort the block and establish posn of original string --*/\r
+                       DoReversibleTransformation();\r
+                       \r
+                       /*--\r
+                       A 6-byte block header, the value chosen arbitrarily\r
+                       as 0x314159265359 :-).  A 32 bit value does not really\r
+                       give a strong enough guarantee that the value will not\r
+                       appear by chance in the compressed datastream.  Worst-case\r
+                       probability of this event, for a 900k block, is about\r
+                       2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits.\r
+                       For a compressed file of size 100Gb -- about 100000 blocks --\r
+                       only a 48-bit marker will do.  NB: normal compression/\r
+                       decompression do *not* rely on these statistical properties.\r
+                       They are only important when trying to recover blocks from\r
+                       damaged files.\r
+                       --*/\r
+                       BsPutUChar(0x31);\r
+                       BsPutUChar(0x41);\r
+                       BsPutUChar(0x59);\r
+                       BsPutUChar(0x26);\r
+                       BsPutUChar(0x53);\r
+                       BsPutUChar(0x59);\r
+                       \r
+                       /*-- Now the block's CRC, so it is in a known place. --*/\r
+                       BsPutint((int)blockCRC);\r
+                       \r
+                       /*-- Now a single bit indicating randomisation. --*/\r
+                       if (blockRandomised) {\r
+                               BsW(1,1);\r
+                               nBlocksRandomised++;\r
+                       } else {\r
+                               BsW(1,0);\r
+                       }\r
+                       \r
+                       /*-- Finally, block's contents proper. --*/\r
+                       MoveToFrontCodeAndSend();\r
+               }\r
+               \r
+               void EndCompression()\r
+               {\r
+                       /*--\r
+                       Now another magic 48-bit number, 0x177245385090, to\r
+                       indicate the end of the last block.  (sqrt(pi), if\r
+                       you want to know.  I did want to use e, but it contains\r
+                       too much repetition -- 27 18 28 18 28 46 -- for me\r
+                       to feel statistically comfortable.  Call me paranoid.)\r
+                       --*/\r
+                       BsPutUChar(0x17);\r
+                       BsPutUChar(0x72);\r
+                       BsPutUChar(0x45);\r
+                       BsPutUChar(0x38);\r
+                       BsPutUChar(0x50);\r
+                       BsPutUChar(0x90);\r
+                       \r
+                       BsPutint((int)combinedCRC);\r
+                       \r
+                       BsFinishedWithStream();\r
+               }\r
+               \r
+               void HbAssignCodes (int[] code, char[] length, int minLen, int maxLen, int alphaSize) \r
+               {\r
+                       int vec = 0;\r
+                       for (int n = minLen; n <= maxLen; ++n) {\r
+                               for (int i = 0; i < alphaSize; ++i) {\r
+                                       if (length[i] == n) {\r
+                                               code[i] = vec;\r
+                                               ++vec;\r
+                                       }\r
+                               }\r
+                               vec <<= 1;\r
+                       }\r
+               }\r
+               \r
+               void BsSetStream(Stream f) \r
+               {\r
+                       baseStream = f;\r
+                       bsLive = 0;\r
+                       bsBuff = 0;\r
+                       bytesOut = 0;\r
+               }\r
+               \r
+               void BsFinishedWithStream()\r
+               {\r
+                       while (bsLive > 0) {\r
+                               int ch = (bsBuff >> 24);\r
+                               baseStream.WriteByte((byte)ch); // write 8-bit\r
+                               bsBuff <<= 8;\r
+                               bsLive -= 8;\r
+                               bytesOut++;\r
+                       }\r
+               }\r
+               \r
+               void BsW(int n, int v)\r
+               {\r
+                       while (bsLive >= 8) {\r
+                               int ch = (bsBuff >> 24);\r
+                               baseStream.WriteByte((byte)ch); // write 8-bit\r
+                               bsBuff <<= 8;\r
+                               bsLive -= 8;\r
+                               ++bytesOut;\r
+                       }\r
+                       bsBuff |= (v << (32 - bsLive - n));\r
+                       bsLive += n;\r
+               }\r
+               \r
+               void BsPutUChar(int c)\r
+               {\r
+                       BsW(8, c);\r
+               }\r
+               \r
+               void BsPutint(int u)\r
+               {\r
+                       BsW(8, (u >> 24) & 0xFF);\r
+                       BsW(8, (u >> 16) & 0xFF);\r
+                       BsW(8, (u >>  8) & 0xFF);\r
+                       BsW(8,  u        & 0xFF);\r
+               }\r
+               \r
+               void BsPutIntVS(int numBits, int c)\r
+               {\r
+                       BsW(numBits, c);\r
+               }\r
+               \r
+               void SendMTFValues()\r
+               {\r
+                       char[][] len = new char[BZip2Constants.N_GROUPS][];\r
+                       for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {\r
+                               len[i] = new char[BZip2Constants.MAX_ALPHA_SIZE];\r
+                       }\r
+                       \r
+                       int gs, ge, totc, bt, bc, iter;\r
+                       int nSelectors = 0, alphaSize, minLen, maxLen, selCtr;\r
+                       int nGroups, nBytes;\r
+                       \r
+                       alphaSize = nInUse + 2;\r
+                       for (int t = 0; t < BZip2Constants.N_GROUPS; t++) {\r
+                               for (int v = 0; v < alphaSize; v++) {\r
+                                       len[t][v] = (char)GREATER_ICOST;\r
+                               }\r
+                       }\r
+                       \r
+                       /*--- Decide how many coding tables to use ---*/\r
+                       if (nMTF <= 0) {\r
+                               Panic();\r
+                       }\r
+                       \r
+                       if (nMTF < 200) {\r
+                               nGroups = 2;\r
+                       } else if (nMTF < 600) {\r
+                               nGroups = 3;\r
+                       } else if (nMTF < 1200) {\r
+                               nGroups = 4;\r
+                       } else if (nMTF < 2400) {\r
+                               nGroups = 5;\r
+                       } else {\r
+                               nGroups = 6;\r
+                       }\r
+                       \r
+                       /*--- Generate an initial set of coding tables ---*/ \r
+                       int nPart = nGroups;\r
+                       int remF  = nMTF;\r
+                       gs = 0;\r
+                       while (nPart > 0) {\r
+                               int tFreq = remF / nPart;\r
+                               int aFreq = 0;\r
+                               ge = gs - 1;\r
+                               while (aFreq < tFreq && ge < alphaSize - 1) {\r
+                                       ge++;\r
+                                       aFreq += mtfFreq[ge];\r
+                               }\r
+                               \r
+                               if (ge > gs && nPart != nGroups && nPart != 1 && ((nGroups - nPart) % 2 == 1)) {\r
+                                       aFreq -= mtfFreq[ge];\r
+                                       ge--;\r
+                               }\r
+                               \r
+                               for (int v = 0; v < alphaSize; v++) {\r
+                                       if (v >= gs && v <= ge) {\r
+                                               len[nPart - 1][v] = (char)LESSER_ICOST;\r
+                                       } else {\r
+                                               len[nPart - 1][v] = (char)GREATER_ICOST;\r
+                                       }\r
+                               }\r
+                               \r
+                               nPart--;\r
+                               gs = ge + 1;\r
+                               remF -= aFreq;\r
+                       }\r
+                       \r
+                       int[][] rfreq = new int[BZip2Constants.N_GROUPS][];\r
+                       for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {\r
+                               rfreq[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];\r
+                       }\r
+                       \r
+                       int[]   fave = new int[BZip2Constants.N_GROUPS];\r
+                       short[] cost = new short[BZip2Constants.N_GROUPS];\r
+                       /*---\r
+                       Iterate up to N_ITERS times to improve the tables.\r
+                       ---*/\r
+                       for (iter = 0; iter < BZip2Constants.N_ITERS; ++iter) {\r
+                               for (int t = 0; t < nGroups; ++t) {\r
+                                       fave[t] = 0;\r
+                               }\r
+                               \r
+                               for (int t = 0; t < nGroups; ++t) {\r
+                                       for (int v = 0; v < alphaSize; ++v) {\r
+                                               rfreq[t][v] = 0;\r
+                                       }\r
+                               }\r
+                               \r
+                               nSelectors = 0;\r
+                               totc = 0;\r
+                               gs   = 0;\r
+                               while (true) {\r
+                                       \r
+                                       /*--- Set group start & end marks. --*/\r
+                                       if (gs >= nMTF) {\r
+                                               break;\r
+                                       }\r
+                                       ge = gs + BZip2Constants.G_SIZE - 1;\r
+                                       if (ge >= nMTF) {\r
+                                               ge = nMTF - 1;\r
+                                       }\r
+                                       \r
+                                       /*--\r
+                                       Calculate the cost of this group as coded\r
+                                       by each of the coding tables.\r
+                                       --*/\r
+                                       for (int t = 0; t < nGroups; t++) {\r
+                                               cost[t] = 0;\r
+                                       }\r
+                                       \r
+                                       if (nGroups == 6) {\r
+                                               short cost0, cost1, cost2, cost3, cost4, cost5;\r
+                                               cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0;\r
+                                               for (int i = gs; i <= ge; ++i) {\r
+                                                       short icv = szptr[i];\r
+                                                       cost0 += (short)len[0][icv];\r
+                                                       cost1 += (short)len[1][icv];\r
+                                                       cost2 += (short)len[2][icv];\r
+                                                       cost3 += (short)len[3][icv];\r
+                                                       cost4 += (short)len[4][icv];\r
+                                                       cost5 += (short)len[5][icv];\r
+                                               }\r
+                                               cost[0] = cost0;\r
+                                               cost[1] = cost1;\r
+                                               cost[2] = cost2;\r
+                                               cost[3] = cost3;\r
+                                               cost[4] = cost4;\r
+                                               cost[5] = cost5;\r
+                                       } else {\r
+                                               for (int i = gs; i <= ge; ++i) {\r
+                                                       short icv = szptr[i];\r
+                                                       for (int t = 0; t < nGroups; t++) {\r
+                                                               cost[t] += (short)len[t][icv];\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       \r
+                                       /*--\r
+                                       Find the coding table which is best for this group,\r
+                                       and record its identity in the selector table.\r
+                                       --*/\r
+                                       bc = 999999999;\r
+                                       bt = -1;\r
+                                       for (int t = 0; t < nGroups; ++t) {\r
+                                               if (cost[t] < bc) {\r
+                                                       bc = cost[t];\r
+                                                       bt = t;\r
+                                               }\r
+                                       }\r
+                                       totc += bc;\r
+                                       fave[bt]++;\r
+                                       selector[nSelectors] = (char)bt;\r
+                                       nSelectors++;\r
+                                       \r
+                                       /*--\r
+                                       Increment the symbol frequencies for the selected table.\r
+                                       --*/\r
+                                       for (int i = gs; i <= ge; ++i) {\r
+                                               ++rfreq[bt][szptr[i]];\r
+                                       }\r
+                                       \r
+                                       gs = ge+1;\r
+                               }\r
+                               \r
+                               /*--\r
+                               Recompute the tables based on the accumulated frequencies.\r
+                               --*/\r
+                               for (int t = 0; t < nGroups; ++t) {\r
+                                       HbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20);\r
+                               }\r
+                       }\r
+                       \r
+                       rfreq = null;\r
+                       fave = null;\r
+                       cost = null;\r
+                       \r
+                       if (!(nGroups < 8)) {\r
+                               Panic();\r
+                       }\r
+                       if (!(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZip2Constants.G_SIZE)))) {\r
+                               Panic();\r
+                       }\r
+                       \r
+                       \r
+                       /*--- Compute MTF values for the selectors. ---*/\r
+                       char[] pos = new char[BZip2Constants.N_GROUPS];\r
+                       char ll_i, tmp2, tmp;\r
+                       for (int i = 0; i < nGroups; i++) {\r
+                               pos[i] = (char)i;\r
+                       }\r
+                       for (int i = 0; i < nSelectors; i++) {\r
+                               ll_i = selector[i];\r
+                               int j = 0;\r
+                               tmp = pos[j];\r
+                               while (ll_i != tmp) {\r
+                                       j++;\r
+                                       tmp2 = tmp;\r
+                                       tmp = pos[j];\r
+                                       pos[j] = tmp2;\r
+                               }\r
+                               pos[0] = tmp;\r
+                               selectorMtf[i] = (char)j;\r
+                       }\r
+                       \r
+                       int[][] code = new int[BZip2Constants.N_GROUPS][];\r
+                       \r
+                       for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) {\r
+                               code[i] = new int[BZip2Constants.MAX_ALPHA_SIZE];\r
+                       }\r
+                       \r
+                       /*--- Assign actual codes for the tables. --*/\r
+                       for (int t = 0; t < nGroups; t++) {\r
+                               minLen = 32;\r
+                               maxLen = 0;\r
+                               for (int i = 0; i < alphaSize; i++) {\r
+                                       if (len[t][i] > maxLen) {\r
+                                               maxLen = len[t][i];\r
+                                       }\r
+                                       if (len[t][i] < minLen) {\r
+                                               minLen = len[t][i];\r
+                                       }\r
+                               }\r
+                               if (maxLen > 20) {\r
+                                       Panic();\r
+                               }\r
+                               if (minLen < 1) {\r
+                                       Panic();\r
+                               }\r
+                               HbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize);\r
+                       }\r
+                       \r
+                       /*--- Transmit the mapping table. ---*/\r
+                       bool[] inUse16 = new bool[16];\r
+                       for (int i = 0; i < 16; ++i) {\r
+                               inUse16[i] = false;\r
+                               for (int j = 0; j < 16; ++j) {\r
+                                       if (inUse[i * 16 + j]) {\r
+                                               inUse16[i] = true; \r
+                                       } // TODO : insert break;\r
+                               }\r
+                       }\r
+                       \r
+                       nBytes = bytesOut;\r
+                       for (int i = 0; i < 16; ++i) {\r
+                               if (inUse16[i]) {\r
+                                       BsW(1,1);\r
+                               } else {\r
+                                       BsW(1,0);\r
+                               }\r
+                       }\r
+                       \r
+                       for (int i = 0; i < 16; ++i) {\r
+                               if (inUse16[i]) {\r
+                                       for (int j = 0; j < 16; ++j) {\r
+                                               if (inUse[i * 16 + j]) {\r
+                                                       BsW(1,1);\r
+                                               } else {\r
+                                                       BsW(1,0);\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       /*--- Now the selectors. ---*/\r
+                       nBytes = bytesOut;\r
+                       BsW(3, nGroups);\r
+                       BsW(15, nSelectors);\r
+                       for (int i = 0; i < nSelectors; ++i) {\r
+                               for (int j = 0; j < selectorMtf[i]; ++j) {\r
+                                       BsW(1,1);\r
+                               }\r
+                               BsW(1,0);\r
+                       }\r
+                       \r
+                       /*--- Now the coding tables. ---*/\r
+                       nBytes = bytesOut;\r
+                       \r
+                       for (int t = 0; t < nGroups; ++t) {\r
+                               int curr = len[t][0];\r
+                               BsW(5, curr);\r
+                               for (int i = 0; i < alphaSize; ++i) {\r
+                                       while (curr < len[t][i]) {\r
+                                               BsW(2, 2);\r
+                                               curr++; /* 10 */\r
+                                       }\r
+                                       while (curr > len[t][i]) {\r
+                                               BsW(2, 3);\r
+                                               curr--; /* 11 */\r
+                                       }\r
+                                       BsW (1, 0);\r
+                               }\r
+                       }\r
+                       \r
+                       /*--- And finally, the block data proper ---*/\r
+                       nBytes = bytesOut;\r
+                       selCtr = 0;\r
+                       gs = 0;\r
+                       while (true) {\r
+                               if (gs >= nMTF) {\r
+                                       break;\r
+                               }\r
+                               ge = gs + BZip2Constants.G_SIZE - 1;\r
+                               if (ge >= nMTF) {\r
+                                       ge = nMTF - 1;\r
+                               }\r
+                               \r
+                               for (int i = gs; i <= ge; i++) {\r
+                                       BsW(len[selector[selCtr]][szptr[i]], code[selector[selCtr]][szptr[i]]);\r
+                               }\r
+                               \r
+                               gs = ge + 1;\r
+                               ++selCtr;\r
+                       }\r
+                       if (!(selCtr == nSelectors)) {\r
+                               Panic();\r
+                       }\r
+               }\r
+               \r
+               void MoveToFrontCodeAndSend () \r
+               {\r
+                       BsPutIntVS(24, origPtr);\r
+                       GenerateMTFValues();\r
+                       SendMTFValues();\r
+               }\r
+               \r
+               Stream baseStream;\r
+               \r
+               void SimpleSort(int lo, int hi, int d) \r
+               {\r
+                       int i, j, h, bigN, hp;\r
+                       int v;\r
+                       \r
+                       bigN = hi - lo + 1;\r
+                       if (bigN < 2) {\r
+                               return;\r
+                       }\r
+                       \r
+                       hp = 0;\r
+                       while (incs[hp] < bigN) {\r
+                               hp++;\r
+                       }\r
+                       hp--;\r
+                       \r
+                       for (; hp >= 0; hp--) {\r
+                               h = incs[hp];\r
+                               \r
+                               i = lo + h;\r
+                               while (true) {\r
+                                       /*-- copy 1 --*/\r
+                                       if (i > hi)\r
+                                               break;\r
+                                       v = zptr[i];\r
+                                       j = i;\r
+                                       while (FullGtU(zptr[j-h]+d, v+d)) {\r
+                                               zptr[j] = zptr[j-h];\r
+                                               j = j - h;\r
+                                               if (j <= (lo + h - 1))\r
+                                                       break;\r
+                                       }\r
+                                       zptr[j] = v;\r
+                                       i++;\r
+                                       \r
+                                       /*-- copy 2 --*/\r
+                                       if (i > hi)\r
+                                               break;\r
+                                       v = zptr[i];\r
+                                       j = i;\r
+                                       while (FullGtU ( zptr[j-h]+d, v+d )) {\r
+                                               zptr[j] = zptr[j-h];\r
+                                               j = j - h;\r
+                                               if (j <= (lo + h - 1))\r
+                                                       break;\r
+                                       }\r
+                                       zptr[j] = v;\r
+                                       i++;\r
+                                       \r
+                                       /*-- copy 3 --*/\r
+                                       if (i > hi)\r
+                                               break;\r
+                                       v = zptr[i];\r
+                                       j = i;\r
+                                       while (FullGtU ( zptr[j-h]+d, v+d)) {\r
+                                               zptr[j] = zptr[j-h];\r
+                                               j = j - h;\r
+                                               if (j <= (lo + h - 1))\r
+                                                       break;\r
+                                       }\r
+                                       zptr[j] = v;\r
+                                       i++;\r
+                                       \r
+                                       if (workDone > workLimit && firstAttempt)\r
+                                               return;\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               void Vswap(int p1, int p2, int n ) \r
+               {\r
+                       int temp = 0;\r
+                       while (n > 0) {\r
+                               temp = zptr[p1];\r
+                               zptr[p1] = zptr[p2];\r
+                               zptr[p2] = temp;\r
+                               p1++;\r
+                               p2++;\r
+                               n--;\r
+                       }\r
+               }\r
+               \r
+               byte Med3(byte a, byte b, byte c ) \r
+               {\r
+                       byte t;\r
+                       if (a > b) {\r
+                               t = a;\r
+                               a = b;\r
+                               b = t;\r
+                       }\r
+                       if (b > c) {\r
+                               t = b;\r
+                               b = c;\r
+                               c = t;\r
+                       }\r
+                       if (a > b) {\r
+                               b = a;\r
+                       }\r
+                       return b;\r
+               }\r
+               \r
+               class StackElem \r
+               {\r
+                       public int ll;\r
+                       public int hh;\r
+                       public int dd;\r
+               }\r
+               \r
+               void QSort3(int loSt, int hiSt, int dSt) \r
+               {\r
+                       int unLo, unHi, ltLo, gtHi, med, n, m;\r
+                       int sp, lo, hi, d;\r
+                       StackElem[] stack = new StackElem[QSORT_STACK_SIZE];\r
+                       for(int count = 0; count < QSORT_STACK_SIZE; count++)\r
+                               stack[count] = new StackElem();\r
+                       \r
+                       sp = 0;\r
+                       \r
+                       stack[sp].ll = loSt;\r
+                       stack[sp].hh = hiSt;\r
+                       stack[sp].dd = dSt;\r
+                       sp++;\r
+                       \r
+                       while (sp > 0) {\r
+                               if (sp >= QSORT_STACK_SIZE) {\r
+                                       Panic();\r
+                               }\r
+                               \r
+                               sp--;\r
+                               lo = stack[sp].ll;\r
+                               hi = stack[sp].hh;\r
+                               d = stack[sp].dd;\r
+                               \r
+                               if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) {\r
+                                       SimpleSort(lo, hi, d);\r
+                                       if (workDone > workLimit && firstAttempt)\r
+                                               return;\r
+                                       continue;\r
+                               }\r
+                               \r
+                               med = Med3(block[zptr[lo] + d + 1],\r
+                                          block[zptr[hi            ] + d  + 1],\r
+                                          block[zptr[(lo + hi) >> 1] + d + 1]);\r
+                               \r
+                               unLo = ltLo = lo;\r
+                               unHi = gtHi = hi;\r
+                               \r
+                               while (true) {\r
+                                       while (true) {\r
+                                               if (unLo > unHi) {\r
+                                                       break;\r
+                                               }\r
+                                               n = ((int)block[zptr[unLo]+d + 1]) - med;\r
+                                               if (n == 0) {\r
+                                                       int temp = 0;\r
+                                                       temp = zptr[unLo];\r
+                                                       zptr[unLo] = zptr[ltLo];\r
+                                                       zptr[ltLo] = temp;\r
+                                                       ltLo++;\r
+                                                       unLo++;\r
+                                                       continue;\r
+                                               }\r
+                                               if (n >  0) {\r
+                                                       break;\r
+                                               }\r
+                                               unLo++;\r
+                                       }\r
+                                       while (true) {\r
+                                               if (unLo > unHi)\r
+                                                       break;\r
+                                               n = ((int)block[zptr[unHi]+d + 1]) - med;\r
+                                               if (n == 0) {\r
+                                                       int temp = 0;\r
+                                                       temp = zptr[unHi];\r
+                                                       zptr[unHi] = zptr[gtHi];\r
+                                                       zptr[gtHi] = temp;\r
+                                                       gtHi--;\r
+                                                       unHi--;\r
+                                                       continue;\r
+                                               };\r
+                                               if (n <  0)\r
+                                                       break;\r
+                                               unHi--;\r
+                                       }\r
+                                       if (unLo > unHi)\r
+                                               break;\r
+                                       {\r
+                                       int temp = zptr[unLo];\r
+                                       zptr[unLo] = zptr[unHi];\r
+                                       zptr[unHi] = temp;\r
+                                       unLo++;\r
+                                       unHi--;\r
+                                       }\r
+                               }\r
+                               \r
+                               if (gtHi < ltLo) {\r
+                                       stack[sp].ll = lo;\r
+                                       stack[sp].hh = hi;\r
+                                       stack[sp].dd = d+1;\r
+                                       sp++;\r
+                                       continue;\r
+                               }\r
+                               \r
+                               n = ((ltLo-lo) < (unLo-ltLo)) ? (ltLo-lo) : (unLo-ltLo);\r
+                               Vswap(lo, unLo-n, n);\r
+                               m = ((hi-gtHi) < (gtHi-unHi)) ? (hi-gtHi) : (gtHi-unHi);\r
+                               Vswap(unLo, hi-m+1, m);\r
+                               \r
+                               n = lo + unLo - ltLo - 1;\r
+                               m = hi - (gtHi - unHi) + 1;\r
+                               \r
+                               stack[sp].ll = lo;\r
+                               stack[sp].hh = n;\r
+                               stack[sp].dd = d;\r
+                               sp++;\r
+                               \r
+                               stack[sp].ll = n + 1;\r
+                               stack[sp].hh = m - 1;\r
+                               stack[sp].dd = d+1;\r
+                               sp++;\r
+                               \r
+                               stack[sp].ll = m;\r
+                               stack[sp].hh = hi;\r
+                               stack[sp].dd = d;\r
+                               sp++;\r
+                       }\r
+               }\r
+               \r
+               void MainSort() \r
+               {\r
+                       int i, j, ss, sb;\r
+                       int[] runningOrder = new int[256];\r
+                       int[] copy = new int[256];\r
+                       bool[] bigDone = new bool[256];\r
+                       int c1, c2;\r
+                       int numQSorted;\r
+                       \r
+                       /*--\r
+                       In the various block-sized structures, live data runs\r
+                       from 0 to last+NUM_OVERSHOOT_BYTES inclusive.  First,\r
+                       set up the overshoot area for block.\r
+                       --*/\r
+                       \r
+                       //   if (verbosity >= 4) fprintf ( stderr, "        sort initialise ...\n" );\r
+                       for (i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {\r
+                               block[last + i + 2] = block[(i % (last + 1)) + 1];\r
+                       }\r
+                       for (i = 0; i <= last + BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {\r
+                               quadrant[i] = 0;\r
+                       }\r
+                       \r
+                       block[0] = (byte)(block[last + 1]);\r
+                       \r
+                       if (last < 4000) {\r
+                               /*--\r
+                               Use simpleSort(), since the full sorting mechanism\r
+                               has quite a large constant overhead.\r
+                               --*/\r
+                               for (i = 0; i <= last; i++)\r
+                                       zptr[i] = i;\r
+                               firstAttempt = false;\r
+                               workDone = workLimit = 0;\r
+                               SimpleSort(0, last, 0);\r
+                       } else {\r
+                               numQSorted = 0;\r
+                               for (i = 0; i <= 255; i++)\r
+                                       bigDone[i] = false;\r
+                               \r
+                               for (i = 0; i <= 65536; i++)\r
+                                       ftab[i] = 0;\r
+                               \r
+                               c1 = block[0];\r
+                               for (i = 0; i <= last; i++) {\r
+                                       c2 = block[i + 1];\r
+                                       ftab[(c1 << 8) + c2]++;\r
+                                       c1 = c2;\r
+                               }\r
+                               \r
+                               for (i = 1; i <= 65536; i++)\r
+                                       ftab[i] += ftab[i - 1];\r
+                               \r
+                               c1 = block[1];\r
+                               for (i = 0; i < last; i++) {\r
+                                       c2 = block[i + 2];\r
+                                       j = (c1 << 8) + c2;\r
+                                       c1 = c2;\r
+                                       ftab[j]--;\r
+                                       zptr[ftab[j]] = i;\r
+                               }\r
+                               \r
+                               j = ((block[last + 1]) << 8) + (block[1]);\r
+                               ftab[j]--;\r
+                               zptr[ftab[j]] = last;\r
+                               \r
+                               /*--\r
+                               Now ftab contains the first loc of every small bucket.\r
+                               Calculate the running order, from smallest to largest\r
+                               big bucket.\r
+                               --*/\r
+                               \r
+                               for (i = 0; i <= 255; i++) {\r
+                                       runningOrder[i] = i;\r
+                               }\r
+                               \r
+                               int vv;\r
+                               int h = 1;\r
+                               do {\r
+                                       h = 3 * h + 1;\r
+                               } while (h <= 256);\r
+                               do {\r
+                                       h = h / 3;\r
+                                       for (i = h; i <= 255; i++) {\r
+                                               vv = runningOrder[i];\r
+                                               j = i;\r
+                                               while ((ftab[((runningOrder[j-h])+1) << 8] - ftab[(runningOrder[j-h]) << 8]) > (ftab[((vv)+1) << 8] - ftab[(vv) << 8])) {\r
+                                                       runningOrder[j] = runningOrder[j-h];\r
+                                                       j = j - h;\r
+                                                       if (j <= (h - 1))\r
+                                                               break;\r
+                                               }\r
+                                               runningOrder[j] = vv;\r
+                                       }\r
+                               } while (h != 1);\r
+                               \r
+                               /*--\r
+                               The main sorting loop.\r
+                               --*/\r
+                               for (i = 0; i <= 255; i++) {\r
+                                       \r
+                                       /*--\r
+                                       Process big buckets, starting with the least full.\r
+                                       --*/\r
+                                       ss = runningOrder[i];\r
+                                       \r
+                                       /*--\r
+                                       Complete the big bucket [ss] by quicksorting\r
+                                       any unsorted small buckets [ss, j].  Hopefully\r
+                                       previous pointer-scanning phases have already\r
+                                       completed many of the small buckets [ss, j], so\r
+                                       we don't have to sort them at all.\r
+                                       --*/\r
+                                       for (j = 0; j <= 255; j++) {\r
+                                               sb = (ss << 8) + j;\r
+                                               if(!((ftab[sb] & SETMASK) == SETMASK) ) {\r
+                                                       int lo = ftab[sb] & CLEARMASK;\r
+                                                       int hi = (ftab[sb+1] & CLEARMASK) - 1;\r
+                                                       if (hi > lo) {\r
+                                                               QSort3(lo, hi, 2);\r
+                                                               numQSorted += (hi - lo + 1);\r
+                                                               if (workDone > workLimit && firstAttempt) {\r
+                                                                       return;\r
+                                                               }\r
+                                                       }\r
+                                                       ftab[sb] |= SETMASK;\r
+                                               }\r
+                                       }\r
+                                       \r
+                                       /*--\r
+                                       The ss big bucket is now done.  Record this fact,\r
+                                       and update the quadrant descriptors.  Remember to\r
+                                       update quadrants in the overshoot area too, if\r
+                                       necessary.  The "if (i < 255)" test merely skips\r
+                                       this updating for the last bucket processed, since\r
+                                       updating for the last bucket is pointless.\r
+                                       --*/\r
+                                       bigDone[ss] = true;\r
+                                       \r
+                                       if (i < 255) {\r
+                                               int bbStart  = ftab[ss << 8] & CLEARMASK;\r
+                                               int bbSize   = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;\r
+                                               int shifts   = 0;\r
+                                               \r
+                                               while ((bbSize >> shifts) > 65534) {\r
+                                                       shifts++;\r
+                                               }\r
+                                               \r
+                                               for (j = 0; j < bbSize; j++) {\r
+                                                       int a2update = zptr[bbStart + j];\r
+                                                       int qVal = (j >> shifts);\r
+                                                       quadrant[a2update] = qVal;\r
+                                                       if (a2update < BZip2Constants.NUM_OVERSHOOT_BYTES) {\r
+                                                               quadrant[a2update + last + 1] = qVal;\r
+                                                       }\r
+                                               }\r
+                                               \r
+                                               if (!(((bbSize-1) >> shifts) <= 65535)) {\r
+                                                       Panic();\r
+                                               }\r
+                                       }\r
+                                       \r
+                                       /*--\r
+                                       Now scan this big bucket so as to synthesise the\r
+                                       sorted order for small buckets [t, ss] for all t != ss.\r
+                                       --*/\r
+                                       for (j = 0; j <= 255; j++) {\r
+                                               copy[j] = ftab[(j << 8) + ss] & CLEARMASK;\r
+                                       }\r
+                                       \r
+                                       for (j = ftab[ss << 8] & CLEARMASK; j < (ftab[(ss+1) << 8] & CLEARMASK); j++) {\r
+                                               c1 = block[zptr[j]];\r
+                                               if (!bigDone[c1]) {\r
+                                                       zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1;\r
+                                                       copy[c1] ++;\r
+                                               }\r
+                                       }\r
+                                       \r
+                                       for (j = 0; j <= 255; j++) {\r
+                                               ftab[(j << 8) + ss] |= SETMASK;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               void RandomiseBlock() \r
+               {\r
+                       int i;\r
+                       int rNToGo = 0;\r
+                       int rTPos  = 0;\r
+                       for (i = 0; i < 256; i++)\r
+                               inUse[i] = false;\r
+                       \r
+                       for (i = 0; i <= last; i++) {\r
+                               if (rNToGo == 0) {\r
+                                       rNToGo = (int)BZip2Constants.rNums[rTPos];\r
+                                       rTPos++;\r
+                                       if(rTPos == 512)\r
+                                               rTPos = 0;\r
+                               }\r
+                               rNToGo--;\r
+                               block[i + 1] ^= (byte)((rNToGo == 1) ? 1 : 0);\r
+                               // handle 16 bit signed numbers\r
+                               block[i + 1] &= 0xFF;\r
+                               \r
+                               inUse[block[i + 1]] = true;\r
+                       }\r
+               }\r
+               \r
+               void DoReversibleTransformation() \r
+               {\r
+                       workLimit = workFactor * last;\r
+                       workDone = 0;\r
+                       blockRandomised = false;\r
+                       firstAttempt = true;\r
+                       \r
+                       MainSort();\r
+                       \r
+                       if (workDone > workLimit && firstAttempt) {\r
+                               RandomiseBlock();\r
+                               workLimit = workDone = 0;\r
+                               blockRandomised = true;\r
+                               firstAttempt = false;\r
+                               MainSort();\r
+                       }\r
+                       \r
+                       origPtr = -1;\r
+                       for (int i = 0; i <= last; i++) {\r
+                               if (zptr[i] == 0) {\r
+                                       origPtr = i;\r
+                                       break;\r
+                               }\r
+                       }\r
+                       \r
+                       if (origPtr == -1) {\r
+                               Panic();\r
+                       }\r
+               }\r
+               \r
+               bool FullGtU(int i1, int i2) \r
+               {\r
+                       int k;\r
+                       byte c1, c2;\r
+                       int s1, s2;\r
+                       \r
+                       c1 = block[i1 + 1];\r
+                       c2 = block[i2 + 1];\r
+                       if (c1 != c2) {\r
+                               return c1 > c2;\r
+                       }\r
+                       i1++;\r
+                       i2++;\r
+                       \r
+                       c1 = block[i1 + 1];\r
+                       c2 = block[i2 + 1];\r
+                       if (c1 != c2) {\r
+                               return c1 > c2;\r
+                       }\r
+                       i1++;\r
+                       i2++;\r
+                       \r
+                       c1 = block[i1 + 1];\r
+                       c2 = block[i2 + 1];\r
+                       if (c1 != c2) {\r
+                               return c1 > c2;\r
+                       }\r
+                       i1++;\r
+                       i2++;\r
+                       \r
+                       c1 = block[i1 + 1];\r
+                       c2 = block[i2 + 1];\r
+                       if (c1 != c2) {\r
+                               return c1 > c2;\r
+                       }\r
+                       i1++;\r
+                       i2++;\r
+                       \r
+                       c1 = block[i1 + 1];\r
+                       c2 = block[i2 + 1];\r
+                       if (c1 != c2)\r
+                               return c1 > c2;\r
+                       i1++;\r
+                       i2++;\r
+                       \r
+                       c1 = block[i1 + 1];\r
+                       c2 = block[i2 + 1];\r
+                       if (c1 != c2) {\r
+                               return c1 > c2;\r
+                       }\r
+                       i1++;\r
+                       i2++;\r
+                       \r
+                       k = last + 1;\r
+                       \r
+                       do {\r
+                               c1 = block[i1 + 1];\r
+                               c2 = block[i2 + 1];\r
+                               if (c1 != c2) {\r
+                                       return c1 > c2;\r
+                               }\r
+                               s1 = quadrant[i1];\r
+                               s2 = quadrant[i2];\r
+                               if (s1 != s2) {\r
+                                       return s1 > s2;\r
+                               }\r
+                               i1++;\r
+                               i2++;\r
+                               \r
+                               c1 = block[i1 + 1];\r
+                               c2 = block[i2 + 1];\r
+                               if (c1 != c2) {\r
+                                       return c1 > c2;\r
+                               }\r
+                               s1 = quadrant[i1];\r
+                               s2 = quadrant[i2];\r
+                               if (s1 != s2) {\r
+                                       return s1 > s2;\r
+                               }\r
+                               i1++;\r
+                               i2++;\r
+                               \r
+                               c1 = block[i1 + 1];\r
+                               c2 = block[i2 + 1];\r
+                               if (c1 != c2) {\r
+                                       return c1 > c2;\r
+                               }\r
+                               s1 = quadrant[i1];\r
+                               s2 = quadrant[i2];\r
+                               if (s1 != s2) {\r
+                                       return s1 > s2;\r
+                               }\r
+                               i1++;\r
+                               i2++;\r
+                               \r
+                               c1 = block[i1 + 1];\r
+                               c2 = block[i2 + 1];\r
+                               if (c1 != c2) {\r
+                                       return c1 > c2;\r
+                               }\r
+                               s1 = quadrant[i1];\r
+                               s2 = quadrant[i2];\r
+                               if (s1 != s2) {\r
+                                       return s1 > s2;\r
+                               }\r
+                               i1++;\r
+                               i2++;\r
+                               \r
+                               if (i1 > last) {\r
+                                       i1 -= last;\r
+                                       i1--;\r
+                               }\r
+                               if (i2 > last) {\r
+                                       i2 -= last;\r
+                                       i2--;\r
+                               }\r
+                               \r
+                               k -= 4;\r
+                               ++workDone;\r
+                       } while (k >= 0);\r
+                       \r
+                       return false;\r
+               }\r
+               \r
+               /*--\r
+               Knuth's increments seem to work better\r
+               than Incerpi-Sedgewick here.  Possibly\r
+               because the number of elems to sort is\r
+               usually small, typically <= 20.\r
+               --*/\r
+               readonly int[] incs = new int[] { 1, 4, 13, 40, 121, 364, 1093, 3280,\r
+                                        9841, 29524, 88573, 265720,\r
+                                        797161, 2391484 };\r
+               \r
+               void AllocateCompressStructures() \r
+               {\r
+                       int n = BZip2Constants.baseBlockSize * blockSize100k;\r
+                       block = new byte[(n + 1 + BZip2Constants.NUM_OVERSHOOT_BYTES)];\r
+                       quadrant = new int[(n + BZip2Constants.NUM_OVERSHOOT_BYTES)];\r
+                       zptr = new int[n];\r
+                       ftab = new int[65537];\r
+                       \r
+                       if (block == null || quadrant == null || zptr == null  || ftab == null) {\r
+                               //              int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537;\r
+                               //              compressOutOfMemory ( totalDraw, n );\r
+                       }\r
+                       \r
+                       /*\r
+                       The back end needs a place to store the MTF values\r
+                       whilst it calculates the coding tables.  We could\r
+                       put them in the zptr array.  However, these values\r
+                       will fit in a short, so we overlay szptr at the\r
+                       start of zptr, in the hope of reducing the number\r
+                       of cache misses induced by the multiple traversals\r
+                       of the MTF values when calculating coding tables.\r
+                       Seems to improve compression speed by about 1%.\r
+                       */\r
+                       //      szptr = zptr;\r
+                       \r
+                       \r
+                       szptr = new short[2 * n];\r
+               }\r
+               \r
+               void GenerateMTFValues() \r
+               {\r
+                       char[] yy = new char[256];\r
+                       int  i, j;\r
+                       char tmp;\r
+                       char tmp2;\r
+                       int zPend;\r
+                       int wr;\r
+                       int EOB;\r
+                       \r
+                       MakeMaps();\r
+                       EOB = nInUse+1;\r
+                       \r
+                       for (i = 0; i <= EOB; i++) {\r
+                               mtfFreq[i] = 0;\r
+                       }\r
+                       \r
+                       wr = 0;\r
+                       zPend = 0;\r
+                       for (i = 0; i < nInUse; i++) {\r
+                               yy[i] = (char) i;\r
+                       }\r
+                       \r
+                       \r
+                       for (i = 0; i <= last; i++) {\r
+                               char ll_i;\r
+                               \r
+                               ll_i = unseqToSeq[block[zptr[i]]];\r
+                               \r
+                               j = 0;\r
+                               tmp = yy[j];\r
+                               while ( ll_i != tmp ) {\r
+                                       j++;\r
+                                       tmp2 = tmp;\r
+                                       tmp = yy[j];\r
+                                       yy[j] = tmp2;\r
+                               }\r
+                               yy[0] = tmp;\r
+                               \r
+                               if (j == 0) {\r
+                                       zPend++;\r
+                               } else {\r
+                                       if (zPend > 0) {\r
+                                               zPend--;\r
+                                               while (true) {\r
+                                                       switch (zPend % 2) {\r
+                                                               case 0:\r
+                                                                       szptr[wr] = (short)BZip2Constants.RUNA;\r
+                                                                       wr++;\r
+                                                                       mtfFreq[BZip2Constants.RUNA]++;\r
+                                                                       break;\r
+                                                               case 1:\r
+                                                                       szptr[wr] = (short)BZip2Constants.RUNB;\r
+                                                                       wr++;\r
+                                                                       mtfFreq[BZip2Constants.RUNB]++;\r
+                                                                       break;\r
+                                                       };\r
+                                                       if (zPend < 2)\r
+                                                               break;\r
+                                                       zPend = (zPend - 2) / 2;\r
+                                               };\r
+                                               zPend = 0;\r
+                                       }\r
+                                       szptr[wr] = (short)(j + 1);\r
+                                       wr++;\r
+                                       mtfFreq[j + 1]++;\r
+                               }\r
+                       }\r
+                       \r
+                       if (zPend > 0) {\r
+                               zPend--;\r
+                               while (true) {\r
+                                       switch (zPend % 2) {\r
+                                               case 0:\r
+                                                       szptr[wr] = (short)BZip2Constants.RUNA;\r
+                                                       wr++;\r
+                                                       mtfFreq[BZip2Constants.RUNA]++;\r
+                                                       break;\r
+                                               case 1:\r
+                                                       szptr[wr] = (short)BZip2Constants.RUNB;\r
+                                                       wr++;\r
+                                                       mtfFreq[BZip2Constants.RUNB]++;\r
+                                                       break;\r
+                                       }\r
+                                       if (zPend < 2)\r
+                                               break;\r
+                                       zPend = (zPend - 2) / 2;\r
+                               }\r
+                       }\r
+                       \r
+                       szptr[wr] = (short)EOB;\r
+                       wr++;\r
+                       mtfFreq[EOB]++;\r
+                       \r
+                       nMTF = wr;\r
+               }\r
+       }\r
+}\r
+\r
+/* This file was derived from a file containing under this license:\r
+ * \r
+ * This file is a part of bzip2 and/or libbzip2, a program and\r
+ * library for lossless, block-sorting data compression.\r
+ * \r
+ * Copyright (C) 1996-1998 Julian R Seward.  All rights reserved.\r
+ * \r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * \r
+ * 1. Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * \r
+ * 2. The origin of this software must not be misrepresented; you must \r
+ * not claim that you wrote the original software.  If you use this \r
+ * software in a product, an acknowledgment in the product \r
+ * documentation would be appreciated but is not required.\r
+ * \r
+ * 3. Altered source versions must be plainly marked as such, and must\r
+ * not be misrepresented as being the original software.\r
+ * \r
+ * 4. The name of the author may not be used to endorse or promote \r
+ * products derived from this software without specific prior written \r
+ * permission.\r
+ * \r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\r
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\r
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\r
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ * \r
+ * Java version ported by Keiron Liddle, Aftex Software <keiron@aftexsw.com> 1999-2001\r
+ */\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/Adler32.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/Adler32.cs
new file mode 100644 (file)
index 0000000..88d19c7
--- /dev/null
@@ -0,0 +1,199 @@
+// Adler32.cs - Computes Adler32 data checksum of a data stream\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This file was translated from java, it was part of the GNU Classpath\r
+// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+\r
+namespace ICSharpCode.SharpZipLib.Checksums {\r
+       \r
+       /// <summary>\r
+       /// Computes Adler32 checksum for a stream of data. An Adler32\r
+       /// checksum is not as reliable as a CRC32 checksum, but a lot faster to\r
+       /// compute.\r
+       /// \r
+       /// The specification for Adler32 may be found in RFC 1950.\r
+       /// ZLIB Compressed Data Format Specification version 3.3)\r
+       /// \r
+       /// \r
+       /// From that document:\r
+       /// \r
+       ///      "ADLER32 (Adler-32 checksum)\r
+       ///       This contains a checksum value of the uncompressed data\r
+       ///       (excluding any dictionary data) computed according to Adler-32\r
+       ///       algorithm. This algorithm is a 32-bit extension and improvement\r
+       ///       of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073\r
+       ///       standard.\r
+       /// \r
+       ///       Adler-32 is composed of two sums accumulated per byte: s1 is\r
+       ///       the sum of all bytes, s2 is the sum of all s1 values. Both sums\r
+       ///       are done modulo 65521. s1 is initialized to 1, s2 to zero.  The\r
+       ///       Adler-32 checksum is stored as s2*65536 + s1 in most-\r
+       ///       significant-byte first (network) order."\r
+       /// \r
+       ///  "8.2. The Adler-32 algorithm\r
+       /// \r
+       ///    The Adler-32 algorithm is much faster than the CRC32 algorithm yet\r
+       ///    still provides an extremely low probability of undetected errors.\r
+       /// \r
+       ///    The modulo on unsigned long accumulators can be delayed for 5552\r
+       ///    bytes, so the modulo operation time is negligible.  If the bytes\r
+       ///    are a, b, c, the second sum is 3a + 2b + c + 3, and so is position\r
+       ///    and order sensitive, unlike the first sum, which is just a\r
+       ///    checksum.  That 65521 is prime is important to avoid a possible\r
+       ///    large class of two-byte errors that leave the check unchanged.\r
+       ///    (The Fletcher checksum uses 255, which is not prime and which also\r
+       ///    makes the Fletcher check insensitive to single byte changes 0 -\r
+       ///    255.)\r
+       /// \r
+       ///    The sum s1 is initialized to 1 instead of zero to make the length\r
+       ///    of the sequence part of s2, so that the length does not have to be\r
+       ///    checked separately. (Any sequence of zeroes has a Fletcher\r
+       ///    checksum of zero.)"\r
+       /// </summary>\r
+       /// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream"/>\r
+       /// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream"/>\r
+       public sealed class Adler32 : IChecksum\r
+       {\r
+               /// <summary>\r
+               /// largest prime smaller than 65536\r
+               /// </summary>\r
+               readonly static uint BASE = 65521;\r
+               \r
+               uint checksum;\r
+               \r
+               /// <summary>\r
+               /// Returns the Adler32 data checksum computed so far.\r
+               /// </summary>\r
+               public long Value {\r
+                       get {\r
+                               return checksum;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Creates a new instance of the <code>Adler32</code> class.\r
+               /// The checksum starts off with a value of 1.\r
+               /// </summary>\r
+               public Adler32()\r
+               {\r
+                       Reset();\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Resets the Adler32 checksum to the initial value.\r
+               /// </summary>\r
+               public void Reset()\r
+               {\r
+                       checksum = 1; //Initialize to 1\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Updates the checksum with the byte b.\r
+               /// </summary>\r
+               /// <param name="bval">\r
+               /// the data value to add. The high byte of the int is ignored.\r
+               /// </param>\r
+               public void Update(int bval)\r
+               {\r
+                       //We could make a length 1 byte array and call update again, but I\r
+                       //would rather not have that overhead\r
+                       uint s1 = checksum & 0xFFFF;\r
+                       uint s2 = checksum >> 16;\r
+                       \r
+                       s1 = (s1 + ((uint)bval & 0xFF)) % BASE;\r
+                       s2 = (s1 + s2) % BASE;\r
+                       \r
+                       checksum = (s2 << 16) + s1;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Updates the checksum with the bytes taken from the array.\r
+               /// </summary>\r
+               /// <param name="buffer">\r
+               /// buffer an array of bytes\r
+               /// </param>\r
+               public void Update(byte[] buffer)\r
+               {\r
+                       Update(buffer, 0, buffer.Length);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Updates the checksum with the bytes taken from the array.\r
+               /// </summary>\r
+               /// <param name="buf">\r
+               /// an array of bytes\r
+               /// </param>\r
+               /// <param name="off">\r
+               /// the start of the data used for this update\r
+               /// </param>\r
+               /// <param name="len">\r
+               /// the number of bytes to use for this update\r
+               /// </param>\r
+               public void Update(byte[] buf, int off, int len)\r
+               {\r
+                       if (buf == null) {\r
+                               throw new ArgumentNullException("buf");\r
+                       }\r
+                       \r
+                       if (off < 0 || len < 0 || off + len > buf.Length) {\r
+                               throw new ArgumentOutOfRangeException();\r
+                       }\r
+                       \r
+                       //(By Per Bothner)\r
+                       uint s1 = checksum & 0xFFFF;\r
+                       uint s2 = checksum >> 16;\r
+                       \r
+                       while (len > 0) {\r
+                               // We can defer the modulo operation:\r
+                               // s1 maximally grows from 65521 to 65521 + 255 * 3800\r
+                               // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31\r
+                               int n = 3800;\r
+                               if (n > len) {\r
+                                       n = len;\r
+                               }\r
+                               len -= n;\r
+                               while (--n >= 0) {\r
+                                       s1 = s1 + (uint)(buf[off++] & 0xFF);\r
+                                       s2 = s2 + s1;\r
+                               }\r
+                               s1 %= BASE;\r
+                               s2 %= BASE;\r
+                       }\r
+                       \r
+                       checksum = (s2 << 16) | s1;\r
+               }\r
+       }\r
+}\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/Crc32.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/Crc32.cs
new file mode 100644 (file)
index 0000000..2c3b28e
--- /dev/null
@@ -0,0 +1,202 @@
+// CRC32.cs - Computes CRC32 data checksum of a data stream\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This file was translated from java, it was part of the GNU Classpath\r
+// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+\r
+namespace ICSharpCode.SharpZipLib.Checksums {\r
+       \r
+       /// <summary>\r
+       /// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:\r
+       /// 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.\r
+       ///\r
+       /// Polynomials over GF(2) are represented in binary, one bit per coefficient,\r
+       /// with the lowest powers in the most significant bit.  Then adding polynomials\r
+       /// is just exclusive-or, and multiplying a polynomial by x is a right shift by\r
+       /// one.  If we call the above polynomial p, and represent a byte as the\r
+       /// polynomial q, also with the lowest power in the most significant bit (so the\r
+       /// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,\r
+       /// where a mod b means the remainder after dividing a by b.\r
+       ///\r
+       /// This calculation is done using the shift-register method of multiplying and\r
+       /// taking the remainder.  The register is initialized to zero, and for each\r
+       /// incoming bit, x^32 is added mod p to the register if the bit is a one (where\r
+       /// x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by\r
+       /// x (which is shifting right by one and adding x^32 mod p if the bit shifted\r
+       /// out is a one).  We start with the highest power (least significant bit) of\r
+       /// q and repeat for all eight bits of q.\r
+       ///\r
+       /// The table is simply the CRC of all possible eight bit values.  This is all\r
+       /// the information needed to generate CRC's on data a byte at a time for all\r
+       /// combinations of CRC register values and incoming bytes.\r
+       /// </summary>\r
+       public sealed class Crc32 : IChecksum\r
+       {\r
+               readonly static uint CrcSeed = 0xFFFFFFFF;\r
+               \r
+               readonly static uint[] CrcTable = new uint[] {\r
+                       0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,\r
+                       0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,\r
+                       0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,\r
+                       0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,\r
+                       0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,\r
+                       0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,\r
+                       0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,\r
+                       0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,\r
+                       0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,\r
+                       0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,\r
+                       0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,\r
+                       0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,\r
+                       0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,\r
+                       0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,\r
+                       0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,\r
+                       0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,\r
+                       0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,\r
+                       0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,\r
+                       0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,\r
+                       0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,\r
+                       0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,\r
+                       0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,\r
+                       0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,\r
+                       0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,\r
+                       0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,\r
+                       0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,\r
+                       0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,\r
+                       0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,\r
+                       0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, \r
+                       0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,\r
+                       0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,\r
+                       0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,\r
+                       0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,\r
+                       0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,\r
+                       0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,\r
+                       0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,\r
+                       0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,\r
+                       0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,\r
+                       0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,\r
+                       0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,\r
+                       0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,\r
+                       0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,\r
+                       0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,\r
+                       0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,\r
+                       0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,\r
+                       0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,\r
+                       0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,\r
+                       0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,\r
+                       0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,\r
+                       0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,\r
+                       0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, \r
+                       0x2D02EF8D\r
+               };\r
+               \r
+               /// <summary>\r
+               /// The crc data checksum so far.\r
+               /// </summary>\r
+               uint crc = 0;\r
+               \r
+               /// <summary>\r
+               /// Returns the CRC32 data checksum computed so far.\r
+               /// </summary>\r
+               public long Value {\r
+                       get {\r
+                               return (long)crc;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Resets the CRC32 data checksum as if no update was ever called.\r
+               /// </summary>\r
+               public void Reset() \r
+               { \r
+                       crc = 0; \r
+               }\r
+               \r
+               /// <summary>\r
+               /// Updates the checksum with the int bval.\r
+               /// </summary>\r
+               /// <param name = "bval">\r
+               /// the byte is taken as the lower 8 bits of bval\r
+               /// </param>\r
+               public void Update(int bval)\r
+               {\r
+                       crc ^= CrcSeed;\r
+                       crc  = CrcTable[(crc ^ bval) & 0xFF] ^ (crc >> 8);\r
+                       crc ^= CrcSeed;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Updates the checksum with the bytes taken from the array.\r
+               /// </summary>\r
+               /// <param name="buffer">\r
+               /// buffer an array of bytes\r
+               /// </param>\r
+               public void Update(byte[] buffer)\r
+               {\r
+                       Update(buffer, 0, buffer.Length);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Adds the byte array to the data checksum.\r
+               /// </summary>\r
+               /// <param name = "buf">\r
+               /// the buffer which contains the data\r
+               /// </param>\r
+               /// <param name = "off">\r
+               /// the offset in the buffer where the data starts\r
+               /// </param>\r
+               /// <param name = "len">\r
+               /// the length of the data\r
+               /// </param>\r
+               public void Update(byte[] buf, int off, int len)\r
+               {\r
+                       if (buf == null) {\r
+                               throw new ArgumentNullException("buf");\r
+                       }\r
+                       \r
+                       if (off < 0 || len < 0 || off + len > buf.Length) {\r
+                               throw new ArgumentOutOfRangeException();\r
+                       }\r
+                       \r
+                       crc ^= CrcSeed;\r
+                       \r
+                       while (--len >= 0) {\r
+                               crc = CrcTable[(crc ^ buf[off++]) & 0xFF] ^ (crc >> 8);\r
+                       }\r
+                       \r
+                       crc ^= CrcSeed;\r
+               }\r
+       }\r
+}\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/IChecksum.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/IChecksum.cs
new file mode 100644 (file)
index 0000000..b8f9d91
--- /dev/null
@@ -0,0 +1,91 @@
+// IChecksum.cs - Interface to compute a data checksum\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This file was translated from java, it was part of the GNU Classpath\r
+// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+namespace ICSharpCode.SharpZipLib.Checksums {\r
+       \r
+       /// <summary>\r
+       /// Interface to compute a data checksum used by checked input/output streams.\r
+       /// A data checksum can be updated by one byte or with a byte array. After each\r
+       /// update the value of the current checksum can be returned by calling\r
+       /// <code>getValue</code>. The complete checksum object can also be reset\r
+       /// so it can be used again with new data.\r
+       /// </summary>\r
+       public interface IChecksum\r
+       {\r
+               /// <summary>\r
+               /// Returns the data checksum computed so far.\r
+               /// </summary>\r
+               long Value {\r
+                       get;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Resets the data checksum as if no update was ever called.\r
+               /// </summary>\r
+               void Reset();\r
+               \r
+               /// <summary>\r
+               /// Adds one byte to the data checksum.\r
+               /// </summary>\r
+               /// <param name = "bval">\r
+               /// the data value to add. The high byte of the int is ignored.\r
+               /// </param>\r
+               void Update(int bval);\r
+               \r
+               /// <summary>\r
+               /// Updates the data checksum with the bytes taken from the array.\r
+               /// </summary>\r
+               /// <param name="buffer">\r
+               /// buffer an array of bytes\r
+               /// </param>\r
+               void Update(byte[] buffer);\r
+               \r
+               /// <summary>\r
+               /// Adds the byte array to the data checksum.\r
+               /// </summary>\r
+               /// <param name = "buf">\r
+               /// the buffer which contains the data\r
+               /// </param>\r
+               /// <param name = "off">\r
+               /// the offset in the buffer where the data starts\r
+               /// </param>\r
+               /// <param name = "len">\r
+               /// the length of the data\r
+               /// </param>\r
+               void Update(byte[] buf, int off, int len);\r
+       }\r
+}\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/StrangeCrc.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Checksums/StrangeCrc.cs
new file mode 100644 (file)
index 0000000..2469e40
--- /dev/null
@@ -0,0 +1,158 @@
+// StrangeCRC.cs - computes a crc used in the bziplib ... I don't think that\r
+//                 this is the 'standard' crc, please correct me, if I'm wrong\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This file was translated from java, it was part of the GNU Classpath\r
+// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+\r
+namespace ICSharpCode.SharpZipLib.Checksums {\r
+       \r
+       public class StrangeCRC : IChecksum\r
+       {\r
+               readonly static uint[] crc32Table = {\r
+                                                        0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,\r
+                                                        0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,\r
+                                                        0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,\r
+                                                        0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,\r
+                                                        0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,\r
+                                                        0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,\r
+                                                        0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,\r
+                                                        0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,\r
+                                                        0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,\r
+                                                        0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,\r
+                                                        0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,\r
+                                                        0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,\r
+                                                        0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,\r
+                                                        0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,\r
+                                                        0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,\r
+                                                        0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,\r
+                                                        0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,\r
+                                                        0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,\r
+                                                        0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,\r
+                                                        0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,\r
+                                                        0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,\r
+                                                        0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,\r
+                                                        0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,\r
+                                                        0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,\r
+                                                        0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,\r
+                                                        0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,\r
+                                                        0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,\r
+                                                        0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,\r
+                                                        0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,\r
+                                                        0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,\r
+                                                        0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,\r
+                                                        0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,\r
+                                                        0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,\r
+                                                        0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,\r
+                                                        0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,\r
+                                                        0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,\r
+                                                        0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,\r
+                                                        0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,\r
+                                                        0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,\r
+                                                        0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,\r
+                                                        0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,\r
+                                                        0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,\r
+                                                        0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,\r
+                                                        0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,\r
+                                                        0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,\r
+                                                        0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,\r
+                                                        0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,\r
+                                                        0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,\r
+                                                        0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,\r
+                                                        0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,\r
+                                                        0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,\r
+                                                        0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,\r
+                                                        0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,\r
+                                                        0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,\r
+                                                        0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,\r
+                                                        0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,\r
+                                                        0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,\r
+                                                        0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,\r
+                                                        0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,\r
+                                                        0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,\r
+                                                        0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,\r
+                                                        0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,\r
+                                                        0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,\r
+                                                        0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4\r
+                                                };\r
+               int globalCrc;\r
+       \r
+               public StrangeCRC() \r
+               {\r
+                       Reset();\r
+               }\r
+       \r
+               public void Reset()\r
+               {\r
+                       globalCrc = -1;\r
+               }\r
+       \r
+               public long Value {\r
+                       get {\r
+                               return ~globalCrc;\r
+                       }\r
+               }\r
+               \r
+               public void Update(int inCh)\r
+               {\r
+                       int temp = (globalCrc >> 24) ^ inCh;\r
+                       if (temp < 0) {\r
+                               temp = 256 + temp;\r
+                       }\r
+                       globalCrc = (int)((globalCrc << 8) ^ crc32Table[temp]);\r
+               }\r
+               \r
+               public void Update(byte[] buf)\r
+               {\r
+                       Update(buf, 0, buf.Length);\r
+               }\r
+               \r
+               public void Update(byte[] buf, int off, int len)\r
+               {\r
+                       if (buf == null) {\r
+                               throw new ArgumentNullException("buf");\r
+                       }\r
+                       \r
+                       if (off < 0 || len < 0 || off + len > buf.Length) {\r
+                               throw new ArgumentOutOfRangeException();\r
+                       }\r
+                       \r
+                       for (int i = 0; i < len; ++i) {\r
+                               Update(buf[off++]);\r
+                       }\r
+               }\r
+       }\r
+}\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipConstants.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipConstants.cs
new file mode 100644 (file)
index 0000000..f96527d
--- /dev/null
@@ -0,0 +1,67 @@
+// GZIPConstants.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This file was translated from java, it was part of the GNU Classpath\r
+// Copyright (C) 2001 Free Software Foundation, Inc.\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+namespace ICSharpCode.SharpZipLib.GZip {\r
+       \r
+       /// <summary>\r
+       /// This class contains constants used for gzip.\r
+       /// </summary>\r
+       public class GZipConstants \r
+       {\r
+               /// <summary>\r
+               /// Magic number found at start of GZIP header\r
+               /// </summary>\r
+               public static readonly int GZIP_MAGIC = 0x1F8B;\r
+               \r
+               /*  The flag byte is divided into individual bits as follows:\r
+                       \r
+                       bit 0   FTEXT\r
+                       bit 1   FHCRC\r
+                       bit 2   FEXTRA\r
+                       bit 3   FNAME\r
+                       bit 4   FCOMMENT\r
+                       bit 5   reserved\r
+                       bit 6   reserved\r
+                       bit 7   reserved\r
+                */\r
+               public const int FTEXT    = 0x1;\r
+               public const int FHCRC    = 0x2;\r
+               public const int FEXTRA   = 0x4;\r
+               public const int FNAME    = 0x8;\r
+               public const int FCOMMENT = 0x10;\r
+       }\r
+}\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipInputStream.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipInputStream.cs
new file mode 100644 (file)
index 0000000..80bcab7
--- /dev/null
@@ -0,0 +1,337 @@
+// GzipInputStream.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This file was translated from java, it was part of the GNU Classpath\r
+// Copyright (C) 2001 Free Software Foundation, Inc.\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.IO;\r
+\r
+using ICSharpCode.SharpZipLib.Checksums;\r
+using ICSharpCode.SharpZipLib.Zip.Compression;\r
+using ICSharpCode.SharpZipLib.Zip.Compression.Streams;\r
+\r
+namespace ICSharpCode.SharpZipLib.GZip {\r
+       \r
+       /// <summary>\r
+       /// This filter stream is used to decompress a "GZIP" format stream.\r
+       /// The "GZIP" format is described baseInputStream RFC 1952.\r
+       /// \r
+       /// author of the original java version : John Leuner\r
+       /// </summary>\r
+       /// <example> This sample shows how to unzip a gzipped file\r
+       /// <code>\r
+       /// using System;\r
+       /// using System.IO;\r
+       /// \r
+       /// using NZlib.GZip;\r
+       /// \r
+       /// class MainClass\r
+       /// {\r
+       ///     public static void Main(string[] args)\r
+       ///     {\r
+       ///             Stream s = new GZipInputStream(File.OpenRead(args[0]));\r
+       ///             FileStream fs = File.Create(Path.GetFileNameWithoutExtension(args[0]));\r
+       ///             int size = 2048;\r
+       ///             byte[] writeData = new byte[2048];\r
+       ///             while (true) {\r
+       ///                     size = s.Read(writeData, 0, size);\r
+       ///                     if (size > 0) {\r
+       ///                             fs.Write(writeData, 0, size);\r
+       ///                     } else {\r
+       ///                             break;\r
+       ///                     }\r
+       ///             }\r
+       ///             s.Close();\r
+       ///     }\r
+       /// }   \r
+       /// </code>\r
+       /// </example>\r
+       public class GZipInputStream : InflaterInputStream \r
+       {\r
+               \r
+               //Variables\r
+               \r
+               /// <summary>\r
+               /// CRC-32 value for uncompressed data\r
+               /// </summary>\r
+               protected Crc32 crc = new Crc32();\r
+               \r
+               /// <summary>\r
+               /// Indicates end of stream\r
+               /// </summary>\r
+               protected bool eos;\r
+               \r
+               /// <summary>\r
+               /// Creates a GzipInputStream with the default buffer size\r
+               /// </summary>\r
+               /// <param name="baseInputStream">\r
+               /// The stream to read compressed data from (baseInputStream GZIP format)\r
+               /// </param>\r
+               public GZipInputStream(Stream baseInputStream) : this(baseInputStream, 4096)\r
+               {\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Creates a GZIPInputStream with the specified buffer size\r
+               /// </summary>\r
+               /// <param name="baseInputStream">\r
+               /// The stream to read compressed data from (baseInputStream GZIP format)\r
+               /// </param>\r
+               /// <param name="size">\r
+               /// Size of the buffer to use\r
+               /// </param>\r
+               public GZipInputStream(Stream baseInputStream, int size) : base(baseInputStream, new Inflater(true), size)\r
+               {\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Reads uncompressed data into an array of bytes\r
+               /// </summary>\r
+               /// <param name="buf">\r
+               /// the buffer to read uncompressed data into\r
+               /// </param>\r
+               /// <param name="offset">\r
+               /// the offset indicating where the data should be placed\r
+               /// </param>\r
+               /// <param name="len">\r
+               /// the number of uncompressed bytes to be read\r
+               /// </param>\r
+               public override int Read(byte[] buf, int offset, int len) \r
+               {\r
+                       // We first have to slurp baseInputStream the GZIP header, then we feed all the\r
+                       // rest of the data to the superclass.\r
+                       //\r
+                       // As we do that we continually update the CRC32. Once the data is\r
+                       // finished, we check the CRC32\r
+                       //\r
+                       // This means we don't need our own buffer, as everything is done\r
+                       // baseInputStream the superclass.\r
+                       if (!readGZIPHeader) {\r
+                               ReadHeader();\r
+                       }\r
+                       \r
+                       if (eos) {\r
+                               return 0;\r
+                       }\r
+                       \r
+                       //    System.err.println("GZIPIS.read(byte[], off, len ... " + offset + " and len " + len);\r
+                       //We don't have to read the header, so we just grab data from the superclass\r
+                       int numRead = base.Read(buf, offset, len);\r
+                       if (numRead > 0) {\r
+                               crc.Update(buf, offset, numRead);\r
+                       }\r
+                       \r
+                       if (inf.IsFinished) {\r
+                               ReadFooter();\r
+                       }\r
+                       return numRead;\r
+               }\r
+               \r
+               private void ReadHeader() \r
+               {\r
+                       /* 1. Check the two magic bytes */\r
+                       Crc32 headCRC = new Crc32();\r
+                       int magic = baseInputStream.ReadByte();\r
+                       if (magic < 0) {\r
+                                       eos = true;\r
+                                       return;\r
+                       }\r
+                       headCRC.Update(magic);\r
+                       if (magic != (GZipConstants.GZIP_MAGIC >> 8)) {\r
+                               throw new IOException("Error baseInputStream GZIP header, first byte doesn't match");\r
+                       }\r
+                               \r
+                       magic = baseInputStream.ReadByte();\r
+                       if (magic != (GZipConstants.GZIP_MAGIC & 0xFF)) {\r
+                               throw new IOException("Error baseInputStream GZIP header,  second byte doesn't match");\r
+                       }\r
+                       headCRC.Update(magic);\r
+                       \r
+                       /* 2. Check the compression type (must be 8) */\r
+                       int CM = baseInputStream.ReadByte();\r
+                       if (CM != 8) {\r
+                               throw new IOException("Error baseInputStream GZIP header, data not baseInputStream deflate format");\r
+                       }\r
+                       headCRC.Update(CM);\r
+                       \r
+                       /* 3. Check the flags */\r
+                       int flags = baseInputStream.ReadByte();\r
+                       if (flags < 0) {\r
+                               throw new Exception("Early EOF baseInputStream GZIP header");\r
+                       }\r
+                       headCRC.Update(flags);\r
+                       \r
+                       /*    This flag byte is divided into individual bits as follows:\r
+                               \r
+                               bit 0   FTEXT\r
+                               bit 1   FHCRC\r
+                               bit 2   FEXTRA\r
+                               bit 3   FNAME\r
+                               bit 4   FCOMMENT\r
+                               bit 5   reserved\r
+                               bit 6   reserved\r
+                               bit 7   reserved\r
+                               */\r
+                               \r
+                       /* 3.1 Check the reserved bits are zero */\r
+                       \r
+                       if ((flags & 0xd0) != 0) {\r
+                               throw new IOException("Reserved flag bits baseInputStream GZIP header != 0");\r
+                       }\r
+                       \r
+                       /* 4.-6. Skip the modification time, extra flags, and OS type */\r
+                       for (int i=0; i< 6; i++) {\r
+                               int readByte = baseInputStream.ReadByte();\r
+                               if (readByte < 0) {\r
+                                       throw new Exception("Early EOF baseInputStream GZIP header");\r
+                               }\r
+                               headCRC.Update(readByte);\r
+                       }\r
+                       \r
+                       /* 7. Read extra field */\r
+                       if ((flags & GZipConstants.FEXTRA) != 0) {\r
+                               /* Skip subfield id */\r
+                               for (int i=0; i< 2; i++) {\r
+                                       int readByte = baseInputStream.ReadByte();\r
+                                       if (readByte < 0) {\r
+                                               throw new Exception("Early EOF baseInputStream GZIP header");\r
+                                       }\r
+                                       headCRC.Update(readByte);\r
+                               }\r
+                               if (baseInputStream.ReadByte() < 0 || baseInputStream.ReadByte() < 0) {\r
+                                       throw new Exception("Early EOF baseInputStream GZIP header");\r
+                               }\r
+                               \r
+                               int len1, len2, extraLen;\r
+                               len1 = baseInputStream.ReadByte();\r
+                               len2 = baseInputStream.ReadByte();\r
+                               if ((len1 < 0) || (len2 < 0)) {\r
+                                       throw new Exception("Early EOF baseInputStream GZIP header");\r
+                               }\r
+                               headCRC.Update(len1);\r
+                               headCRC.Update(len2);\r
+                               \r
+                               extraLen = (len1 << 8) | len2;\r
+                               for (int i = 0; i < extraLen;i++) {\r
+                                       int readByte = baseInputStream.ReadByte();\r
+                                       if (readByte < 0) {\r
+                                               throw new Exception("Early EOF baseInputStream GZIP header");\r
+                                       }\r
+                                       headCRC.Update(readByte);\r
+                               }\r
+                       }\r
+                       \r
+                       /* 8. Read file name */\r
+                       if ((flags & GZipConstants.FNAME) != 0) {\r
+                               int readByte;\r
+                               while ( (readByte = baseInputStream.ReadByte()) > 0) {\r
+                                       headCRC.Update(readByte);\r
+                               }\r
+                               if (readByte < 0) {\r
+                                       throw new Exception("Early EOF baseInputStream GZIP file name");\r
+                               }\r
+                               headCRC.Update(readByte);\r
+                       }\r
+                       \r
+                       /* 9. Read comment */\r
+                       if ((flags & GZipConstants.FCOMMENT) != 0) {\r
+                               int readByte;\r
+                               while ( (readByte = baseInputStream.ReadByte()) > 0) {\r
+                                       headCRC.Update(readByte);\r
+                               }\r
+                               \r
+                               if (readByte < 0) {\r
+                                       throw new Exception("Early EOF baseInputStream GZIP comment");\r
+                               }\r
+                               headCRC.Update(readByte);\r
+                       }\r
+                       \r
+                       /* 10. Read header CRC */\r
+                       if ((flags & GZipConstants.FHCRC) != 0) {\r
+                               int tempByte;\r
+                               int crcval = baseInputStream.ReadByte();\r
+                               if (crcval < 0) {\r
+                                       throw new Exception("Early EOF baseInputStream GZIP header");\r
+                               }\r
+                               \r
+                               tempByte = baseInputStream.ReadByte();\r
+                               if (tempByte < 0) {\r
+                                       throw new Exception("Early EOF baseInputStream GZIP header");\r
+                               }\r
+                               \r
+                               crcval = (crcval << 8) | tempByte;\r
+                               if (crcval != ((int) headCRC.Value & 0xffff)) {\r
+                                       throw new IOException("Header CRC value mismatch");\r
+                               }\r
+                       }\r
+                       \r
+                       readGZIPHeader = true;\r
+                       //System.err.println("Read GZIP header");\r
+               }\r
+               \r
+               private void ReadFooter() \r
+               {\r
+                       byte[] footer = new byte[8];\r
+                       int avail = inf.RemainingInput;\r
+                       if (avail > 8) {\r
+                               avail = 8;\r
+                       }\r
+                       System.Array.Copy(buf, len - inf.RemainingInput, footer, 0, avail);\r
+                       int needed = 8 - avail;\r
+                       while (needed > 0) {\r
+                               int count = baseInputStream.Read(footer, 8-needed, needed);\r
+                               if (count <= 0) {\r
+                                       throw new Exception("Early EOF baseInputStream GZIP footer");\r
+                               }\r
+                               needed -= count; //Jewel Jan 16\r
+                       }\r
+                       int crcval = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8) | ((footer[2] & 0xff) << 16) | (footer[3] << 24);\r
+                       if (crcval != (int) crc.Value) {\r
+                               throw new IOException("GZIP crc sum mismatch, theirs \"" + crcval + "\" and ours \"" + (int) crc.Value);\r
+                       }\r
+                       int total = (footer[4] & 0xff) | ((footer[5] & 0xff) << 8) | ((footer[6] & 0xff) << 16) | (footer[7] << 24);\r
+                       if (total != inf.TotalOut) {\r
+                               throw new IOException("Number of bytes mismatch");\r
+                       }\r
+                       /* XXX Should we support multiple members.\r
+                       * Difficult, since there may be some bytes still baseInputStream buf\r
+                       */\r
+                       eos = true;\r
+               }\r
+               \r
+               /* Have we read the GZIP header yet? */\r
+               private bool readGZIPHeader;\r
+       }\r
+}\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipOutputStream.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/GZip/GZipOutputStream.cs
new file mode 100644 (file)
index 0000000..a2b8b11
--- /dev/null
@@ -0,0 +1,170 @@
+// GzipOutputStream.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This file was translated from java, it was part of the GNU Classpath\r
+// Copyright (C) 2001 Free Software Foundation, Inc.\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.IO;\r
+\r
+using ICSharpCode.SharpZipLib.Checksums;\r
+using ICSharpCode.SharpZipLib.Zip.Compression;\r
+using ICSharpCode.SharpZipLib.Zip.Compression.Streams;\r
+\r
+namespace ICSharpCode.SharpZipLib.GZip {\r
+       \r
+       /// <summary>\r
+       /// This filter stream is used to compress a stream into a "GZIP" stream.\r
+       /// The "GZIP" format is described in RFC 1952.\r
+       ///\r
+       /// author of the original java version : John Leuner\r
+       /// </summary>\r
+       /// <example> This sample shows how to gzip a file\r
+       /// <code>\r
+       /// using System;\r
+       /// using System.IO;\r
+       /// \r
+       /// using NZlib.GZip;\r
+       /// \r
+       /// class MainClass\r
+       /// {\r
+       ///     public static void Main(string[] args)\r
+       ///     {\r
+       ///             Stream s = new GZipOutputStream(File.Create(args[0] + ".gz"));\r
+       ///             FileStream fs = File.OpenRead(args[0]);\r
+       ///             byte[] writeData = new byte[fs.Length];\r
+       ///             fs.Read(writeData, 0, (int)fs.Length);\r
+       ///             s.Write(writeData, 0, writeData.Length);\r
+       ///             s.Close();\r
+       ///     }\r
+       /// }   \r
+       /// </code>\r
+       /// </example>\r
+       public class GZipOutputStream : DeflaterOutputStream\r
+       {\r
+               //Variables\r
+               \r
+               /// <summary>\r
+               /// CRC-32 value for uncompressed data\r
+               /// </summary>\r
+               protected Crc32 crc = new Crc32();\r
+               \r
+               // Constructors\r
+               \r
+               /// <summary>\r
+               /// Creates a GzipOutputStream with the default buffer size\r
+               /// </summary>\r
+               /// <param name="baseOutputStream">\r
+               /// The stream to read data (to be compressed) from\r
+               /// </param>\r
+               public GZipOutputStream(Stream baseOutputStream) : this(baseOutputStream, 4096)\r
+               {\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Creates a GZIPOutputStream with the specified buffer size\r
+               /// </summary>\r
+               /// <param name="baseOutputStream">\r
+               /// The stream to read data (to be compressed) from\r
+               /// </param>\r
+               /// <param name="size">\r
+               /// Size of the buffer to use\r
+               /// </param>\r
+               public GZipOutputStream(Stream baseOutputStream, int size) : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true), size)\r
+               {\r
+                       // TODO : find out correctness, orgininally this was : (int) (System.currentTimeMillis() / 1000L);\r
+                       int mod_time = (int)(DateTime.Now.Ticks / 10000L);  // Ticks give back 100ns intervals\r
+                       byte[] gzipHeader = {\r
+                               /* The two magic bytes */\r
+                               (byte) (GZipConstants.GZIP_MAGIC >> 8), (byte) GZipConstants.GZIP_MAGIC,\r
+                               \r
+                               /* The compression type */\r
+                               (byte) Deflater.DEFLATED,\r
+                               \r
+                               /* The flags (not set) */\r
+                               0,\r
+                               \r
+                               /* The modification time */\r
+                               (byte) mod_time, (byte) (mod_time >> 8),\r
+                               (byte) (mod_time >> 16), (byte) (mod_time >> 24),\r
+                               \r
+                               /* The extra flags */\r
+                               0,\r
+                               \r
+                               /* The OS type (unknown) */\r
+                               (byte) 255\r
+                       };\r
+                       \r
+                       baseOutputStream.Write(gzipHeader, 0, gzipHeader.Length);\r
+                       //    System.err.println("wrote GZIP header (" + gzipHeader.length + " bytes )");\r
+               }\r
+               \r
+               public override void Write(byte[] buf, int off, int len)\r
+               {\r
+                       crc.Update(buf, off, len);\r
+                       base.Write(buf, off, len);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Writes remaining compressed output data to the output stream\r
+               /// and closes it.\r
+               /// </summary>\r
+               public override void Close()\r
+               {\r
+                       Finish();\r
+                       baseOutputStream.Close();\r
+               }\r
+               \r
+               public override void Finish()\r
+               {\r
+                       base.Finish();\r
+                       \r
+                       int totalin = def.TotalIn;\r
+                       int crcval = (int) (crc.Value & 0xffffffff);\r
+                       \r
+                       //    System.err.println("CRC val is " + Integer.toHexString( crcval )                 + " and length " + Integer.toHexString(totalin));\r
+                       \r
+                       byte[] gzipFooter = {\r
+                               (byte) crcval, (byte) (crcval >> 8),\r
+                               (byte) (crcval >> 16), (byte) (crcval >> 24),\r
+                               \r
+                               (byte) totalin, (byte) (totalin >> 8),\r
+                               (byte) (totalin >> 16), (byte) (totalin >> 24)\r
+                       };\r
+                       \r
+                       baseOutputStream.Write(gzipFooter, 0, gzipFooter.Length);\r
+                       //    System.err.println("wrote GZIP trailer (" + gzipFooter.length + " bytes )");\r
+               }\r
+       }\r
+}\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/InvalidHeaderException.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/InvalidHeaderException.cs
new file mode 100644 (file)
index 0000000..e6a2000
--- /dev/null
@@ -0,0 +1,72 @@
+// BZip2OutputStream.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.IO;\r
+\r
+using ICSharpCode.SharpZipLib.Checksums;\r
+\r
+namespace ICSharpCode.SharpZipLib.Tar {\r
+       \r
+       /// <summary>\r
+       /// This exception is used to indicate that there is a problem\r
+       /// with a TAR archive header.\r
+       /// </summary>\r
+       public class InvalidHeaderException : System.IO.IOException\r
+       {\r
+               public InvalidHeaderException()\r
+               {\r
+               }\r
+       \r
+               public InvalidHeaderException(string msg) : base(msg)\r
+               {\r
+               }\r
+       }\r
+}\r
+\r
+/* The original Java file had this header:\r
+** Authored by Timothy Gerard Endres\r
+** <mailto:time@gjt.org>  <http://www.trustice.com>\r
+** \r
+** This work has been placed into the public domain.\r
+** You may use this work in any way and for any purpose you wish.\r
+**\r
+** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,\r
+** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR\r
+** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY\r
+** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR\r
+** REDISTRIBUTION OF THIS SOFTWARE. \r
+** \r
+*/\r
+\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarArchive.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarArchive.cs
new file mode 100644 (file)
index 0000000..e2b115b
--- /dev/null
@@ -0,0 +1,693 @@
+// TarInputStream.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+//\r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.IO;\r
+using System.Text;\r
+\r
+namespace ICSharpCode.SharpZipLib.Tar {\r
+       \r
+       public delegate void ProgressMessageHandler(TarArchive archive, string message);\r
+       \r
+       /// <summary>\r
+       /// The TarArchive class implements the concept of a\r
+       /// tar archive. A tar archive is a series of entries, each of\r
+       /// which represents a file system object. Each entry in\r
+       /// the archive consists of a header record. Directory entries\r
+       /// consist only of the header record, and are followed by entries\r
+       /// for the directory's contents. File entries consist of a\r
+       /// header record followed by the number of records needed to\r
+       /// contain the file's contents. All entries are written on\r
+       /// record boundaries. Records are 512 bytes long.\r
+       /// \r
+       /// TarArchives are instantiated in either read or write mode,\r
+       /// based upon whether they are instantiated with an InputStream\r
+       /// or an OutputStream. Once instantiated TarArchives read/write\r
+       /// mode can not be changed.\r
+       /// \r
+       /// There is currently no support for random access to tar archives.\r
+       /// However, it seems that subclassing TarArchive, and using the\r
+       /// TarBuffer.getCurrentRecordNum() and TarBuffer.getCurrentBlockNum()\r
+       /// methods, this would be rather trvial.\r
+       /// </summary>\r
+       public class TarArchive\r
+       {\r
+               protected bool verbose;\r
+               protected bool debug;\r
+               protected bool keepOldFiles;\r
+               protected bool asciiTranslate;\r
+               \r
+               protected int    userId;\r
+               protected string userName;\r
+               protected int    groupId;\r
+               protected string groupName;\r
+               \r
+               protected string rootPath;\r
+               protected string pathPrefix;\r
+               \r
+               protected int    recordSize;\r
+               protected byte[] recordBuf;\r
+               \r
+               protected TarInputStream  tarIn;\r
+               protected TarOutputStream tarOut;\r
+               \r
+               public event ProgressMessageHandler ProgressMessageEvent;\r
+               \r
+               protected virtual void OnProgressMessageEvent(string message)\r
+               {\r
+                       if (ProgressMessageEvent != null) {\r
+                               ProgressMessageEvent(this, message);\r
+                       }\r
+               }\r
+               \r
+               protected TarArchive()\r
+               {\r
+               }\r
+               \r
+               /// <summary>\r
+               /// The InputStream based constructors create a TarArchive for the\r
+               /// purposes of e'x'tracting or lis't'ing a tar archive. Thus, use\r
+               /// these constructors when you wish to extract files from or list\r
+               /// the contents of an existing tar archive.\r
+               /// </summary>\r
+               public static TarArchive CreateInputTarArchive(Stream inputStream)\r
+               {\r
+                       return CreateInputTarArchive(inputStream, TarBuffer.DEFAULT_BLKSIZE);\r
+               }\r
+               \r
+               public static TarArchive CreateInputTarArchive(Stream inputStream, int blockSize)\r
+               {\r
+                       return CreateInputTarArchive(inputStream, blockSize, TarBuffer.DEFAULT_RCDSIZE);\r
+               }\r
+               \r
+               public static TarArchive CreateInputTarArchive(Stream inputStream, int blockSize, int recordSize)\r
+               {\r
+                       TarArchive archive = new TarArchive();\r
+                       archive.tarIn = new TarInputStream(inputStream, blockSize, recordSize);\r
+                       archive.Initialize(recordSize);\r
+                       return archive;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// The OutputStream based constructors create a TarArchive for the\r
+               /// purposes of 'c'reating a tar archive. Thus, use these constructors\r
+               /// when you wish to create a new tar archive and write files into it.\r
+               /// </summary>\r
+               public static TarArchive CreateOutputTarArchive(Stream outputStream)\r
+               {\r
+                       return CreateOutputTarArchive(outputStream, TarBuffer.DEFAULT_BLKSIZE);\r
+               }\r
+               \r
+               public static TarArchive CreateOutputTarArchive(Stream outputStream, int blockSize)\r
+               {\r
+                       return CreateOutputTarArchive(outputStream, blockSize, TarBuffer.DEFAULT_RCDSIZE);\r
+               }\r
+               \r
+               public static TarArchive CreateOutputTarArchive(Stream outputStream, int blockSize, int recordSize)\r
+               {\r
+                       TarArchive archive = new TarArchive();\r
+                       archive.tarOut = new TarOutputStream(outputStream, blockSize, recordSize);\r
+                       archive.Initialize(recordSize);\r
+                       return archive;\r
+               }\r
+               \r
+               \r
+               /// <summary>\r
+               /// Common constructor initialization code.\r
+               /// </summary>\r
+               void Initialize(int recordSize)\r
+               {\r
+                       this.rootPath   = null;\r
+                       this.pathPrefix = null;\r
+                       \r
+//                     this.tempPath   = System.getProperty( "user.dir" );\r
+                       \r
+                       this.userId    = 0;\r
+                       this.userName  = String.Empty;\r
+                       this.groupId   = 0;\r
+                       this.groupName = String.Empty;\r
+                       \r
+                       this.debug           = false;\r
+                       this.verbose         = false;\r
+                       this.keepOldFiles    = false;\r
+                       \r
+                       this.recordBuf = new byte[RecordSize];\r
+               }\r
+               \r
+               /**\r
+               * Set the debugging flag.\r
+               *\r
+               * @param debugF The new debug setting.\r
+               */\r
+               public void SetDebug(bool debugF)\r
+               {\r
+                       this.debug = debugF;\r
+                       if (this.tarIn != null) {\r
+                               this.tarIn.SetDebug(debugF);\r
+                       } \r
+                       if (this.tarOut != null) {\r
+                               this.tarOut.SetDebug(debugF);\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get/Set the verbosity setting.\r
+               /// </summary>\r
+               public bool IsVerbose {\r
+                       get {\r
+                               return verbose;\r
+                       }\r
+                       set {\r
+                               verbose = value;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Set the flag that determines whether existing files are\r
+               /// kept, or overwritten during extraction.\r
+               /// </summary>\r
+               /// <param name="keepOldFiles">\r
+               /// If true, do not overwrite existing files.\r
+               /// </param>\r
+               public void SetKeepOldFiles(bool keepOldFiles)\r
+               {\r
+                       this.keepOldFiles = keepOldFiles;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Set the ascii file translation flag. If ascii file translatio\r
+               /// is true, then the MIME file type will be consulted to determine\r
+               /// if the file is of type 'text/*'. If the MIME type is not found,\r
+               /// then the TransFileTyper is consulted if it is not null. If\r
+               /// either of these two checks indicates the file is an ascii text\r
+               /// file, it will be translated. The translation converts the local\r
+               /// operating system's concept of line ends into the UNIX line end,\r
+               /// '\n', which is the defacto standard for a TAR archive. This makes\r
+               /// text files compatible with UNIX, and since most tar implementations\r
+               /// text files compatible with UNIX, and since most tar implementations\r
+               /// </summary>\r
+               /// <param name= "asciiTranslate">\r
+               /// If true, translate ascii text files.\r
+               /// </param>\r
+               public void SetAsciiTranslation(bool asciiTranslate)\r
+               {\r
+                       this.asciiTranslate = asciiTranslate;\r
+               }\r
+               \r
+               /*\r
+               /// <summary>\r
+               /// Set the object that will determine if a file is of type\r
+               /// ascii text for translation purposes.\r
+               /// </summary>\r
+               /// <param name="transTyper">\r
+               /// The new TransFileTyper object.\r
+               /// </param>\r
+               public void SetTransFileTyper(TarTransFileTyper transTyper)\r
+               {\r
+                       this.transTyper = transTyper;\r
+               }*/\r
+               \r
+               /// <summary>\r
+               /// Set user and group information that will be used to fill in the\r
+               /// tar archive's entry headers. Since Java currently provides no means\r
+               /// of determining a user name, user id, group name, or group id for\r
+               /// a given File, TarArchive allows the programmer to specify values\r
+               /// to be used in their place.\r
+               /// </summary>\r
+               /// <param name="userId">\r
+               /// The user Id to use in the headers.\r
+               /// </param>\r
+               /// <param name="userName">\r
+               /// The user name to use in the headers.\r
+               /// </param>\r
+               /// <param name="groupId">\r
+               /// The group id to use in the headers.\r
+               /// </param>\r
+               /// <param name="groupName">\r
+               /// The group name to use in the headers.\r
+               /// </param>\r
+               public void SetUserInfo(int userId, string userName, int groupId, string groupName)\r
+               {\r
+                       this.userId    = userId;\r
+                       this.userName  = userName;\r
+                       this.groupId   = groupId;\r
+                       this.groupName = groupName;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get the user id being used for archive entry headers.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// The current user id.\r
+               /// </returns>\r
+               public int UserId {\r
+                       get {\r
+                               return this.userId;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get the user name being used for archive entry headers.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// The current user name.\r
+               /// </returns>\r
+               public string UserName {\r
+                       get {\r
+                               return this.userName;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get the group id being used for archive entry headers.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// The current group id.\r
+               /// </returns>\r
+               public int GroupId {\r
+                       get {\r
+                               return this.groupId;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get the group name being used for archive entry headers.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// The current group name.\r
+               /// </returns>\r
+               public string GroupName {\r
+                       get {\r
+                               return this.groupName;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get the archive's record size. Because of its history, tar\r
+               /// supports the concept of buffered IO consisting of BLOCKS of\r
+               /// RECORDS. This allowed tar to match the IO characteristics of\r
+               /// the physical device being used. Of course, in the Java world,\r
+               /// this makes no sense, WITH ONE EXCEPTION - archives are expected\r
+               /// to be propertly "blocked". Thus, all of the horrible TarBuffer\r
+               /// support boils down to simply getting the "boundaries" correct.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// The record size this archive is using.\r
+               /// </returns>\r
+               public int RecordSize {\r
+                       get {\r
+                               if (this.tarIn != null) {\r
+                                       return this.tarIn.GetRecordSize();\r
+                               } else if (this.tarOut != null) {\r
+                                       return this.tarOut.GetRecordSize();\r
+                               }\r
+                               return TarBuffer.DEFAULT_RCDSIZE;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Close the archive. This simply calls the underlying\r
+               /// tar stream's close() method.\r
+               /// </summary>\r
+               public void CloseArchive()\r
+               {\r
+                       if (this.tarIn != null) {\r
+                               this.tarIn.Close();\r
+                       } else if (this.tarOut != null) {\r
+                               this.tarOut.Flush();\r
+                               this.tarOut.Close();\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Perform the "list" command and list the contents of the archive.\r
+               /// \r
+               /// NOTE That this method uses the progress display to actually list\r
+               /// the conents. If the progress display is not set, nothing will be\r
+               /// listed!\r
+               /// </summary>\r
+               public void ListContents()\r
+               {\r
+                       while (true) {\r
+                               TarEntry entry = this.tarIn.GetNextEntry();\r
+                               \r
+                               if (entry == null) {\r
+                                       if (this.debug) {\r
+                                               Console.Error.WriteLine("READ EOF RECORD");\r
+                                       }\r
+                                       break;\r
+                               }\r
+                               OnProgressMessageEvent(entry.Name);\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Perform the "extract" command and extract the contents of the archive.\r
+               /// </summary>\r
+               /// <param name="destDir">\r
+               /// The destination directory into which to extract.\r
+               /// </param>\r
+               public void ExtractContents(string destDir)\r
+               {\r
+                       while (true) {\r
+                               TarEntry entry = this.tarIn.GetNextEntry();\r
+                               \r
+                               if (entry == null) {\r
+                                       if (this.debug) {\r
+                                               Console.Error.WriteLine("READ EOF RECORD");\r
+                                       }\r
+                                       break;\r
+                               }\r
+                               \r
+                               this.ExtractEntry(destDir, entry);\r
+                       }\r
+               }\r
+               \r
+               void EnsureDirectoryExists(string directoryName)\r
+               {\r
+                       if (!Directory.Exists(directoryName)) {\r
+                               try {\r
+                                       Directory.CreateDirectory(directoryName);\r
+                               } catch (Exception e) {\r
+                                       throw new IOException("error making directory path '" + directoryName + "', " + e.Message);\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               \r
+               bool IsBinary(string filename)\r
+               {\r
+                       FileStream fs = File.OpenRead(filename);\r
+                       \r
+                       byte[] content = new byte[fs.Length];\r
+                       \r
+                       fs.Read(content, 0, (int)fs.Length);\r
+                       fs.Close();\r
+                       \r
+                       // assume that ascii 0 or \r
+                       // ascii 255 are only found in non text files.\r
+                       // and that all non text files contain 0 and 255\r
+                       foreach (byte b in content) {\r
+                               if (b == 0 || b == 255) {\r
+                                       return true;\r
+                               }\r
+                       }\r
+                       \r
+                       return false;\r
+               }               \r
+               \r
+               /// <summary>\r
+               /// Extract an entry from the archive. This method assumes that the\r
+               /// tarIn stream has been properly set with a call to getNextEntry().\r
+               /// </summary>\r
+               /// <param name="destDir">\r
+               /// The destination directory into which to extract.\r
+               /// </param>\r
+               /// <param name="entry">\r
+               /// The TarEntry returned by tarIn.getNextEntry().\r
+               /// </param>\r
+               void ExtractEntry(string destDir, TarEntry entry)\r
+               {\r
+                       if (this.verbose) {\r
+                               OnProgressMessageEvent(entry.Name);\r
+                       }\r
+                       \r
+                       string name = entry.Name;\r
+                       name = name.Replace('/', Path.DirectorySeparatorChar);\r
+                       \r
+                       if (!destDir.EndsWith(Path.DirectorySeparatorChar.ToString())) {\r
+                               destDir += Path.DirectorySeparatorChar;\r
+                       }\r
+                       \r
+                       string destFile = destDir + name;\r
+                       \r
+                       if (entry.IsDirectory) {\r
+                               EnsureDirectoryExists(destFile);\r
+                       } else {\r
+                               string parentDirectory = Path.GetDirectoryName(destFile);\r
+                               EnsureDirectoryExists(parentDirectory);\r
+                               \r
+                               if (this.keepOldFiles && File.Exists(destFile)) {\r
+                                       if (this.verbose) {\r
+                                               OnProgressMessageEvent("not overwriting " + entry.Name);\r
+                                       }\r
+                               } else {\r
+                                       bool asciiTrans = false;\r
+                                       Stream outputStream = File.Create(destFile);\r
+                                       if (this.asciiTranslate) {\r
+                                               asciiTrans = !IsBinary(destFile);\r
+// original java sourcecode : \r
+//                                             MimeType mime      = null;\r
+//                                             string contentType = null;\r
+//                                             try {\r
+//                                                     contentType = FileTypeMap.getDefaultFileTypeMap().getContentType( destFile );\r
+//                                                     \r
+//                                                     mime = new MimeType(contentType);\r
+//                                                     \r
+//                                                     if (mime.getPrimaryType().equalsIgnoreCase( "text" )) {\r
+//                                                             asciiTrans = true;\r
+//                                                     } else if ( this.transTyper != null ) {\r
+//                                                         if ( this.transTyper.isAsciiFile( entry.getName() ) ) {\r
+//                                                             asciiTrans = true;\r
+//                                                         }\r
+//                                                     }\r
+//                                             } catch (MimeTypeParseException ex) {\r
+//                                             }\r
+//                                             \r
+//                                             if (this.debug) {\r
+//                                                     Console.Error.WriteLine(("EXTRACT TRANS? '" + asciiTrans + "'  ContentType='" + contentType + "'  PrimaryType='" + mime.getPrimaryType() + "'" );\r
+//                                             }\r
+                                       }\r
+                                       \r
+                                       StreamWriter outw = null;\r
+                                       if (asciiTrans) {\r
+                                               outw = new StreamWriter(outputStream);\r
+                                       }\r
+                                       \r
+                                       byte[] rdbuf = new byte[32 * 1024];\r
+                                       \r
+                                       while (true) {\r
+                                               int numRead = this.tarIn.Read(rdbuf, 0, rdbuf.Length);\r
+                                               \r
+                                               if (numRead <= 0) {\r
+                                                       break;\r
+                                               }\r
+                                               \r
+                                               if (asciiTrans) {\r
+                                                       for (int off = 0, b = 0; b < numRead; ++b) {\r
+                                                               if (rdbuf[b] == 10) {\r
+                                                                       string s = Encoding.ASCII.GetString(rdbuf, off, (b - off));\r
+                                                                       outw.WriteLine(s);\r
+                                                                       off = b + 1;\r
+                                                               }\r
+                                                       }\r
+                                               } else {\r
+                                                       outputStream.Write(rdbuf, 0, numRead);\r
+                                               }\r
+                                       }\r
+                                       \r
+                                       if (asciiTrans) {\r
+                                               outw.Close();\r
+                                       } else {\r
+                                               outputStream.Close();\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Write an entry to the archive. This method will call the putNextEntry\r
+               /// and then write the contents of the entry, and finally call closeEntry()()\r
+               /// for entries that are files. For directories, it will call putNextEntry(),\r
+               /// and then, if the recurse flag is true, process each entry that is a\r
+               /// child of the directory.\r
+               /// </summary>\r
+               /// <param name="entry">\r
+               /// The TarEntry representing the entry to write to the archive.\r
+               /// </param>\r
+               /// <param name="recurse">\r
+               /// If true, process the children of directory entries.\r
+               /// </param>\r
+               public void WriteEntry(TarEntry entry, bool recurse)\r
+               {\r
+                       bool asciiTrans = false;\r
+                       \r
+                       string tempFileName = null;\r
+                       string eFile        = entry.File;\r
+                       \r
+                       // Work on a copy of the entry so we can manipulate it.\r
+                       // Note that we must distinguish how the entry was constructed.\r
+                       //\r
+                       if (eFile == null || eFile.Length == 0) {\r
+                               entry = TarEntry.CreateTarEntry(entry.Name);\r
+                       } else {\r
+                               //\r
+                               // The user may have explicitly set the entry's name to\r
+                               // something other than the file's path, so we must save\r
+                               // and restore it. This should work even when the name\r
+                               // was set from the File's name.\r
+                               //\r
+                               string saveName = entry.Name;\r
+                               entry = TarEntry.CreateEntryFromFile(eFile);\r
+                               entry.Name = saveName;\r
+                       }\r
+                       \r
+                       if (this.verbose) {\r
+                               OnProgressMessageEvent(entry.Name);\r
+                       }\r
+                       \r
+                       if (this.asciiTranslate && !entry.IsDirectory) {\r
+                               asciiTrans = !IsBinary(eFile);\r
+// original java source :\r
+//                             MimeType mime = null;\r
+//                             string contentType = null;\r
+//     \r
+//                             try {\r
+//                                     contentType = FileTypeMap.getDefaultFileTypeMap(). getContentType( eFile );\r
+//                                     \r
+//                                     mime = new MimeType( contentType );\r
+//                                     \r
+//                                     if ( mime.getPrimaryType().\r
+//                                         equalsIgnoreCase( "text" ) )\r
+//                                         {\r
+//                                             asciiTrans = true;\r
+//                                         }\r
+//                                         else if ( this.transTyper != null )\r
+//                                         {\r
+//                                             if ( this.transTyper.isAsciiFile( eFile ) )\r
+//                                             {\r
+//                                                     asciiTrans = true;\r
+//                                             }\r
+//                                         }\r
+//                             } catch ( MimeTypeParseException ex )\r
+//                             {\r
+//     //                               IGNORE THIS ERROR...\r
+//                             }\r
+//                     \r
+//                     if (this.debug) {\r
+//                             Console.Error.WriteLine("CREATE TRANS? '" + asciiTrans + "'  ContentType='" + contentType + "'  PrimaryType='" + mime.getPrimaryType()+ "'" );\r
+//                     }\r
+                       \r
+                       if (asciiTrans) {\r
+                               tempFileName = Path.GetTempFileName();\r
+                               \r
+                               StreamReader inStream  = File.OpenText(eFile);\r
+                               Stream       outStream = new BufferedStream(File.Create(tempFileName));\r
+                               \r
+                               while (true) {\r
+                                       string line = inStream.ReadLine();\r
+                                       if (line == null) {\r
+                                               break;\r
+                                       }\r
+                                       byte[] data = Encoding.ASCII.GetBytes(line);\r
+                                       outStream.Write(data, 0, data.Length);\r
+                                       outStream.WriteByte((byte)'\n');\r
+                               }\r
+                               \r
+                               inStream.Close();\r
+                               outStream.Flush();\r
+                               outStream.Close();\r
+                               \r
+                               entry.Size = new FileInfo(tempFileName).Length;\r
+                               \r
+                               eFile = tempFileName;\r
+                       }\r
+                       }\r
+                   \r
+                   string newName = null;\r
+               \r
+                       if (this.rootPath != null) {\r
+                               if (entry.Name.StartsWith(this.rootPath)) {\r
+                                       newName = entry.Name.Substring(this.rootPath.Length + 1 );\r
+                               }\r
+                       }\r
+                       \r
+                       if (this.pathPrefix != null) {\r
+                               newName = (newName == null) ? this.pathPrefix + "/" + entry.Name : this.pathPrefix + "/" + newName;\r
+                       }\r
+                       \r
+                       if (newName != null) {\r
+                               entry.Name = newName;\r
+                       }\r
+                       \r
+                       this.tarOut.PutNextEntry(entry);\r
+                       \r
+                       if (entry.IsDirectory) {\r
+                               if (recurse) {\r
+                                       TarEntry[] list = entry.GetDirectoryEntries();\r
+                                       for (int i = 0; i < list.Length; ++i) {\r
+                                               this.WriteEntry(list[i], recurse);\r
+                                       }\r
+                               }\r
+                       } else {\r
+                               Stream inputStream = File.OpenRead(eFile);\r
+                               int numWritten = 0;\r
+                               byte[] eBuf = new byte[32 * 1024];\r
+                               while (true) {\r
+                                       int numRead = inputStream.Read(eBuf, 0, eBuf.Length);\r
+                                       \r
+                                       if (numRead <=0) {\r
+                                               break;\r
+                                       }\r
+                                       \r
+                                       this.tarOut.Write(eBuf, 0, numRead);\r
+                                       numWritten +=  numRead;\r
+                               }\r
+                               Console.WriteLine("written " + numWritten + " bytes");\r
+                               \r
+                               inputStream.Close();\r
+                               \r
+                               if (tempFileName != null && tempFileName.Length > 0) {\r
+                                       File.Delete(tempFileName);\r
+                               }\r
+                               \r
+                               this.tarOut.CloseEntry();\r
+                       }\r
+               }\r
+       }\r
+}\r
+/* The original Java file had this header:\r
+       ** Authored by Timothy Gerard Endres\r
+       ** <mailto:time@gjt.org>  <http://www.trustice.com>\r
+       **\r
+       ** This work has been placed into the public domain.\r
+       ** You may use this work in any way and for any purpose you wish.\r
+       **\r
+       ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,\r
+       ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR\r
+       ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY\r
+       ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR\r
+       ** REDISTRIBUTION OF THIS SOFTWARE.\r
+       **\r
+       */\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarBuffer.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarBuffer.cs
new file mode 100644 (file)
index 0000000..834c72c
--- /dev/null
@@ -0,0 +1,437 @@
+// TarBuffer.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+//\r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.IO;\r
+using System.Text;\r
+\r
+namespace ICSharpCode.SharpZipLib.Tar {\r
+       \r
+       /// <summary>\r
+       /// The TarBuffer class implements the tar archive concept\r
+       /// of a buffered input stream. This concept goes back to the\r
+       /// days of blocked tape drives and special io devices. In the\r
+       /// C# universe, the only real function that this class\r
+       /// performs is to ensure that files have the correct "block"\r
+       /// size, or other tars will complain.\r
+       /// <p>\r
+       /// You should never have a need to access this class directly.\r
+       /// TarBuffers are created by Tar IO Streams.\r
+       /// </p>\r
+       /// </summary>\r
+       public class TarBuffer\r
+       {\r
+               public static readonly int DEFAULT_RCDSIZE = 512;\r
+               public static readonly int DEFAULT_BLKSIZE = DEFAULT_RCDSIZE * 20;\r
+               \r
+               Stream inputStream;\r
+               Stream outputStream;\r
+               \r
+               byte[] blockBuffer;\r
+               int    currBlkIdx;\r
+               int    currRecIdx;\r
+               int    blockSize;\r
+               int    recordSize;\r
+               int    recsPerBlock;\r
+               \r
+               bool   debug;\r
+               \r
+               protected TarBuffer()\r
+               {\r
+               }\r
+               \r
+               public static TarBuffer CreateInputTarBuffer(Stream inputStream)\r
+               {\r
+                       return CreateInputTarBuffer(inputStream, TarBuffer.DEFAULT_BLKSIZE);\r
+               }\r
+               public static TarBuffer CreateInputTarBuffer(Stream inputStream, int blockSize )\r
+               {\r
+                       return CreateInputTarBuffer(inputStream, blockSize, TarBuffer.DEFAULT_RCDSIZE);\r
+               }\r
+               public static TarBuffer CreateInputTarBuffer(Stream inputStream, int blockSize, int recordSize)\r
+               {\r
+                       TarBuffer tarBuffer = new TarBuffer();\r
+                       tarBuffer.inputStream  = inputStream;\r
+                       tarBuffer.outputStream = null;\r
+                       tarBuffer.Initialize(blockSize, recordSize);\r
+                       \r
+                       return tarBuffer;\r
+               }\r
+\r
+               public static TarBuffer CreateOutputTarBuffer(Stream outputStream)\r
+               {\r
+                       return CreateOutputTarBuffer(outputStream, TarBuffer.DEFAULT_BLKSIZE);\r
+               }\r
+               public static TarBuffer CreateOutputTarBuffer(Stream outputStream, int blockSize )\r
+               {\r
+                       return CreateOutputTarBuffer(outputStream, blockSize, TarBuffer.DEFAULT_RCDSIZE);\r
+               }\r
+               public static TarBuffer CreateOutputTarBuffer(Stream outputStream, int blockSize, int recordSize)\r
+               {\r
+                       TarBuffer tarBuffer = new TarBuffer();\r
+                       tarBuffer.inputStream  = null;\r
+                       tarBuffer.outputStream = outputStream;\r
+                       tarBuffer.Initialize(blockSize, recordSize);\r
+                       \r
+                       return tarBuffer;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Initialization common to all constructors.\r
+               /// </summary>\r
+               void Initialize(int blockSize, int recordSize)\r
+               {\r
+                       this.debug        = false;\r
+                       this.blockSize    = blockSize;\r
+                       this.recordSize   = recordSize;\r
+                       this.recsPerBlock = this.blockSize / this.recordSize;\r
+                       this.blockBuffer  = new byte[this.blockSize];\r
+                       \r
+                       if (inputStream != null) {\r
+                               this.currBlkIdx = -1;\r
+                               this.currRecIdx = this.recsPerBlock;\r
+                       } else {\r
+                               this.currBlkIdx = 0;\r
+                               this.currRecIdx = 0;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get the TAR Buffer's block size. Blocks consist of multiple records.\r
+               /// </summary>\r
+               public int GetBlockSize()\r
+               {\r
+                       return this.blockSize;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get the TAR Buffer's record size.\r
+               /// </summary>\r
+               public int GetRecordSize()\r
+               {\r
+                       return this.recordSize;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Set the debugging flag for the buffer.\r
+               /// </summary>\r
+               public void SetDebug(bool debug)\r
+               {\r
+                       this.debug = debug;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Determine if an archive record indicate End of Archive. End of\r
+               /// archive is indicated by a record that consists entirely of null bytes.\r
+               /// </summary>\r
+               /// <param name = "record">\r
+               /// The record data to check.\r
+               /// </param>\r
+               public bool IsEOFRecord(byte[] record)\r
+               {\r
+                       for (int i = 0, sz = this.GetRecordSize(); i < sz; ++i) {\r
+                               if (record[i] != 0) {\r
+                                       return false;\r
+                               }\r
+                       }\r
+                       \r
+                       return true;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Skip over a record on the input stream.\r
+               /// </summary>\r
+               public void SkipRecord()\r
+               {\r
+                       if (this.debug) {\r
+                               Console.Error.WriteLine("SkipRecord: recIdx = " + this.currRecIdx + " blkIdx = " + this.currBlkIdx);\r
+                       }\r
+                       \r
+                       if (this.inputStream == null) {\r
+                               throw new System.IO.IOException("no input stream defined");\r
+                       }\r
+                       \r
+                       if (this.currRecIdx >= this.recsPerBlock) {\r
+                               if (!this.ReadBlock()) {\r
+                                       return; // UNDONE\r
+                               }\r
+                       }\r
+                       \r
+                       this.currRecIdx++;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Read a record from the input stream and return the data.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// The record data.\r
+               /// </returns>\r
+               public byte[] ReadRecord()\r
+               {\r
+                       if (this.debug) {\r
+                               Console.Error.WriteLine( "ReadRecord: recIdx = " + this.currRecIdx + " blkIdx = " + this.currBlkIdx );\r
+                       }\r
+                       \r
+                       if (this.inputStream == null) {\r
+                               throw new System.IO.IOException("no input stream defined");\r
+                       }\r
+                       \r
+                       if (this.currRecIdx >= this.recsPerBlock) {\r
+                               if (!this.ReadBlock()) {\r
+                                       return null;\r
+                               }\r
+                       }\r
+                       \r
+                       byte[] result = new byte[this.recordSize];\r
+                       \r
+                       Array.Copy(this.blockBuffer, (this.currRecIdx * this.recordSize), result, 0, this.recordSize );\r
+                       this.currRecIdx++;\r
+                       return result;\r
+               }\r
+               \r
+               /// <returns>\r
+               /// false if End-Of-File, else true\r
+               /// </returns>\r
+               bool ReadBlock()\r
+               {\r
+                       Console.WriteLine(this.debug);\r
+                       if (this.debug) {\r
+                               Console.Error.WriteLine("ReadBlock: blkIdx = " + this.currBlkIdx);\r
+                       }\r
+                       \r
+                       if (this.inputStream == null) {\r
+                               throw new System.IO.IOException("no input stream stream defined");\r
+                       }\r
+                                               \r
+                       this.currRecIdx = 0;\r
+                       \r
+                       int offset = 0;\r
+                       int bytesNeeded = this.blockSize;\r
+                       for (; bytesNeeded > 0 ;) {\r
+                               long numBytes = this.inputStream.Read(this.blockBuffer, offset, bytesNeeded);\r
+                               \r
+                               //\r
+                               // NOTE\r
+                               // We have fit EOF, and the block is not full!\r
+                               //\r
+                               // This is a broken archive. It does not follow the standard\r
+                               // blocking algorithm. However, because we are generous, and\r
+                               // it requires little effort, we will simply ignore the error\r
+                               // and continue as if the entire block were read. This does\r
+                               // not appear to break anything upstream. We used to return\r
+                               // false in this case.\r
+                               //\r
+                               // Thanks to 'Yohann.Roussel@alcatel.fr' for this fix.\r
+                               //\r
+                               if (numBytes <= 0) {\r
+                                       break;\r
+                               }\r
+                               \r
+                               offset      += (int)numBytes;\r
+                               bytesNeeded -= (int)numBytes;\r
+                               if (numBytes != this.blockSize) {\r
+                                       if (this.debug) {\r
+                                               Console.Error.WriteLine("ReadBlock: INCOMPLETE READ " + numBytes + " of " + this.blockSize + " bytes read.");\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       this.currBlkIdx++;\r
+                       return true;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get the current block number, zero based.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// The current zero based block number.\r
+               /// </returns>\r
+               public int GetCurrentBlockNum()\r
+               {\r
+                       return this.currBlkIdx;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get the current record number, within the current block, zero based.\r
+               /// Thus, current offset = (currentBlockNum * recsPerBlk) + currentRecNum.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// The current zero based record number.\r
+               /// </returns>\r
+               public int GetCurrentRecordNum()\r
+               {\r
+                       return this.currRecIdx - 1;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Write an archive record to the archive.\r
+               /// </summary>\r
+               /// <param name="record">\r
+               /// The record data to write to the archive.\r
+               /// </param>\r
+               /// \r
+               public void WriteRecord(byte[] record)\r
+               {\r
+                       if (this.debug) {\r
+                               Console.Error.WriteLine("WriteRecord: recIdx = " + this.currRecIdx + " blkIdx = " + this.currBlkIdx );\r
+                       }\r
+                       \r
+                       if (this.outputStream == null) {\r
+                               throw new System.IO.IOException("no output stream defined");\r
+                       }\r
+                                               \r
+                       if (record.Length != this.recordSize) {\r
+                               throw new IOException("record to write has length '" + record.Length + "' which is not the record size of '" + this.recordSize + "'" );\r
+                       }\r
+                       \r
+                       if (this.currRecIdx >= this.recsPerBlock) {\r
+                               this.WriteBlock();\r
+                       }\r
+                       Array.Copy(record, 0, this.blockBuffer, (this.currRecIdx * this.recordSize), this.recordSize );\r
+                       this.currRecIdx++;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Write an archive record to the archive, where the record may be\r
+               /// inside of a larger array buffer. The buffer must be "offset plus\r
+               /// record size" long.\r
+               /// </summary>\r
+               /// <param name="buf">\r
+               /// The buffer containing the record data to write.\r
+               /// </param>\r
+               /// <param name="offset">\r
+               /// The offset of the record data within buf.\r
+               /// </param>\r
+               public void WriteRecord(byte[] buf, int offset)\r
+               {\r
+                       if (this.debug) {\r
+                               Console.Error.WriteLine("WriteRecord: recIdx = " + this.currRecIdx + " blkIdx = " + this.currBlkIdx );\r
+                       }\r
+                       \r
+                       if (this.outputStream == null) {\r
+                               throw new System.IO.IOException("no output stream stream defined");\r
+                       }\r
+                                               \r
+                       if ((offset + this.recordSize) > buf.Length) {\r
+                               throw new IOException("record has length '" + buf.Length + "' with offset '" + offset + "' which is less than the record size of '" + this.recordSize + "'" );\r
+                       }\r
+                       \r
+                       if (this.currRecIdx >= this.recsPerBlock) {\r
+                               this.WriteBlock();\r
+                       }\r
+                       \r
+                       Array.Copy(buf, offset, this.blockBuffer, (this.currRecIdx * this.recordSize), this.recordSize );\r
+                       \r
+                       this.currRecIdx++;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Write a TarBuffer block to the archive.\r
+               /// </summary>\r
+               void WriteBlock()\r
+               {\r
+                       if (this.debug) {\r
+                               Console.Error.WriteLine("WriteBlock: blkIdx = " + this.currBlkIdx);\r
+                       }\r
+                       \r
+                       if (this.outputStream == null) {\r
+                               throw new System.IO.IOException("no output stream defined");\r
+                       }\r
+                       \r
+                       this.outputStream.Write(this.blockBuffer, 0, this.blockSize);\r
+                       this.outputStream.Flush();\r
+                       \r
+                       this.currRecIdx = 0;\r
+                       this.currBlkIdx++;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Flush the current data block if it has any data in it.\r
+               /// </summary>\r
+               void Flush()\r
+               {\r
+                       if (this.debug) {\r
+                               Console.Error.WriteLine("TarBuffer.FlushBlock() called.");\r
+                       }\r
+                       \r
+                       if (this.outputStream == null) {\r
+                               throw new System.IO.IOException("no output base stream defined");\r
+                       }\r
+                       \r
+                       if (this.currRecIdx > 0) {\r
+                               this.WriteBlock();\r
+                       }\r
+                       outputStream.Flush();\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Close the TarBuffer. If this is an output buffer, also flush the\r
+               /// current block before closing.\r
+               /// </summary>\r
+               public void Close()\r
+               {\r
+                       if (this.debug) {\r
+                               Console.Error.WriteLine("TarBuffer.Close().");\r
+                       }\r
+                       \r
+                       if (outputStream != null ) {\r
+                               Flush();\r
+       \r
+//                             if ( this.outStream != System.out\r
+//                                             && this.outStream != System.err ) {\r
+                               outputStream.Close();\r
+                               outputStream = null;\r
+                       } else if (inputStream != null) {\r
+//                             if (this.inStream != System.in ) {\r
+                               inputStream.Close();\r
+                               inputStream = null;\r
+                       }\r
+               }\r
+       }\r
+}\r
+/* The original Java file had this header:\r
+       *\r
+       ** Authored by Timothy Gerard Endres\r
+       ** <mailto:time@gjt.org>  <http://www.trustice.com>\r
+       **\r
+       ** This work has been placed into the public domain.\r
+       ** You may use this work in any way and for any purpose you wish.\r
+       **\r
+       ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,\r
+       ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR\r
+       ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY\r
+       ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR\r
+       ** REDISTRIBUTION OF THIS SOFTWARE.\r
+       **\r
+       */\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarEntry.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarEntry.cs
new file mode 100644 (file)
index 0000000..308aeb2
--- /dev/null
@@ -0,0 +1,672 @@
+// TarEntry.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.IO;\r
+using System.Text;\r
+\r
+namespace ICSharpCode.SharpZipLib.Tar {\r
+       \r
+       /// <summary>\r
+       /// This class represents an entry in a Tar archive. It consists\r
+       /// of the entry's header, as well as the entry's File. Entries\r
+       /// can be instantiated in one of three ways, depending on how\r
+       /// they are to be used.\r
+       /// <p>\r
+       /// TarEntries that are created from the header bytes read from\r
+       /// an archive are instantiated with the TarEntry( byte[] )\r
+       /// constructor. These entries will be used when extracting from\r
+       /// or listing the contents of an archive. These entries have their\r
+       /// header filled in using the header bytes. They also set the File\r
+       /// to null, since they reference an archive entry not a file.</p>\r
+       /// <p>\r
+       /// TarEntries that are created from Files that are to be written\r
+       /// into an archive are instantiated with the TarEntry( File )\r
+       /// constructor. These entries have their header filled in using\r
+       /// the File's information. They also keep a reference to the File\r
+       /// for convenience when writing entries.</p>\r
+       /// <p>\r
+       /// Finally, TarEntries can be constructed from nothing but a name.\r
+       /// This allows the programmer to construct the entry by hand, for\r
+       /// instance when only an InputStream is available for writing to\r
+       /// the archive, and the header information is constructed from\r
+       /// other information. In this case the header fields are set to\r
+       /// defaults and the File is set to null.</p>\r
+       /// \r
+       /// <p>\r
+       /// The C structure for a Tar Entry's header is:\r
+       /// <pre>\r
+       /// struct header {\r
+       ///     char    name[NAMSIZ];\r
+       ///     char    mode[8];\r
+       ///     char    uid[8];\r
+       ///     char    gid[8];\r
+       ///     char    size[12];\r
+       ///     char    mtime[12];\r
+       ///     char    chksum[8];\r
+       ///     char    linkflag;\r
+       ///     char    linkname[NAMSIZ];\r
+       ///     char    magic[8];\r
+       ///     char    uname[TUNMLEN];\r
+       ///     char    gname[TGNMLEN];\r
+       ///     char    devmajor[8];\r
+       ///     char    devminor[8];\r
+       ///     } header;\r
+       /// </pre>\r
+       /// </p>\r
+       /// <see cref="TarHeader"/>\r
+       /// </summary>\r
+       public class TarEntry\r
+       {\r
+               /// <summary>\r
+               /// If this entry represents a File, this references it.\r
+               /// </summary>\r
+               protected string    file;\r
+               \r
+               /// <summary>\r
+               /// This is the entry's header information.\r
+               /// </summary>\r
+               protected TarHeader     header;\r
+               \r
+               /// <summary>\r
+               /// Only Create Entries with the static CreateXYZ methods or a headerBuffer.\r
+               /// </summary>\r
+               private TarEntry()\r
+               {\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Construct an entry from an archive's header bytes. File is set\r
+               /// to null.\r
+               /// </summary>\r
+               /// <param name = "headerBuf">\r
+               /// The header bytes from a tar archive entry.\r
+               /// </param>\r
+               public TarEntry(byte[] headerBuf)\r
+               {\r
+                       this.Initialize();\r
+                       this.ParseTarHeader(this.header, headerBuf);\r
+               }\r
+               \r
+                               \r
+               \r
+               /// <summary>\r
+               /// Construct an entry with only a name. This allows the programmer\r
+               /// to construct the entry's header "by hand". File is set to null.\r
+               /// </summary>\r
+               public static TarEntry CreateTarEntry(string name)\r
+               {\r
+                       TarEntry entry = new TarEntry();\r
+                       entry.Initialize();\r
+                       entry.NameTarHeader(entry.header, name);\r
+                       return entry;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Construct an entry for a file. File is set to file, and the\r
+               /// header is constructed from information from the file.\r
+               /// </summary>\r
+               /// <param name = "fileName">\r
+               /// The file that the entry represents.\r
+               /// </param>\r
+               public static TarEntry CreateEntryFromFile(string fileName)\r
+               {\r
+                       TarEntry entry = new TarEntry();\r
+                       entry.Initialize();\r
+                       entry.GetFileTarHeader(entry.header, fileName);\r
+                       return entry;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Initialization code common to all constructors.\r
+               /// </summary>\r
+               void Initialize()\r
+               {\r
+                       this.file   = null;\r
+                       this.header = new TarHeader();\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Determine if the two entries are equal. Equality is determined\r
+               /// by the header names being equal.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// True if the entries are equal.\r
+               /// </returns>\r
+               public override bool Equals(object it)\r
+               {\r
+                       if (!(it is TarEntry)) {\r
+                               return false;\r
+                       }\r
+                       return this.header.name.ToString().Equals(((TarEntry)it).header.name.ToString());\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Must be overridden when you override Equals.\r
+               /// </summary>\r
+               public override int GetHashCode()\r
+               {\r
+                       return this.header.name.ToString().GetHashCode();\r
+               }\r
+               \r
+               \r
+               /// <summary>\r
+               /// Determine if the given entry is a descendant of this entry.\r
+               /// Descendancy is determined by the name of the descendant\r
+               /// starting with this entry's name.\r
+               /// </summary>\r
+               /// <param name = "desc">\r
+               /// Entry to be checked as a descendent of this.\r
+               /// </param>\r
+               /// <returns>\r
+               /// True if entry is a descendant of this.\r
+               /// </returns>\r
+               public bool IsDescendent(TarEntry desc)\r
+               {\r
+                       return desc.header.name.ToString().StartsWith(this.header.name.ToString());\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get this entry's header.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// This entry's TarHeader.\r
+               /// </returns>\r
+               public TarHeader TarHeader {\r
+                       get {\r
+                               return this.header;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get/Set this entry's name.\r
+               /// </summary>\r
+               public string Name {\r
+                       get {\r
+                               return this.header.name.ToString();\r
+                       }\r
+                       set {\r
+                               this.header.name = new StringBuilder(value);\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get/set this entry's user id.\r
+               /// </summary>\r
+               public int UserId {\r
+                       get {\r
+                               return this.header.userId;\r
+                       }\r
+                       set {\r
+                               this.header.userId = value;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get/set this entry's group id.\r
+               /// </summary>\r
+               public int GroupId {\r
+                       get {\r
+                               return this.header.groupId;\r
+                       }\r
+                       set {\r
+                               this.header.groupId = value;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get/set this entry's user name.\r
+               /// </summary>\r
+               public string UserName {\r
+                       get {\r
+                               return this.header.userName.ToString();\r
+                       }\r
+                       set {\r
+                               this.header.userName = new StringBuilder(value);\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get/set this entry's group name.\r
+               /// </summary>\r
+               public string GroupName {\r
+                       get {\r
+                               return this.header.groupName.ToString();\r
+                       }\r
+                       set {\r
+                               this.header.groupName = new StringBuilder(value);\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Convenience method to set this entry's group and user ids.\r
+               /// </summary>\r
+               /// <param name="userId">\r
+               /// This entry's new user id.\r
+               /// </param>\r
+               /// <param name="groupId">\r
+               /// This entry's new group id.\r
+               /// </param>\r
+               public void SetIds(int userId, int groupId)\r
+               {\r
+                       UserId  = userId; \r
+                       GroupId = groupId;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Convenience method to set this entry's group and user names.\r
+               /// </summary>\r
+               /// <param name="userName">\r
+               /// This entry's new user name.\r
+               /// </param>\r
+               /// <param name="groupName">\r
+               /// This entry's new group name.\r
+               /// </param>\r
+               public void SetNames(string userName, string groupName)\r
+               {\r
+                       UserName  = userName;\r
+                       GroupName = groupName;\r
+               }\r
+\r
+//     TODO :\r
+//             /**\r
+//             * Set this entry's modification time. The parameter passed\r
+//             * to this method is in "Java time".\r
+//             *\r
+//             * @param time This entry's new modification time.\r
+//             */\r
+//             public void setModTime( long time )\r
+//             {\r
+//                     this.header.modTime = time / 1000;\r
+//             }\r
+               \r
+               /// Convert time to DateTimes\r
+               /**\r
+               * Get/Set this entry's modification time.\r
+               *\r
+               * @param time This entry's new modification time.\r
+               */\r
+               public DateTime ModTime {\r
+                       get {\r
+                               return this.header.modTime;\r
+                       }\r
+                       set {\r
+                               this.header.modTime = value;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get this entry's file.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// This entry's file.\r
+               /// </returns>\r
+               public string File {\r
+                       get {\r
+                               return this.file;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get/set this entry's file size.\r
+               /// </summary>\r
+               public long Size {\r
+                       get {\r
+                               return this.header.size;\r
+                       }\r
+                       set {\r
+                               this.header.size = value;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Convenience method that will modify an entry's name directly\r
+               /// in place in an entry header buffer byte array.\r
+               /// </summary>\r
+               /// <param name="outbuf">\r
+               /// The buffer containing the entry header to modify.\r
+               /// </param>\r
+               /// <param name="newName">\r
+               /// The new name to place into the header buffer.\r
+               /// </param>\r
+               public void AdjustEntryName(byte[] outbuf, string newName)\r
+               {\r
+                       int offset = 0;\r
+                       offset = TarHeader.GetNameBytes(new StringBuilder(newName), outbuf, offset, TarHeader.NAMELEN);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Return whether or not this entry represents a directory.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// True if this entry is a directory.\r
+               /// </returns>\r
+               public bool IsDirectory\r
+               {\r
+                       get {\r
+                               if (this.file != null) {\r
+                                       return Directory.Exists(file);\r
+                               }\r
+                               \r
+                               if (this.header != null) {\r
+                                       if (this.header.linkFlag == TarHeader.LF_DIR || this.header.name.ToString().EndsWith( "/" )) {\r
+                                               return true;\r
+                                       }\r
+                               }\r
+                               return false;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Fill in a TarHeader with information from a File.\r
+               /// </summary>\r
+               /// <param name="hdr">\r
+               /// The TarHeader to fill in.\r
+               /// </param>\r
+               /// <param name="file">\r
+               /// The file from which to get the header information.\r
+               /// </param>\r
+               public void GetFileTarHeader(TarHeader hdr, string file)\r
+               {\r
+                       this.file = file;\r
+                       \r
+                       string name = Path.GetDirectoryName(file);\r
+                       \r
+                       if (Path.DirectorySeparatorChar == '\\') { // check if the OS is a windows\r
+                               // Strip off drive letters!\r
+                               if (name.Length > 2) {\r
+                                       char ch1 = name[0];\r
+                                       char ch2 = name[1];\r
+                                       \r
+                                       if (ch2 == ':' && Char.IsLetter(ch1)) {\r
+                                               name = name.Substring(2);\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       name = name.Replace(Path.DirectorySeparatorChar, '/');\r
+                       \r
+                       // No absolute pathnames\r
+                       // Windows (and Posix?) paths can start with "\\NetworkDrive\",\r
+                       // so we loop on starting /'s.\r
+                       while (name.StartsWith("/")) {\r
+                               name = name.Substring(1);\r
+                       }\r
+                       \r
+                       hdr.linkName = new StringBuilder(String.Empty);\r
+                       hdr.name     = new StringBuilder(name);\r
+                       \r
+                       if (Directory.Exists(file)) {\r
+                               hdr.mode     = 040755; // TODO : what does this magic number ?? Mike\r
+                               hdr.linkFlag = TarHeader.LF_DIR;\r
+                               if (hdr.name[hdr.name.Length - 1] != '/') {\r
+                                       hdr.name.Append("/");\r
+                               }\r
+                               hdr.size     = 0;\r
+                       } else {\r
+                               hdr.mode     = 0100644; // TODO : again a magic number\r
+                               hdr.linkFlag = TarHeader.LF_NORMAL;\r
+                               Console.WriteLine(file.Replace('/', Path.DirectorySeparatorChar));\r
+                               hdr.size     = new FileInfo(file.Replace('/', Path.DirectorySeparatorChar)).Length;\r
+                       }\r
+                       \r
+                       // UNDONE When File lets us get the userName, use it!\r
+                       hdr.modTime = System.IO.File.GetLastAccessTime(file.Replace('/', Path.DirectorySeparatorChar));\r
+                       hdr.checkSum = 0;\r
+                       hdr.devMajor = 0;\r
+                       hdr.devMinor = 0;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// If this entry represents a file, and the file is a directory, return\r
+               /// an array of TarEntries for this entry's children.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// An array of TarEntry's for this entry's children.\r
+               /// </returns>\r
+               public TarEntry[] GetDirectoryEntries()\r
+               {\r
+                       if (this.file == null || !Directory.Exists(this.file)) {\r
+                               return new TarEntry[0];\r
+                       }\r
+                       \r
+                       string[]   list   = Directory.GetFileSystemEntries(this.file);\r
+                       TarEntry[] result = new TarEntry[list.Length];\r
+                       \r
+                       string dirName = file;\r
+                       if (!dirName.EndsWith(Path.DirectorySeparatorChar.ToString())) {\r
+                               dirName += Path.DirectorySeparatorChar;\r
+                       }\r
+                       \r
+                       for (int i = 0; i < list.Length; ++i) {\r
+                               result[i] = TarEntry.CreateEntryFromFile(list[i]);\r
+                       }\r
+                       \r
+                       return result;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Compute the checksum of a tar entry header.\r
+               /// </summary>\r
+               /// <param name = "buf">\r
+               /// The tar entry's header buffer.\r
+               /// </param>\r
+               /// <returns>\r
+               /// The computed checksum.\r
+               /// </returns>\r
+               public long ComputeCheckSum(byte[] buf)\r
+               {\r
+                       long sum = 0;\r
+                       for (int i = 0; i < buf.Length; ++i) {\r
+                               sum += 255 & buf[i]; // TODO : I think the 255 & x isn't neccessary += buf[i] should be enough. CHECK IT!\r
+                       }\r
+                       return sum;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Write an entry's header information to a header buffer.\r
+               /// </summary>\r
+               /// <param name = "outbuf">\r
+               /// The tar entry header buffer to fill in.\r
+               /// </param>\r
+               public void WriteEntryHeader(byte[] outbuf)\r
+               {\r
+                       int offset = 0;\r
+                       \r
+                       offset = TarHeader.GetNameBytes(this.header.name, outbuf, offset, TarHeader.NAMELEN);\r
+                       offset = TarHeader.GetOctalBytes(this.header.mode, outbuf, offset, TarHeader.MODELEN);\r
+                       offset = TarHeader.GetOctalBytes(this.header.userId, outbuf, offset, TarHeader.UIDLEN);\r
+                       offset = TarHeader.GetOctalBytes(this.header.groupId, outbuf, offset, TarHeader.GIDLEN);\r
+                       \r
+                       long size = this.header.size;\r
+                       \r
+                       offset = TarHeader.GetLongOctalBytes(size, outbuf, offset, TarHeader.SIZELEN);\r
+                       offset = TarHeader.GetLongOctalBytes(GetCTime(this.header.modTime), outbuf, offset, TarHeader.MODTIMELEN);\r
+                       \r
+                       int csOffset = offset;\r
+                       for (int c = 0; c < TarHeader.CHKSUMLEN; ++c) {\r
+                               outbuf[offset++] = (byte)' ';\r
+                       }\r
+                       \r
+                       outbuf[offset++] = this.header.linkFlag;\r
+                       \r
+                       offset = TarHeader.GetNameBytes(this.header.linkName, outbuf, offset, TarHeader.NAMELEN);\r
+                       offset = TarHeader.GetNameBytes(this.header.magic, outbuf, offset, TarHeader.MAGICLEN);\r
+                       offset = TarHeader.GetNameBytes(this.header.userName, outbuf, offset, TarHeader.UNAMELEN);\r
+                       offset = TarHeader.GetNameBytes(this.header.groupName, outbuf, offset, TarHeader.GNAMELEN);\r
+                       \r
+                       offset = TarHeader.GetOctalBytes(this.header.devMajor, outbuf, offset, TarHeader.DEVLEN);\r
+                       offset = TarHeader.GetOctalBytes(this.header.devMinor, outbuf, offset, TarHeader.DEVLEN);\r
+                       \r
+                       for (; offset < outbuf.Length;) {\r
+                               outbuf[offset++] = 0;\r
+                       }\r
+                       \r
+                       long checkSum = this.ComputeCheckSum(outbuf);\r
+                       \r
+                       TarHeader.GetCheckSumOctalBytes(checkSum, outbuf, csOffset, TarHeader.CHKSUMLEN);\r
+               }\r
+               \r
+               // time conversion functions\r
+               readonly static long     timeConversionFactor = 10000000L;\r
+               readonly static DateTime datetTime1970        = new DateTime(1970, 1, 1, 0, 0, 0, 0);\r
+               \r
+               static int GetCTime(System.DateTime dateTime)\r
+               {\r
+                       return (int)((dateTime.Ticks - datetTime1970.Ticks) / timeConversionFactor);\r
+               }\r
+               \r
+               static DateTime GetDateTimeFromCTime(long ticks)\r
+               {\r
+                       return new DateTime(datetTime1970.Ticks + ticks * timeConversionFactor);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Parse an entry's TarHeader information from a header buffer.\r
+               /// </summary>\r
+               /// <param name ="hdr">\r
+               /// Parse an entry's TarHeader information from a header buffer.\r
+               /// </param>\r
+               /// <param name = "header">\r
+               /// The tar entry header buffer to get information from.\r
+               /// </param>\r
+               public void ParseTarHeader(TarHeader hdr, byte[] header)\r
+               {\r
+                       int offset = 0;\r
+                       \r
+                       hdr.name = TarHeader.ParseName(header, offset, TarHeader.NAMELEN);\r
+                       \r
+                       offset += TarHeader.NAMELEN;\r
+                       \r
+                       hdr.mode = (int)TarHeader.ParseOctal(header, offset, TarHeader.MODELEN);\r
+                       \r
+                       offset += TarHeader.MODELEN;\r
+                       \r
+                       hdr.userId = (int)TarHeader.ParseOctal(header, offset, TarHeader.UIDLEN);\r
+                       \r
+                       offset += TarHeader.UIDLEN;\r
+                       \r
+                       hdr.groupId = (int)TarHeader.ParseOctal(header, offset, TarHeader.GIDLEN);\r
+                       \r
+                       offset += TarHeader.GIDLEN;\r
+                       \r
+                       hdr.size = TarHeader.ParseOctal(header, offset, TarHeader.SIZELEN);\r
+                       \r
+                       offset += TarHeader.SIZELEN;\r
+                       \r
+                       hdr.modTime = GetDateTimeFromCTime(TarHeader.ParseOctal(header, offset, TarHeader.MODTIMELEN));\r
+                       \r
+                       offset += TarHeader.MODTIMELEN;\r
+                       \r
+                       hdr.checkSum = (int)TarHeader.ParseOctal(header, offset, TarHeader.CHKSUMLEN);\r
+                       \r
+                       offset += TarHeader.CHKSUMLEN;\r
+                       \r
+                       hdr.linkFlag = header[ offset++ ];\r
+                       \r
+                       hdr.linkName = TarHeader.ParseName(header, offset, TarHeader.NAMELEN);\r
+                       \r
+                       offset += TarHeader.NAMELEN;\r
+                       \r
+                       hdr.magic = TarHeader.ParseName(header, offset, TarHeader.MAGICLEN);\r
+                       \r
+                       offset += TarHeader.MAGICLEN;\r
+                       \r
+                       hdr.userName = TarHeader.ParseName(header, offset, TarHeader.UNAMELEN);\r
+                       \r
+                       offset += TarHeader.UNAMELEN;\r
+                       \r
+                       hdr.groupName = TarHeader.ParseName(header, offset, TarHeader.GNAMELEN);\r
+                       \r
+                       offset += TarHeader.GNAMELEN;\r
+                       \r
+                       hdr.devMajor = (int)TarHeader.ParseOctal(header, offset, TarHeader.DEVLEN);\r
+                       \r
+                       offset += TarHeader.DEVLEN;\r
+                       \r
+                       hdr.devMinor = (int)TarHeader.ParseOctal(header, offset, TarHeader.DEVLEN);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Fill in a TarHeader given only the entry's name.\r
+               /// </summary>\r
+               /// <param name="hdr">\r
+               /// The TarHeader to fill in.\r
+               /// </param>\r
+               /// <param name="name">\r
+               /// The tar entry name.\r
+               /// </param>\r
+               public void NameTarHeader(TarHeader hdr, string name)\r
+               {\r
+                       bool isDir = name.EndsWith("/");\r
+                       \r
+                       hdr.checkSum = 0;\r
+                       hdr.devMajor = 0;\r
+                       hdr.devMinor = 0;\r
+                       \r
+                       hdr.name = new StringBuilder(name);\r
+                       hdr.mode = isDir ? 040755 : 0100644; // TODO : I think I've seen these magics before ...\r
+                       hdr.userId   = 0;\r
+                       hdr.groupId  = 0;\r
+                       hdr.size     = 0;\r
+                       hdr.checkSum = 0;\r
+                       \r
+                       hdr.modTime  = DateTime.Now;//(new java.util.Date()).getTime() / 1000;\r
+                       \r
+                       hdr.linkFlag = isDir ? TarHeader.LF_DIR : TarHeader.LF_NORMAL;\r
+                       \r
+                       hdr.linkName  = new StringBuilder(String.Empty);\r
+                       hdr.userName  = new StringBuilder(String.Empty);\r
+                       hdr.groupName = new StringBuilder(String.Empty);\r
+                       \r
+                       hdr.devMajor = 0;\r
+                       hdr.devMinor = 0;\r
+               }\r
+       }\r
+}\r
+/* The original Java file had this header:\r
+       *\r
+       ** Authored by Timothy Gerard Endres\r
+       ** <mailto:time@gjt.org>  <http://www.trustice.com>\r
+       **\r
+       ** This work has been placed into the public domain.\r
+       ** You may use this work in any way and for any purpose you wish.\r
+       **\r
+       ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,\r
+       ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR\r
+       ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY\r
+       ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR\r
+       ** REDISTRIBUTION OF THIS SOFTWARE.\r
+       **\r
+       */\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarHeader.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarHeader.cs
new file mode 100644 (file)
index 0000000..a381ed0
--- /dev/null
@@ -0,0 +1,500 @@
+// TarHeader.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.Text;\r
+\r
+namespace ICSharpCode.SharpZipLib.Tar {\r
+       \r
+       \r
+       /// <summary>\r
+       /// This class encapsulates the Tar Entry Header used in Tar Archives.\r
+       /// The class also holds a number of tar constants, used mostly in headers.\r
+       /// </summary>\r
+       public class TarHeader : ICloneable\r
+       {\r
+               /// <summary>\r
+               /// The length of the name field in a header buffer.\r
+               /// </summary>\r
+               public readonly static int NAMELEN = 100;\r
+               \r
+               /// <summary>\r
+               /// The length of the mode field in a header buffer.\r
+               /// </summary>\r
+               public readonly static int MODELEN = 8;\r
+               \r
+               /// <summary>\r
+               /// The length of the user id field in a header buffer.\r
+               /// </summary>\r
+               public readonly static int UIDLEN = 8;\r
+               \r
+               /// <summary>\r
+               /// The length of the group id field in a header buffer.\r
+               /// </summary>\r
+               public readonly static int GIDLEN = 8;\r
+               \r
+               /// <summary>\r
+               /// The length of the checksum field in a header buffer.\r
+               /// </summary>\r
+               public readonly static int CHKSUMLEN = 8;\r
+               \r
+               /// <summary>\r
+               /// The length of the size field in a header buffer.\r
+               /// </summary>\r
+               public readonly static int SIZELEN = 12;\r
+               \r
+               /// <summary>\r
+               /// The length of the magic field in a header buffer.\r
+               /// </summary>\r
+               public readonly static int MAGICLEN = 8;\r
+               \r
+               /// <summary>\r
+               /// The length of the modification time field in a header buffer.\r
+               /// </summary>\r
+               public readonly static int MODTIMELEN = 12;\r
+               \r
+               /// <summary>\r
+               /// The length of the user name field in a header buffer.\r
+               /// </summary>\r
+               public readonly static int UNAMELEN = 32;\r
+               \r
+               /// <summary>\r
+               /// The length of the group name field in a header buffer.\r
+               /// </summary>\r
+               public readonly static int GNAMELEN = 32;\r
+               \r
+               /// <summary>\r
+               /// The length of the devices field in a header buffer.\r
+               /// </summary>\r
+               public readonly static int DEVLEN = 8;\r
+               \r
+               /// <summary>\r
+               /// LF_ constants represent the "link flag" of an entry, or more commonly,\r
+               /// the "entry type". This is the "old way" of indicating a normal file.\r
+               /// </summary>\r
+               public readonly static byte     LF_OLDNORM      = 0;\r
+               \r
+               /// <summary>\r
+               /// Normal file type.\r
+               /// </summary>\r
+               public readonly static byte     LF_NORMAL       = (byte) '0';\r
+               \r
+               /// <summary>\r
+               /// Link file type.\r
+               /// </summary>\r
+               public readonly static byte     LF_LINK         = (byte) '1';\r
+               \r
+               /// <summary>\r
+               /// Symbolic link file type.\r
+               /// </summary>\r
+               public readonly static byte     LF_SYMLINK      = (byte) '2';\r
+               \r
+               /// <summary>\r
+               /// Character device file type.\r
+               /// </summary>\r
+               public readonly static byte     LF_CHR          = (byte) '3';\r
+               \r
+               /// <summary>\r
+               /// Block device file type.\r
+               /// </summary>\r
+               public readonly static byte     LF_BLK          = (byte) '4';\r
+               \r
+               /// <summary>\r
+               /// Directory file type.\r
+               /// </summary>\r
+               public readonly static byte     LF_DIR          = (byte) '5';\r
+               \r
+               /// <summary>\r
+               /// FIFO (pipe) file type.\r
+               /// </summary>\r
+               public readonly static byte     LF_FIFO         = (byte) '6';\r
+               \r
+               /// <summary>\r
+               /// Contiguous file type.\r
+               /// </summary>\r
+               public readonly static byte     LF_CONTIG       = (byte) '7';\r
+               \r
+               /// <summary>\r
+               /// The magic tag representing a POSIX tar archive.\r
+               /// </summary>\r
+               public readonly static string   TMAGIC          = "ustar";\r
+               \r
+               /// <summary>\r
+               /// The magic tag representing a GNU tar archive.\r
+               /// </summary>\r
+               public readonly static string   GNU_TMAGIC      = "ustar  ";\r
+               \r
+               /// <summary>\r
+               /// The entry's name.\r
+               /// </summary>\r
+               public StringBuilder name;\r
+               \r
+               /// <summary>\r
+               /// The entry's permission mode.\r
+               /// </summary>\r
+               public int mode;\r
+               \r
+               /// <summary>\r
+               /// The entry's user id.\r
+               /// </summary>\r
+               public int userId;\r
+               \r
+               /// <summary>\r
+               /// The entry's group id.\r
+               /// </summary>\r
+               public int groupId;\r
+               \r
+               /// <summary>\r
+               /// The entry's size.\r
+               /// </summary>\r
+               public long size;\r
+               \r
+               /// <summary>\r
+               /// The entry's modification time.\r
+               /// </summary>\r
+               public DateTime modTime;\r
+               \r
+               /// <summary>\r
+               /// The entry's checksum.\r
+               /// </summary>\r
+               public int checkSum;\r
+               \r
+               /// <summary>\r
+               /// The entry's link flag.\r
+               /// </summary>\r
+               public byte linkFlag;\r
+               \r
+               /// <summary>\r
+               /// The entry's link name.\r
+               /// </summary>\r
+               public StringBuilder linkName;\r
+               \r
+               /// <summary>\r
+               /// The entry's magic tag.\r
+               /// </summary>\r
+               public StringBuilder magic;\r
+               \r
+               /// <summary>\r
+               /// The entry's user name.\r
+               /// </summary>\r
+               public StringBuilder userName;\r
+               \r
+               /// <summary>\r
+               /// The entry's group name.\r
+               /// </summary>\r
+               public StringBuilder groupName;\r
+               \r
+               /// <summary>\r
+               /// The entry's major device number.\r
+               /// </summary>\r
+               public int devMajor;\r
+               \r
+               /// <summary>\r
+               /// The entry's minor device number.\r
+               /// </summary>\r
+               public int devMinor;\r
+               \r
+               public TarHeader()\r
+               {\r
+                       this.magic = new StringBuilder(TarHeader.TMAGIC);\r
+                       \r
+                       this.name     = new StringBuilder();\r
+                       this.linkName = new StringBuilder();\r
+                       \r
+                       string user = Environment.UserName;\r
+                       \r
+                       if (user.Length > 31) {\r
+                               user = user.Substring(0, 31);\r
+                       }\r
+                       \r
+                       this.userId    = 0;\r
+                       this.groupId   = 0;\r
+                       this.userName  = new StringBuilder(user);\r
+                       this.groupName = new StringBuilder(String.Empty);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// TarHeaders can be cloned.\r
+               /// </summary>\r
+               public object Clone()\r
+               {\r
+                       TarHeader hdr = new TarHeader();\r
+                       \r
+                       hdr.name      = (this.name == null) ? null : new StringBuilder(this.name.ToString());\r
+                       hdr.mode      = this.mode;\r
+                       hdr.userId    = this.userId;\r
+                       hdr.groupId   = this.groupId;\r
+                       hdr.size      = this.size;\r
+                       hdr.modTime   = this.modTime;\r
+                       hdr.checkSum  = this.checkSum;\r
+                       hdr.linkFlag  = this.linkFlag;\r
+                       hdr.linkName  = (this.linkName == null)  ? null : new StringBuilder(this.linkName.ToString());\r
+                       hdr.magic     = (this.magic == null)     ? null : new StringBuilder(this.magic.ToString());\r
+                       hdr.userName  = (this.userName == null)  ? null : new StringBuilder(this.userName.ToString());\r
+                       hdr.groupName = (this.groupName == null) ? null : new StringBuilder(this.groupName.ToString());\r
+                       hdr.devMajor  = this.devMajor;\r
+                       hdr.devMinor  = this.devMinor;\r
+                       \r
+                       return hdr;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get the name of this entry.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// The entry's name.\r
+               /// </returns>\r
+               public string GetName()\r
+               {\r
+                       return this.name.ToString();\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Parse an octal string from a header buffer. This is used for the\r
+               /// file permission mode value.\r
+               /// </summary>\r
+               /// <param name = "header">\r
+               /// The header buffer from which to parse.\r
+               /// </param>\r
+               /// <param name = "offset">\r
+               /// The offset into the buffer from which to parse.\r
+               /// </param>\r
+               /// <param name = "length">\r
+               /// The number of header bytes to parse.\r
+               /// </param>\r
+               /// <returns>\r
+               /// The long value of the octal string.\r
+               /// </returns>\r
+               public static long ParseOctal(byte[] header, int offset, int length)\r
+               {\r
+                       long result = 0;\r
+                       bool stillPadding = true;\r
+                       \r
+                       int end = offset + length;\r
+                       for (int i = offset; i < end ; ++i) {\r
+                               if (header[i] == 0) {\r
+                                       break;\r
+                               }\r
+                               \r
+                               if (header[i] == (byte)' ' || header[i] == '0') {\r
+                                       if (stillPadding) {\r
+                                               continue;\r
+                                       }\r
+                                       \r
+                                       if (header[i] == (byte)' ') {\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               \r
+                               stillPadding = false;\r
+                               \r
+                               result = (result << 3) + (header[i] - '0');\r
+                       }\r
+                       \r
+                       return result;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Parse an entry name from a header buffer.\r
+               /// </summary>\r
+               /// <param name="header">\r
+               /// The header buffer from which to parse.\r
+               /// </param>\r
+               /// <param name="offset">\r
+               /// The offset into the buffer from which to parse.\r
+               /// </param>\r
+               /// <param name="length">\r
+               /// The number of header bytes to parse.\r
+               /// </param>\r
+               /// <returns>\r
+               /// The header's entry name.\r
+               /// </returns>\r
+               public static StringBuilder ParseName(byte[] header, int offset, int length)\r
+               {\r
+                       StringBuilder result = new StringBuilder(length);\r
+                       \r
+                       for (int i = offset; i < offset + length; ++i) {\r
+                               if (header[i] == 0) {\r
+                                       break;\r
+                               }\r
+                               result.Append((char)header[i]);\r
+                       }\r
+                       \r
+                       return result;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Determine the number of bytes in an entry name.\r
+               /// </summary>\r
+               /// <param name="name">\r
+               /// </param>\r
+               /// <param name="buf">\r
+               /// The header buffer from which to parse.\r
+               /// </param>\r
+               /// <param name="offset">\r
+               /// The offset into the buffer from which to parse.\r
+               /// </param>\r
+               /// <param name="length">\r
+               /// The number of header bytes to parse.\r
+               /// </param>\r
+               /// <returns>\r
+               /// The number of bytes in a header's entry name.\r
+               /// </returns>\r
+               public static int GetNameBytes(StringBuilder name, byte[] buf, int offset, int length)\r
+               {\r
+                       int i;\r
+                       \r
+                       for (i = 0 ; i < length && i < name.Length; ++i) {\r
+                               buf[offset + i] = (byte)name[i];\r
+                       }\r
+                       \r
+                       for (; i < length ; ++i) {\r
+                               buf[offset + i] = 0;\r
+                       }\r
+                       \r
+                       return offset + length;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Parse an octal integer from a header buffer.\r
+               /// </summary>\r
+               /// <param name = "val">\r
+               /// </param>\r
+               /// <param name = "buf">\r
+               /// The header buffer from which to parse.\r
+               /// </param>\r
+               /// <param name = "offset">\r
+               /// The offset into the buffer from which to parse.\r
+               /// </param>\r
+               /// <param name = "length">\r
+               /// The number of header bytes to parse.\r
+               /// </param>\r
+               /// <returns>\r
+               /// The integer value of the octal bytes.\r
+               /// </returns>\r
+               public static int GetOctalBytes(long val, byte[] buf, int offset, int length)\r
+               {\r
+                       byte[] result = new byte[length];\r
+                       \r
+                       int idx = length - 1;\r
+                       \r
+                       buf[offset + idx] = 0;\r
+                       --idx;\r
+                       buf[offset + idx] = (byte)' ';\r
+                       --idx;\r
+                       \r
+                       if (val == 0) {\r
+                               buf[offset + idx] = (byte)'0';\r
+                               --idx;\r
+                       } else {\r
+                               for (long v = val; idx >= 0 && v > 0; --idx) {\r
+                                       buf[offset + idx] = (byte)((byte)'0' + (byte)(v & 7));\r
+                                       v >>= 3;\r
+                               }\r
+                       }\r
+                               \r
+                       for (; idx >= 0; --idx) {\r
+                               buf[offset + idx] = (byte)' ';\r
+                       }\r
+                       \r
+                       return offset + length;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Parse an octal long integer from a header buffer.\r
+               /// </summary>\r
+               /// <param name = "val">\r
+               /// </param>\r
+               /// <param name = "buf">\r
+               /// The header buffer from which to parse.\r
+               /// </param>\r
+               /// <param name = "offset">\r
+               /// The offset into the buffer from which to parse.\r
+               /// </param>\r
+               /// <param name = "length">\r
+               /// The number of header bytes to parse.\r
+               /// </param>\r
+               /// <returns>\r
+               /// The long value of the octal bytes.\r
+               /// </returns>\r
+               public static int GetLongOctalBytes(long val, byte[] buf, int offset, int length)\r
+               {\r
+                       byte[] temp = new byte[length + 1];\r
+                       TarHeader.GetOctalBytes(val, temp, 0, length + 1);\r
+                       Array.Copy(temp, 0, buf, offset, length);\r
+                       return offset + length;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Parse the checksum octal integer from a header buffer.\r
+               /// </summary>\r
+               /// <param name = "val">\r
+               /// </param>\r
+               /// <param name = "buf">\r
+               /// The header buffer from which to parse.\r
+               /// </param>\r
+               /// <param name = "offset">\r
+               /// The offset into the buffer from which to parse.\r
+               /// </param>\r
+               /// <param name = "length">\r
+               /// The number of header bytes to parse.\r
+               /// </param>\r
+               /// <returns>\r
+               /// The integer value of the entry's checksum.\r
+               /// </returns>\r
+               public static int GetCheckSumOctalBytes(long val, byte[] buf, int offset, int length)\r
+               {\r
+                       TarHeader.GetOctalBytes(val, buf, offset, length);\r
+                       buf[offset + length - 1] = (byte)' ';\r
+                       buf[offset + length - 2] = 0;\r
+                       return offset + length;\r
+               }\r
+       }\r
+}\r
+\r
+/* The original Java file had this header:\r
+ * \r
+** Authored by Timothy Gerard Endres\r
+** <mailto:time@gjt.org>  <http://www.trustice.com>\r
+** \r
+** This work has been placed into the public domain.\r
+** You may use this work in any way and for any purpose you wish.\r
+**\r
+** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,\r
+** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR\r
+** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY\r
+** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR\r
+** REDISTRIBUTION OF THIS SOFTWARE. \r
+** \r
+*/\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarInputStream.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarInputStream.cs
new file mode 100644 (file)
index 0000000..8519560
--- /dev/null
@@ -0,0 +1,522 @@
+// TarInputStream.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+//\r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.IO;\r
+using System.Text;\r
+\r
+namespace ICSharpCode.SharpZipLib.Tar {\r
+       \r
+       /// <summary>\r
+       /// The TarInputStream reads a UNIX tar archive as an InputStream.\r
+       /// methods are provided to position at each successive entry in\r
+       /// the archive, and the read each entry as a normal input stream\r
+       /// using read().\r
+       /// </summary>\r
+       public class TarInputStream : Stream\r
+       {\r
+               protected bool debug;\r
+               protected bool hasHitEOF;\r
+               \r
+               protected int entrySize;\r
+               protected int entryOffset;\r
+               \r
+               protected byte[] readBuf;\r
+               \r
+               protected TarBuffer buffer;\r
+               protected TarEntry  currEntry;\r
+               protected IEntryFactory eFactory;\r
+               \r
+               Stream inputStream;\r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override bool CanRead {\r
+                       get {\r
+                               return inputStream.CanRead;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override bool CanSeek {\r
+                       get {\r
+                               return inputStream.CanSeek;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override bool CanWrite {\r
+                       get {\r
+                               return inputStream.CanWrite;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override long Length {\r
+                       get {\r
+                               return inputStream.Length;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override long Position {\r
+                       get {\r
+                               return inputStream.Position;\r
+                       }\r
+                       set {\r
+                               inputStream.Position = value;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Flushes the baseInputStream\r
+               /// </summary>\r
+               public override void Flush()\r
+               {\r
+                       inputStream.Flush();\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override long Seek(long offset, SeekOrigin origin)\r
+               {\r
+                       return inputStream.Seek(offset, origin);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override void SetLength(long val)\r
+               {\r
+                       inputStream.SetLength(val);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override void Write(byte[] array, int offset, int count)\r
+               {\r
+                       inputStream.Write(array, offset, count);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override void WriteByte(byte val)\r
+               {\r
+                       inputStream.WriteByte(val);\r
+               }\r
+                       \r
+               \r
+               public TarInputStream(Stream inputStream) : this(inputStream, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE)\r
+               {\r
+               }\r
+               \r
+               public TarInputStream(Stream inputStream, int blockSize) : this(inputStream, blockSize, TarBuffer.DEFAULT_RCDSIZE)\r
+               {\r
+               }\r
+               \r
+               public TarInputStream(Stream inputStream, int blockSize, int recordSize)\r
+               {\r
+                       this.inputStream = inputStream;\r
+                       this.buffer      = TarBuffer.CreateInputTarBuffer(inputStream, blockSize, recordSize);\r
+                       \r
+                       this.readBuf = null;\r
+                       this.debug     = false;\r
+                       this.hasHitEOF = false;\r
+                       this.eFactory  = null;\r
+               }\r
+               \r
+               public void SetDebug(bool debugF)\r
+               {\r
+                       this.debug = debugF;\r
+                       SetBufferDebug(debugF);\r
+               }\r
+               public void SetBufferDebug(bool debug)\r
+               {\r
+                       this.buffer.SetDebug(debug);\r
+               }\r
+               \r
+               \r
+               \r
+               public void SetEntryFactory(IEntryFactory factory)\r
+               {\r
+                       this.eFactory = factory;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Closes this stream. Calls the TarBuffer's close() method.\r
+               /// The underlying stream is closed by the TarBuffer.\r
+               /// </summary>\r
+               public override void Close()\r
+               {\r
+                       this.buffer.Close();\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get the record size being used by this stream's TarBuffer.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// TarBuffer record size.\r
+               /// </returns>\r
+               public int GetRecordSize()\r
+               {\r
+                       return this.buffer.GetRecordSize();\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get the available data that can be read from the current\r
+               /// entry in the archive. This does not indicate how much data\r
+               /// is left in the entire archive, only in the current entry.\r
+               /// This value is determined from the entry's size header field\r
+               /// and the amount of data already read from the current entry.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// The number of available bytes for the current entry.\r
+               /// </returns>\r
+               public int Available {\r
+                       get {\r
+                               return this.entrySize - this.entryOffset;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Skip bytes in the input buffer. This skips bytes in the\r
+               /// current entry's data, not the entire archive, and will\r
+               /// stop at the end of the current entry's data if the number\r
+               /// to skip extends beyond that point.\r
+               /// </summary>\r
+               /// <param name="numToSkip">\r
+               /// The number of bytes to skip.\r
+               /// </param>\r
+               public void Skip(int numToSkip)\r
+               {\r
+                       // REVIEW\r
+                       // This is horribly inefficient, but it ensures that we\r
+                       // properly skip over bytes via the TarBuffer...\r
+                       //\r
+                       byte[] skipBuf = new byte[8 * 1024];\r
+                       \r
+                       for (int num = numToSkip; num > 0;){\r
+                               int numRead = this.Read(skipBuf, 0, (num > skipBuf.Length ? skipBuf.Length : num));\r
+                               \r
+                               if (numRead == -1) {\r
+                                       break;\r
+                               }\r
+                               \r
+                               num -= numRead;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Since we do not support marking just yet, we return false.\r
+               /// </summary>\r
+               public bool IsMarkSupported {\r
+                       get {\r
+                               return false;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Since we do not support marking just yet, we do nothing.\r
+               /// </summary>\r
+               /// <param name ="markLimit">\r
+               /// The limit to mark.\r
+               /// </param>\r
+               public void Mark(int markLimit)\r
+               {\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Since we do not support marking just yet, we do nothing.\r
+               /// </summary>\r
+               public void Reset()\r
+               {\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get the next entry in this tar archive. This will skip\r
+               /// over any remaining data in the current entry, if there\r
+               /// is one, and place the input stream at the header of the\r
+               /// next entry, and read the header and instantiate a new\r
+               /// TarEntry from the header bytes and return that entry.\r
+               /// If there are no more entries in the archive, null will\r
+               /// be returned to indicate that the end of the archive has\r
+               /// been reached.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// The next TarEntry in the archive, or null.\r
+               /// </returns>\r
+               public TarEntry GetNextEntry()\r
+               {\r
+                       if (this.hasHitEOF) {\r
+                               return null;\r
+                       }\r
+                       \r
+                       if (this.currEntry != null) {\r
+                               int numToSkip = this.entrySize - this.entryOffset;\r
+                               \r
+                               if (this.debug) {\r
+                                       Console.Error.WriteLine("TarInputStream: SKIP currENTRY '" + this.currEntry.Name + "' SZ " + this.entrySize + " OFF " + this.entryOffset + "  skipping " + numToSkip + " bytes");\r
+                               }\r
+                               \r
+                               if (numToSkip > 0) {\r
+                                       this.Skip(numToSkip);\r
+                               }\r
+                               \r
+                               this.readBuf = null;\r
+                       }\r
+                       \r
+                       byte[] headerBuf = this.buffer.ReadRecord();\r
+                       \r
+                       if (headerBuf == null) {\r
+                               if (this.debug) {\r
+                                       Console.Error.WriteLine("READ NULL RECORD");\r
+                               }\r
+                               \r
+                               this.hasHitEOF = true;\r
+                       } else if (this.buffer.IsEOFRecord(headerBuf)) {\r
+                               if (this.debug) {\r
+                                       Console.Error.WriteLine( "READ EOF RECORD" );\r
+                               }\r
+                               \r
+                               this.hasHitEOF = true;\r
+                       }\r
+                       \r
+                       if (this.hasHitEOF) {\r
+                               this.currEntry = null;\r
+                       } else {\r
+                               try {\r
+                                       if (this.eFactory == null) {\r
+                                               this.currEntry = new TarEntry(headerBuf);\r
+                                       } else {\r
+                                               this.currEntry = this.eFactory.CreateEntry(headerBuf);\r
+                                       }\r
+                                       \r
+                                       if (!(headerBuf[257] == 'u' && headerBuf[258] == 's' && headerBuf[259] == 't' && headerBuf[260] == 'a' && headerBuf[261] == 'r')) {\r
+                                               throw new InvalidHeaderException("header magic is not 'ustar', but '" + headerBuf[257] + headerBuf[258] + headerBuf[259] + headerBuf[260] + headerBuf[261] + \r
+                                                                                "', or (dec) " + ((int)headerBuf[257]) + ", " + ((int)headerBuf[258]) + ", " + ((int)headerBuf[259]) + ", " + ((int)headerBuf[260]) + ", " + ((int)headerBuf[261]));\r
+                                       }\r
+                                               \r
+                                       if (this.debug) {\r
+                                       Console.Error.WriteLine("TarInputStream: SET CURRENTRY '" + this.currEntry.Name + "' size = " + this.currEntry.Size);\r
+                                       }\r
+                       \r
+                                       this.entryOffset = 0;\r
+                                       \r
+                                       // REVIEW How do we resolve this discrepancy?!\r
+                                       this.entrySize = (int) this.currEntry.Size;\r
+                               } catch (InvalidHeaderException ex) {\r
+                                       this.entrySize = 0;\r
+                                       this.entryOffset = 0;\r
+                                       this.currEntry = null;\r
+                                       throw new InvalidHeaderException("bad header in block " + this.buffer.GetCurrentBlockNum() + " record " + this.buffer.GetCurrentRecordNum() + ", " + ex.Message);\r
+                               }\r
+                       }\r
+                       return this.currEntry;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Reads a byte from the current tar archive entry.\r
+               /// This method simply calls read(byte[], int, int).\r
+               /// </summary>\r
+               public override int ReadByte()\r
+               {\r
+                       byte[] oneByteBuffer = new byte[1];\r
+                       int num = this.Read(oneByteBuffer, 0, 1);\r
+                       if (num <= 0) { // return -1 to indicate that no byte was read.\r
+                               return -1;\r
+                       }\r
+                       return (int)oneByteBuffer[0];\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Reads bytes from the current tar archive entry.\r
+               /// \r
+               /// This method is aware of the boundaries of the current\r
+               /// entry in the archive and will deal with them as if they\r
+               /// entry in the archive and will deal with them as if they\r
+               /// </summary>\r
+               /// <param name="buf">\r
+               /// The buffer into which to place bytes read.\r
+               /// </param>\r
+               /// <param name="offset">\r
+               /// The offset at which to place bytes read.\r
+               /// </param>\r
+               /// <param name="numToRead">\r
+               /// The number of bytes to read.\r
+               /// </param>\r
+               /// <returns>\r
+               /// The number of bytes read, or -1 at EOF.\r
+               /// </returns>\r
+               public override int Read(byte[] buf, int offset, int numToRead)\r
+               {\r
+                       int totalRead = 0;\r
+                       \r
+                       if (this.entryOffset >= this.entrySize) {\r
+                               return -1;\r
+                       }\r
+                       \r
+                       if ((numToRead + this.entryOffset) > this.entrySize) {\r
+                               numToRead = this.entrySize - this.entryOffset;\r
+                       }\r
+                       \r
+                       if (this.readBuf != null) {\r
+                               int sz = (numToRead > this.readBuf.Length) ? this.readBuf.Length : numToRead;\r
+                               \r
+                               Array.Copy(this.readBuf, 0, buf, offset, sz);\r
+                               \r
+                               if (sz >= this.readBuf.Length) {\r
+                                       this.readBuf = null;\r
+                               } else {\r
+                                       int newLen = this.readBuf.Length - sz;\r
+                                       byte[] newBuf = new byte[ newLen ];\r
+                                       Array.Copy(this.readBuf, sz, newBuf, 0, newLen);\r
+                                       this.readBuf = newBuf;\r
+                               }\r
+                               \r
+                               totalRead += sz;\r
+                               numToRead -= sz;\r
+                               offset += sz;\r
+                       }\r
+                       \r
+                       while (numToRead > 0) {\r
+                               byte[] rec = this.buffer.ReadRecord();\r
+                               if (rec == null) {\r
+                                       // Unexpected EOF!\r
+                                       throw new IOException("unexpected EOF with " + numToRead + " bytes unread");\r
+                               }\r
+                               \r
+                               int sz     = numToRead;\r
+                               int recLen = rec.Length;\r
+                               \r
+                               if (recLen > sz) {\r
+                                       Array.Copy(rec, 0, buf, offset, sz);\r
+                                       this.readBuf = new byte[recLen - sz];\r
+                                       Array.Copy(rec, sz, this.readBuf, 0, recLen - sz);\r
+                               } else {\r
+                                       sz = recLen;\r
+                                       Array.Copy(rec, 0, buf, offset, recLen);\r
+                               }\r
+                               \r
+                               totalRead += sz;\r
+                               numToRead -= sz;\r
+                               offset += sz;\r
+                       }\r
+                       \r
+                       this.entryOffset += totalRead;\r
+                       \r
+                       return totalRead;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Copies the contents of the current tar archive entry directly into\r
+               /// an output stream.\r
+               /// </summary>\r
+               /// <param name="outputStream">\r
+               /// The OutputStream into which to write the entry's data.\r
+               /// </param>\r
+               public void CopyEntryContents(Stream outputStream)\r
+               {\r
+                       byte[] buf = new byte[32 * 1024];\r
+                       \r
+                       while (true) {\r
+                               int numRead = this.Read(buf, 0, buf.Length);\r
+                               if (numRead <= 0) {\r
+                                       break;\r
+                               }\r
+                               outputStream.Write(buf, 0, numRead);\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// This interface is provided, with the method setEntryFactory(), to allow\r
+               /// the programmer to have their own TarEntry subclass instantiated for the\r
+               /// entries return from getNextEntry().\r
+               /// </summary>\r
+               public interface IEntryFactory\r
+               {\r
+                       TarEntry CreateEntry(string name);\r
+                       \r
+                       TarEntry CreateEntryFromFile(string fileName);\r
+                       \r
+                       TarEntry CreateEntry(byte[] headerBuf);\r
+               }\r
+               \r
+               public class EntryFactoryAdapter : IEntryFactory\r
+               {\r
+                       public TarEntry CreateEntry(string name)\r
+                       {\r
+                               return TarEntry.CreateTarEntry(name);\r
+                       }\r
+                       \r
+                       public TarEntry CreateEntryFromFile(string fileName)\r
+                       {\r
+                               return TarEntry.CreateEntryFromFile(fileName);\r
+                       }\r
+                       \r
+                       public TarEntry CreateEntry(byte[] headerBuf)\r
+                       {\r
+                               return new TarEntry(headerBuf);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       \r
+}\r
+\r
+/* The original Java file had this header:\r
+       ** Authored by Timothy Gerard Endres\r
+       ** <mailto:time@gjt.org>  <http://www.trustice.com>\r
+       **\r
+       ** This work has been placed into the public domain.\r
+       ** You may use this work in any way and for any purpose you wish.\r
+       **\r
+       ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,\r
+       ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR\r
+       ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY\r
+       ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR\r
+       ** REDISTRIBUTION OF THIS SOFTWARE.\r
+       **\r
+       */\r
+       \r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarOutputStream.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Tar/TarOutputStream.cs
new file mode 100644 (file)
index 0000000..778452d
--- /dev/null
@@ -0,0 +1,379 @@
+// TarOutputStream.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.IO;\r
+using System.Text;\r
+\r
+namespace ICSharpCode.SharpZipLib.Tar {\r
+       \r
+       /// <summary>\r
+       /// The TarOutputStream writes a UNIX tar archive as an OutputStream.\r
+       /// Methods are provided to put entries, and then write their contents\r
+       /// by writing to this stream using write().\r
+       /// </summary>\r
+       /// public\r
+       public class TarOutputStream : Stream\r
+       {\r
+               protected bool   debug;\r
+               protected int    currSize;\r
+               protected int    currBytes;\r
+               protected byte[] recordBuf;\r
+               protected int    assemLen;\r
+               protected byte[] assemBuf;\r
+               \r
+               protected TarBuffer buffer;\r
+               protected Stream    outputStream;\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override bool CanRead {\r
+                       get {\r
+                               return outputStream.CanRead;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override bool CanSeek {\r
+                       get {\r
+                               return outputStream.CanSeek;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override bool CanWrite {\r
+                       get {\r
+                               return outputStream.CanWrite;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override long Length {\r
+                       get {\r
+                               return outputStream.Length;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override long Position {\r
+                       get {\r
+                               return outputStream.Position;\r
+                       }\r
+                       set {\r
+                               outputStream.Position = value;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override long Seek(long offset, SeekOrigin origin)\r
+               {\r
+                       return outputStream.Seek(offset, origin);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override void SetLength(long val)\r
+               {\r
+                       outputStream.SetLength(val);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override int ReadByte()\r
+               {\r
+                       return outputStream.ReadByte();\r
+               }\r
+               \r
+               /// <summary>\r
+               /// I needed to implement the abstract member.\r
+               /// </summary>\r
+               public override int Read(byte[] b, int off, int len)\r
+               {\r
+                       return outputStream.Read(b, off, len);\r
+               }\r
+               \r
+               public override void Flush()\r
+               {\r
+                       outputStream.Flush();\r
+               }\r
+                               \r
+               public TarOutputStream(Stream outputStream) : this(outputStream, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE)\r
+               {\r
+               }\r
+               \r
+               public TarOutputStream(Stream outputStream, int blockSize) : this(outputStream, blockSize, TarBuffer.DEFAULT_RCDSIZE)\r
+               {\r
+               }\r
+               \r
+               public TarOutputStream(Stream outputStream, int blockSize, int recordSize)\r
+               {\r
+                       this.outputStream = outputStream;\r
+                       this.buffer       = TarBuffer.CreateOutputTarBuffer(outputStream, blockSize, recordSize);\r
+                       \r
+                       this.debug     = false;\r
+                       this.assemLen  = 0;\r
+                       this.assemBuf  = new byte[recordSize];\r
+                       this.recordBuf = new byte[recordSize];\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Sets the debugging flag.\r
+               /// </summary>\r
+               /// <param name = "debugF">\r
+               /// True to turn on debugging.\r
+               /// </param>\r
+               public void SetDebug(bool debugF)\r
+               {\r
+                       this.debug = debugF;\r
+                       SetBufferDebug(debugF);\r
+               }\r
+               \r
+               public void SetBufferDebug(bool debug)\r
+               {\r
+                       this.buffer.SetDebug(debug);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Ends the TAR archive without closing the underlying OutputStream.\r
+               /// The result is that the EOF record of nulls is written.\r
+               /// </summary>\r
+               public void Finish()\r
+               {\r
+                       this.WriteEOFRecord();\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Ends the TAR archive and closes the underlying OutputStream.\r
+               /// This means that finish() is called followed by calling the\r
+               /// TarBuffer's close().\r
+               /// </summary>\r
+               public override void Close()\r
+               {\r
+                       this.Finish();\r
+                       this.buffer.Close();\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Get the record size being used by this stream's TarBuffer.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// The TarBuffer record size.\r
+               /// </returns>\r
+               public int GetRecordSize()\r
+               {\r
+                       return this.buffer.GetRecordSize();\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Put an entry on the output stream. This writes the entry's\r
+               /// header record and positions the output stream for writing\r
+               /// the contents of the entry. Once this method is called, the\r
+               /// stream is ready for calls to write() to write the entry's\r
+               /// contents. Once the contents are written, closeEntry()\r
+               /// <B>MUST</B> be called to ensure that all buffered data\r
+               /// is completely written to the output stream.\r
+               /// </summary>\r
+               /// <param name="entry">\r
+               /// The TarEntry to be written to the archive.\r
+               /// </param>\r
+               public void PutNextEntry(TarEntry entry)\r
+               {\r
+                       if (entry.TarHeader.name.Length > TarHeader.NAMELEN) {\r
+                               throw new InvalidHeaderException("file name '" + entry.TarHeader.name + "' is too long ( > " + TarHeader.NAMELEN + " bytes )");\r
+                       }\r
+                       \r
+                       entry.WriteEntryHeader(this.recordBuf);\r
+                       this.buffer.WriteRecord(this.recordBuf);\r
+                       \r
+                       this.currBytes = 0;\r
+                       \r
+                       this.currSize = entry.IsDirectory ? 0 : (int)entry.Size;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Close an entry. This method MUST be called for all file\r
+               /// entries that contain data. The reason is that we must\r
+               /// buffer data written to the stream in order to satisfy\r
+               /// the buffer's record based writes. Thus, there may be\r
+               /// data fragments still being assembled that must be written\r
+               /// to the output stream before this entry is closed and the\r
+               /// next entry written.\r
+               /// </summary>\r
+               public void CloseEntry()\r
+               {\r
+                       if (this.assemLen > 0) {\r
+                               for (int i = this.assemLen; i < this.assemBuf.Length; ++i) {\r
+                                       this.assemBuf[i] = 0;\r
+                               }\r
+                               \r
+                               this.buffer.WriteRecord(this.assemBuf);\r
+                               \r
+                               this.currBytes += this.assemLen;\r
+                               this.assemLen = 0;\r
+                       }\r
+                       \r
+                       if (this.currBytes < this.currSize) {\r
+                               throw new IOException("entry closed at '" + this.currBytes + "' before the '" + this.currSize + "' bytes specified in the header were written");\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Writes a byte to the current tar archive entry.\r
+               /// This method simply calls Write(byte[], int, int).\r
+               /// </summary>\r
+               /// <param name="b">\r
+               /// The byte written.\r
+               /// </param>\r
+               public override void WriteByte(byte b)\r
+               {\r
+                       this.Write(new byte[] { b }, 0, 1);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Writes bytes to the current tar archive entry. This method\r
+               /// is aware of the current entry and will throw an exception if\r
+               /// you attempt to write bytes past the length specified for the\r
+               /// current entry. The method is also (painfully) aware of the\r
+               /// record buffering required by TarBuffer, and manages buffers\r
+               /// that are not a multiple of recordsize in length, including\r
+               /// assembling records from small buffers.\r
+               /// </summary>\r
+               /// <param name = "wBuf">\r
+               /// The buffer to write to the archive.\r
+               /// </param>\r
+               /// <param name = "wOffset">\r
+               /// The offset in the buffer from which to get bytes.\r
+               /// </param>\r
+               /// <param name = "numToWrite">\r
+               /// The number of bytes to write.\r
+               /// </param>\r
+               public override void Write(byte[] wBuf, int wOffset, int numToWrite)\r
+               {\r
+                       if ((this.currBytes + numToWrite) > this.currSize) {\r
+                               throw new IOException("request to write '" + numToWrite + "' bytes exceeds size in header of '" + this.currSize + "' bytes");\r
+                       }\r
+                       \r
+                       //\r
+                       // We have to deal with assembly!!!\r
+                       // The programmer can be writing little 32 byte chunks for all\r
+                       // we know, and we must assemble complete records for writing.\r
+                       // REVIEW Maybe this should be in TarBuffer? Could that help to\r
+                       //        eliminate some of the buffer copying.\r
+                       //\r
+                       if (this.assemLen > 0) {\r
+                               if ((this.assemLen + numToWrite ) >= this.recordBuf.Length) {\r
+                                       int aLen = this.recordBuf.Length - this.assemLen;\r
+                                       \r
+                                       Array.Copy(this.assemBuf, 0, this.recordBuf, 0, this.assemLen);\r
+                                       \r
+                                       Array.Copy(wBuf, wOffset, this.recordBuf, this.assemLen, aLen);\r
+                                       \r
+                                       this.buffer.WriteRecord(this.recordBuf);\r
+                                       \r
+                                       this.currBytes += this.recordBuf.Length;\r
+                                       \r
+                                       wOffset    += aLen;\r
+                                       numToWrite -= aLen;\r
+                                       \r
+                                       this.assemLen = 0;\r
+                               } else {// ( (this.assemLen + numToWrite ) < this.recordBuf.length )\r
+                                       Array.Copy(wBuf, wOffset, this.assemBuf, this.assemLen, numToWrite);\r
+                                       wOffset       += numToWrite;\r
+                                       this.assemLen += numToWrite;\r
+                                       numToWrite -= numToWrite;\r
+                               }\r
+                       }\r
+                       \r
+                       //\r
+                       // When we get here we have EITHER:\r
+                       //   o An empty "assemble" buffer.\r
+                       //   o No bytes to write (numToWrite == 0)\r
+                       //\r
+                       while (numToWrite > 0) {\r
+                               if (numToWrite < this.recordBuf.Length) {\r
+                                       Array.Copy(wBuf, wOffset, this.assemBuf, this.assemLen, numToWrite);\r
+                                       this.assemLen += numToWrite;\r
+                                       break;\r
+                               }\r
+                               \r
+                               this.buffer.WriteRecord(wBuf, wOffset);\r
+                               \r
+                               int num = this.recordBuf.Length;\r
+                               this.currBytes += num;\r
+                               numToWrite     -= num;\r
+                               wOffset        += num;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Write an EOF (end of archive) record to the tar archive.\r
+               /// An EOF record consists of a record of all zeros.\r
+               /// </summary>\r
+               void WriteEOFRecord()\r
+               {\r
+                       for (int i = 0; i < this.recordBuf.Length; ++i) {\r
+                               this.recordBuf[i] = 0;\r
+                       }\r
+                       this.buffer.WriteRecord(this.recordBuf);\r
+               }\r
+       }\r
+}\r
+\r
+/* The original Java file had this header:\r
+       ** Authored by Timothy Gerard Endres\r
+       ** <mailto:time@gjt.org>  <http://www.trustice.com>\r
+       **\r
+       ** This work has been placed into the public domain.\r
+       ** You may use this work in any way and for any purpose you wish.\r
+       **\r
+       ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,\r
+       ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR\r
+       ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY\r
+       ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR\r
+       ** REDISTRIBUTION OF THIS SOFTWARE.\r
+       **\r
+       */\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipConstants.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipConstants.cs
new file mode 100644 (file)
index 0000000..7bad3d6
--- /dev/null
@@ -0,0 +1,124 @@
+// ZipConstants.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This file was translated from java, it was part of the GNU Classpath\r
+// Copyright (C) 2001 Free Software Foundation, Inc.\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System.Text;\r
+\r
+namespace ICSharpCode.SharpZipLib.Zip {\r
+       \r
+       /// <summary>\r
+       /// This class contains constants used for zip.\r
+       /// </summary>\r
+       public sealed class ZipConstants\r
+       {\r
+               /* The local file header */\r
+               public const int LOCHDR = 30;\r
+               public const int LOCSIG = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);\r
+               \r
+               public const int LOCVER =  4;\r
+               public const int LOCFLG =  6;\r
+               public const int LOCHOW =  8;\r
+               public const int LOCTIM = 10;\r
+               public const int LOCCRC = 14;\r
+               public const int LOCSIZ = 18;\r
+               public const int LOCLEN = 22;\r
+               public const int LOCNAM = 26;\r
+               public const int LOCEXT = 28;\r
+               \r
+               /* The Data descriptor */\r
+               public const int EXTSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);\r
+               public const int EXTHDR = 16;\r
+               \r
+               public const int EXTCRC =  4;\r
+               public const int EXTSIZ =  8;\r
+               public const int EXTLEN = 12;\r
+               \r
+               /* The central directory file header */\r
+               public const int CENSIG = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);\r
+               \r
+               /* The central directory file header for 64bit ZIP*/\r
+               public const int CENSIG64 = 0x06064b50;\r
+               \r
+               public const int CENHDR = 46;\r
+               \r
+               public const int CENVEM =  4;\r
+               public const int CENVER =  6;\r
+               public const int CENFLG =  8;\r
+               public const int CENHOW = 10;\r
+               public const int CENTIM = 12;\r
+               public const int CENCRC = 16;\r
+               public const int CENSIZ = 20;\r
+               public const int CENLEN = 24;\r
+               public const int CENNAM = 28;\r
+               public const int CENEXT = 30;\r
+               public const int CENCOM = 32;\r
+               public const int CENDSK = 34;\r
+               public const int CENATT = 36;\r
+               public const int CENATX = 38;\r
+               public const int CENOFF = 42;\r
+               \r
+               /* The entries in the end of central directory */\r
+               public const int ENDSIG = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);\r
+               public const int ENDHDR = 22;\r
+               \r
+               /* The following two fields are missing in SUN JDK */\r
+               public const int ENDNRD =  4;\r
+               public const int ENDDCD =  6;\r
+               \r
+               public const int ENDSUB =  8;\r
+               public const int ENDTOT = 10;\r
+               public const int ENDSIZ = 12;\r
+               public const int ENDOFF = 16;\r
+               public const int ENDCOM = 20;\r
+               \r
+               /* Using the codepage 1252 doesn't solve the 8bit ASCII problem :/\r
+                  any help would be appreciated.\r
+                \r
+                 // get encoding for latin characters (like Ã¶, Ã¼, ÃŸ or Ã´)\r
+                 static Encoding ecp1252 = Encoding.GetEncoding(1252);\r
+               */\r
+               public static string ConvertToString(byte[] data)\r
+               {\r
+                       \r
+                       return Encoding.ASCII.GetString(data);\r
+               }\r
+               \r
+               public static byte[] ConvertToArray(string str)\r
+               {\r
+                       return Encoding.ASCII.GetBytes(str);\r
+               }\r
+       }\r
+}\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs
new file mode 100644 (file)
index 0000000..5ebce93
--- /dev/null
@@ -0,0 +1,393 @@
+// ZipEntry.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This file was translated from java, it was part of the GNU Classpath\r
+// Copyright (C) 2001 Free Software Foundation, Inc.\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+\r
+namespace ICSharpCode.SharpZipLib.Zip {\r
+       \r
+       public enum CompressionMethod\r
+       {\r
+               Stored   = 0,\r
+               Deflated = 8,\r
+       }\r
+       \r
+       /// <summary>\r
+       /// This class represents a member of a zip archive.  ZipFile and\r
+       /// ZipInputStream will give you instances of this class as information\r
+       /// about the members in an archive.  On the other hand ZipOutputStream\r
+       /// needs an instance of this class to create a new member.\r
+       ///\r
+       /// author of the original java version : Jochen Hoenicke\r
+       /// </summary>\r
+       public class ZipEntry : ICloneable\r
+       {\r
+               static int KNOWN_SIZE   = 1;\r
+               static int KNOWN_CSIZE  = 2;\r
+               static int KNOWN_CRC    = 4;\r
+               static int KNOWN_TIME   = 8;\r
+               \r
+               DateTime cal = DateTime.Now;\r
+               \r
+               string name;\r
+               uint   size;\r
+               ushort version;\r
+               uint   compressedSize;\r
+               int    crc;\r
+               \r
+               ushort known = 0;\r
+               CompressionMethod  method = CompressionMethod.Deflated;\r
+               byte[] extra = null;\r
+               string comment = null;\r
+               \r
+               public int zipFileIndex = -1;  /* used by ZipFile */\r
+               public int flags;              /* used by ZipOutputStream */\r
+               public int offset;             /* used by ZipFile and ZipOutputStream */\r
+               \r
+               /// <summary>\r
+               /// Creates a zip entry with the given name.\r
+               /// </summary>\r
+               /// <param name="name">\r
+               /// the name. May include directory components separated by '/'.\r
+               /// </param>\r
+               public ZipEntry(string name)\r
+               {\r
+                       if (name == null) {\r
+                               throw new System.ArgumentNullException("name");\r
+                       }\r
+                       this.name = name;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Creates a copy of the given zip entry.\r
+               /// </summary>\r
+               /// <param name="e">\r
+               /// the entry to copy.\r
+               /// </param>\r
+               public ZipEntry(ZipEntry e)\r
+               {\r
+                       name = e.name;\r
+                       known = e.known;\r
+                       size = e.size;\r
+                       compressedSize = e.compressedSize;\r
+                       crc = e.crc;\r
+//                     time = e.time;\r
+                       method = e.method;\r
+                       extra = e.extra;\r
+                       comment = e.comment;\r
+               }\r
+               \r
+               public ushort Version {\r
+                       get {\r
+                               return version;\r
+                       }\r
+                       set {\r
+                               version = value;\r
+                       }\r
+               }\r
+               \r
+               public int DosTime {\r
+                       get {\r
+//                             if ((known & KNOWN_TIME) == 0) {\r
+//                                     return 0;\r
+//                             }\r
+                               lock (this) {\r
+                                       return (cal.Year - 1980 & 0x7f) << 25 |\r
+                                              (cal.Month + 1) << 21 | \r
+                                              (cal.Day ) << 16 | \r
+                                              (cal.Hour) << 11 |\r
+                                              (cal.Minute) << 5 |\r
+                                              (cal.Second) >> 1;\r
+                               }\r
+                       }\r
+                       set {\r
+                               // Guard against invalid or missing date causing\r
+                               // IndexOutOfBoundsException.\r
+                               try {\r
+                                       lock (this) {\r
+                                               cal = CalculateDateTime(value);\r
+//                                             time = (int) (cal.Millisecond / 1000L);\r
+                                       }\r
+                                       known |= (ushort)KNOWN_TIME;\r
+                               } catch (Exception) {\r
+                                       /* Ignore illegal time stamp */\r
+                                       known &= (ushort)~KNOWN_TIME;\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Gets/Sets the time of last modification of the entry.\r
+               /// </summary>\r
+               public DateTime DateTime {\r
+                       get {\r
+                               return cal;\r
+                       }\r
+                       set {\r
+                               lock (this) {\r
+                                       cal = value;\r
+//                                     time = (int) (cal.Millisecond / 1000L);                                 \r
+                               }\r
+                               known |= (ushort)KNOWN_TIME;\r
+                       }\r
+               }\r
+                       \r
+               /// <summary>\r
+               /// Returns the entry name.  The path components in the entry are\r
+               /// always separated by slashes ('/').\r
+               /// </summary>\r
+               public string Name {\r
+                       get {\r
+                               return name;\r
+                       }\r
+               }\r
+               \r
+//             /// <summary>\r
+//             /// Gets/Sets the time of last modification of the entry.\r
+//             /// </summary>\r
+//             /// <returns>\r
+//             /// the time of last modification of the entry, or -1 if unknown.\r
+//             /// </returns>\r
+//             public long Time {\r
+//                     get {\r
+//                             return (known & KNOWN_TIME) != 0 ? time * 1000L : -1;\r
+//                     }\r
+//                     set {\r
+//                             this.time = (int) (value / 1000L);\r
+//                             this.known |= (ushort)KNOWN_TIME;\r
+//                     }\r
+//             }\r
+               \r
+               /// <summary>\r
+               /// Gets/Sets the size of the uncompressed data.\r
+               /// </summary>\r
+               /// <exception cref="System.ArgumentOutOfRangeException">\r
+               /// if size is not in 0..0xffffffffL\r
+               /// </exception>\r
+               /// <returns>\r
+               /// the size or -1 if unknown.\r
+               /// </returns>\r
+               public long Size {\r
+                       get {\r
+                               return (known & KNOWN_SIZE) != 0 ? (long)size : -1L;\r
+                       }\r
+                       set {\r
+                               if (((ulong)value & 0xFFFFFFFF00000000L) != 0) {\r
+                                       throw new ArgumentOutOfRangeException("size");\r
+                               }\r
+                               this.size  = (uint)value;\r
+                               this.known |= (ushort)KNOWN_SIZE;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Gets/Sets the size of the compressed data.\r
+               /// </summary>\r
+               /// <exception cref="System.ArgumentOutOfRangeException">\r
+               /// if csize is not in 0..0xffffffffL\r
+               /// </exception>\r
+               /// <returns>\r
+               /// the size or -1 if unknown.\r
+               /// </returns>\r
+               public long CompressedSize {\r
+                       get {\r
+                               return (known & KNOWN_CSIZE) != 0 ? (long)compressedSize : -1L;\r
+                       }\r
+                       set {\r
+                               if (((ulong)value & 0xffffffff00000000L) != 0) {\r
+                                       throw new ArgumentOutOfRangeException();\r
+                               }\r
+                               this.compressedSize = (uint)value;\r
+                               this.known |= (ushort)KNOWN_CSIZE;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Gets/Sets the crc of the uncompressed data.\r
+               /// </summary>\r
+               /// <exception cref="System.ArgumentOutOfRangeException">\r
+               /// if crc is not in 0..0xffffffffL\r
+               /// </exception>\r
+               /// <returns>\r
+               /// the crc or -1 if unknown.\r
+               /// </returns>\r
+               public long Crc {\r
+                       get {\r
+                               return (known & KNOWN_CRC) != 0 ? crc & 0xffffffffL : -1L;\r
+                       }\r
+                       set {\r
+                               if (((ulong)crc & 0xffffffff00000000L) != 0) {\r
+                                       throw new Exception();\r
+                               }\r
+                               this.crc = (int)value;\r
+                               this.known |= (ushort)KNOWN_CRC;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Gets/Sets the compression method. Only DEFLATED and STORED are supported.\r
+               /// </summary>\r
+               /// <exception cref="System.ArgumentOutOfRangeException">\r
+               /// if method is not supported.\r
+               /// </exception>\r
+               /// <returns>\r
+               /// the compression method or -1 if unknown.\r
+               /// </returns>\r
+               /// <see cref="ZipOutputStream.DEFLATED"/>\r
+               /// <see cref="ZipOutputStream.STORED"/>\r
+               public CompressionMethod CompressionMethod {\r
+                       get {\r
+                               return method;\r
+                       }\r
+                       set {\r
+                           this.method = value;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Gets/Sets the extra data.\r
+               /// </summary>\r
+               /// <exception cref="System.ArgumentOutOfRangeException">\r
+               /// if extra is longer than 0xffff bytes.\r
+               /// </exception>\r
+               /// <returns>\r
+               /// the extra data or null if not set.\r
+               /// </returns>\r
+               public byte[] ExtraData {\r
+                       get {\r
+                               return extra;\r
+                       }\r
+                       set {\r
+                               if (value == null) {\r
+                                       this.extra = null;\r
+                                       return;\r
+                               }\r
+                               \r
+                               if (value.Length > 0xffff) {\r
+                                       throw new System.ArgumentOutOfRangeException();\r
+                               }\r
+                               this.extra = value;\r
+                               try {\r
+                                       int pos = 0;\r
+                                       while (pos < extra.Length) {\r
+                                               int sig = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8;\r
+                                               int len = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8;\r
+                                               if (sig == 0x5455) {\r
+                                                       /* extended time stamp, unix format by Rainer Prem <Rainer@Prem.de> */\r
+                                                       int flags = extra[pos];\r
+                                                       if ((flags & 1) != 0) {\r
+                                                               int iTime = ((extra[pos+1] & 0xff)       |\r
+                                                                            (extra[pos+2] & 0xff) << 8  |\r
+                                                                            (extra[pos+3] & 0xff) << 16 |\r
+                                                                            (extra[pos+4] & 0xff) << 24);\r
+                                                               \r
+                                                               cal = (new DateTime ( 1970, 1, 1, 0, 0, 0 ) + \r
+                                                                      new TimeSpan ( 0, 0, 0, iTime, 0 )).ToLocalTime ();\r
+                                                               known |= (ushort)KNOWN_TIME;\r
+                                                       }\r
+                                               }\r
+                                               pos += len;\r
+                                       }\r
+                               } catch (Exception) {\r
+                                       /* be lenient */\r
+                                       return;\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Gets/Sets the entry comment.\r
+               /// </summary>\r
+               /// <exception cref="System.ArgumentOutOfRangeException">\r
+               /// if comment is longer than 0xffff.\r
+               /// </exception>\r
+               /// <returns>\r
+               /// the comment or null if not set.\r
+               /// </returns>\r
+               public string Comment {\r
+                       get {\r
+                               return comment;\r
+                       }\r
+                       set {\r
+                               if (value.Length > 0xffff) {\r
+                                       throw new ArgumentOutOfRangeException();\r
+                               }\r
+                               this.comment = value;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Gets true, if the entry is a directory.  This is solely\r
+               /// determined by the name, a trailing slash '/' marks a directory.\r
+               /// </summary>\r
+               public bool IsDirectory {\r
+                       get {\r
+                               int nlen = name.Length;\r
+                               return nlen > 0 && name[nlen - 1] == '/';\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Creates a copy of this zip entry.\r
+               /// </summary>\r
+               public object Clone()\r
+               {\r
+                       return this.MemberwiseClone();\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Gets the string representation of this ZipEntry.  This is just\r
+               /// the name as returned by getName().\r
+               /// </summary>\r
+               public override string ToString()\r
+               {\r
+                       return name;\r
+               }\r
+               \r
+               DateTime CalculateDateTime(int dosTime)\r
+               {\r
+                       int sec = 2 * (dosTime & 0x1f);\r
+                       int min = (dosTime >> 5) & 0x3f;\r
+                       int hrs = (dosTime >> 11) & 0x1f;\r
+                       int day = (dosTime >> 16) & 0x1f;\r
+                       int mon = ((dosTime >> 21) & 0xf);\r
+                       int year = ((dosTime >> 25) & 0x7f) + 1980; /* since 1900 */\r
+                               \r
+                       return new DateTime(year, mon, day, hrs, min, sec);\r
+               }\r
+               \r
+       }\r
+}\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipFile.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipFile.cs
new file mode 100644 (file)
index 0000000..fff7bdb
--- /dev/null
@@ -0,0 +1,521 @@
+// ZipFile.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This file was translated from java, it was part of the GNU Classpath\r
+// Copyright (C) 2001 Free Software Foundation, Inc.\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.Collections;\r
+using System.IO;\r
+using System.Text;\r
+\r
+using ICSharpCode.SharpZipLib.Zip.Compression.Streams;\r
+using ICSharpCode.SharpZipLib.Zip.Compression;\r
+\r
+namespace ICSharpCode.SharpZipLib.Zip {\r
+       \r
+       /// <summary>\r
+       /// This class represents a Zip archive.  You can ask for the contained\r
+       /// entries, or get an input stream for a file entry.  The entry is\r
+       /// automatically decompressed.\r
+       /// \r
+       /// This class is thread safe:  You can open input streams for arbitrary\r
+       /// entries in different threads.\r
+       /// \r
+       /// author of the original java version : Jochen Hoenicke\r
+       /// </summary>\r
+       /// <example>\r
+       /// using System;\r
+       /// using System.Text;\r
+       /// using System.Collections;\r
+       /// using System.IO;\r
+       /// \r
+       /// using NZlib.Zip;\r
+       /// \r
+       /// class MainClass\r
+       /// {\r
+       ///     static public void Main(string[] args)\r
+       ///     {\r
+       ///             ZipFile zFile = new ZipFile(args[0]);\r
+       ///             Console.WriteLine("Listing of : " + zFile.Name);\r
+       ///             Console.WriteLine("");\r
+       ///             Console.WriteLine("Raw Size    Size      Date     Time     Name");\r
+       ///             Console.WriteLine("--------  --------  --------  ------  ---------");\r
+       ///             foreach (ZipEntry e in zFile) {\r
+       ///                     DateTime d = e.DateTime;\r
+       ///                     Console.WriteLine("{0, -10}{1, -10}{2}  {3}   {4}", e.Size, e.CompressedSize,\r
+       ///                                                                         d.ToString("dd-MM-yy"), d.ToString("t"),\r
+       ///                                                                         e.Name);\r
+       ///             }\r
+       ///     }\r
+       /// }\r
+       /// </example>\r
+       public class ZipFile : IEnumerable\r
+       {\r
+               string     name;\r
+               Stream     baseStream;\r
+               ZipEntry[] entries;\r
+               \r
+               /// <summary>\r
+               /// Opens a Zip file with the given name for reading.\r
+               /// </summary>\r
+               /// <exception name="System.IO.IOException">\r
+               /// IOException if a i/o error occured.\r
+               /// </exception>\r
+               /// <exception name="ICSharpCode.SharpZipLib.ZipException">\r
+               /// if the file doesn't contain a valid zip archive.\r
+               /// </exception>\r
+               public ZipFile(string name) : this(File.OpenRead(name))\r
+               {\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Opens a Zip file reading the given FileStream\r
+               /// </summary>\r
+               /// <exception name="System.IO.IOException">\r
+               /// IOException if a i/o error occured.\r
+               /// </exception>\r
+               /// <exception name="ICSharpCode.SharpZipLib.ZipException">\r
+               /// if the file doesn't contain a valid zip archive.\r
+               /// </exception>\r
+               public ZipFile(FileStream file)\r
+               {\r
+                       this.baseStream  = file;\r
+                       this.name = file.Name;\r
+                       ReadEntries();\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Opens a Zip file reading the given Stream\r
+               /// </summary>\r
+               /// <exception name="System.IO.IOException">\r
+               /// IOException if a i/o error occured.\r
+               /// </exception>\r
+               /// <exception name="ICSharpCode.SharpZipLib.ZipException">\r
+               /// if the file doesn't contain a valid zip archive.\r
+               /// </exception>\r
+               public ZipFile(Stream baseStream)\r
+               {\r
+                       this.baseStream  = baseStream;\r
+                       this.name = null;\r
+                       ReadEntries();\r
+               }\r
+               \r
+               \r
+               /// <summary>\r
+               /// Read an unsigned short in little endian byte order.\r
+               /// </summary>\r
+               /// <exception name="System.IO.IOException">\r
+               /// if a i/o error occured.\r
+               /// </exception>\r
+               /// <exception name="System.IO.EndOfStreamException">\r
+               /// if the file ends prematurely\r
+               /// </exception>\r
+               int ReadLeShort()\r
+               {\r
+                       return baseStream.ReadByte() | baseStream.ReadByte() << 8;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Read an int in little endian byte order.\r
+               /// </summary>\r
+               /// <exception name="System.IO.IOException">\r
+               /// if a i/o error occured.\r
+               /// </exception>\r
+               /// <exception name="System.IO.EndOfStreamException">\r
+               /// if the file ends prematurely\r
+               /// </exception>\r
+               int ReadLeInt()\r
+               {\r
+                       return ReadLeShort() | ReadLeShort() << 16;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Read the central directory of a zip file and fill the entries\r
+               /// array.  This is called exactly once by the constructors.\r
+               /// </summary>\r
+               /// <exception name="System.IO.IOException">\r
+               /// if a i/o error occured.\r
+               /// </exception>\r
+               /// <exception name="ICSharpCode.SharpZipLib.ZipException">\r
+               /// if the central directory is malformed\r
+               /// </exception>\r
+               void ReadEntries()\r
+               {\r
+                       /* Search for the End Of Central Directory.  When a zip comment is\r
+                       * present the directory may start earlier.\r
+                       * FIXME: This searches the whole file in a very slow manner if the\r
+                       * file isn't a zip file.\r
+                       */\r
+                       long pos = baseStream.Length - ZipConstants.ENDHDR;\r
+                       do {\r
+                               if (pos < 0) {\r
+                                       throw new ZipException("central directory not found, probably not a zip file");\r
+                               }\r
+                               baseStream.Seek(pos--, SeekOrigin.Begin);\r
+                       } while (ReadLeInt() != ZipConstants.ENDSIG);\r
+                       \r
+                       long oldPos = baseStream.Position;\r
+                       baseStream.Position += ZipConstants.ENDTOT - ZipConstants.ENDNRD;\r
+                       \r
+                       if (baseStream.Position - oldPos != ZipConstants.ENDTOT - ZipConstants.ENDNRD) {\r
+                               throw new EndOfStreamException();\r
+                       }\r
+                       int count = ReadLeShort();\r
+                       \r
+                       oldPos = baseStream.Position;\r
+                       baseStream.Position += ZipConstants.ENDOFF - ZipConstants.ENDSIZ;\r
+                       \r
+                       if (baseStream.Position - oldPos != ZipConstants.ENDOFF - ZipConstants.ENDSIZ) {\r
+                               throw new EndOfStreamException();\r
+                       }\r
+                       \r
+                       int centralOffset = ReadLeInt();\r
+                       \r
+                       entries = new ZipEntry[count];\r
+                       baseStream.Seek(centralOffset, SeekOrigin.Begin);\r
+                       for (int i = 0; i < count; i++) {\r
+                               if (ReadLeInt() != ZipConstants.CENSIG) {\r
+                                       throw new ZipException("Wrong Central Directory signature");\r
+                               }\r
+                               \r
+                               oldPos = baseStream.Position;\r
+                               baseStream.Position += ZipConstants.CENHOW - ZipConstants.CENVEM;\r
+                               \r
+                               if (baseStream.Position - oldPos != ZipConstants.CENHOW - ZipConstants.CENVEM) {\r
+                                       throw new EndOfStreamException();\r
+                               }\r
+                               int method = ReadLeShort();\r
+                               int dostime = ReadLeInt();\r
+                               int crc = ReadLeInt();\r
+                               int csize = ReadLeInt();\r
+                               int size = ReadLeInt();\r
+                               int nameLen = ReadLeShort();\r
+                               int extraLen = ReadLeShort();\r
+                               int commentLen = ReadLeShort();\r
+                               \r
+                               oldPos = baseStream.Position;\r
+                               baseStream.Position += ZipConstants.CENOFF - ZipConstants.CENDSK;\r
+                               if (baseStream.Position - oldPos != ZipConstants.CENOFF - ZipConstants.CENDSK) {\r
+                                       throw new EndOfStreamException();\r
+                               }\r
+                               int offset = ReadLeInt();\r
+                               \r
+                               byte[] buffer = new byte[Math.Max(nameLen, commentLen)];\r
+                               \r
+                               baseStream.Read(buffer, 0, nameLen);\r
+                               string name = ZipConstants.ConvertToString(buffer);\r
+                               \r
+                               ZipEntry entry = new ZipEntry(name);\r
+                               entry.CompressionMethod = (CompressionMethod)method;\r
+                               entry.Crc = crc & 0xffffffffL;\r
+                               entry.Size = size & 0xffffffffL;\r
+                               entry.CompressedSize = csize & 0xffffffffL;\r
+                               entry.DosTime = dostime;\r
+                               if (extraLen > 0) {\r
+                                       byte[] extra = new byte[extraLen];\r
+                                       baseStream.Read(extra, 0, extraLen);\r
+                                       entry.ExtraData = extra;\r
+                               }\r
+                               if (commentLen > 0) {\r
+                                       baseStream.Read(buffer, 0, commentLen);\r
+                                       entry.Comment = ZipConstants.ConvertToString(buffer);\r
+                               }\r
+                               entry.zipFileIndex = i;\r
+                               entry.offset = offset;\r
+                               entries[i] = entry;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Closes the ZipFile.  This also closes all input streams given by\r
+               /// this class.  After this is called, no further method should be\r
+               /// called.\r
+               /// </summary>\r
+               /// <exception name="System.IO.IOException">\r
+               /// if a i/o error occured.\r
+               /// </exception>\r
+               public void Close()\r
+               {\r
+                       entries = null;\r
+                       lock(baseStream) {\r
+                               baseStream.Close();\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Returns an IEnumerator of all Zip entries in this Zip file.\r
+               /// </summary>\r
+               public IEnumerator GetEnumerator()\r
+               {\r
+                       if (entries == null) {\r
+                               throw new InvalidOperationException("ZipFile has closed");\r
+                       }\r
+                       \r
+                       return new ZipEntryEnumeration(entries);\r
+               }\r
+               \r
+               int GetEntryIndex(string name)\r
+               {\r
+                       for (int i = 0; i < entries.Length; i++) {\r
+                               if (name.Equals(entries[i].Name)) {\r
+                                       return i;\r
+                               }\r
+                       }\r
+                       return -1;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Searches for a zip entry in this archive with the given name.\r
+               /// </summary>\r
+               /// <param name="name">\r
+               /// the name. May contain directory components separated by slashes ('/').\r
+               /// </param>\r
+               /// <returns>\r
+               /// the zip entry, or null if no entry with that name exists.\r
+               /// </returns>\r
+               public ZipEntry GetEntry(string name)\r
+               {\r
+                       if (entries == null) {\r
+                               throw new InvalidOperationException("ZipFile has closed");\r
+                       }\r
+                       int index = GetEntryIndex(name);\r
+                       return index >= 0 ? (ZipEntry) entries[index].Clone() : null;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Checks, if the local header of the entry at index i matches the\r
+               /// central directory, and returns the offset to the data.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// the start offset of the (compressed) data.\r
+               /// </returns>\r
+               /// <exception name="System.IO.IOException">\r
+               /// if a i/o error occured.\r
+               /// </exception>\r
+               /// <exception name="ICSharpCode.SharpZipLib.ZipException">\r
+               /// if the local header doesn't match the central directory header\r
+               /// </exception>\r
+               long CheckLocalHeader(ZipEntry entry)\r
+               {\r
+                       lock(baseStream) {\r
+                               baseStream.Seek(entry.offset, SeekOrigin.Begin);\r
+                               if (ReadLeInt() != ZipConstants.LOCSIG) {\r
+                                       throw new ZipException("Wrong Local header signature");\r
+                               }\r
+                               \r
+                               /* skip version and flags */\r
+                               long oldPos = baseStream.Position;\r
+                               baseStream.Position += ZipConstants.LOCHOW - ZipConstants.LOCVER;\r
+                               if (baseStream.Position - oldPos != ZipConstants.LOCHOW - ZipConstants.LOCVER) {\r
+                                       throw new EndOfStreamException();\r
+                               }\r
+                               \r
+                               if (entry.CompressionMethod != (CompressionMethod)ReadLeShort()) {\r
+                                       throw new ZipException("Compression method mismatch");\r
+                               }\r
+                               \r
+                               /* Skip time, crc, size and csize */\r
+                               oldPos = baseStream.Position;\r
+                               baseStream.Position += ZipConstants.LOCNAM - ZipConstants.LOCTIM;\r
+                               \r
+                               if (baseStream.Position - oldPos != ZipConstants.LOCNAM - ZipConstants.LOCTIM) {\r
+                                       throw new EndOfStreamException();\r
+                               }\r
+                               \r
+                               if (entry.Name.Length != ReadLeShort()) {\r
+                                       throw new ZipException("file name length mismatch");\r
+                               }\r
+                               \r
+                               int extraLen = entry.Name.Length + ReadLeShort();\r
+                               return entry.offset + ZipConstants.LOCHDR + extraLen;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Creates an input stream reading the given zip entry as\r
+               /// uncompressed data.  Normally zip entry should be an entry\r
+               /// returned by GetEntry().\r
+               /// </summary>\r
+               /// <returns>\r
+               /// the input stream.\r
+               /// </returns>\r
+               /// <exception name="System.IO.IOException">\r
+               /// if a i/o error occured.\r
+               /// </exception>\r
+               /// <exception name="ICSharpCode.SharpZipLib.ZipException">\r
+               /// if the Zip archive is malformed.\r
+               /// </exception>\r
+               public Stream GetInputStream(ZipEntry entry)\r
+               {\r
+                       if (entries == null) {\r
+                               throw new InvalidOperationException("ZipFile has closed");\r
+                       }\r
+                       \r
+                       int index = entry.zipFileIndex;\r
+                       if (index < 0 || index >= entries.Length || entries[index].Name != entry.Name) {\r
+                               index = GetEntryIndex(entry.Name);\r
+                               if (index < 0) {\r
+                                       throw new IndexOutOfRangeException();\r
+                               }\r
+                       }\r
+                       \r
+                       long start = CheckLocalHeader(entries[index]);\r
+                       CompressionMethod method = entries[index].CompressionMethod;\r
+                       Stream istr = new PartialInputStream(baseStream, start, entries[index].CompressedSize);\r
+                       switch (method) {\r
+                               case CompressionMethod.Stored:\r
+                                       return istr;\r
+                               case CompressionMethod.Deflated:\r
+                                       return new InflaterInputStream(istr, new Inflater(true));\r
+                               default:\r
+                                       throw new ZipException("Unknown compression method " + method);\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Returns the name of this zip file.\r
+               /// </summary>\r
+               public string Name {\r
+                       get {\r
+                               return name;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Returns the number of entries in this zip file.\r
+               /// </summary>\r
+               public int Size {\r
+                       get {\r
+                               try {\r
+                                       return entries.Length;\r
+                               } catch (Exception) {\r
+                                       throw new InvalidOperationException("ZipFile has closed");\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               class ZipEntryEnumeration : IEnumerator\r
+               {\r
+                       ZipEntry[] array;\r
+                       int ptr = -1;\r
+                       \r
+                       public ZipEntryEnumeration(ZipEntry[] arr)\r
+                       {\r
+                               array = arr;\r
+                       }\r
+                       \r
+                       public object Current {\r
+                               get {\r
+                                       return array[ptr];\r
+                               }\r
+                       }\r
+                       \r
+                       public void Reset()\r
+                       {\r
+                               ptr = -1;\r
+                       }\r
+                       \r
+                       public bool MoveNext() \r
+                       {\r
+                               return (++ptr < array.Length);\r
+                       }\r
+               }\r
+               \r
+               class PartialInputStream : InflaterInputStream\r
+               {\r
+                       Stream baseStream;\r
+                       long filepos, end;\r
+                       \r
+                       public PartialInputStream(Stream baseStream, long start, long len) : base(baseStream)\r
+                       {\r
+                               this.baseStream = baseStream;\r
+                               filepos = start;\r
+                               end = start + len;\r
+                       }\r
+                       \r
+                       public override int Available {\r
+                               get {\r
+                                       long amount = end - filepos;\r
+                                       if (amount > Int32.MaxValue) {\r
+                                               return Int32.MaxValue;\r
+                                       }\r
+                                       \r
+                                       return (int) amount;\r
+                               }\r
+                       }\r
+                       \r
+                       public override int ReadByte()\r
+                       {\r
+                               if (filepos == end) {\r
+                                       return -1;\r
+                               }\r
+                               lock(baseStream) {\r
+                                       baseStream.Seek(filepos++, SeekOrigin.Begin);\r
+                                       return baseStream.ReadByte();\r
+                               }\r
+                       }\r
+                       \r
+                       public override int Read(byte[] b, int off, int len)\r
+                       {\r
+                               if (len > end - filepos) {\r
+                                       len = (int) (end - filepos);\r
+                                       if (len == 0) {\r
+                                               return -1;\r
+                                       }\r
+                               }\r
+                               lock(baseStream) {\r
+                                       baseStream.Seek(filepos, SeekOrigin.Begin);\r
+                                       int count = baseStream.Read(b, off, len);\r
+                                       if (count > 0) {\r
+                                               filepos += len;\r
+                                       }\r
+                                       return count;\r
+                               }\r
+                       }\r
+                       \r
+                       public long SkipBytes(long amount)\r
+                       {\r
+                               if (amount < 0) {\r
+                                       throw new ArgumentOutOfRangeException();\r
+                               }\r
+                               if (amount > end - filepos) {\r
+                                       amount = end - filepos;\r
+                               }\r
+                               filepos += amount;\r
+                               return amount;\r
+                       }\r
+               }\r
+       }\r
+}\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipInputStream.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipInputStream.cs
new file mode 100644 (file)
index 0000000..9bcd9f6
--- /dev/null
@@ -0,0 +1,431 @@
+// ZipInputStream.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This file was translated from java, it was part of the GNU Classpath\r
+// Copyright (C) 2001 Free Software Foundation, Inc.\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.Text;\r
+using System.IO;\r
+\r
+using ICSharpCode.SharpZipLib.Checksums;\r
+using ICSharpCode.SharpZipLib.Zip.Compression;\r
+using ICSharpCode.SharpZipLib.Zip.Compression.Streams;\r
+\r
+namespace ICSharpCode.SharpZipLib.Zip {\r
+       \r
+       /// <summary>\r
+       /// This is a FilterInputStream that reads the files baseInputStream an zip archive\r
+       /// one after another.  It has a special method to get the zip entry of\r
+       /// the next file.  The zip entry contains information about the file name\r
+       /// size, compressed size, CRC, etc.\r
+       /// It includes support for STORED and DEFLATED entries.\r
+       /// \r
+       /// author of the original java version : Jochen Hoenicke\r
+       /// </summary>\r
+       /// <example> This sample shows how to read a zip file\r
+       /// <code>\r
+       /// using System;\r
+       /// using System.Text;\r
+       /// using System.IO;\r
+       /// \r
+       /// using NZlib.Zip;\r
+       /// \r
+       /// class MainClass\r
+       /// {\r
+       ///     public static void Main(string[] args)\r
+       ///     {\r
+       ///             ZipInputStream s = new ZipInputStream(File.OpenRead(args[0]));\r
+       ///             \r
+       ///             ZipEntry theEntry;\r
+       ///             while ((theEntry = s.GetNextEntry()) != null) {\r
+       ///                     Console.WriteLine("File " + theEntry.Name);\r
+       ///                     int size = 2048;\r
+       ///                     byte[] data = new byte[2048];\r
+       ///                     \r
+       ///                     Console.Write("Show contents (y/n) ?");\r
+       ///                     if (Console.ReadLine() == "y") {\r
+       ///                             while (true) {\r
+       ///                                     size = s.Read(data, 0, data.Length);\r
+       ///                                     if (size > 0) {\r
+       ///                                             Console.Write(new ASCIIEncoding().GetString(data, 0, size));\r
+       ///                                     } else {\r
+       ///                                             break;\r
+       ///                                     }\r
+       ///                             }\r
+       ///                     }\r
+       ///                     Console.WriteLine();\r
+       ///             }\r
+       ///             s.Close();\r
+       ///     }\r
+       /// }   \r
+       /// </code>\r
+       /// </example>\r
+       public class ZipInputStream : InflaterInputStream\r
+       {\r
+               private Crc32 crc = new Crc32();\r
+               private ZipEntry entry = null;\r
+               \r
+               private long csize;\r
+               private long size;\r
+               private int method;\r
+               private int flags;\r
+               private long avail;\r
+               \r
+               /// <summary>\r
+               /// Creates a new Zip input stream, reading a zip archive.\r
+               /// </summary>\r
+               public ZipInputStream(Stream baseInputStream) : base(baseInputStream, new Inflater(true))\r
+               {\r
+                       \r
+               }\r
+               \r
+               private void FillBuf()\r
+               {\r
+                       avail = len = baseInputStream.Read(buf, 0, buf.Length);\r
+               }\r
+               \r
+               private int ReadBuf(byte[] outBuf, int offset, int length)\r
+               {\r
+                       if (avail <= 0) {\r
+                               FillBuf();\r
+                               if (avail <= 0) {\r
+                                       return -1;\r
+                               }\r
+                       }\r
+                       if (length > avail) {\r
+                               length = (int)avail;\r
+                       }\r
+                       System.Array.Copy(buf, len - (int)avail, outBuf, offset, length);\r
+                       avail -= length;\r
+                       return length;\r
+               }\r
+               \r
+               private void ReadFully(byte[] outBuf)\r
+               {\r
+                       int off = 0;\r
+                       int len = outBuf.Length;\r
+                       while (len > 0) {\r
+                               int count = ReadBuf(outBuf, off, len);\r
+                               if (count == -1) {\r
+                                       throw new Exception(); \r
+                               }\r
+                               off += count;\r
+                               len -= count;\r
+                       }\r
+               }\r
+               \r
+               private int ReadLeByte()\r
+               {\r
+                       if (avail <= 0) {\r
+                               FillBuf();\r
+                               if (avail <= 0) {\r
+                                       throw new ZipException("EOF in header");\r
+                               }\r
+                       }\r
+                       return buf[len - avail--] & 0xff;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Read an unsigned short baseInputStream little endian byte order.\r
+               /// </summary>\r
+               private int ReadLeShort()\r
+               {\r
+                       return ReadLeByte() | (ReadLeByte() << 8);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Read an int baseInputStream little endian byte order.\r
+               /// </summary>\r
+               private int ReadLeInt()\r
+               {\r
+                       return ReadLeShort() | (ReadLeShort() << 16);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Read an int baseInputStream little endian byte order.\r
+               /// </summary>\r
+               private long ReadLeLong()\r
+               {\r
+                       return ReadLeInt() | (ReadLeInt() << 32);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Open the next entry from the zip archive, and return its description.\r
+               /// If the previous entry wasn't closed, this method will close it.\r
+               /// </summary>\r
+               public ZipEntry GetNextEntry()\r
+               {\r
+                       if (crc == null) {\r
+                               throw new InvalidOperationException("Closed.");\r
+                       }\r
+                       if (entry != null) {\r
+                               CloseEntry();\r
+                       }\r
+                       \r
+                       int header = ReadLeInt();\r
+                       if (header == ZipConstants.CENSIG) {\r
+                               /* Central Header reached. */\r
+                               Close();\r
+                               return null;\r
+                       }\r
+                       if (header != ZipConstants.LOCSIG) {\r
+                               throw new ZipException("Wrong Local header signature" + header);\r
+                       }\r
+                       \r
+                       short version = (short)ReadLeShort();\r
+                       \r
+                       flags = ReadLeShort();\r
+                       method = ReadLeShort();\r
+                       int dostime = ReadLeInt();\r
+                       int crc2 = ReadLeInt();\r
+                       csize = ReadLeInt();\r
+                       size = ReadLeInt();\r
+                       int nameLen = ReadLeShort();\r
+                       int extraLen = ReadLeShort();\r
+                       \r
+                       if (method == ZipOutputStream.STORED && csize != size) {\r
+                               throw new ZipException("Stored, but compressed != uncompressed");\r
+                       }\r
+                       \r
+                       byte[] buffer = new byte[nameLen];\r
+                       ReadFully(buffer);\r
+                       \r
+                       string name = ZipConstants.ConvertToString(buffer);\r
+                       \r
+                       entry = new ZipEntry(name);\r
+                       \r
+                       entry.Version = (ushort)version;\r
+                       if (method != 0 && method != 8) {\r
+                               throw new ZipException("unknown compression method " + method);\r
+                       }\r
+                       entry.CompressionMethod = (CompressionMethod)method;\r
+                       \r
+                       if ((flags & 8) == 0) {\r
+                               entry.Crc  = crc2 & 0xFFFFFFFFL;\r
+                               entry.Size = size & 0xFFFFFFFFL;\r
+                               entry.CompressedSize = csize & 0xFFFFFFFFL;\r
+                       }\r
+                       entry.DosTime = dostime;\r
+                       if (extraLen > 0) {\r
+                               byte[] extra = new byte[extraLen];\r
+                               ReadFully(extra);\r
+                               entry.ExtraData = extra;\r
+                       }\r
+                       \r
+                       if (method == ZipOutputStream.DEFLATED && avail > 0) {\r
+                               System.Array.Copy(buf, len - (int)avail, buf, 0, (int)avail);\r
+                               len = (int)avail;\r
+                               avail = 0;\r
+                               inf.SetInput(buf, 0, len);\r
+                       }\r
+                       return entry;\r
+               }\r
+               \r
+               private void ReadDataDescr()\r
+               {\r
+                       if (ReadLeInt() != ZipConstants.EXTSIG) {\r
+                               throw new ZipException("Data descriptor signature not found");\r
+                       }\r
+                       entry.Crc = ReadLeInt() & 0xFFFFFFFFL;\r
+                       csize = ReadLeInt();\r
+                       size = ReadLeInt();\r
+                       entry.Size = size & 0xFFFFFFFFL;\r
+                       entry.CompressedSize = csize & 0xFFFFFFFFL;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Closes the current zip entry and moves to the next one.\r
+               /// </summary>\r
+               public void CloseEntry()\r
+               {\r
+                       if (crc == null) {\r
+                               throw new InvalidOperationException("Closed.");\r
+                       }\r
+                       if (entry == null) {\r
+                               return;\r
+                       }\r
+                       \r
+                       if (method == ZipOutputStream.DEFLATED) {\r
+                               if ((flags & 8) != 0) {\r
+                                       /* We don't know how much we must skip, read until end. */\r
+                                       byte[] tmp = new byte[2048];\r
+                                       while (Read(tmp, 0, tmp.Length) > 0)\r
+                                               ;\r
+                                       /* read will close this entry */\r
+                                       return;\r
+                               }\r
+                               csize -= inf.TotalIn;\r
+                               avail = inf.RemainingInput;\r
+                       }\r
+                       if (avail > csize && csize >= 0) {\r
+                               avail -= csize;\r
+                       } else {\r
+                               csize -= avail;\r
+                               avail = 0;\r
+                               while (csize != 0) {\r
+                                       int skipped = (int)base.Skip(csize & 0xFFFFFFFFL);\r
+                                       \r
+                                       if (skipped <= 0) {\r
+                                               throw new ZipException("zip archive ends early.");\r
+                                       }\r
+                                       \r
+                                       csize -= skipped;\r
+                               }\r
+                       }\r
+                       \r
+                       size = 0;\r
+                       crc.Reset();\r
+                       if (method == ZipOutputStream.DEFLATED) {\r
+                               inf.Reset();\r
+                       }\r
+                       entry = null;\r
+               }\r
+               \r
+               public override int Available {\r
+                       get {\r
+                               return entry != null ? 1 : 0;\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Reads a byte from the current zip entry.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// the byte or -1 on EOF.\r
+               /// </returns>\r
+               /// <exception name="System.IO.IOException">\r
+               /// IOException if a i/o error occured.\r
+               /// </exception>\r
+               /// <exception name="ICSharpCode.SharpZipLib.ZipException">\r
+               /// ZipException if the deflated stream is corrupted.\r
+               /// </exception>\r
+               public override int ReadByte()\r
+               {\r
+                       byte[] b = new byte[1];\r
+                       if (Read(b, 0, 1) <= 0) {\r
+                               return -1;\r
+                       }\r
+                       return b[0] & 0xff;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Reads a block of bytes from the current zip entry.\r
+               /// </summary>\r
+               /// <returns>\r
+               /// the number of bytes read (may be smaller, even before EOF), or -1 on EOF.\r
+               /// </returns>\r
+               /// <exception name="Exception">\r
+               /// IOException if a i/o error occured.\r
+               /// ZipException if the deflated stream is corrupted.\r
+               /// </exception>\r
+               public override int Read(byte[] b, int off, int len)\r
+               {\r
+                       if (crc == null) {\r
+                               throw new InvalidOperationException("Closed.");\r
+                       }\r
+                       if (entry == null) {\r
+                               return -1;\r
+                       }\r
+                       bool finished = false;\r
+                       \r
+                       switch (method) {\r
+                               case ZipOutputStream.DEFLATED:\r
+                                       len = base.Read(b, off, len);\r
+                                       if (len < 0) {\r
+                                               if (!inf.IsFinished) {\r
+                                                       throw new ZipException("Inflater not finished!?");\r
+                                               }\r
+                                               avail = inf.RemainingInput;\r
+                                               if ((flags & 8) != 0) {\r
+                                                       ReadDataDescr();\r
+                                               }\r
+                                               \r
+                                               if (inf.TotalIn != csize || inf.TotalOut != size) {\r
+                                                       throw new ZipException("size mismatch: " + csize + ";" + size + " <-> " + inf.TotalIn + ";" + inf.TotalOut);\r
+                                               }\r
+                                               inf.Reset();\r
+                                               finished = true;\r
+                                       }\r
+                                       break;\r
+                               \r
+                               case ZipOutputStream.STORED:\r
+                                       \r
+                                       if (len > csize && csize >= 0) {\r
+                                               len = (int)csize;\r
+                                       }\r
+                                       len = ReadBuf(b, off, len);\r
+                                       if (len > 0) {\r
+                                               csize -= len;\r
+                                               size -= len;\r
+                                       }\r
+                                       \r
+                                       if (csize == 0) {\r
+                                               finished = true;\r
+                                       } else {\r
+                                               if (len < 0) {\r
+                                                       throw new ZipException("EOF in stored block");\r
+                                               }\r
+                                       }\r
+                                       break;\r
+                       }\r
+                       \r
+                       if (len > 0) {\r
+                               crc.Update(b, off, len);\r
+                       }\r
+                       \r
+                       if (finished) {\r
+                               if ((crc.Value & 0xFFFFFFFFL) != entry.Crc) {\r
+                                       throw new ZipException("CRC mismatch");\r
+                               }\r
+                               crc.Reset();\r
+                               entry = null;\r
+                       }\r
+                       return len;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Closes the zip file.\r
+               /// </summary>\r
+               /// <exception name="Exception">\r
+               /// if a i/o error occured.\r
+               /// </exception>\r
+               public override void Close()\r
+               {\r
+                       base.Close();\r
+                       crc = null;\r
+                       entry = null;\r
+               }\r
+       }\r
+}\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs
new file mode 100644 (file)
index 0000000..6a78b67
--- /dev/null
@@ -0,0 +1,509 @@
+// ZipOutputStream.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This file was translated from java, it was part of the GNU Classpath\r
+// Copyright (C) 2001 Free Software Foundation, Inc.\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+using System.IO;\r
+using System.Collections;\r
+using System.Text;\r
+\r
+using ICSharpCode.SharpZipLib.Checksums;\r
+using ICSharpCode.SharpZipLib.Zip.Compression;\r
+using ICSharpCode.SharpZipLib.Zip.Compression.Streams;\r
+\r
+namespace ICSharpCode.SharpZipLib.Zip {\r
+       \r
+       /// <summary>\r
+       /// This is a FilterOutputStream that writes the files into a zip\r
+       /// archive one after another.  It has a special method to start a new\r
+       /// zip entry.  The zip entries contains information about the file name\r
+       /// size, compressed size, CRC, etc.\r
+       /// \r
+       /// It includes support for STORED and DEFLATED entries.\r
+       /// This class is not thread safe.\r
+       /// \r
+       /// author of the original java version : Jochen Hoenicke\r
+       /// </summary>\r
+       /// <example> This sample shows how to create a zip file\r
+       /// <code>\r
+       /// using System;\r
+       /// using System.IO;\r
+       /// \r
+       /// using NZlib.Zip;\r
+       /// \r
+       /// class MainClass\r
+       /// {\r
+       ///     public static void Main(string[] args)\r
+       ///     {\r
+       ///             string[] filenames = Directory.GetFiles(args[0]);\r
+       ///             \r
+       ///             ZipOutputStream s = new ZipOutputStream(File.Create(args[1]));\r
+       ///             \r
+       ///             s.SetLevel(5); // 0 - store only to 9 - means best compression\r
+       ///             \r
+       ///             foreach (string file in filenames) {\r
+       ///                     FileStream fs = File.OpenRead(file);\r
+       ///                     \r
+       ///                     byte[] buffer = new byte[fs.Length];\r
+       ///                     fs.Read(buffer, 0, buffer.Length);\r
+       ///                     \r
+       ///                     ZipEntry entry = new ZipEntry(file);\r
+       ///                     \r
+       ///                     s.PutNextEntry(entry);\r
+       ///                     \r
+       ///                     s.Write(buffer, 0, buffer.Length);\r
+       ///                     \r
+       ///             }\r
+       ///             \r
+       ///             s.Finish();\r
+       ///             s.Close();\r
+       ///     }\r
+       /// }   \r
+       /// </code>\r
+       /// </example>\r
+       public class ZipOutputStream : DeflaterOutputStream\r
+       {\r
+               private ArrayList entries  = new ArrayList();\r
+               private Crc32     crc      = new Crc32();\r
+               private ZipEntry  curEntry = null;\r
+               \r
+               private CompressionMethod curMethod;\r
+               private int size;\r
+               private int offset = 0;\r
+               \r
+               private byte[] zipComment = new byte[0];\r
+               private int defaultMethod = DEFLATED;\r
+               \r
+               \r
+               /// <summary>\r
+               /// Our Zip version is hard coded to 1.0 resp. 2.0\r
+               /// </summary>\r
+               private const int ZIP_STORED_VERSION   = 10;\r
+               private const int ZIP_DEFLATED_VERSION = 20;\r
+               \r
+               /// <summary>\r
+               /// Compression method.  This method doesn't compress at all.\r
+               /// </summary>\r
+               public const int STORED      =  0;\r
+               \r
+               /// <summary>\r
+               /// Compression method.  This method uses the Deflater.\r
+               /// </summary>\r
+               public const int DEFLATED    =  8;\r
+               \r
+               /// <summary>\r
+               /// Creates a new Zip output stream, writing a zip archive.\r
+               /// </summary>\r
+               /// <param name="baseOutputStream">\r
+               /// the output stream to which the zip archive is written.\r
+               /// </param>\r
+               public ZipOutputStream(Stream baseOutputStream) : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true))\r
+               { \r
+               }\r
+               \r
+               /// <summary>\r
+               /// Set the zip file comment.\r
+               /// </summary>\r
+               /// <param name="comment">\r
+               /// the comment.\r
+               /// </param>\r
+               /// <exception name ="ArgumentException">\r
+               /// if UTF8 encoding of comment is longer than 0xffff bytes.\r
+               /// </exception>\r
+               public void SetComment(string comment)\r
+               {\r
+                       byte[] commentBytes = ZipConstants.ConvertToArray(comment);\r
+                       if (commentBytes.Length > 0xffff) {\r
+                               throw new ArgumentException("Comment too long.");\r
+                       }\r
+                       zipComment = commentBytes;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Sets default compression method.  If the Zip entry specifies\r
+               /// another method its method takes precedence.\r
+               /// </summary>\r
+               /// <param name = "method">\r
+               /// the method.\r
+               /// </param>\r
+               /// <exception name = "ArgumentException">\r
+               /// if method is not supported.\r
+               /// </exception>\r
+               public void SetMethod(int method)\r
+               {\r
+                       if (method != STORED && method != DEFLATED) {\r
+                               throw new ArgumentException("Method not supported.");\r
+                       }\r
+                       defaultMethod = method;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Sets default compression level.  The new level will be activated\r
+               /// immediately.\r
+               /// </summary>\r
+               /// <exception cref="System.ArgumentOutOfRangeException">\r
+               /// if level is not supported.\r
+               /// </exception>\r
+               /// <see cref="Deflater"/>\r
+               public void SetLevel(int level)\r
+               {\r
+                       def.SetLevel(level);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Write an unsigned short in little endian byte order.\r
+               /// </summary>\r
+               private  void WriteLeShort(int value)\r
+               {\r
+                       baseOutputStream.WriteByte((byte)value);\r
+                       baseOutputStream.WriteByte((byte)(value >> 8));\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Write an int in little endian byte order.\r
+               /// </summary>\r
+               private void WriteLeInt(int value)\r
+               {\r
+                       WriteLeShort(value);\r
+                       WriteLeShort(value >> 16);\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Write an int in little endian byte order.\r
+               /// </summary>\r
+               private void WriteLeLong(long value)\r
+               {\r
+                       WriteLeInt((int)value);\r
+                       WriteLeInt((int)(value >> 32));\r
+               }\r
+               \r
+               \r
+               bool shouldWriteBack = false;\r
+               long seekPos         = -1;\r
+               /// <summary>\r
+               /// Starts a new Zip entry. It automatically closes the previous\r
+               /// entry if present.  If the compression method is stored, the entry\r
+               /// must have a valid size and crc, otherwise all elements (except\r
+               /// name) are optional, but must be correct if present.  If the time\r
+               /// is not set in the entry, the current time is used.\r
+               /// </summary>\r
+               /// <param name="entry">\r
+               /// the entry.\r
+               /// </param>\r
+               /// <exception cref="System.IO.IOException">\r
+               /// if an I/O error occured.\r
+               /// </exception>\r
+               /// <exception cref="System.InvalidOperationException">\r
+               /// if stream was finished\r
+               /// </exception>\r
+               public void PutNextEntry(ZipEntry entry)\r
+               {\r
+                       if (entries == null) {\r
+                               throw new InvalidOperationException("ZipOutputStream was finished");\r
+                       }\r
+                       \r
+                       CompressionMethod method = entry.CompressionMethod;\r
+                       int flags = 0;\r
+                       \r
+                       switch (method) {\r
+                               case CompressionMethod.Stored:\r
+                                       if (entry.CompressedSize >= 0) {\r
+                                               if (entry.Size < 0) {\r
+                                                       entry.Size = entry.CompressedSize;\r
+                                               } else if (entry.Size != entry.CompressedSize) {\r
+                                                       throw new ZipException("Method STORED, but compressed size != size");\r
+                                               }\r
+                                       } else {\r
+                                               entry.CompressedSize = entry.Size;\r
+                                       }\r
+                                       \r
+                                       if (entry.Size < 0) {\r
+                                               throw new ZipException("Method STORED, but size not set");\r
+                                       } else if (entry.Crc < 0) {\r
+                                               throw new ZipException("Method STORED, but crc not set");\r
+                                       }\r
+                                       break;\r
+                               case CompressionMethod.Deflated:\r
+                                       if (entry.CompressedSize < 0 || entry.Size < 0 || entry.Crc < 0) {\r
+                                               flags |= 8;\r
+                                       }\r
+                                       break;\r
+                       }\r
+                       \r
+                       if (curEntry != null) {\r
+                               CloseEntry();\r
+                       }\r
+                       \r
+//                     if (entry.DosTime < 0) {\r
+//                             entry.Time = System.Environment.TickCount;\r
+//                     }\r
+                       \r
+                       entry.flags  = flags;\r
+                       entry.offset = offset;\r
+                       entry.CompressionMethod = (CompressionMethod)method;\r
+                       \r
+                       curMethod    = method;\r
+                       // Write the local file header\r
+                       WriteLeInt(ZipConstants.LOCSIG);\r
+                       \r
+                       // write ZIP version\r
+                       WriteLeShort(method == CompressionMethod.Stored ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION);\r
+                       if ((flags & 8) == 0) {\r
+                               WriteLeShort(flags);\r
+                               WriteLeShort((byte)method);\r
+                               WriteLeInt(entry.DosTime);\r
+                               WriteLeInt((int)entry.Crc);\r
+                               WriteLeInt((int)entry.CompressedSize);\r
+                               WriteLeInt((int)entry.Size);\r
+                       } else {\r
+                               if (baseOutputStream.CanSeek) {\r
+                                       shouldWriteBack = true;\r
+                                       WriteLeShort((short)(flags & ~8));\r
+                               } else {\r
+                                       shouldWriteBack = false;\r
+                                       WriteLeShort(flags);\r
+                               }\r
+                               WriteLeShort((byte)method);\r
+                               WriteLeInt(entry.DosTime);\r
+                               seekPos = baseOutputStream.Position;\r
+                               WriteLeInt(0);\r
+                               WriteLeInt(0);\r
+                               WriteLeInt(0);\r
+                       }\r
+                       byte[] name = ZipConstants.ConvertToArray(entry.Name);\r
+                       \r
+                       if (name.Length > 0xFFFF) {\r
+                               throw new ZipException("Name too long.");\r
+                       }\r
+                       byte[] extra = entry.ExtraData;\r
+                       if (extra == null) {\r
+                               extra = new byte[0];\r
+                       }\r
+                       if (extra.Length > 0xFFFF) {\r
+                               throw new ZipException("Extra data too long.");\r
+                       }\r
+                       \r
+                       WriteLeShort(name.Length);\r
+                       WriteLeShort(extra.Length);\r
+                       baseOutputStream.Write(name, 0, name.Length);\r
+                       baseOutputStream.Write(extra, 0, extra.Length);\r
+                       \r
+                       offset += ZipConstants.LOCHDR + name.Length + extra.Length;\r
+                       \r
+                       /* Activate the entry. */\r
+                       curEntry = entry;\r
+                       crc.Reset();\r
+                       if (method == CompressionMethod.Deflated) {\r
+                               def.Reset();\r
+                       }\r
+                       size = 0;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Closes the current entry.\r
+               /// </summary>\r
+               /// <exception cref="System.IO.IOException">\r
+               /// if an I/O error occured.\r
+               /// </exception>\r
+               /// <exception cref="System.InvalidOperationException">\r
+               /// if no entry is active.\r
+               /// </exception>\r
+               public void CloseEntry()\r
+               {\r
+                       if (curEntry == null) {\r
+                               throw new InvalidOperationException("No open entry");\r
+                       }\r
+                       \r
+                       /* First finish the deflater, if appropriate */\r
+                       if (curMethod == CompressionMethod.Deflated) {\r
+                               base.Finish();\r
+                       }\r
+                       \r
+                       int csize = curMethod == CompressionMethod.Deflated ? def.TotalOut : size;\r
+                       \r
+                       if (curEntry.Size < 0) {\r
+                               curEntry.Size = size;\r
+                       } else if (curEntry.Size != size) {\r
+                               throw new ZipException("size was " + size +\r
+                                                      ", but I expected " + curEntry.Size);\r
+                       }\r
+                       \r
+                       if (curEntry.CompressedSize < 0) {\r
+                               curEntry.CompressedSize = csize;\r
+                       } else if (curEntry.CompressedSize != csize) {\r
+                               throw new ZipException("compressed size was " + csize + \r
+                                                      ", but I expected " + curEntry.CompressedSize);\r
+                       }\r
+                       \r
+                       if (curEntry.Crc < 0) {\r
+                               curEntry.Crc = crc.Value;\r
+                       } else if (curEntry.Crc != crc.Value) {\r
+                               throw new ZipException("crc was " + crc.Value +\r
+                                                      ", but I expected " + \r
+                                                      curEntry.Crc);\r
+                       }\r
+                       \r
+                       offset += csize;\r
+                       \r
+                       /* Now write the data descriptor entry if needed. */\r
+                       if (curMethod == CompressionMethod.Deflated && (curEntry.flags & 8) != 0) {\r
+                               if (shouldWriteBack) {\r
+                                       long curPos = baseOutputStream.Position;\r
+                                       baseOutputStream.Seek(seekPos, SeekOrigin.Begin);\r
+                                       WriteLeInt((int)curEntry.Crc);\r
+                                       WriteLeInt((int)curEntry.CompressedSize);\r
+                                       WriteLeInt((int)curEntry.Size);\r
+                                       baseOutputStream.Seek(curPos, SeekOrigin.Begin);\r
+                                       shouldWriteBack = false;\r
+                               } else {\r
+                                       WriteLeInt(ZipConstants.EXTSIG);\r
+                                       WriteLeInt((int)curEntry.Crc);\r
+                                       WriteLeInt((int)curEntry.CompressedSize);\r
+                                       WriteLeInt((int)curEntry.Size);\r
+                                       offset += ZipConstants.EXTHDR;\r
+                               }\r
+                       }\r
+                       \r
+                       entries.Add(curEntry);\r
+                       curEntry = null;\r
+               }\r
+           \r
+           \r
+               /// <summary>\r
+               /// Writes the given buffer to the current entry.\r
+               /// </summary>\r
+               /// <exception cref="System.IO.IOException">\r
+               /// if an I/O error occured.\r
+               /// </exception>\r
+               /// <exception cref="System.InvalidOperationException">\r
+               /// if no entry is active.\r
+               /// </exception>\r
+               public override void Write(byte[] b, int off, int len)\r
+               {\r
+                       if (curEntry == null) {\r
+                               throw new InvalidOperationException("No open entry.");\r
+                       }\r
+                       \r
+                       switch (curMethod) {\r
+                               case CompressionMethod.Deflated:\r
+                                       base.Write(b, off, len);\r
+                                       break;\r
+                               case CompressionMethod.Stored:\r
+                                       baseOutputStream.Write(b, off, len);\r
+                                       break;\r
+                       }\r
+                       \r
+                       crc.Update(b, off, len);\r
+                       size += len;\r
+               }\r
+               \r
+           \r
+               /// <summary>\r
+               /// Finishes the stream.  This will write the central directory at the\r
+               /// end of the zip file and flush the stream.\r
+               /// </summary>\r
+               /// <exception cref="System.IO.IOException">\r
+               /// if an I/O error occured.\r
+               /// </exception>\r
+           public override void Finish()\r
+           {\r
+               if (entries == null) {\r
+                       return;\r
+               }\r
+               if (curEntry != null) {\r
+                       CloseEntry();\r
+               }\r
+               \r
+               int numEntries = 0;\r
+               int sizeEntries = 0;\r
+               \r
+               foreach (ZipEntry entry in entries) {\r
+                       // TODO : check the appnote file for compilance with the central directory standard\r
+                       CompressionMethod method = entry.CompressionMethod;\r
+                       WriteLeInt(ZipConstants.CENSIG); \r
+                       WriteLeShort(method == CompressionMethod.Stored ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION);\r
+                       WriteLeShort(method == CompressionMethod.Stored ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION);\r
+                       WriteLeShort(entry.flags);\r
+                       WriteLeShort((short)method);\r
+                       WriteLeInt(entry.DosTime);\r
+                       WriteLeInt((int)entry.Crc);\r
+                       WriteLeInt((int)entry.CompressedSize);\r
+                       WriteLeInt((int)entry.Size);\r
+                       \r
+                       byte[] name = ZipConstants.ConvertToArray(entry.Name);\r
+                       \r
+                       if (name.Length > 0xffff) {\r
+                               throw new ZipException("Name too long.");\r
+                       }\r
+                       byte[] extra = entry.ExtraData;\r
+                       if (extra == null) {\r
+                               extra = new byte[0];\r
+                       }\r
+                       string strComment = entry.Comment;\r
+                       byte[] comment = strComment != null ? ZipConstants.ConvertToArray(strComment) : new byte[0];\r
+                       if (comment.Length > 0xffff) {\r
+                               throw new ZipException("Comment too long.");\r
+                       }\r
+                       \r
+                       WriteLeShort(name.Length);\r
+                       WriteLeShort(extra.Length);\r
+                       WriteLeShort(comment.Length);\r
+                       WriteLeShort(0); /* disk number */\r
+                       WriteLeShort(0); /* internal file attr */\r
+                       WriteLeInt(0);   /* external file attr */\r
+                       WriteLeInt(entry.offset);\r
+                       \r
+                       baseOutputStream.Write(name,    0, name.Length);\r
+                       baseOutputStream.Write(extra,   0, extra.Length);\r
+                       baseOutputStream.Write(comment, 0, comment.Length);\r
+                       ++numEntries;\r
+                       sizeEntries += ZipConstants.CENHDR + name.Length + extra.Length + comment.Length;\r
+               }\r
+               \r
+               WriteLeInt(ZipConstants.ENDSIG);\r
+               WriteLeShort(0); /* disk number */\r
+               WriteLeShort(0); /* disk with start of central dir */\r
+               WriteLeShort(numEntries);\r
+               WriteLeShort(numEntries);\r
+               WriteLeInt(sizeEntries);\r
+               WriteLeInt(offset);\r
+               WriteLeShort(zipComment.Length);\r
+               baseOutputStream.Write(zipComment, 0, zipComment.Length);\r
+               baseOutputStream.Flush();\r
+               entries = null;\r
+           }\r
+       }\r
+}\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/ZipException.cs b/mcs/class/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib/ZipException.cs
new file mode 100644 (file)
index 0000000..97362e8
--- /dev/null
@@ -0,0 +1,61 @@
+// ZipException.cs\r
+// Copyright (C) 2001 Mike Krueger\r
+//\r
+// This file was translated from java, it was part of the GNU Classpath\r
+// Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.\r
+//\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+//\r
+// Linking this library statically or dynamically with other modules is\r
+// making a combined work based on this library.  Thus, the terms and\r
+// conditions of the GNU General Public License cover the whole\r
+// combination.\r
+// \r
+// As a special exception, the copyright holders of this library give you\r
+// permission to link this library with independent modules to produce an\r
+// executable, regardless of the license terms of these independent\r
+// modules, and to copy and distribute the resulting executable under\r
+// terms of your choice, provided that you also meet, for each linked\r
+// independent module, the terms and conditions of the license of that\r
+// module.  An independent module is a module which is not derived from\r
+// or based on this library.  If you modify this library, you may extend\r
+// this exception to your version of the library, but you are not\r
+// obligated to do so.  If you do not wish to do so, delete this\r
+// exception statement from your version.\r
+\r
+using System;\r
+\r
+namespace ICSharpCode.SharpZipLib {\r
+       \r
+       /// <summary>\r
+       /// Is thrown during the creation or input of a zip file.\r
+       /// </summary>\r
+       public class ZipException : Exception\r
+       {\r
+               /// <summary>\r
+               /// Initializes a new instance of the ZipException class with default properties.\r
+               /// </summary>\r
+               public ZipException()\r
+               {\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Initializes a new instance of the ZipException class with a specified error message.\r
+               /// </summary>\r
+               public ZipException(string msg) : base(msg)\r
+               {\r
+               }\r
+       }\r
+}\r
diff --git a/mcs/class/ICSharpCode.SharpZipLib/README b/mcs/class/ICSharpCode.SharpZipLib/README
new file mode 100644 (file)
index 0000000..19f0f25
--- /dev/null
@@ -0,0 +1,21 @@
+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/ICSharpCode.SharpZipLib/SharpZipLib.build b/mcs/class/ICSharpCode.SharpZipLib/SharpZipLib.build
new file mode 100644 (file)
index 0000000..2ecb427
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<!-- NAnt build file for System.Data.dll -->
+
+<project name="System.Data" default="build">
+       <property name="debug" value="false"/>
+
+       <target name="build">
+               <csc target="library" output="../lib/ICSharpCode.SharpZipLib.dll" debug="${debug}">
+                       <arg value="/nowarn:1595"/>
+                       <arg value="/nowarn:0067"/>
+                       <arg value="/nowarn:0109"/>
+                       <arg value="/nowarn:0169"/>
+                       <arg value="/nowarn:0679"/>
+                       <arg value="/nowarn:0649"/>
+                       <arg value="/unsafe"/>
+                       <arg value="/noconfig"/>
+                       <arg value="/r:System.dll"/>
+                       <arg value="/r:System.Xml.dll"/>
+                       <sources>
+                               <includes name="**/*.cs"/> 
+                               <includes name="**/**/*.cs"/>
+                       </sources>
+                       <references>
+                               <includes name="../lib/corlib.dll"/>
+                               <includes name="../lib/System.dll"/>
+                               <includes name="../lib/System.Xml.dll"/>
+                       </references>
+               </csc>
+       </target>
+       <target name="test" depends="build">
+               <nant basedir="Test" target="test"/>
+       </target>
+       <target name="clean">
+               <delete file="../lib/ICSharpCode.SharpZipLib.dll" failonerror="false"/>
+       </target>
+</project>
diff --git a/mcs/class/ICSharpCode.SharpZipLib/list b/mcs/class/ICSharpCode.SharpZipLib/list
new file mode 100644 (file)
index 0000000..98de302
--- /dev/null
@@ -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/ICSharpCode.SharpZipLib/makefile.gnu b/mcs/class/ICSharpCode.SharpZipLib/makefile.gnu
new file mode 100644 (file)
index 0000000..2d5715b
--- /dev/null
@@ -0,0 +1,14 @@
+topdir = ../..
+
+TEST_DIR= 
+LIBRARY = $(topdir)/class/lib/ICSharpCode.SharpZipLib.dll
+
+LIB_LIST = list
+LIB_FLAGS = -r corlib -r System -r System.Xml
+
+SOURCES_INCLUDE=*.cs
+SOURCES_EXCLUDE=
+
+export MONO_PATH_PREFIX = $(topdir)/class/lib:
+
+include $(topdir)/class/library.make