context: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements. See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License. You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  
  /*
   * This package is based on the work done by Keiron Liddle, Aftex Software
   * <keiron@aftexsw.com> to whom the Ant project is very grateful for his
   * great code.
   */
  
  using System.IO;
  
  namespace Org.BouncyCastle.Apache.Bzip2
  {
  	/**
      * An input stream that decompresses from the BZip2 format (with the file
      * header chars) to be read as any other stream.
      *
      * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
      *
      * <b>NB:</b> note this class has been modified to read the leading BZ from the
      * start of the BZIP2 stream to make it compatible with other PGP programs.
      */
      public class CBZip2InputStream : Stream 
  	{
          private static void Cadvise() {
              //System.out.Println("CRC Error");
              //throw new CCoruptionError();
          }
  
  //        private static void BadBGLengths() {
  //            Cadvise();
  //        }
  //
  //        private static void BitStreamEOF() {
  //            Cadvise();
  //        }
  
          private static void CompressedStreamEOF() {
              Cadvise();
          }
  
          private void MakeMaps() {
              int i;
              nInUse = 0;
              for (i = 0; i < 256; i++) {
                  if (inUse[i]) {
                      seqToUnseq[nInUse] = (char) i;
                      unseqToSeq[i] = (char) nInUse;
                      nInUse++;
                  }
              }
          }
  
          /*
          index of the last char in the block, so
          the block size == last + 1.
          */
          private int  last;
  
          /*
          index in zptr[] of original string after sorting.
          */
          private int  origPtr;
  
          /*
          always: in the range 0 .. 9.
          The current block size is 100000 * this number.
          */
          private int blockSize100k;
  
          private bool blockRandomised;
  
          private int bsBuff;
          private int bsLive;
          private CRC mCrc = new CRC();
  
          private bool[] inUse = new bool[256];
          private int nInUse;
  
          private char[] seqToUnseq = new char[256];
          private char[] unseqToSeq = new char[256];
  
          private char[] selector = new char[BZip2Constants.MAX_SELECTORS];
          private char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS];
  
          private int[] tt;
          private char[] ll8;
  
          /*
          freq table collected to save a pass over the data
          during decompression.
          */
          private int[] unzftab = new int[256];
  
          private int[][] limit = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
          private int[][] basev = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
          private int[][] perm = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
          private int[] minLens = new int[BZip2Constants.N_GROUPS];
  
          private Stream bsStream;
  
          private bool streamEnd = false;
  
          private int currentChar = -1;
  
          private const int START_BLOCK_STATE = 1;
          private const int RAND_PART_A_STATE = 2;
          private const int RAND_PART_B_STATE = 3;
          private const int RAND_PART_C_STATE = 4;
          private const int NO_RAND_PART_A_STATE = 5;
          private const int NO_RAND_PART_B_STATE = 6;
          private const int NO_RAND_PART_C_STATE = 7;
  
          private int currentState = START_BLOCK_STATE;
  
          private int storedBlockCRC, storedCombinedCRC;
          private int computedBlockCRC, computedCombinedCRC;
  
          int i2, count, chPrev, ch2;
          int i, tPos;
          int rNToGo = 0;
          int rTPos  = 0;
          int j2;
          char z;
  
          public CBZip2InputStream(Stream zStream) {
              ll8 = null;
              tt = null;
              BsSetStream(zStream);
              Initialize();
              InitBlock();
              SetupBlock();
          }
  
          internal static int[][] InitIntArray(int n1, int n2) {
              int[][] a = new int[n1][];
              for (int k = 0; k < n1; ++k) {
                  a[k] = new int[n2];
              }
              return a;
          }
  
          internal static char[][] InitCharArray(int n1, int n2) {
              char[][] a = new char[n1][];
              for (int k = 0; k < n1; ++k) {
                  a[k] = new char[n2];
              }
              return a;
          }
  
          public override int ReadByte() {
              if (streamEnd) {
                  return -1;
              } else {
                  int retChar = currentChar;
                  switch (currentState) {
                  case START_BLOCK_STATE:
                      break;
                  case RAND_PART_A_STATE:
                      break;
                  case RAND_PART_B_STATE:
                      SetupRandPartB();
                      break;
                  case RAND_PART_C_STATE:
                      SetupRandPartC();
                      break;
                  case NO_RAND_PART_A_STATE:
                      break;
                  case NO_RAND_PART_B_STATE:
                      SetupNoRandPartB();
                      break;
                  case NO_RAND_PART_C_STATE:
                      SetupNoRandPartC();
                      break;
                  default:
                      break;
                  }
                  return retChar;
              }
          }
  
          private void Initialize() {
              char magic3, magic4;
              magic3 = BsGetUChar();
              magic4 = BsGetUChar();
              if (magic3 != 'B' && magic4 != 'Z')
              {
                  throw new IOException("Not a BZIP2 marked stream");
              }
              magic3 = BsGetUChar();
              magic4 = BsGetUChar();
              if (magic3 != 'h' || magic4 < '1' || magic4 > '9') {
                  BsFinishedWithStream();
                  streamEnd = true;
                  return;
              }
  
              SetDecompressStructureSizes(magic4 - '0');
              computedCombinedCRC = 0;
          }
  
          private void InitBlock() {
              char magic1, magic2, magic3, magic4;
              char magic5, magic6;
              magic1 = BsGetUChar();
              magic2 = BsGetUChar();
  
gt:             magic3 = BsGetUChar();