| 1: | // BZip2InputStream.cs | |
| 2: | // Copyright (C) 2001 Mike Krueger | |
| 3: | // | |
| 4: | // This program is free software; you can redistribute it and/or | |
| 5: | // modify it under the terms of the GNU General Public License | |
| 6: | // as published by the Free Software Foundation; either version 2 | |
| 7: | // of the License, or (at your option) any later version. | |
| 8: | // | |
| 9: | // This program is distributed in the hope that it will be useful, | |
| 10: | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11: | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12: | // GNU General Public License for more details. | |
| 13: | // | |
| 14: | // You should have received a copy of the GNU General Public License | |
| 15: | // along with this program; if not, write to the Free Software | |
| 16: | // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
| 17: | // | |
| 18: | // Linking this library statically or dynamically with other modules is | |
| 19: | // making a combined work based on this library. Thus, the terms and | |
| 20: | // conditions of the GNU General Public License cover the whole | |
| 21: | // combination. | |
| 22: | // | |
| 23: | // As a special exception, the copyright holders of this library give you | |
| 24: | // permission to link this library with independent modules to produce an | |
| 25: | // executable, regardless of the license terms of these independent | |
| 26: | // modules, and to copy and distribute the resulting executable under | |
| 27: | // terms of your choice, provided that you also meet, for each linked | |
| 28: | // independent module, the terms and conditions of the license of that | |
| 29: | // module. An independent module is a module which is not derived from | |
| 30: | // or based on this library. If you modify this library, you may extend | |
| 31: | // this exception to your version of the library, but you are not | |
| 32: | // obligated to do so. If you do not wish to do so, delete this | |
| 33: | // exception statement from your version. | |
| 34: | ||
| 35: | using System; | |
| 36: | using System.IO; | |
| 37: | ||
| 38: | using ICSharpCode.SharpZipLib.Checksums; | |
| 39: | ||
| 40: | namespace ICSharpCode.SharpZipLib.BZip2 { | |
| 41: | ||
| 42: | /// <summary> | |
| 43: | /// An input stream that decompresses from the BZip2 format (without the file | |
| 44: | /// header chars) to be read as any other stream. | |
| 45: | /// </summary> | |
| 46: | public class BZip2InputStream : Stream | |
| 47: | { | |
| 48: | /// <summary> | |
| 49: | /// I needed to implement the abstract member. | |
| 50: | /// </summary> | |
| 51: | public override bool CanRead { | |
| 52: | get { | |
| 53: | return baseStream.CanRead; | |
| 54: | } | |
| 55: | } | |
| 56: | ||
| 57: | /// <summary> | |
| 58: | /// I needed to implement the abstract member. | |
| 59: | /// </summary> | |
| 60: | public override bool CanSeek { | |
| 61: | get { | |
| 62: | return baseStream.CanSeek; | |
| 63: | } | |
| 64: | } | |
| 65: | ||
| 66: | /// <summary> | |
| 67: | /// I needed to implement the abstract member. | |
| 68: | /// </summary> | |
| 69: | public override bool CanWrite { | |
| 70: | get { | |
| 71: | return baseStream.CanWrite; | |
| 72: | } | |
| 73: | } | |
| 74: | ||
| 75: | /// <summary> | |
| 76: | /// I needed to implement the abstract member. | |
| 77: | /// </summary> | |
| 78: | public override long Length { | |
| 79: | get { | |
| 80: | return baseStream.Length; | |
| 81: | } | |
| 82: | } | |
| 83: | ||
| 84: | /// <summary> | |
| 85: | /// I needed to implement the abstract member. | |
| 86: | /// </summary> | |
| 87: | public override long Position { | |
| 88: | get { | |
| 89: | return baseStream.Position; | |
| 90: | } | |
| 91: | set { | |
| 92: | baseStream.Position = value; | |
| 93: | } | |
| 94: | } | |
| 95: | ||
| 96: | /// <summary> | |
| 97: | /// Flushes the baseInputStream | |
| 98: | /// </summary> | |
| 99: | public override void Flush() | |
| 100: | { | |
| 101: | if (baseStream != null) { | |
| 102: | baseStream.Flush(); | |
| 103: | } | |
| 104: | } | |
| 105: | ||
| 106: | /// <summary> | |
| 107: | /// I needed to implement the abstract member. | |
| 108: | /// </summary> | |
| 109: | public override long Seek(long offset, SeekOrigin origin) | |
| 110: | { | |
| 111: | return baseStream.Seek(offset, origin); | |
| 112: | } | |
| 113: | ||
| 114: | /// <summary> | |
| 115: | /// I needed to implement the abstract member. | |
| 116: | /// </summary> | |
| 117: | public override void SetLength(long val) | |
| 118: | { | |
| 119: | baseStream.SetLength(val); | |
| 120: | } | |
| 121: | ||
| 122: | /// <summary> | |
| 123: | /// I needed to implement the abstract member. | |
| 124: | /// </summary> | |
| 125: | public override void Write(byte[] array, int offset, int count) | |
| 126: | { | |
| 127: | baseStream.Write(array, offset, count); | |
| 128: | } | |
| 129: | ||
| 130: | /// <summary> | |
| 131: | /// I needed to implement the abstract member. | |
| 132: | /// </summary> | |
| 133: | public override void WriteByte(byte val) | |
| 134: | { | |
| 135: | baseStream.WriteByte(val); | |
| 136: | } | |
| 137: | ||
| 138: | public override int Read(byte[] b, int off, int len) | |
| 139: | { | |
| 140: | for (int i = 0; i < len; ++i) { | |
| 141: | int rb = ReadByte(); | |
| 142: | if (rb == -1) { | |
| 143: | return i; | |
| 144: | } | |
| 145: | b[off + i] = (byte)rb; | |
| 146: | } | |
| 147: | return len; | |
| 148: | } | |
| 149: | ||
| 150: | /// <summary> | |
| 151: | /// Closes the input stream | |
| 152: | /// </summary> | |
| 153: | public override void Close() | |
| 154: | { | |
| 155: | if (baseStream != null) { | |
| 156: | baseStream.Close(); | |
| 157: | } | |
| 158: | } | |
| 159: | ||
| 160: | static void Cadvise() | |
| 161: | { | |
| 162: | Console.WriteLine("CRC Error"); | |
| 163: | //throw new CCoruptionError(); | |
| 164: | } | |
| 165: | ||
| 166: | static void BadBGLengths() | |
| 167: | { | |
| 168: | Console.WriteLine("bad BG lengths"); | |
| 169: | } | |
| 170: | ||
| 171: | static void bitStreamEOF() | |
| 172: | { | |
| 173: | Console.WriteLine("bit stream eof"); | |
| 174: | } | |
| 175: | ||
| 176: | static void CompressedStreamEOF() | |
| 177: | { | |
| 178: | Console.WriteLine("compressed stream eof"); | |
| 179: | } | |
| 180: | ||
| 181: | void MakeMaps() | |
| 182: | { | |
| 183: | nInUse = 0; | |
| 184: | for (int i = 0; i < 256; ++i) { | |
| 185: | if (inUse[i]) { | |
| 186: | seqToUnseq[nInUse] = (byte)i; | |
| 187: | unseqToSeq[i] = (byte)nInUse; | |
| 188: | nInUse++; | |
| 189: | } | |
| 190: | } | |
| 191: | } | |
| 192: | ||
| 193: | /*-- | |
| 194: | index of the last char in the block, so | |
| 195: | the block size == last + 1. | |
| 196: | --*/ | |
| 197: | int last; | |
| 198: | ||
| 199: | /*-- | |
| 200: | index in zptr[] of original string after sorting. | |
| 201: | --*/ | |
| 202: | int origPtr; | |
| 203: | ||
| 204: | /*-- | |
| 205: | always: in the range 0 .. 9. | |
| 206: | The current block size is 100000 * this number. | |
| 207: | --*/ | |
| 208: | int blockSize100k; | |
| 209: | ||
| 210: | bool blockRandomised; | |
| 211: | ||
| 212: | // private int bytesIn; | |
| 213: | // private int bytesOut; | |
| 214: | int bsBuff; | |
| 215: | int bsLive; | |
| 216: | IChecksum mCrc = new StrangeCRC(); | |
| 217: | ||
| 218: | bool[] inUse = new bool[256]; | |
| 219: | int nInUse; | |
| 220: | ||
| 221: | byte[] seqToUnseq = new byte[256]; | |
| 222: | byte[] unseqToSeq = new byte[256]; | |
| 223: | ||
| 224: | byte[] selector = new byte[BZip2Constants.MAX_SELECTORS]; | |
| 225: | byte[] selectorMtf = new byte[BZip2Constants.MAX_SELECTORS]; | |
| 226: | ||
| 227: | int[] tt; | |
| 228: | byte[] ll8; | |
| 229: | ||
| 230: | /*-- | |
| 231: | freq table collected to save a pass over the data | |
| 232: | during decompression. | |
| 233: | --*/ | |
| 234: | int[] unzftab = new int[256]; | |
| 235: | ||
| 236: | int[][] limit = new int[BZip2Constants.N_GROUPS][]; | |
| 237: | int[][] baseArray = new int[BZip2Constants.N_GROUPS][]; | |
| 238: | int[][] perm = new int[BZip2Constants.N_GROUPS][]; | |
| 239: | int[] minLens = new int[BZip2Constants.N_GROUPS]; | |
| 240: | ||
| 241: | Stream baseStream; | |
| 242: | bool streamEnd = false; | |
| 243: | ||
| 244: | int currentChar = -1; | |
| 245: | ||
| 246: | const int START_BLOCK_STATE = 1; | |
| 247: | const int RAND_PART_A_STATE = 2; | |
| 248: | const int RAND_PART_B_STATE = 3; | |
| 249: | const int RAND_PART_C_STATE = 4; | |
| 250: | const int NO_RAND_PART_A_STATE = 5; | |
| 251: | const int NO_RAND_PART_B_STATE = 6; | |
| 252: | const int NO_RAND_PART_C_STATE = 7; | |
| 253: | ||
| 254: | int currentState = START_BLOCK_STATE; | |
| 255: | ||
| 256: | int storedBlockCRC, storedCombinedCRC; | |
| 257: | int computedBlockCRC; | |
| 258: | uint computedCombinedCRC; | |
| 259: | ||
| 260: | int count, chPrev, ch2; | |
| 261: | int tPos; | |
| 262: | int rNToGo = 0; | |
| 263: | int rTPos = 0; | |
| 264: | int i2, j2; | |
| 265: | byte z; | |
| 266: | ||
| 267: | public BZip2InputStream(Stream zStream) | |
| 268: | { | |
| 269: | // init arrays | |
| 270: | for (int i = 0; i < BZip2Constants.N_GROUPS; ++i) { | |
| 271: | limit[i] = new int[BZip2Constants.MAX_ALPHA_SIZE]; | |
| 272: | baseArray[i] = new int[BZip2Constants.MAX_ALPHA_SIZE]; | |
| 273: | perm[i] = new int[BZip2Constants.MAX_ALPHA_SIZE]; | |
| 274: | } | |
| 275: | ||
| 276: | ll8 = null; | |
| 277: | tt = null; | |
| 278: | BsSetStream(zStream); | |
| 279: | Initialize(); | |
| 280: | InitBlock(); | |
| 281: | SetupBlock(); | |
| 282: | } | |
| 283: | ||
| 284: | public override int ReadByte() | |
| 285: | { | |
| 286: | if (streamEnd) { | |
| 287: | return -1; | |
| 288: | } | |
| 289: | ||
| 290: | int retChar = currentChar; | |
| 291: | switch (currentState) { | |
| 292: | case RAND_PART_B_STATE: | |
| 293: | SetupRandPartB(); | |
| 294: | break; | |
| 295: | case RAND_PART_C_STATE: | |
| 296: | SetupRandPartC(); | |
| 297: | break; | |
| 298: | case NO_RAND_PART_B_STATE: | |
| 299: | SetupNoRandPartB(); | |
| 300: | break; | |
| 301: | case NO_RAND_PART_C_STATE: | |
| 302: | SetupNoRandPartC(); | |
| 303: | break; | |
| 304: | case START_BLOCK_STATE: | |
| 305: | case NO_RAND_PART_A_STATE: | |
| 306: | case RAND_PART_A_STATE: | |
| 307: | break; | |
| 308: | default: | |
| 309: | break; | |
| 310: | } | |
| 311: | return retChar; | |
| 312: | } | |
| 313: | ||
| 314: | void Initialize() | |
| 315: | { | |
| 316: | char magic3 = BsGetUChar(); | |
| 317: | char magic4 = BsGetUChar(); | |
| 318: | ||
| 319: | if (magic3 != 'h' || magic4 < '1' || magic4 > '9') { | |
| 320: | streamEnd = true; | |
| 321: | return; | |
| 322: | } | |
| 323: | ||
| 324: | SetDecompressStructureSizes(magic4 - '0'); | |
| 325: | computedCombinedCRC = 0; | |
| 326: | } | |
| 327: | ||
| 328: | void InitBlock() | |
| 329: | { | |
| 330: | char magic1 = BsGetUChar(); | |
| 331: | char magic2 = BsGetUChar(); | |
| 332: | char magic3 = BsGetUChar(); | |
| 333: | char magic4 = BsGetUChar(); | |
| 334: | char magic5 = BsGetUChar(); | |
| 335: | char magic6 = BsGetUChar(); | |
| 336: | ||
| 337: | if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45 && magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) { | |
| 338: | Complete(); | |
| 339: | return; | |
| 340: | } | |
| 341: | ||
| 342: | if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) { | |
| 343: | BadBlockHeader(); | |
| 344: | streamEnd = true; | |
| 345: | return; | |
| 346: | } | |
| 347: | ||
| 348: | storedBlockCRC = BsGetInt32(); | |
| 349: | ||
| 350: | blockRandomised = (BsR(1) == 1); | |
| 351: | ||
| 352: | // currBlockNo++; | |
| 353: | GetAndMoveToFrontDecode(); | |
| 354: | ||
| 355: | mCrc.Reset(); | |
| 356: | currentState = START_BLOCK_STATE; | |
| 357: | } | |
| 358: | ||
| 359: | void EndBlock() | |
| 360: | { | |
| 361: | computedBlockCRC = (int)mCrc.Value; | |
| 362: | ||
| 363: | /*-- A bad CRC is considered a fatal error. --*/ | |
| 364: | if (storedBlockCRC != computedBlockCRC) { | |
| 365: | CrcError(); | |
| 366: | } | |
| 367: | ||
| 368: | // 1528150659 | |
| 369: | computedCombinedCRC = ((computedCombinedCRC << 1) & 0xFFFFFFFF) | (computedCombinedCRC >> 31); | |
| 370: | computedCombinedCRC = computedCombinedCRC ^ (uint)computedBlockCRC; | |
| 371: | } | |
| 372: | ||
| 373: | void Complete() | |
| 374: | { | |
| 375: | storedCombinedCRC = BsGetInt32(); | |
| 376: | if (storedCombinedCRC != (int)computedCombinedCRC) { | |
| 377: | CrcError(); | |
| 378: | } | |
| 379: | ||
| 380: | streamEnd = true; | |
| 381: | } | |
| 382: | ||
| 383: | static void BlockOverrun() | |
| 384: | { | |
| 385: | Console.WriteLine("Block overrun"); | |
| 386: | } | |
| 387: | ||
| 388: | static void BadBlockHeader() | |
| 389: | { | |
| 390: | Console.WriteLine("Bad block header"); | |
| 391: | } | |
| 392: | ||
| 393: | static void CrcError() | |
| 394: | { | |
| 395: | Console.WriteLine("crc error"); | |
| 396: | } | |
| 397: | ||
| 398: | ||
| 399: | void BsSetStream(Stream f) | |
| 400: | { | |
| 401: | baseStream = f; | |
| 402: | bsLive = 0; | |
| 403: | bsBuff = 0; | |
| 404: | } | |
| 405: | ||
| 406: | void FillBuffer() | |
| 407: | { | |
| 408: | int thech = 0; | |
| 409: | ||
| 410: | try { | |
| 411: | thech = baseStream.ReadByte(); | |
| 412: | } catch (Exception) { | |
| 413: | CompressedStreamEOF(); | |
| 414: | } | |
| 415: | ||
| 416: | if (thech == -1) { | |
| 417: | CompressedStreamEOF(); | |
| 418: | } | |
| 419: | ||
| 420: | bsBuff = (bsBuff << 8) | (thech & 0xFF); | |