1370b324cSopenharmony_ci/* Ppmd7Enc.c -- Ppmd7z (PPMdH with 7z Range Coder) Encoder
2370b324cSopenharmony_ci2023-04-02 : Igor Pavlov : Public domain
3370b324cSopenharmony_ciThis code is based on:
4370b324cSopenharmony_ci  PPMd var.H (2001): Dmitry Shkarin : Public domain */
5370b324cSopenharmony_ci
6370b324cSopenharmony_ci
7370b324cSopenharmony_ci#include "Precomp.h"
8370b324cSopenharmony_ci
9370b324cSopenharmony_ci#include "Ppmd7.h"
10370b324cSopenharmony_ci
11370b324cSopenharmony_ci#define kTopValue ((UInt32)1 << 24)
12370b324cSopenharmony_ci
13370b324cSopenharmony_ci#define R (&p->rc.enc)
14370b324cSopenharmony_ci
15370b324cSopenharmony_civoid Ppmd7z_Init_RangeEnc(CPpmd7 *p)
16370b324cSopenharmony_ci{
17370b324cSopenharmony_ci  R->Low = 0;
18370b324cSopenharmony_ci  R->Range = 0xFFFFFFFF;
19370b324cSopenharmony_ci  R->Cache = 0;
20370b324cSopenharmony_ci  R->CacheSize = 1;
21370b324cSopenharmony_ci}
22370b324cSopenharmony_ci
23370b324cSopenharmony_ciZ7_NO_INLINE
24370b324cSopenharmony_cistatic void Ppmd7z_RangeEnc_ShiftLow(CPpmd7 *p)
25370b324cSopenharmony_ci{
26370b324cSopenharmony_ci  if ((UInt32)R->Low < (UInt32)0xFF000000 || (unsigned)(R->Low >> 32) != 0)
27370b324cSopenharmony_ci  {
28370b324cSopenharmony_ci    Byte temp = R->Cache;
29370b324cSopenharmony_ci    do
30370b324cSopenharmony_ci    {
31370b324cSopenharmony_ci      IByteOut_Write(R->Stream, (Byte)(temp + (Byte)(R->Low >> 32)));
32370b324cSopenharmony_ci      temp = 0xFF;
33370b324cSopenharmony_ci    }
34370b324cSopenharmony_ci    while (--R->CacheSize != 0);
35370b324cSopenharmony_ci    R->Cache = (Byte)((UInt32)R->Low >> 24);
36370b324cSopenharmony_ci  }
37370b324cSopenharmony_ci  R->CacheSize++;
38370b324cSopenharmony_ci  R->Low = (UInt32)((UInt32)R->Low << 8);
39370b324cSopenharmony_ci}
40370b324cSopenharmony_ci
41370b324cSopenharmony_ci#define RC_NORM_BASE(p) if (R->Range < kTopValue) { R->Range <<= 8;  Ppmd7z_RangeEnc_ShiftLow(p);
42370b324cSopenharmony_ci#define RC_NORM_1(p)    RC_NORM_BASE(p) }
43370b324cSopenharmony_ci#define RC_NORM(p)      RC_NORM_BASE(p)  RC_NORM_BASE(p) }}
44370b324cSopenharmony_ci
45370b324cSopenharmony_ci// we must use only one type of Normalization from two: LOCAL or REMOTE
46370b324cSopenharmony_ci#define RC_NORM_LOCAL(p)    // RC_NORM(p)
47370b324cSopenharmony_ci#define RC_NORM_REMOTE(p)   RC_NORM(p)
48370b324cSopenharmony_ci
49370b324cSopenharmony_ci/*
50370b324cSopenharmony_ci#define Ppmd7z_RangeEnc_Encode(p, start, _size_) \
51370b324cSopenharmony_ci  { UInt32 size = _size_; \
52370b324cSopenharmony_ci    R->Low += start * R->Range; \
53370b324cSopenharmony_ci    R->Range *= size; \
54370b324cSopenharmony_ci    RC_NORM_LOCAL(p); }
55370b324cSopenharmony_ci*/
56370b324cSopenharmony_ci
57370b324cSopenharmony_ciZ7_FORCE_INLINE
58370b324cSopenharmony_ci// Z7_NO_INLINE
59370b324cSopenharmony_cistatic void Ppmd7z_RangeEnc_Encode(CPpmd7 *p, UInt32 start, UInt32 size)
60370b324cSopenharmony_ci{
61370b324cSopenharmony_ci  R->Low += start * R->Range;
62370b324cSopenharmony_ci  R->Range *= size;
63370b324cSopenharmony_ci  RC_NORM_LOCAL(p)
64370b324cSopenharmony_ci}
65370b324cSopenharmony_ci
66370b324cSopenharmony_civoid Ppmd7z_Flush_RangeEnc(CPpmd7 *p)
67370b324cSopenharmony_ci{
68370b324cSopenharmony_ci  unsigned i;
69370b324cSopenharmony_ci  for (i = 0; i < 5; i++)
70370b324cSopenharmony_ci    Ppmd7z_RangeEnc_ShiftLow(p);
71370b324cSopenharmony_ci}
72370b324cSopenharmony_ci
73370b324cSopenharmony_ci
74370b324cSopenharmony_ci
75370b324cSopenharmony_ci#define RC_Encode(start, size)  Ppmd7z_RangeEnc_Encode(p, start, size);
76370b324cSopenharmony_ci#define RC_EncodeFinal(start, size)  RC_Encode(start, size) RC_NORM_REMOTE(p)
77370b324cSopenharmony_ci
78370b324cSopenharmony_ci#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
79370b324cSopenharmony_ci#define SUFFIX(ctx) CTX((ctx)->Suffix)
80370b324cSopenharmony_ci// typedef CPpmd7_Context * CTX_PTR;
81370b324cSopenharmony_ci#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
82370b324cSopenharmony_ci
83370b324cSopenharmony_civoid Ppmd7_UpdateModel(CPpmd7 *p);
84370b324cSopenharmony_ci
85370b324cSopenharmony_ci#define MASK(sym) ((unsigned char *)charMask)[sym]
86370b324cSopenharmony_ci
87370b324cSopenharmony_ciZ7_FORCE_INLINE
88370b324cSopenharmony_cistatic
89370b324cSopenharmony_civoid Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol)
90370b324cSopenharmony_ci{
91370b324cSopenharmony_ci  size_t charMask[256 / sizeof(size_t)];
92370b324cSopenharmony_ci
93370b324cSopenharmony_ci  if (p->MinContext->NumStats != 1)
94370b324cSopenharmony_ci  {
95370b324cSopenharmony_ci    CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
96370b324cSopenharmony_ci    UInt32 sum;
97370b324cSopenharmony_ci    unsigned i;
98370b324cSopenharmony_ci
99370b324cSopenharmony_ci
100370b324cSopenharmony_ci
101370b324cSopenharmony_ci
102370b324cSopenharmony_ci    R->Range /= p->MinContext->Union2.SummFreq;
103370b324cSopenharmony_ci
104370b324cSopenharmony_ci    if (s->Symbol == symbol)
105370b324cSopenharmony_ci    {
106370b324cSopenharmony_ci      // R->Range /= p->MinContext->Union2.SummFreq;
107370b324cSopenharmony_ci      RC_EncodeFinal(0, s->Freq)
108370b324cSopenharmony_ci      p->FoundState = s;
109370b324cSopenharmony_ci      Ppmd7_Update1_0(p);
110370b324cSopenharmony_ci      return;
111370b324cSopenharmony_ci    }
112370b324cSopenharmony_ci    p->PrevSuccess = 0;
113370b324cSopenharmony_ci    sum = s->Freq;
114370b324cSopenharmony_ci    i = (unsigned)p->MinContext->NumStats - 1;
115370b324cSopenharmony_ci    do
116370b324cSopenharmony_ci    {
117370b324cSopenharmony_ci      if ((++s)->Symbol == symbol)
118370b324cSopenharmony_ci      {
119370b324cSopenharmony_ci        // R->Range /= p->MinContext->Union2.SummFreq;
120370b324cSopenharmony_ci        RC_EncodeFinal(sum, s->Freq)
121370b324cSopenharmony_ci        p->FoundState = s;
122370b324cSopenharmony_ci        Ppmd7_Update1(p);
123370b324cSopenharmony_ci        return;
124370b324cSopenharmony_ci      }
125370b324cSopenharmony_ci      sum += s->Freq;
126370b324cSopenharmony_ci    }
127370b324cSopenharmony_ci    while (--i);
128370b324cSopenharmony_ci
129370b324cSopenharmony_ci    // R->Range /= p->MinContext->Union2.SummFreq;
130370b324cSopenharmony_ci    RC_Encode(sum, p->MinContext->Union2.SummFreq - sum)
131370b324cSopenharmony_ci
132370b324cSopenharmony_ci    p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol);
133370b324cSopenharmony_ci    PPMD_SetAllBitsIn256Bytes(charMask)
134370b324cSopenharmony_ci    // MASK(s->Symbol) = 0;
135370b324cSopenharmony_ci    // i = p->MinContext->NumStats - 1;
136370b324cSopenharmony_ci    // do { MASK((--s)->Symbol) = 0; } while (--i);
137370b324cSopenharmony_ci    {
138370b324cSopenharmony_ci      CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext);
139370b324cSopenharmony_ci      MASK(s->Symbol) = 0;
140370b324cSopenharmony_ci      do
141370b324cSopenharmony_ci      {
142370b324cSopenharmony_ci        unsigned sym0 = s2[0].Symbol;
143370b324cSopenharmony_ci        unsigned sym1 = s2[1].Symbol;
144370b324cSopenharmony_ci        s2 += 2;
145370b324cSopenharmony_ci        MASK(sym0) = 0;
146370b324cSopenharmony_ci        MASK(sym1) = 0;
147370b324cSopenharmony_ci      }
148370b324cSopenharmony_ci      while (s2 < s);
149370b324cSopenharmony_ci    }
150370b324cSopenharmony_ci  }
151370b324cSopenharmony_ci  else
152370b324cSopenharmony_ci  {
153370b324cSopenharmony_ci    UInt16 *prob = Ppmd7_GetBinSumm(p);
154370b324cSopenharmony_ci    CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);
155370b324cSopenharmony_ci    UInt32 pr = *prob;
156370b324cSopenharmony_ci    const UInt32 bound = (R->Range >> 14) * pr;
157370b324cSopenharmony_ci    pr = PPMD_UPDATE_PROB_1(pr);
158370b324cSopenharmony_ci    if (s->Symbol == symbol)
159370b324cSopenharmony_ci    {
160370b324cSopenharmony_ci      *prob = (UInt16)(pr + (1 << PPMD_INT_BITS));
161370b324cSopenharmony_ci      // RangeEnc_EncodeBit_0(p, bound);
162370b324cSopenharmony_ci      R->Range = bound;
163370b324cSopenharmony_ci      RC_NORM_1(p)
164370b324cSopenharmony_ci
165370b324cSopenharmony_ci      // p->FoundState = s;
166370b324cSopenharmony_ci      // Ppmd7_UpdateBin(p);
167370b324cSopenharmony_ci      {
168370b324cSopenharmony_ci        const unsigned freq = s->Freq;
169370b324cSopenharmony_ci        CPpmd7_Context *c = CTX(SUCCESSOR(s));
170370b324cSopenharmony_ci        p->FoundState = s;
171370b324cSopenharmony_ci        p->PrevSuccess = 1;
172370b324cSopenharmony_ci        p->RunLength++;
173370b324cSopenharmony_ci        s->Freq = (Byte)(freq + (freq < 128));
174370b324cSopenharmony_ci        // NextContext(p);
175370b324cSopenharmony_ci        if (p->OrderFall == 0 && (const Byte *)c > p->Text)
176370b324cSopenharmony_ci          p->MaxContext = p->MinContext = c;
177370b324cSopenharmony_ci        else
178370b324cSopenharmony_ci          Ppmd7_UpdateModel(p);
179370b324cSopenharmony_ci      }
180370b324cSopenharmony_ci      return;
181370b324cSopenharmony_ci    }
182370b324cSopenharmony_ci
183370b324cSopenharmony_ci    *prob = (UInt16)pr;
184370b324cSopenharmony_ci    p->InitEsc = p->ExpEscape[pr >> 10];
185370b324cSopenharmony_ci    // RangeEnc_EncodeBit_1(p, bound);
186370b324cSopenharmony_ci    R->Low += bound;
187370b324cSopenharmony_ci    R->Range -= bound;
188370b324cSopenharmony_ci    RC_NORM_LOCAL(p)
189370b324cSopenharmony_ci
190370b324cSopenharmony_ci    PPMD_SetAllBitsIn256Bytes(charMask)
191370b324cSopenharmony_ci    MASK(s->Symbol) = 0;
192370b324cSopenharmony_ci    p->PrevSuccess = 0;
193370b324cSopenharmony_ci  }
194370b324cSopenharmony_ci
195370b324cSopenharmony_ci  for (;;)
196370b324cSopenharmony_ci  {
197370b324cSopenharmony_ci    CPpmd_See *see;
198370b324cSopenharmony_ci    CPpmd_State *s;
199370b324cSopenharmony_ci    UInt32 sum, escFreq;
200370b324cSopenharmony_ci    CPpmd7_Context *mc;
201370b324cSopenharmony_ci    unsigned i, numMasked;
202370b324cSopenharmony_ci
203370b324cSopenharmony_ci    RC_NORM_REMOTE(p)
204370b324cSopenharmony_ci
205370b324cSopenharmony_ci    mc = p->MinContext;
206370b324cSopenharmony_ci    numMasked = mc->NumStats;
207370b324cSopenharmony_ci
208370b324cSopenharmony_ci    do
209370b324cSopenharmony_ci    {
210370b324cSopenharmony_ci      p->OrderFall++;
211370b324cSopenharmony_ci      if (!mc->Suffix)
212370b324cSopenharmony_ci        return; /* EndMarker (symbol = -1) */
213370b324cSopenharmony_ci      mc = Ppmd7_GetContext(p, mc->Suffix);
214370b324cSopenharmony_ci      i = mc->NumStats;
215370b324cSopenharmony_ci    }
216370b324cSopenharmony_ci    while (i == numMasked);
217370b324cSopenharmony_ci
218370b324cSopenharmony_ci    p->MinContext = mc;
219370b324cSopenharmony_ci
220370b324cSopenharmony_ci    // see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq);
221370b324cSopenharmony_ci    {
222370b324cSopenharmony_ci      if (i != 256)
223370b324cSopenharmony_ci      {
224370b324cSopenharmony_ci        unsigned nonMasked = i - numMasked;
225370b324cSopenharmony_ci        see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]]
226370b324cSopenharmony_ci            + p->HiBitsFlag
227370b324cSopenharmony_ci            + (nonMasked < (unsigned)SUFFIX(mc)->NumStats - i)
228370b324cSopenharmony_ci            + 2 * (unsigned)(mc->Union2.SummFreq < 11 * i)
229370b324cSopenharmony_ci            + 4 * (unsigned)(numMasked > nonMasked);
230370b324cSopenharmony_ci        {
231370b324cSopenharmony_ci          // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ
232370b324cSopenharmony_ci          unsigned summ = (UInt16)see->Summ; // & 0xFFFF
233370b324cSopenharmony_ci          unsigned r = (summ >> see->Shift);
234370b324cSopenharmony_ci          see->Summ = (UInt16)(summ - r);
235370b324cSopenharmony_ci          escFreq = r + (r == 0);
236370b324cSopenharmony_ci        }
237370b324cSopenharmony_ci      }
238370b324cSopenharmony_ci      else
239370b324cSopenharmony_ci      {
240370b324cSopenharmony_ci        see = &p->DummySee;
241370b324cSopenharmony_ci        escFreq = 1;
242370b324cSopenharmony_ci      }
243370b324cSopenharmony_ci    }
244370b324cSopenharmony_ci
245370b324cSopenharmony_ci    s = Ppmd7_GetStats(p, mc);
246370b324cSopenharmony_ci    sum = 0;
247370b324cSopenharmony_ci    // i = mc->NumStats;
248370b324cSopenharmony_ci
249370b324cSopenharmony_ci    do
250370b324cSopenharmony_ci    {
251370b324cSopenharmony_ci      const unsigned cur = s->Symbol;
252370b324cSopenharmony_ci      if ((int)cur == symbol)
253370b324cSopenharmony_ci      {
254370b324cSopenharmony_ci        const UInt32 low = sum;
255370b324cSopenharmony_ci        const UInt32 freq = s->Freq;
256370b324cSopenharmony_ci        unsigned num2;
257370b324cSopenharmony_ci
258370b324cSopenharmony_ci        Ppmd_See_UPDATE(see)
259370b324cSopenharmony_ci        p->FoundState = s;
260370b324cSopenharmony_ci        sum += escFreq;
261370b324cSopenharmony_ci
262370b324cSopenharmony_ci        num2 = i / 2;
263370b324cSopenharmony_ci        i &= 1;
264370b324cSopenharmony_ci        sum += freq & (0 - (UInt32)i);
265370b324cSopenharmony_ci        if (num2 != 0)
266370b324cSopenharmony_ci        {
267370b324cSopenharmony_ci          s += i;
268370b324cSopenharmony_ci          for (;;)
269370b324cSopenharmony_ci          {
270370b324cSopenharmony_ci            unsigned sym0 = s[0].Symbol;
271370b324cSopenharmony_ci            unsigned sym1 = s[1].Symbol;
272370b324cSopenharmony_ci            s += 2;
273370b324cSopenharmony_ci            sum += (s[-2].Freq & (unsigned)(MASK(sym0)));
274370b324cSopenharmony_ci            sum += (s[-1].Freq & (unsigned)(MASK(sym1)));
275370b324cSopenharmony_ci            if (--num2 == 0)
276370b324cSopenharmony_ci              break;
277370b324cSopenharmony_ci          }
278370b324cSopenharmony_ci        }
279370b324cSopenharmony_ci
280370b324cSopenharmony_ci
281370b324cSopenharmony_ci        R->Range /= sum;
282370b324cSopenharmony_ci        RC_EncodeFinal(low, freq)
283370b324cSopenharmony_ci        Ppmd7_Update2(p);
284370b324cSopenharmony_ci        return;
285370b324cSopenharmony_ci      }
286370b324cSopenharmony_ci      sum += (s->Freq & (unsigned)(MASK(cur)));
287370b324cSopenharmony_ci      s++;
288370b324cSopenharmony_ci    }
289370b324cSopenharmony_ci    while (--i);
290370b324cSopenharmony_ci
291370b324cSopenharmony_ci    {
292370b324cSopenharmony_ci      const UInt32 total = sum + escFreq;
293370b324cSopenharmony_ci      see->Summ = (UInt16)(see->Summ + total);
294370b324cSopenharmony_ci
295370b324cSopenharmony_ci      R->Range /= total;
296370b324cSopenharmony_ci      RC_Encode(sum, escFreq)
297370b324cSopenharmony_ci    }
298370b324cSopenharmony_ci
299370b324cSopenharmony_ci    {
300370b324cSopenharmony_ci      const CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext);
301370b324cSopenharmony_ci      s--;
302370b324cSopenharmony_ci      MASK(s->Symbol) = 0;
303370b324cSopenharmony_ci      do
304370b324cSopenharmony_ci      {
305370b324cSopenharmony_ci        const unsigned sym0 = s2[0].Symbol;
306370b324cSopenharmony_ci        const unsigned sym1 = s2[1].Symbol;
307370b324cSopenharmony_ci        s2 += 2;
308370b324cSopenharmony_ci        MASK(sym0) = 0;
309370b324cSopenharmony_ci        MASK(sym1) = 0;
310370b324cSopenharmony_ci      }
311370b324cSopenharmony_ci      while (s2 < s);
312370b324cSopenharmony_ci    }
313370b324cSopenharmony_ci  }
314370b324cSopenharmony_ci}
315370b324cSopenharmony_ci
316370b324cSopenharmony_ci
317370b324cSopenharmony_civoid Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim)
318370b324cSopenharmony_ci{
319370b324cSopenharmony_ci  for (; buf < lim; buf++)
320370b324cSopenharmony_ci  {
321370b324cSopenharmony_ci    Ppmd7z_EncodeSymbol(p, *buf);
322370b324cSopenharmony_ci  }
323370b324cSopenharmony_ci}
324370b324cSopenharmony_ci
325370b324cSopenharmony_ci#undef kTopValue
326370b324cSopenharmony_ci#undef WRITE_BYTE
327370b324cSopenharmony_ci#undef RC_NORM_BASE
328370b324cSopenharmony_ci#undef RC_NORM_1
329370b324cSopenharmony_ci#undef RC_NORM
330370b324cSopenharmony_ci#undef RC_NORM_LOCAL
331370b324cSopenharmony_ci#undef RC_NORM_REMOTE
332370b324cSopenharmony_ci#undef R
333370b324cSopenharmony_ci#undef RC_Encode
334370b324cSopenharmony_ci#undef RC_EncodeFinal
335370b324cSopenharmony_ci#undef SUFFIX
336370b324cSopenharmony_ci#undef CTX
337370b324cSopenharmony_ci#undef SUCCESSOR
338370b324cSopenharmony_ci#undef MASK
339