context: /*
  * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
  * Original author: Edmund Wagner
  * Creation date: 21.06.2007
  *
  * Source: $HeadURL$
  * Last changed: $LastChangedDate$
  * 
  * the unrar licence applies to all junrar source and binary distributions 
  * you are not allowed to use this source to re-create the RAR compression algorithm
  * 
  * Here some html entities which can be used for escaping javadoc tags:
  * "&":  "&#038;" or "&amp;"
  * "<":  "&#060;" or "&lt;"
  * ">":  "&#062;" or "&gt;"
  * "@":  "&#064;" 
  */
  using System;
  using System.IO;
  using SharpCompress.Compressor.Rar.decode;
  using SharpCompress.Compressor.Rar.VM;
  
  namespace SharpCompress.Compressor.Rar
  {
  
      /// <summary> DOCUMENT ME
      /// 
      /// </summary>
      /// <author>  $LastChangedBy$
      /// </author>
      /// <version>  $LastChangedRevision$
      /// </version>
      internal abstract class Unpack15 : BitInput
      {
  
          protected internal int readBorder;
  
          protected internal bool suspended;
  
          protected internal bool unpAllBuf;
  
          //protected internal ComprDataIO unpIO;
  
          protected Stream readStream;
          protected Stream writeStream;
  
          protected internal bool unpSomeRead;
  
          protected internal int readTop;
  
          protected internal long destUnpSize;
  
          protected internal byte[] window;
  
          protected internal int[] oldDist = new int[4];
  
          protected internal int unpPtr, wrPtr;
  
          protected internal int oldDistPtr;
  
          protected internal int[] ChSet = new int[256], ChSetA = new int[256], ChSetB = new int[256], ChSetC = new int[256];
  
          protected internal int[] Place = new int[256], PlaceA = new int[256], PlaceB = new int[256], PlaceC = new int[256];
  
          protected internal int[] NToPl = new int[256], NToPlB = new int[256], NToPlC = new int[256];
  
          protected internal int FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3;
  
          protected internal int Buf60, NumHuf, StMode, LCount, FlagsCnt;
  
          protected internal int Nhfb, Nlzb, MaxDist3;
  
          protected internal int lastDist, lastLength;
  
          private const int STARTL1 = 2;
  
          private static int[] DecL1 = new int[] { 0x8000, 0xa000, 0xc000, 0xd000, 0xe000, 0xea00, 0xee00, 0xf000, 0xf200, 0xf200, 0xffff };
  
          private static int[] PosL1 = new int[] { 0, 0, 0, 2, 3, 5, 7, 11, 16, 20, 24, 32, 32 };
  
          private const int STARTL2 = 3;
  
          private static int[] DecL2 = new int[] { 0xa000, 0xc000, 0xd000, 0xe000, 0xea00, 0xee00, 0xf000, 0xf200, 0xf240, 0xffff };
  
          private static int[] PosL2 = new int[] { 0, 0, 0, 0, 5, 7, 9, 13, 18, 22, 26, 34, 36 };
  
          private const int STARTHF0 = 4;
  
          private static int[] DecHf0 = new int[] { 0x8000, 0xc000, 0xe000, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xffff };
  
          private static int[] PosHf0 = new int[] { 0, 0, 0, 0, 0, 8, 16, 24, 33, 33, 33, 33, 33 };
  
          private const int STARTHF1 = 5;
  
          private static int[] DecHf1 = new int[] { 0x2000, 0xc000, 0xe000, 0xf000, 0xf200, 0xf200, 0xf7e0, 0xffff };
  
          private static int[] PosHf1 = new int[] { 0, 0, 0, 0, 0, 0, 4, 44, 60, 76, 80, 80, 127 };
  
          private const int STARTHF2 = 5;
  
          private static int[] DecHf2 = new int[] { 0x1000, 0x2400, 0x8000, 0xc000, 0xfa00, 0xffff, 0xffff, 0xffff };
  
          private static int[] PosHf2 = new int[] { 0, 0, 0, 0, 0, 0, 2, 7, 53, 117, 233, 0, 0 };
  
          private const int STARTHF3 = 6;
  
          private static int[] DecHf3 = new int[] { 0x800, 0x2400, 0xee00, 0xfe80, 0xffff, 0xffff, 0xffff };
  
          private static int[] PosHf3 = new int[] { 0, 0, 0, 0, 0, 0, 0, 2, 16, 218, 251, 0, 0 };
  
          private const int STARTHF4 = 8;
  
          private static int[] DecHf4 = new int[] { 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff };
  
          private static int[] PosHf4 = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0 };
  
          internal static int[] ShortLen1 = new int[] { 1, 3, 4, 4, 5, 6, 7, 8, 8, 4, 4, 5, 6, 6, 4, 0 };
  
          internal static int[] ShortXor1 = new int[] { 0, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xc0, 0x80, 0x90, 0x98, 0x9c, 0xb0 };
  
          internal static int[] ShortLen2 = new int[] { 2, 3, 3, 3, 4, 4, 5, 6, 6, 4, 4, 5, 6, 6, 4, 0 };
  
          internal static int[] ShortXor2 = new int[] { 0, 0x40, 0x60, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, 0xfc, 0xc0, 0x80, 0x90, 0x98, 0x9c, 0xb0 };
  
          protected internal abstract void unpInitData(bool solid);
  
          protected void unpack15(bool solid)
          {
              if (suspended)
              {
                  unpPtr = wrPtr;
              }
              else
              {
                  unpInitData(solid);
                  oldUnpInitData(solid);
                  unpReadBuf();
                  if (!solid)
                  {
                      initHuff();
                      unpPtr = 0;
                  }
                  else
                  {
                      unpPtr = wrPtr;
                  }
                  --destUnpSize;
              }
              if (destUnpSize >= 0)
              {
                  getFlagsBuf();
                  FlagsCnt = 8;
              }
  
              while (destUnpSize >= 0)
              {
                  unpPtr &= Compress.MAXWINMASK;
  
                  if (inAddr > readTop - 30 && !unpReadBuf())
                  {
                      break;
                  }
                  if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 270 && wrPtr != unpPtr)
                  {
                      oldUnpWriteBuf();
                      if (suspended)
                      {
                          return;
                      }
                  }
                  if (StMode != 0)
                  {
                      huffDecode();
                      continue;
                  }
  
                  if (--FlagsCnt < 0)
                  {
                      getFlagsBuf();
                      FlagsCnt = 7;
                  }
  
                  if ((FlagBuf & 0x80) != 0)
                  {
                      FlagBuf <<= 1;
                      if (Nlzb > Nhfb)
                      {
                          longLZ();
                      }
                      else
                      {
                          huffDecode();
                      }
                  }
                  else
                  {
                      FlagBuf <<= 1;
                      if (--FlagsCnt < 0)
                      {
                          getFlagsBuf();
                          FlagsCnt = 7;
                      }
                      if ((FlagBuf & 0x80) != 0)
                      {
                          FlagBuf <<= 1;
                          if (Nlzb > Nhfb)
                          {
                              huffDecode();
                          }
                          else
                          {
                              longLZ();
                          }
                      }
                      else
                      {
                          FlagBuf <<= 1;
                          shortLZ();
                      }
                  }
              }
              oldUnpWriteBuf();
          }
  
  
  
          protected bool unpReadBuf()
          {
              int dataSize = readTop - inAddr;
              if (dataSize < 0)
              {
                  return (false);
              }
              if (inAddr > BitInput.MAX_SIZE / 2)
              {
                  if (dataSize > 0)
                  {
                      //memmove(InBuf,InBuf+InAddr,DataSize);
                      //		    	for (int i = 0; i < dataSize; i++) {
                      //					inBuf[i] = inBuf[inAddr + i];
                      //				}
                      Array.Copy(InBuf, inAddr, InBuf, 0, dataSize);
                  }
                  inAddr = 0;
                  readTop = dataSize;
              }
              else
              {
                  dataSize = readTop;
              }
              //int readCode=UnpIO->UnpRead(InBuf+DataSize,(BitInput::MAX_SIZE-DataSize)&~0xf);
              int readCode = readStream.Read(InBuf, dataSize, (BitInput.MAX_SIZE - dataSize) & ~0xf);
              if (readCode > 0)
              {
                  readTop += readCode;
              }
              readBorder = readTop - 30;
              return (readCode != -1);
          }
  
          private int getShortLen1(int pos)
          {
              return pos == 1 ? Buf60 + 3 : ShortLen1[pos];
          }
  
          private int getShortLen2(int pos)
          {
              return pos == 3 ? Buf60 + 3 : ShortLen2[pos];
          }
  
          private void shortLZ()
          {
              int Length, SaveLength;
              int LastDistance;
              int Distance;
              int DistancePlace;
              NumHuf = 0;
  
              int BitField = GetBits();
              if (LCount == 2)
              {
                  AddBits(1);
                  if (BitField >= 0x8000)
                  {
                      oldCopyString(lastDist, lastLength);
                      return;
                  }
                  BitField <<= 1;
                  LCount = 0;
              }
              BitField = Utility.URShift(BitField, 8);
              if (AvrLn1 < 37)
              {
                  for (Length = 0; ; Length++)
                  {
                      if (((BitField ^ ShortXor1[Length]) & (~(Utility.URShift(0xff, getShortLen1(Length))))) == 0)
                      {
                          break;
                      }
                  }
                  AddBits(getShortLen1(Length));
              }
              else
              {
                  for (Length = 0; ; Length++)
                  {
                      if (((BitField ^ ShortXor2[Length]) & (~(0xff >> getShortLen2(Length)))) == 0)
                      {
                          break;
                      }
                  }
                  AddBits(getShortLen2(Length));
              }
  
              if (Length >= 9)
              {
                  if (Length == 9)
                  {
                      LCount++;
                      oldCopyString(lastDist, lastLength);
                      return;
                  }
                  if (Length == 14)
                  {
                      LCount = 0;
                      Length = decodeNum(GetBits(), STARTL2, DecL2, PosL2) + 5;
                      Distance = (GetBits() >> 1) | 0x8000;
                      AddBits(15);
                      lastLength = Length;
                      lastDist = Distance;
                      oldCopyString(Distance, Length);
                      return;
                  }
  
                  LCount = 0;
                  SaveLength = Length;
  
gt:                 Distance = oldDist[(oldDistPtr - (Length - 9)) & 3];