text: /* Ppmd7aDec.c -- PPMd7a (PPMdH) Decoder
  2021-04-13 : Igor Pavlov : Public domain
  This code is based on:
    PPMd var.H (2001): Dmitry Shkarin : Public domain
    Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
  
  #include "Precomp.h"
  
  #include "Ppmd7.h"
  
  #define kTop (1 << 24)
  #define kBot (1 << 15)
  
  #define READ_BYTE(p) IByteIn_Read((p)->Stream)
  
  BoolInt Ppmd7a_RangeDec_Init(CPpmd7_RangeDec *p)
  {
    unsigned i;
    p->Code = 0;
    p->Range = 0xFFFFFFFF;
    p->Low = 0;
    
    for (i = 0; i < 4; i++)
      p->Code = (p->Code << 8) | READ_BYTE(p);
    return (p->Code < 0xFFFFFFFF);
  }
  
  #define RC_NORM(p) \
    while ((p->Low ^ (p->Low + p->Range)) < kTop \
      || (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) { \
        p->Code = (p->Code << 8) | READ_BYTE(p); \
        p->Range <<= 8; p->Low <<= 8; }
  
  // we must use only one type of Normalization from two: LOCAL or REMOTE
  #define RC_NORM_LOCAL(p)    // RC_NORM(p)
  #define RC_NORM_REMOTE(p)   RC_NORM(p)
  
  #define R (&p->rc.dec)
  
  MY_FORCE_INLINE
  // MY_NO_INLINE
  static void RangeDec_Decode(CPpmd7 *p, UInt32 start, UInt32 size)
  {
    start *= R->Range;
    R->Low += start;
    R->Code -= start;
    R->Range *= size;
    RC_NORM_LOCAL(R)
  }
  
  #define RC_Decode(start, size) RangeDec_Decode(p, start, size);
  #define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R)
  #define RC_GetThreshold(total) (R->Code / (R->Range /= (total)))
  
  
  #define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
  typedef CPpmd7_Context * CTX_PTR;
  #define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
  void Ppmd7_UpdateModel(CPpmd7 *p);
  
  #define MASK(sym) ((unsigned char *)charMask)[sym]
  
  
  int Ppmd7a_DecodeSymbol(CPpmd7 *p)
  {
    size_t charMask[256 / sizeof(size_t)];
  
    if (p->MinContext->NumStats != 1)
    {
      CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
      unsigned i;
      UInt32 count, hiCnt;
      UInt32 summFreq = p->MinContext->Union2.SummFreq;
  
      if (summFreq > R->Range)
        return PPMD7_SYM_ERROR;
  
      count = RC_GetThreshold(summFreq);
      hiCnt = count;
      
      if ((Int32)(count -= s->Freq) < 0)
      {
        Byte sym;
        RC_DecodeFinal(0, s->Freq);
        p->FoundState = s;
        sym = s->Symbol;
        Ppmd7_Update1_0(p);
        return sym;
      }
    
      p->PrevSuccess = 0;
      i = (unsigned)p->MinContext->NumStats - 1;
      
      do
      {
        if ((Int32)(count -= (++s)->Freq) < 0)
        {
          Byte sym;
          RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq);
          p->FoundState = s;
          sym = s->Symbol;
          Ppmd7_Update1(p);
          return sym;
        }
      }
      while (--i);
      
      if (hiCnt >= summFreq)
        return PPMD7_SYM_ERROR;
      
      hiCnt -= count;
      RC_Decode(hiCnt, summFreq - hiCnt);
  
      p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol);
      PPMD_SetAllBitsIn256Bytes(charMask);
      // i = p->MinContext->NumStats - 1;
      // do { MASK((--s)->Symbol) = 0; } while (--i);
      {
        CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext);
        MASK(s->Symbol) = 0;
        do
        {
          unsigned sym0 = s2[0].Symbol;
          unsigned sym1 = s2[1].Symbol;
          s2 += 2;
          MASK(sym0) = 0;
          MASK(sym1) = 0;
        }
        while (s2 < s);
      }
    }
    else
    {
      CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);
      UInt16 *prob = Ppmd7_GetBinSumm(p);
      UInt32 pr = *prob;
      UInt32 size0 = (R->Range >> 14) * pr;
      pr = PPMD_UPDATE_PROB_1(pr);
  
      if (R->Code < size0)
      {
        Byte sym;
        *prob = (UInt16)(pr + (1 << PPMD_INT_BITS));
        
        // RangeDec_DecodeBit0(size0);
        R->Range = size0;
        RC_NORM(R)
        
          
          
        // sym = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;
        // Ppmd7_UpdateBin(p);
        {
          unsigned freq = s->Freq;
          CTX_PTR c = CTX(SUCCESSOR(s));
          sym = s->Symbol;
          p->FoundState = s;
          p->PrevSuccess = 1;
          p->RunLength++;
          s->Freq = (Byte)(freq + (freq < 128));
          // NextContext(p);
          if (p->OrderFall == 0 && (const Byte *)c > p->Text)
            p->MaxContext = p->MinContext = c;
          else
            Ppmd7_UpdateModel(p);
        }
        return sym;
      }
  
      *prob = (UInt16)pr;
      p->InitEsc = p->ExpEscape[pr >> 10];
  
      // RangeDec_DecodeBit1(size0);
      R->Low += size0;
      R->Code -= size0;
      R->Range = (R->Range & ~((UInt32)PPMD_BIN_SCALE - 1)) - size0;
      RC_NORM_LOCAL(R)
      
      PPMD_SetAllBitsIn256Bytes(charMask);
      MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;
      p->PrevSuccess = 0;
    }
  
    for (;;)
    {
      CPpmd_State *s, *s2;
      UInt32 freqSum, count, hiCnt;
  
      CPpmd_See *see;
      CPpmd7_Context *mc;
      unsigned numMasked;
      RC_NORM_REMOTE(R)
      mc = p->MinContext;
      numMasked = mc->NumStats;
  
      do
      {
        p->OrderFall++;
        if (!mc->Suffix)
          return PPMD7_SYM_END;
        mc = Ppmd7_GetContext(p, mc->Suffix);
      }
      while (mc->NumStats == numMasked);
      
      s = Ppmd7_GetStats(p, mc);
  
      {
        unsigned num = mc->NumStats;
        unsigned num2 = num / 2;
        
        num &= 1;
        hiCnt = (s->Freq & (unsigned)(MASK(s->Symbol))) & (0 - (UInt32)num);
        s += num;
        p->MinContext = mc;
  
        do
        {
          unsigned sym0 = s[0].Symbol;
          unsigned sym1 = s[1].Symbol;
          s += 2;
          hiCnt += (s[-2].Freq & (unsigned)(MASK(sym0)));
          hiCnt += (s[-1].Freq & (unsigned)(MASK(sym1)));
        }
        while (--num2);
      }
  
      see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);
      freqSum += hiCnt;
  
      if (freqSum > R->Range)
        return PPMD7_SYM_ERROR;
  
      count = RC_GetThreshold(freqSum);
      
      if (count < hiCnt)
      {
        Byte sym;
  
        s = Ppmd7_GetStats(p, p->MinContext);
        hiCnt = count;
        // count -= s->Freq & (unsigned)(MASK(s->Symbol));
        // if ((Int32)count >= 0)
        {
          for (;;)
          {
            count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
            // count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
          };
        }
        s--;
        RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq);
  
        // new (see->Summ) value can overflow over 16-bits in some rare cases
        Ppmd_See_Update(see);
        p->FoundState = s;
        sym = s->Symbol;
        Ppmd7_Update2(p);
        return sym;
      }
  
      if (count >= freqSum)
        return PPMD7_SYM_ERROR;
      
      RC_Decode(hiCnt, freqSum - hiCnt);
  
      // We increase (see->Summ) for sum of Freqs of all non_Masked symbols.
      // new (see->Summ) value can overflow over 16-bits in some rare cases
      see->Summ = (UInt16)(see->Summ + freqSum);
  
      s = Ppmd7_GetStats(p, p->MinContext);
      s2 = s + p->MinContext->NumStats;
      do
      {
        MASK(s->Symbol) = 0;
        s++;
      }
      while (s != s2);
    }
  }
  