1:  //------------------------------------------------------------------------------
   2:  // Copyright (c) Microsoft Corporation. All rights reserved.
   3:  //------------------------------------------------------------------------------
   4:   
   5:  using System;
   6:  using System.Collections.Generic;
   7:   
   8:  namespace Microsoft.Protocols.TestTools.StackSdk.RemoteDesktop.Rdpegfx
   9:  {
  10:      /// <summary>
  11:      /// Simplified Run-Length (SRL) Decoder 
  12:      /// </summary>
  13:      public class SRLDecoder
  14:      {
  15:          // Constants used within the RLGR1/RLGR3 algorithm
  16:          const int KPMAX = 80;  // max value for kp or krp
  17:          const int LSGR = 3;  // shift count to convert kp to k
  18:          const int UP_GR = 4;  // increase in kp after a zero run in RL mode
  19:          const int DN_GR = 6;  // decrease in kp after a nonzero symbol in RL mode
  20:          const int UQ_GR = 3;   // increase in kp after nonzero symbol in GR mode
  21:          const int DQ_GR = 3;   // decrease in kp after zero symbol in GR mode
  22:   
  23:          List<short> decodedList;
  24:          byte[] encodedBytes = null;
  25:          //BitArray bitsToDecode = null;
  26:          int dataOffset = 0;
  27:   
  28:          int k = 1;
  29:          int kp = 8; // k << LSGR;
  30:          int termsToDecode = RdpegfxTileUtils.ComponentElementCount;
  31:          bool zeroRLTerminated;
  32:   
  33:          /// <summary>
  34:          /// SRL decode the input data.
  35:          /// </summary>
  36:          /// <param name="encodedData">The input data to be decoded.</param>
  37:          public SRLDecoder(byte[] encodedData)
  38:          {
  39:              encodedBytes = encodedData;
  40:              //bitsToDecode = new BitArray(encodedData);
  41:              decodedList = new List<short>();
  42:              dataOffset = 0;
  43:              zeroRLTerminated = false;
  44:          }
  45:   
  46:          //
  47:          // Gets (returns) the next nBits from the bitstream
  48:          // The layout of N bits in the bitstream with regard to a byte array is: 
  49:          //     [0..N] -> [0..7](MSB..LSB),[8..15](MSB..LSB) ...,
  50:          // where (MSB..LSB) denotes a byte.  
  51:          //
  52:          uint GetBits(uint nBits)
  53:          {
  54:              uint output = 0;
  55:              int outOffset = (int)nBits - 1;
  56:              while (outOffset >= 0)
  57:              {
  58:                  int bitOffset = dataOffset & 7;
  59:                  int byteOffset = dataOffset >> 3;
  60:                  //uint outBit = (uint)(bitsToDecode.Get(bitOffset++) ? 1:0);
  61:                  uint outBit = (uint)((encodedBytes[byteOffset] & (byte)(1 << (7 - bitOffset))) == 0 ? 0 : 1);
  62:                  output |= (outBit << outOffset--);
  63:                  dataOffset++;
  64:              }
  65:              return output;
  66:          }
  67:   
  68:          bool hasMoreBits(int bitCount)
  69:          {
  70:              int targetOffset = dataOffset + bitCount;
  71:   
  72:              int bitOffset = targetOffset & 7;
  73:              int byteOffset = targetOffset >> 3;
  74:              if (byteOffset < encodedBytes.Length) return true;
  75:              return false;
  76:          }
  77:   
  78:          //
  79:          // From current output pointer, write "value", check and update *termsToDecode
  80:          // 
  81:          void WriteValue(
  82:              int value,
  83:              ref int termsToDecode
  84:              )
  85:          {
  86:              if (termsToDecode > 0)
  87:              {
  88:                  this.decodedList.Add((short)value);
  89:                  termsToDecode--;
  90:              }
  91:          }
  92:   
  93:   
  94:          //
  95:          // From current output pointer, write next nZeroes terms with value 0; 
  96:          // check and update *termsToDecode
  97:          //
  98:          void WriteZeroes(
  99:              uint nZeroes,
 100:              ref int termsToDecode
 101:              )
 102:          {
 103:              for (int i = 0; i < nZeroes && termsToDecode > 0; i++)
 104:              {
 105:                  WriteValue(0, ref termsToDecode);
 106:              }
 107:          }
 108:   
 109:   
 110:          //
 111:          // Update the passed parameter and clamp it to the range [0,KPMAX]
 112:          // Return the value of parameter right-shifted by LSGR
 113:          //
 114:          int UpdateParam(
 115:              ref int param,    // parameter to update
 116:              int deltaP    // update delta
 117:              )
 118:          {
 119:              param += deltaP;// adjust parameter
 120:              if (param > KPMAX) param = KPMAX;// max clamp
 121:              if (param < 0) param = 0;// min clamp
 122:              return (param >> LSGR);
 123:          }
 124:   
 125:          
 126:          /// <summary>
 127:          /// Decode one element from the given data
 128:          /// </summary>
 129:          /// <param name="bitCount">The count of bits to be decoded.</param>
 130:          /// <returns>The decoded element.</returns>
 131:          public short? DecodeOne(int bitCount)
 132:          {
 133:              short? decodedValue = null;
 134:              if (this.decodedList.Count > 0)
 135:              {
 136:                  decodedValue = this.decodedList[0];
 137:                  this.decodedList.RemoveAt(0);
 138:                  return decodedValue;
 139:              }
 140:   
 141:              if (hasMoreBits(1))
 142:              {
 143:                  if (!zeroRLTerminated)
 144:                  {
 145:                      int run;
 146:                      // RL MODE
 147:                      while (hasMoreBits(1) && GetBits(1) == 0)
 148:                      {
 149:                          // we have an RL escape "0", which translates to a run (1<<k) of zeros
 150:                          WriteZeroes((uint)(1 << k), ref termsToDecode);
 151:                          k = UpdateParam(ref kp, UP_GR);  // raise k and kp up because of zero run
 152:                      }
 153:   
 154:                      if (hasMoreBits(k))
 155:                      {
 156:                          // next k bits will contain remaining run of zeros
 157:                          run = (int)GetBits((uint)k);
 158:                          WriteZeroes((uint)run, ref termsToDecode);
 159:                          k = UpdateParam(ref kp, -DN_GR);
 160:                      }
 161:   
 162:                      zeroRLTerminated = true;
 163:                  }
 164:                  else
 165:                  {
 166:                      // get nonzero value, starting with sign bit and 
 167:                      // then Unary Code for magnitude - 1
 168:                      uint sign = GetBits(1);
 169:   
 170:                      int mag = 0;
 171:                      int maxReadBits = (1 << bitCount) - 2;
 172:   
 173:                      while (hasMoreBits(1) && maxReadBits > 0 && GetBits(1) == 0)
 174:                      {
 175:                          maxReadBits--;
 176:                          mag++;
 177:                      }
 178:   
 179:                      mag += 1;
 180:                      WriteValue(sign != 0 ? -mag : mag, ref termsToDecode);
 181:   
 182:                      zeroRLTerminated = false;
 183:                  }
 184:   
 185:              }
 186:   
 187:              if (this.decodedList.Count > 0)
 188:              {
 189:                  decodedValue = this.decodedList[0];
 190:                  this.decodedList.RemoveAt(0);
 191:              }
 192:              else if (hasMoreBits(1))
 193:              {
 194:                  decodedValue = DecodeOne(bitCount);
 195:              }
 196:   
 197:              return decodedValue;
 198:          }
 199:      }
 200:  }