1baa3858d3f5d128a5c8466b700098109edcad5f2repo sync/* Ppmd7Enc.c -- PPMdH Encoder
2baa3858d3f5d128a5c8466b700098109edcad5f2repo sync2010-03-12 : Igor Pavlov : Public domain
3baa3858d3f5d128a5c8466b700098109edcad5f2repo syncThis code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
4baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
5cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#include "Precomp.h"
6cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky
7baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#include "Ppmd7.h"
8baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
9baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define kTopValue (1 << 24)
10baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
11baa3858d3f5d128a5c8466b700098109edcad5f2repo syncvoid Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p)
12baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
13baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->Low = 0;
14baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->Range = 0xFFFFFFFF;
15baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->Cache = 0;
16baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->CacheSize = 1;
17baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
18baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
19baa3858d3f5d128a5c8466b700098109edcad5f2repo syncstatic void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p)
20baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
21baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if ((UInt32)p->Low < (UInt32)0xFF000000 || (unsigned)(p->Low >> 32) != 0)
22baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
23baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    Byte temp = p->Cache;
24baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    do
25baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
26baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      p->Stream->Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32)));
27baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      temp = 0xFF;
28baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
29baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    while(--p->CacheSize != 0);
30baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p->Cache = (Byte)((UInt32)p->Low >> 24);
31baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
32baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->CacheSize++;
33baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->Low = (UInt32)p->Low << 8;
34baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
35baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
36baa3858d3f5d128a5c8466b700098109edcad5f2repo syncstatic void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total)
37baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
38baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->Low += start * (p->Range /= total);
39baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->Range *= size;
40baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  while (p->Range < kTopValue)
41baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
42baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p->Range <<= 8;
43baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    RangeEnc_ShiftLow(p);
44baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
45baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
46baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
47baa3858d3f5d128a5c8466b700098109edcad5f2repo syncstatic void RangeEnc_EncodeBit_0(CPpmd7z_RangeEnc *p, UInt32 size0)
48baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
49baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->Range = (p->Range >> 14) * size0;
50baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  while (p->Range < kTopValue)
51baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
52baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p->Range <<= 8;
53baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    RangeEnc_ShiftLow(p);
54baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
55baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
56baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
57baa3858d3f5d128a5c8466b700098109edcad5f2repo syncstatic void RangeEnc_EncodeBit_1(CPpmd7z_RangeEnc *p, UInt32 size0)
58baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
59baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  UInt32 newBound = (p->Range >> 14) * size0;
60baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->Low += newBound;
61baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->Range -= newBound;
62baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  while (p->Range < kTopValue)
63baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
64baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p->Range <<= 8;
65baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    RangeEnc_ShiftLow(p);
66baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
67baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
68baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
69baa3858d3f5d128a5c8466b700098109edcad5f2repo syncvoid Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p)
70baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
71baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  unsigned i;
72baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  for (i = 0; i < 5; i++)
73baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    RangeEnc_ShiftLow(p);
74baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
75baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
76baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
77baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define MASK(sym) ((signed char *)charMask)[sym]
78baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
79baa3858d3f5d128a5c8466b700098109edcad5f2repo syncvoid Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol)
80baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
81baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size_t charMask[256 / sizeof(size_t)];
82baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (p->MinContext->NumStats != 1)
83baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
84baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
85baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    UInt32 sum;
86baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    unsigned i;
87baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (s->Symbol == symbol)
88baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
89baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      RangeEnc_Encode(rc, 0, s->Freq, p->MinContext->SummFreq);
90baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      p->FoundState = s;
91baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      Ppmd7_Update1_0(p);
92baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      return;
93baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
94baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p->PrevSuccess = 0;
95baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    sum = s->Freq;
96baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    i = p->MinContext->NumStats - 1;
97baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    do
98baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
99baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      if ((++s)->Symbol == symbol)
100baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      {
101baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        RangeEnc_Encode(rc, sum, s->Freq, p->MinContext->SummFreq);
102baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        p->FoundState = s;
103baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        Ppmd7_Update1(p);
104baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        return;
105baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      }
106baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      sum += s->Freq;
107baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
108baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    while (--i);
109baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
110baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];
111baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    PPMD_SetAllBitsIn256Bytes(charMask);
112baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    MASK(s->Symbol) = 0;
113baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    i = p->MinContext->NumStats - 1;
114baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    do { MASK((--s)->Symbol) = 0; } while (--i);
115baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    RangeEnc_Encode(rc, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq);
116baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
117baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  else
118baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
119baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    UInt16 *prob = Ppmd7_GetBinSumm(p);
120baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);
121baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (s->Symbol == symbol)
122baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
123baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      RangeEnc_EncodeBit_0(rc, *prob);
124baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
125baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      p->FoundState = s;
126baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      Ppmd7_UpdateBin(p);
127baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      return;
128baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
129baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    else
130baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
131baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      RangeEnc_EncodeBit_1(rc, *prob);
132baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
133baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      p->InitEsc = PPMD7_kExpEscape[*prob >> 10];
134baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      PPMD_SetAllBitsIn256Bytes(charMask);
135baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      MASK(s->Symbol) = 0;
136baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      p->PrevSuccess = 0;
137baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
138baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
139baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  for (;;)
140baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
141baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    UInt32 escFreq;
142baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    CPpmd_See *see;
143baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    CPpmd_State *s;
144baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    UInt32 sum;
145baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    unsigned i, numMasked = p->MinContext->NumStats;
146baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    do
147baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
148baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      p->OrderFall++;
149baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      if (!p->MinContext->Suffix)
150baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        return; /* EndMarker (symbol = -1) */
151baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);
152baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
153baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    while (p->MinContext->NumStats == numMasked);
154baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
155baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq);
156baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    s = Ppmd7_GetStats(p, p->MinContext);
157baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    sum = 0;
158baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    i = p->MinContext->NumStats;
159baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    do
160baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
161baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      int cur = s->Symbol;
162baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      if (cur == symbol)
163baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      {
164baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        UInt32 low = sum;
165baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        CPpmd_State *s1 = s;
166baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        do
167baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        {
168baa3858d3f5d128a5c8466b700098109edcad5f2repo sync          sum += (s->Freq & (int)(MASK(s->Symbol)));
169baa3858d3f5d128a5c8466b700098109edcad5f2repo sync          s++;
170baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        }
171baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        while (--i);
172baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        RangeEnc_Encode(rc, low, s1->Freq, sum + escFreq);
173baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        Ppmd_See_Update(see);
174baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        p->FoundState = s1;
175baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        Ppmd7_Update2(p);
176baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        return;
177baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      }
178baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      sum += (s->Freq & (int)(MASK(cur)));
179baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      MASK(cur) = 0;
180baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      s++;
181baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
182baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    while (--i);
183baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
184baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    RangeEnc_Encode(rc, sum, escFreq, sum + escFreq);
185baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    see->Summ = (UInt16)(see->Summ + sum + escFreq);
186baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
187baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
188