Coverage Report

Created: 2026-02-14 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/minizip-ng/third_party/ppmd/C/Ppmd8.c
Line
Count
Source
1
/* Ppmd8.c -- PPMdI codec
2
2023-09-07 : Igor Pavlov : Public domain
3
This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */
4
5
#include "Precomp.h"
6
7
#include <string.h>
8
9
#include "Ppmd8.h"
10
11
12
13
14
MY_ALIGN(16)
15
static const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
16
MY_ALIGN(16)
17
static const UInt16 PPMD8_kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
18
19
272M
#define MAX_FREQ 124
20
69.3M
#define UNIT_SIZE 12
21
22
35.6M
#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
23
72.8M
#define U2I(nu) (p->Units2Indx[(size_t)(nu) - 1])
24
58.0M
#define I2U(indx) ((unsigned)p->Indx2Units[indx])
25
26
27
279M
#define REF(ptr) Ppmd_GetRef(p, ptr)
28
29
22.2M
#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))
30
31
390M
#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref))
32
199M
#define STATS(ctx) Ppmd8_GetStats(p, ctx)
33
54.0M
#define ONE_STATE(ctx) Ppmd8Context_OneState(ctx)
34
245M
#define SUFFIX(ctx) CTX((ctx)->Suffix)
35
36
typedef CPpmd8_Context * PPMD8_CTX_PTR;
37
38
struct CPpmd8_Node_;
39
40
typedef Ppmd_Ref_Type(struct CPpmd8_Node_) CPpmd8_Node_Ref;
41
42
typedef struct CPpmd8_Node_
43
{
44
  UInt32 Stamp;
45
  
46
  CPpmd8_Node_Ref Next;
47
  UInt32 NU;
48
} CPpmd8_Node;
49
50
32.8M
#define NODE(r)  Ppmd_GetPtr_Type(p, r, CPpmd8_Node)
51
52
void Ppmd8_Construct(CPpmd8 *p)
53
1.74k
{
54
1.74k
  unsigned i, k, m;
55
56
1.74k
  p->Base = NULL;
57
58
68.1k
  for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)
59
66.3k
  {
60
66.3k
    unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);
61
223k
    do { p->Units2Indx[k++] = (Byte)i; } while (--step);
62
66.3k
    p->Indx2Units[i] = (Byte)k;
63
66.3k
  }
64
65
1.74k
  p->NS2BSIndx[0] = (0 << 1);
66
1.74k
  p->NS2BSIndx[1] = (1 << 1);
67
1.74k
  memset(p->NS2BSIndx + 2, (2 << 1), 9);
68
1.74k
  memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);
69
70
10.4k
  for (i = 0; i < 5; i++)
71
8.73k
    p->NS2Indx[i] = (Byte)i;
72
  
73
447k
  for (m = i, k = 1; i < 260; i++)
74
445k
  {
75
445k
    p->NS2Indx[i] = (Byte)m;
76
445k
    if (--k == 0)
77
38.4k
      k = (++m) - 4;
78
445k
  }
79
80
1.74k
  memcpy(p->ExpEscape, PPMD8_kExpEscape, 16);
81
1.74k
}
82
83
84
void Ppmd8_Free(CPpmd8 *p, ISzAllocPtr alloc)
85
3.40k
{
86
3.40k
  ISzAlloc_Free(alloc, p->Base);
87
3.40k
  p->Size = 0;
88
3.40k
  p->Base = NULL;
89
3.40k
}
90
91
92
BoolInt Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAllocPtr alloc)
93
1.70k
{
94
1.70k
  if (!p->Base || p->Size != size)
95
1.70k
  {
96
1.70k
    Ppmd8_Free(p, alloc);
97
1.70k
    p->AlignOffset = (4 - size) & 3;
98
1.70k
    if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size)) == NULL)
99
0
      return False;
100
1.70k
    p->Size = size;
101
1.70k
  }
102
1.70k
  return True;
103
1.70k
}
104
105
106
107
// ---------- Internal Memory Allocator ----------
108
109
110
111
112
113
114
35.0M
#define EMPTY_NODE 0xFFFFFFFF
115
116
117
static void Ppmd8_InsertNode(CPpmd8 *p, void *node, unsigned indx)
118
33.2M
{
119
33.2M
  ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE;
120
33.2M
  ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx];
121
33.2M
  ((CPpmd8_Node *)node)->NU = I2U(indx);
122
33.2M
  p->FreeList[indx] = REF(node);
123
33.2M
  p->Stamps[indx]++;
124
33.2M
}
125
126
127
static void *Ppmd8_RemoveNode(CPpmd8 *p, unsigned indx)
128
29.9M
{
129
29.9M
  CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]);
130
29.9M
  p->FreeList[indx] = node->Next;
131
29.9M
  p->Stamps[indx]--;
132
133
29.9M
  return node;
134
29.9M
}
135
136
137
static void Ppmd8_SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx)
138
6.94M
{
139
6.94M
  unsigned i, nu = I2U(oldIndx) - I2U(newIndx);
140
6.94M
  ptr = (Byte *)ptr + U2B(I2U(newIndx));
141
6.94M
  if (I2U(i = U2I(nu)) != nu)
142
2.83M
  {
143
2.83M
    unsigned k = I2U(--i);
144
2.83M
    Ppmd8_InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);
145
2.83M
  }
146
6.94M
  Ppmd8_InsertNode(p, ptr, i);
147
6.94M
}
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
static void Ppmd8_GlueFreeBlocks(CPpmd8 *p)
163
736
{
164
  /*
165
  we use first UInt32 field of 12-bytes UNITs as record type stamp
166
    CPpmd_State    { Byte Symbol; Byte Freq; : Freq != 0xFF
167
    CPpmd8_Context { Byte NumStats; Byte Flags; UInt16 SummFreq;  : Flags != 0xFF ???
168
    CPpmd8_Node    { UInt32 Stamp            : Stamp == 0xFFFFFFFF for free record
169
                                             : Stamp == 0 for guard
170
    Last 12-bytes UNIT in array is always contains 12-bytes order-0 CPpmd8_Context record
171
  */
172
736
  CPpmd8_Node_Ref n;
173
174
736
  p->GlueCount = 1 << 13;
175
736
  memset(p->Stamps, 0, sizeof(p->Stamps));
176
  
177
  /* we set guard NODE at LoUnit */
178
736
  if (p->LoUnit != p->HiUnit)
179
449
    ((CPpmd8_Node *)(void *)p->LoUnit)->Stamp = 0;
180
181
736
  {
182
    /* Glue free blocks */
183
736
    CPpmd8_Node_Ref *prev = &n;
184
736
    unsigned i;
185
28.7k
    for (i = 0; i < PPMD_NUM_INDEXES; i++)
186
27.9k
    {
187
188
27.9k
      CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i];
189
27.9k
      p->FreeList[i] = 0;
190
1.69M
      while (next != 0)
191
1.67M
      {
192
1.67M
        CPpmd8_Node *node = NODE(next);
193
1.67M
        UInt32 nu = node->NU;
194
1.67M
        *prev = next;
195
1.67M
        next = node->Next;
196
1.67M
        if (nu != 0)
197
1.27M
        {
198
1.27M
          CPpmd8_Node *node2;
199
1.27M
          prev = &(node->Next);
200
1.84M
          while ((node2 = node + nu)->Stamp == EMPTY_NODE)
201
569k
          {
202
569k
            nu += node2->NU;
203
569k
            node2->NU = 0;
204
569k
            node->NU = nu;
205
569k
          }
206
1.27M
        }
207
1.67M
      }
208
27.9k
    }
209
210
736
    *prev = 0;
211
736
  }
212
213
214
215
  
216
217
218
219
220
221
222
  
223
224
  
225
  
226
  
227
  
228
  
229
  
230
  
231
  
232
  /* Fill lists of free blocks */
233
1.27M
  while (n != 0)
234
1.27M
  {
235
1.27M
    CPpmd8_Node *node = NODE(n);
236
1.27M
    UInt32 nu = node->NU;
237
1.27M
    unsigned i;
238
1.27M
    n = node->Next;
239
1.27M
    if (nu == 0)
240
177k
      continue;
241
1.13M
    for (; nu > 128; nu -= 128, node += 128)
242
34.1k
      Ppmd8_InsertNode(p, node, PPMD_NUM_INDEXES - 1);
243
1.10M
    if (I2U(i = U2I(nu)) != nu)
244
74.7k
    {
245
74.7k
      unsigned k = I2U(--i);
246
74.7k
      Ppmd8_InsertNode(p, node + k, (unsigned)nu - k - 1);
247
74.7k
    }
248
1.10M
    Ppmd8_InsertNode(p, node, i);
249
1.10M
  }
250
736
}
251
252
253
Z7_NO_INLINE
254
static void *Ppmd8_AllocUnitsRare(CPpmd8 *p, unsigned indx)
255
7.84M
{
256
7.84M
  unsigned i;
257
  
258
7.84M
  if (p->GlueCount == 0)
259
736
  {
260
736
    Ppmd8_GlueFreeBlocks(p);
261
736
    if (p->FreeList[indx] != 0)
262
630
      return Ppmd8_RemoveNode(p, indx);
263
736
  }
264
  
265
7.84M
  i = indx;
266
  
267
7.84M
  do
268
69.8M
  {
269
69.8M
    if (++i == PPMD_NUM_INDEXES)
270
910k
    {
271
910k
      UInt32 numBytes = U2B(I2U(indx));
272
910k
      Byte *us = p->UnitsStart;
273
910k
      p->GlueCount--;
274
910k
      return ((UInt32)(us - p->Text) > numBytes) ? (p->UnitsStart = us - numBytes) : (NULL);
275
910k
    }
276
69.8M
  }
277
68.8M
  while (p->FreeList[i] == 0);
278
  
279
6.93M
  {
280
6.93M
    void *block = Ppmd8_RemoveNode(p, i);
281
6.93M
    Ppmd8_SplitBlock(p, block, i, indx);
282
6.93M
    return block;
283
7.84M
  }
284
7.84M
}
285
286
287
static void *Ppmd8_AllocUnits(CPpmd8 *p, unsigned indx)
288
44.5M
{
289
44.5M
  if (p->FreeList[indx] != 0)
290
19.5M
    return Ppmd8_RemoveNode(p, indx);
291
24.9M
  {
292
24.9M
    UInt32 numBytes = U2B(I2U(indx));
293
24.9M
    Byte *lo = p->LoUnit;
294
24.9M
    if ((UInt32)(p->HiUnit - lo) >= numBytes)
295
21.2M
    {
296
21.2M
      p->LoUnit = lo + numBytes;
297
21.2M
      return lo;
298
21.2M
    }
299
24.9M
  }
300
3.72M
  return Ppmd8_AllocUnitsRare(p, indx);
301
24.9M
}
302
303
304
#define MEM_12_CPY(dest, src, num) \
305
22.2M
  { UInt32 *d = (UInt32 *)(dest); \
306
22.2M
    const UInt32 *z = (const UInt32 *)(src); \
307
22.2M
    unsigned n = (num); \
308
251M
    do { \
309
251M
      d[0] = z[0]; \
310
251M
      d[1] = z[1]; \
311
251M
      d[2] = z[2]; \
312
251M
      z += 3; \
313
251M
      d += 3; \
314
251M
    } while (--n); \
315
22.2M
  }
316
317
318
319
static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
320
54.6k
{
321
54.6k
  unsigned i0 = U2I(oldNU);
322
54.6k
  unsigned i1 = U2I(newNU);
323
54.6k
  if (i0 == i1)
324
2.93k
    return oldPtr;
325
51.7k
  if (p->FreeList[i1] != 0)
326
40.7k
  {
327
40.7k
    void *ptr = Ppmd8_RemoveNode(p, i1);
328
40.7k
    MEM_12_CPY(ptr, oldPtr, newNU)
329
40.7k
    Ppmd8_InsertNode(p, oldPtr, i0);
330
40.7k
    return ptr;
331
40.7k
  }
332
10.9k
  Ppmd8_SplitBlock(p, oldPtr, i0, i1);
333
10.9k
  return oldPtr;
334
51.7k
}
335
336
337
static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu)
338
0
{
339
0
  Ppmd8_InsertNode(p, ptr, U2I(nu));
340
0
}
341
342
343
static void SpecialFreeUnit(CPpmd8 *p, void *ptr)
344
139
{
345
139
  if ((Byte *)ptr != p->UnitsStart)
346
137
    Ppmd8_InsertNode(p, ptr, 0);
347
2
  else
348
2
  {
349
    #ifdef PPMD8_FREEZE_SUPPORT
350
    *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts() */
351
    #endif
352
2
    p->UnitsStart += UNIT_SIZE;
353
2
  }
354
139
}
355
356
357
/*
358
static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu)
359
{
360
  unsigned indx = U2I(nu);
361
  void *ptr;
362
  if ((Byte *)oldPtr > p->UnitsStart + (1 << 14) || REF(oldPtr) > p->FreeList[indx])
363
    return oldPtr;
364
  ptr = Ppmd8_RemoveNode(p, indx);
365
  MEM_12_CPY(ptr, oldPtr, nu)
366
  if ((Byte *)oldPtr != p->UnitsStart)
367
    Ppmd8_InsertNode(p, oldPtr, indx);
368
  else
369
    p->UnitsStart += U2B(I2U(indx));
370
  return ptr;
371
}
372
*/
373
374
static void ExpandTextArea(CPpmd8 *p)
375
0
{
376
0
  UInt32 count[PPMD_NUM_INDEXES];
377
0
  unsigned i;
378
 
379
0
  memset(count, 0, sizeof(count));
380
0
  if (p->LoUnit != p->HiUnit)
381
0
    ((CPpmd8_Node *)(void *)p->LoUnit)->Stamp = 0;
382
  
383
0
  {
384
0
    CPpmd8_Node *node = (CPpmd8_Node *)(void *)p->UnitsStart;
385
0
    while (node->Stamp == EMPTY_NODE)
386
0
    {
387
0
      UInt32 nu = node->NU;
388
0
      node->Stamp = 0;
389
0
      count[U2I(nu)]++;
390
0
      node += nu;
391
0
    }
392
0
    p->UnitsStart = (Byte *)node;
393
0
  }
394
  
395
0
  for (i = 0; i < PPMD_NUM_INDEXES; i++)
396
0
  {
397
0
    UInt32 cnt = count[i];
398
0
    if (cnt == 0)
399
0
      continue;
400
0
    {
401
0
      CPpmd8_Node_Ref *prev = (CPpmd8_Node_Ref *)&p->FreeList[i];
402
0
      CPpmd8_Node_Ref n = *prev;
403
0
      p->Stamps[i] -= cnt;
404
0
      for (;;)
405
0
      {
406
0
        CPpmd8_Node *node = NODE(n);
407
0
        n = node->Next;
408
0
        if (node->Stamp != 0)
409
0
        {
410
0
          prev = &node->Next;
411
0
          continue;
412
0
        }
413
0
        *prev = n;
414
0
        if (--cnt == 0)
415
0
          break;
416
0
      }
417
0
    }
418
0
  }
419
0
}
420
421
422
178M
#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
423
static void Ppmd8State_SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
424
180M
{
425
180M
  Ppmd_SET_SUCCESSOR(p, v)
426
180M
}
427
428
2.66k
#define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); }
429
430
Z7_NO_INLINE
431
static
432
void Ppmd8_RestartModel(CPpmd8 *p)
433
2.18k
{
434
2.18k
  unsigned i, k, m;
435
436
2.18k
  memset(p->FreeList, 0, sizeof(p->FreeList));
437
2.18k
  memset(p->Stamps, 0, sizeof(p->Stamps));
438
2.18k
  RESET_TEXT(0)
439
2.18k
  p->HiUnit = p->Text + p->Size;
440
2.18k
  p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;
441
2.18k
  p->GlueCount = 0;
442
443
2.18k
  p->OrderFall = p->MaxOrder;
444
2.18k
  p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;
445
2.18k
  p->PrevSuccess = 0;
446
447
2.18k
  {
448
2.18k
    CPpmd8_Context *mc = (PPMD8_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */
449
2.18k
    CPpmd_State *s = (CPpmd_State *)p->LoUnit; /* Ppmd8_AllocUnits(p, PPMD_NUM_INDEXES - 1); */
450
    
451
2.18k
    p->LoUnit += U2B(256 / 2);
452
2.18k
    p->MaxContext = p->MinContext = mc;
453
2.18k
    p->FoundState = s;
454
2.18k
    mc->Flags = 0;
455
2.18k
    mc->NumStats = 256 - 1;
456
2.18k
    mc->Union2.SummFreq = 256 + 1;
457
2.18k
    mc->Union4.Stats = REF(s);
458
2.18k
    mc->Suffix = 0;
459
460
561k
    for (i = 0; i < 256; i++, s++)
461
559k
    {
462
559k
      s->Symbol = (Byte)i;
463
559k
      s->Freq = 1;
464
559k
      Ppmd8State_SetSuccessor(s, 0);
465
559k
    }
466
2.18k
  }
467
468
  
469
  
470
  
471
  
472
  
473
  
474
  
475
  
476
  
477
  
478
  
479
56.8k
  for (i = m = 0; m < 25; m++)
480
54.6k
  {
481
524k
    while (p->NS2Indx[i] == m)
482
469k
      i++;
483
491k
    for (k = 0; k < 8; k++)
484
437k
    {
485
437k
      unsigned r;
486
437k
      UInt16 *dest = p->BinSumm[m] + k;
487
437k
      const UInt16 val = (UInt16)(PPMD_BIN_SCALE - PPMD8_kInitBinEsc[k] / (i + 1));
488
3.93M
      for (r = 0; r < 64; r += 8)
489
3.49M
        dest[r] = val;
490
437k
    }
491
54.6k
  }
492
493
54.6k
  for (i = m = 0; m < 24; m++)
494
52.4k
  {
495
52.4k
    unsigned summ;
496
52.4k
    CPpmd_See *s;
497
609k
    while (p->NS2Indx[(size_t)i + 3] == m + 3)
498
557k
      i++;
499
52.4k
    s = p->See[m];
500
52.4k
    summ = ((2 * i + 5) << (PPMD_PERIOD_BITS - 4));
501
1.73M
    for (k = 0; k < 32; k++, s++)
502
1.67M
    {
503
1.67M
      s->Summ = (UInt16)summ;
504
1.67M
      s->Shift = (PPMD_PERIOD_BITS - 4);
505
1.67M
      s->Count = 7;
506
1.67M
    }
507
52.4k
  }
508
509
2.18k
  p->DummySee.Summ = 0; /* unused */
510
2.18k
  p->DummySee.Shift = PPMD_PERIOD_BITS;
511
2.18k
  p->DummySee.Count = 64; /* unused */
512
2.18k
}
513
514
515
void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod)
516
1.70k
{
517
1.70k
  p->MaxOrder = maxOrder;
518
1.70k
  p->RestoreMethod = restoreMethod;
519
1.70k
  Ppmd8_RestartModel(p);
520
1.70k
}
521
522
523
294k
#define FLAG_RESCALED  (1 << 2)
524
// #define FLAG_SYM_HIGH  (1 << 3)
525
16.3k
#define FLAG_PREV_HIGH (1 << 4)
526
527
82.3k
#define HiBits_Prepare(sym) ((unsigned)(sym) + 0xC0)
528
529
117M
#define HiBits_Convert_3(flags) (((flags) >> (8 - 3)) & (1 << 3))
530
28.5M
#define HiBits_Convert_4(flags) (((flags) >> (8 - 4)) & (1 << 4))
531
532
117M
#define PPMD8_HiBitsFlag_3(sym) HiBits_Convert_3(HiBits_Prepare(sym))
533
28.5M
#define PPMD8_HiBitsFlag_4(sym) HiBits_Convert_4(HiBits_Prepare(sym))
534
535
// #define PPMD8_HiBitsFlag_3(sym) (0x08 * ((sym) >= 0x40))
536
// #define PPMD8_HiBitsFlag_4(sym) (0x10 * ((sym) >= 0x40))
537
538
/*
539
Refresh() is called when we remove some symbols (successors) in context.
540
It increases Escape_Freq for sum of all removed symbols.
541
*/
542
543
static void Refresh(CPpmd8 *p, PPMD8_CTX_PTR ctx, unsigned oldNU, unsigned scale)
544
602
{
545
602
  unsigned i = ctx->NumStats, escFreq, sumFreq, flags;
546
602
  CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1);
547
602
  ctx->Union4.Stats = REF(s);
548
549
  // #ifdef PPMD8_FREEZE_SUPPORT
550
  /*
551
    (ctx->Union2.SummFreq >= ((UInt32)1 << 15)) can be in FREEZE mode for some files.
552
    It's not good for range coder. So new versions of support fix:
553
       -   original PPMdI code rev.1
554
       +   original PPMdI code rev.2
555
       -   7-Zip default ((PPMD8_FREEZE_SUPPORT is not defined)
556
       +   7-Zip (p->RestoreMethod >= PPMD8_RESTORE_METHOD_FREEZE)
557
    if we       use that fixed line, we can lose compatibility with some files created before fix
558
    if we don't use that fixed line, the program can work incorrectly in FREEZE mode in rare case.
559
  */
560
  // if (p->RestoreMethod >= PPMD8_RESTORE_METHOD_FREEZE)
561
602
  {
562
602
    scale |= (ctx->Union2.SummFreq >= ((UInt32)1 << 15));
563
602
  }
564
  // #endif
565
566
567
568
602
  flags = HiBits_Prepare(s->Symbol);
569
602
  {
570
602
    unsigned freq = s->Freq;
571
602
    escFreq = ctx->Union2.SummFreq - freq;
572
602
    freq = (freq + scale) >> scale;
573
602
    sumFreq = freq;
574
602
    s->Freq = (Byte)freq;
575
602
  }
576
 
577
602
  do
578
81.7k
  {
579
81.7k
    unsigned freq = (++s)->Freq;
580
81.7k
    escFreq -= freq;
581
81.7k
    freq = (freq + scale) >> scale;
582
81.7k
    sumFreq += freq;
583
81.7k
    s->Freq = (Byte)freq;
584
81.7k
    flags |= HiBits_Prepare(s->Symbol);
585
81.7k
  }
586
81.7k
  while (--i);
587
  
588
602
  ctx->Union2.SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale));
589
602
  ctx->Flags = (Byte)((ctx->Flags & (FLAG_PREV_HIGH + FLAG_RESCALED * scale)) + HiBits_Convert_3(flags));
590
602
}
591
592
593
static void SWAP_STATES(CPpmd_State *t1, CPpmd_State *t2)
594
39.0M
{
595
39.0M
  CPpmd_State tmp = *t1;
596
39.0M
  *t1 = *t2;
597
39.0M
  *t2 = tmp;
598
39.0M
}
599
600
601
/*
602
CutOff() reduces contexts:
603
  It conversts Successors at MaxOrder to another Contexts to NULL-Successors
604
  It removes RAW-Successors and NULL-Successors that are not Order-0
605
      and it removes contexts when it has no Successors.
606
  if the (Union4.Stats) is close to (UnitsStart), it moves it up.
607
*/
608
609
static CPpmd_Void_Ref CutOff(CPpmd8 *p, PPMD8_CTX_PTR ctx, unsigned order)
610
0
{
611
0
  int ns = ctx->NumStats;
612
0
  unsigned nu;
613
0
  CPpmd_State *stats;
614
  
615
0
  if (ns == 0)
616
0
  {
617
0
    CPpmd_State *s = ONE_STATE(ctx);
618
0
    CPpmd_Void_Ref successor = SUCCESSOR(s);
619
0
    if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart)
620
0
    {
621
0
      if (order < p->MaxOrder)
622
0
        successor = CutOff(p, CTX(successor), order + 1);
623
0
      else
624
0
        successor = 0;
625
0
      Ppmd8State_SetSuccessor(s, successor);
626
0
      if (successor || order <= 9) /* O_BOUND */
627
0
        return REF(ctx);
628
0
    }
629
0
    SpecialFreeUnit(p, ctx);
630
0
    return 0;
631
0
  }
632
633
0
  nu = ((unsigned)ns + 2) >> 1;
634
  // ctx->Union4.Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), nu));
635
0
  {
636
0
    unsigned indx = U2I(nu);
637
0
    stats = STATS(ctx);
638
639
0
    if ((UInt32)((Byte *)stats - p->UnitsStart) <= (1 << 14)
640
0
        && (CPpmd_Void_Ref)ctx->Union4.Stats <= p->FreeList[indx])
641
0
    {
642
0
      void *ptr = Ppmd8_RemoveNode(p, indx);
643
0
      ctx->Union4.Stats = STATS_REF(ptr);
644
0
      MEM_12_CPY(ptr, (const void *)stats, nu)
645
0
      if ((Byte *)stats != p->UnitsStart)
646
0
        Ppmd8_InsertNode(p, stats, indx);
647
0
      else
648
0
        p->UnitsStart += U2B(I2U(indx));
649
0
      stats = ptr;
650
0
    }
651
0
  }
652
653
0
  {
654
0
    CPpmd_State *s = stats + (unsigned)ns;
655
0
    do
656
0
    {
657
0
      CPpmd_Void_Ref successor = SUCCESSOR(s);
658
0
      if ((Byte *)Ppmd8_GetPtr(p, successor) < p->UnitsStart)
659
0
      {
660
0
        CPpmd_State *s2 = stats + (unsigned)(ns--);
661
0
        if (order)
662
0
        {
663
0
          if (s != s2)
664
0
            *s = *s2;
665
0
        }
666
0
        else
667
0
        {
668
0
          SWAP_STATES(s, s2);
669
0
          Ppmd8State_SetSuccessor(s2, 0);
670
0
        }
671
0
      }
672
0
      else
673
0
      {
674
0
        if (order < p->MaxOrder)
675
0
          Ppmd8State_SetSuccessor(s, CutOff(p, CTX(successor), order + 1));
676
0
        else
677
0
          Ppmd8State_SetSuccessor(s, 0);
678
0
      }
679
0
    }
680
0
    while (--s >= stats);
681
0
  }
682
  
683
0
  if (ns != ctx->NumStats && order)
684
0
  {
685
0
    if (ns < 0)
686
0
    {
687
0
      FreeUnits(p, stats, nu);
688
0
      SpecialFreeUnit(p, ctx);
689
0
      return 0;
690
0
    }
691
0
    ctx->NumStats = (Byte)ns;
692
0
    if (ns == 0)
693
0
    {
694
0
      const Byte sym = stats->Symbol;
695
0
      ctx->Flags = (Byte)((ctx->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(sym));
696
      // *ONE_STATE(ctx) = *stats;
697
0
      ctx->Union2.State2.Symbol = sym;
698
0
      ctx->Union2.State2.Freq = (Byte)(((unsigned)stats->Freq + 11) >> 3);
699
0
      ctx->Union4.State4.Successor_0 = stats->Successor_0;
700
0
      ctx->Union4.State4.Successor_1 = stats->Successor_1;
701
0
      FreeUnits(p, stats, nu);
702
0
    }
703
0
    else
704
0
    {
705
0
      Refresh(p, ctx, nu, ctx->Union2.SummFreq > 16 * (unsigned)ns);
706
0
    }
707
0
  }
708
  
709
0
  return REF(ctx);
710
0
}
711
712
713
714
#ifdef PPMD8_FREEZE_SUPPORT
715
716
/*
717
RemoveBinContexts()
718
  It conversts Successors at MaxOrder to another Contexts to NULL-Successors
719
  It changes RAW-Successors to NULL-Successors
720
  removes Bin Context without Successor, if suffix of that context is also binary.
721
*/
722
723
static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, PPMD8_CTX_PTR ctx, unsigned order)
724
{
725
  if (!ctx->NumStats)
726
  {
727
    CPpmd_State *s = ONE_STATE(ctx);
728
    CPpmd_Void_Ref successor = SUCCESSOR(s);
729
    if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart && order < p->MaxOrder)
730
      successor = RemoveBinContexts(p, CTX(successor), order + 1);
731
    else
732
      successor = 0;
733
    Ppmd8State_SetSuccessor(s, successor);
734
    /* Suffix context can be removed already, since different (high-order)
735
       Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */
736
    if (!successor && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF))
737
    {
738
      FreeUnits(p, ctx, 1);
739
      return 0;
740
    }
741
  }
742
  else
743
  {
744
    CPpmd_State *s = STATS(ctx) + ctx->NumStats;
745
    do
746
    {
747
      CPpmd_Void_Ref successor = SUCCESSOR(s);
748
      if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart && order < p->MaxOrder)
749
        Ppmd8State_SetSuccessor(s, RemoveBinContexts(p, CTX(successor), order + 1));
750
      else
751
        Ppmd8State_SetSuccessor(s, 0);
752
    }
753
    while (--s >= STATS(ctx));
754
  }
755
  
756
  return REF(ctx);
757
}
758
759
#endif
760
761
762
763
static UInt32 GetUsedMemory(const CPpmd8 *p)
764
0
{
765
0
  UInt32 v = 0;
766
0
  unsigned i;
767
0
  for (i = 0; i < PPMD_NUM_INDEXES; i++)
768
0
    v += p->Stamps[i] * I2U(i);
769
0
  return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v);
770
0
}
771
772
#ifdef PPMD8_FREEZE_SUPPORT
773
  #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor)
774
#else
775
483
  #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1)
776
#endif
777
778
779
static void RestoreModel(CPpmd8 *p, PPMD8_CTX_PTR ctxError
780
    #ifdef PPMD8_FREEZE_SUPPORT
781
    , PPMD8_CTX_PTR fSuccessor
782
    #endif
783
    )
784
483
{
785
483
  PPMD8_CTX_PTR c;
786
483
  CPpmd_State *s;
787
483
  RESET_TEXT(0)
788
789
  // we go here in cases of error of allocation for context (c1)
790
  // Order(MinContext) < Order(ctxError) <= Order(MaxContext)
791
  
792
  // We remove last symbol from each of contexts [p->MaxContext ... ctxError) contexts
793
  // So we rollback all created (symbols) before error.
794
797
  for (c = p->MaxContext; c != ctxError; c = SUFFIX(c))
795
314
    if (--(c->NumStats) == 0)
796
139
    {
797
139
      s = STATS(c);
798
139
      c->Flags = (Byte)((c->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(s->Symbol));
799
      // *ONE_STATE(c) = *s;
800
139
      c->Union2.State2.Symbol = s->Symbol;
801
139
      c->Union2.State2.Freq = (Byte)(((unsigned)s->Freq + 11) >> 3);
802
139
      c->Union4.State4.Successor_0 = s->Successor_0;
803
139
      c->Union4.State4.Successor_1 = s->Successor_1;
804
805
139
      SpecialFreeUnit(p, s);
806
139
    }
807
175
    else
808
175
    {
809
      /* Refresh() can increase Escape_Freq on value of Freq of last symbol, that was added before error.
810
         so the largest possible increase for Escape_Freq is (8) from value before ModelUpoadet() */
811
175
      Refresh(p, c, ((unsigned)c->NumStats + 3) >> 1, 0);
812
175
    }
813
 
814
  // increase Escape Freq for context [ctxError ... p->MinContext)
815
960
  for (; c != p->MinContext; c = SUFFIX(c))
816
477
    if (c->NumStats == 0)
817
13
    {
818
      // ONE_STATE(c)
819
13
      c->Union2.State2.Freq = (Byte)(((unsigned)c->Union2.State2.Freq + 1) >> 1);
820
13
    }
821
464
    else if ((c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 4)) > 128 + 4 * c->NumStats)
822
427
      Refresh(p, c, ((unsigned)c->NumStats + 2) >> 1, 1);
823
824
  #ifdef PPMD8_FREEZE_SUPPORT
825
  if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
826
  {
827
    p->MaxContext = fSuccessor;
828
    p->GlueCount += !(p->Stamps[1] & 1); // why?
829
  }
830
  else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE)
831
  {
832
    while (p->MaxContext->Suffix)
833
      p->MaxContext = SUFFIX(p->MaxContext);
834
    RemoveBinContexts(p, p->MaxContext, 0);
835
    // we change the current mode to (PPMD8_RESTORE_METHOD_FREEZE + 1)
836
    p->RestoreMethod = PPMD8_RESTORE_METHOD_FREEZE + 1;
837
    p->GlueCount = 0;
838
    p->OrderFall = p->MaxOrder;
839
  }
840
  else
841
  #endif
842
483
  if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1))
843
483
    Ppmd8_RestartModel(p);
844
0
  else
845
0
  {
846
0
    while (p->MaxContext->Suffix)
847
0
      p->MaxContext = SUFFIX(p->MaxContext);
848
0
    do
849
0
    {
850
0
      CutOff(p, p->MaxContext, 0);
851
0
      ExpandTextArea(p);
852
0
    }
853
0
    while (GetUsedMemory(p) > 3 * (p->Size >> 2));
854
0
    p->GlueCount = 0;
855
0
    p->OrderFall = p->MaxOrder;
856
0
  }
857
483
  p->MinContext = p->MaxContext;
858
483
}
859
860
861
862
Z7_NO_INLINE
863
static PPMD8_CTX_PTR Ppmd8_CreateSuccessors(CPpmd8 *p, BoolInt skip, CPpmd_State *s1, PPMD8_CTX_PTR c)
864
30.4M
{
865
866
30.4M
  CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);
867
30.4M
  Byte newSym, newFreq, flags;
868
30.4M
  unsigned numPs = 0;
869
30.4M
  CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; /* fixed over Shkarin's code. Maybe it could work without + 1 too. */
870
  
871
30.4M
  if (!skip)
872
21.2M
    ps[numPs++] = p->FoundState;
873
  
874
50.2M
  while (c->Suffix)
875
50.0M
  {
876
50.0M
    CPpmd_Void_Ref successor;
877
50.0M
    CPpmd_State *s;
878
50.0M
    c = SUFFIX(c);
879
    
880
50.0M
    if (s1) { s = s1; s1 = NULL; }
881
19.9M
    else if (c->NumStats != 0)
882
12.5M
    {
883
12.5M
      Byte sym = p->FoundState->Symbol;
884
759M
      for (s = STATS(c); s->Symbol != sym; s++);
885
12.5M
      if (s->Freq < MAX_FREQ - 9) { s->Freq++; c->Union2.SummFreq++; }
886
12.5M
    }
887
7.38M
    else
888
7.38M
    {
889
7.38M
      s = ONE_STATE(c);
890
7.38M
      s->Freq = (Byte)(s->Freq + (!SUFFIX(c)->NumStats & (s->Freq < 24)));
891
7.38M
    }
892
50.0M
    successor = SUCCESSOR(s);
893
50.0M
    if (successor != upBranch)
894
30.1M
    {
895
896
30.1M
      c = CTX(successor);
897
30.1M
      if (numPs == 0)
898
1.82M
      {
899
        
900
       
901
1.82M
        return c;
902
1.82M
      }
903
28.3M
      break;
904
30.1M
    }
905
19.8M
    ps[numPs++] = s;
906
19.8M
  }
907
  
908
  
909
  
910
  
911
  
912
28.5M
  newSym = *(const Byte *)Ppmd8_GetPtr(p, upBranch);
913
28.5M
  upBranch++;
914
28.5M
  flags = (Byte)(PPMD8_HiBitsFlag_4(p->FoundState->Symbol) + PPMD8_HiBitsFlag_3(newSym));
915
  
916
28.5M
  if (c->NumStats == 0)
917
654k
    newFreq = c->Union2.State2.Freq;
918
27.9M
  else
919
27.9M
  {
920
27.9M
    UInt32 cf, s0;
921
27.9M
    CPpmd_State *s;
922
1.29G
    for (s = STATS(c); s->Symbol != newSym; s++);
923
27.9M
    cf = (UInt32)s->Freq - 1;
924
27.9M
    s0 = (UInt32)c->Union2.SummFreq - c->NumStats - cf;
925
    /*
926
    
927
928
      max(newFreq)= (s->Freq - 1), when (s0 == 1)
929
930
931
    */
932
27.9M
    newFreq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0)));
933
27.9M
  }
934
935
936
937
28.5M
  do
938
41.1M
  {
939
41.1M
    PPMD8_CTX_PTR c1;
940
    /* = AllocContext(p); */
941
41.1M
    if (p->HiUnit != p->LoUnit)
942
33.6M
      c1 = (PPMD8_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE);
943
7.52M
    else if (p->FreeList[0] != 0)
944
3.39M
      c1 = (PPMD8_CTX_PTR)Ppmd8_RemoveNode(p, 0);
945
4.12M
    else
946
4.12M
    {
947
4.12M
      c1 = (PPMD8_CTX_PTR)Ppmd8_AllocUnitsRare(p, 0);
948
4.12M
      if (!c1)
949
10
        return NULL;
950
4.12M
    }
951
41.1M
    c1->Flags = flags;
952
41.1M
    c1->NumStats = 0;
953
41.1M
    c1->Union2.State2.Symbol = newSym;
954
41.1M
    c1->Union2.State2.Freq = newFreq;
955
41.1M
    Ppmd8State_SetSuccessor(ONE_STATE(c1), upBranch);
956
41.1M
    c1->Suffix = REF(c);
957
41.1M
    Ppmd8State_SetSuccessor(ps[--numPs], REF(c1));
958
41.1M
    c = c1;
959
41.1M
  }
960
41.1M
  while (numPs != 0);
961
  
962
28.5M
  return c;
963
28.5M
}
964
965
966
static PPMD8_CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, PPMD8_CTX_PTR c)
967
301k
{
968
301k
  CPpmd_State *s = NULL;
969
301k
  PPMD8_CTX_PTR c1 = c;
970
301k
  CPpmd_Void_Ref upBranch = REF(p->Text);
971
  
972
  #ifdef PPMD8_FREEZE_SUPPORT
973
  /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */
974
  CPpmd_State *ps[PPMD8_MAX_ORDER + 1];
975
  unsigned numPs = 0;
976
  ps[numPs++] = p->FoundState;
977
  #endif
978
979
301k
  Ppmd8State_SetSuccessor(p->FoundState, upBranch);
980
301k
  p->OrderFall++;
981
982
301k
  for (;;)
983
301k
  {
984
301k
    if (s1)
985
0
    {
986
0
      c = SUFFIX(c);
987
0
      s = s1;
988
0
      s1 = NULL;
989
0
    }
990
301k
    else
991
301k
    {
992
301k
      if (!c->Suffix)
993
301k
      {
994
        #ifdef PPMD8_FREEZE_SUPPORT
995
        if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
996
        {
997
          do { Ppmd8State_SetSuccessor(ps[--numPs], REF(c)); } while (numPs);
998
          RESET_TEXT(1)
999
          p->OrderFall = 1;
1000
        }
1001
        #endif
1002
301k
        return c;
1003
301k
      }
1004
0
      c = SUFFIX(c);
1005
0
      if (c->NumStats)
1006
0
      {
1007
0
        if ((s = STATS(c))->Symbol != p->FoundState->Symbol)
1008
0
          do { s++; } while (s->Symbol != p->FoundState->Symbol);
1009
0
        if (s->Freq < MAX_FREQ - 9)
1010
0
        {
1011
0
          s->Freq = (Byte)(s->Freq + 2);
1012
0
          c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2);
1013
0
        }
1014
0
      }
1015
0
      else
1016
0
      {
1017
0
        s = ONE_STATE(c);
1018
0
        s->Freq = (Byte)(s->Freq + (s->Freq < 32));
1019
0
      }
1020
0
    }
1021
0
    if (SUCCESSOR(s))
1022
0
      break;
1023
    #ifdef PPMD8_FREEZE_SUPPORT
1024
    ps[numPs++] = s;
1025
    #endif
1026
0
    Ppmd8State_SetSuccessor(s, upBranch);
1027
0
    p->OrderFall++;
1028
0
  }
1029
  
1030
  #ifdef PPMD8_FREEZE_SUPPORT
1031
  if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
1032
  {
1033
    c = CTX(SUCCESSOR(s));
1034
    do { Ppmd8State_SetSuccessor(ps[--numPs], REF(c)); } while (numPs);
1035
    RESET_TEXT(1)
1036
    p->OrderFall = 1;
1037
    return c;
1038
  }
1039
  else
1040
  #endif
1041
0
  if (SUCCESSOR(s) <= upBranch)
1042
0
  {
1043
0
    PPMD8_CTX_PTR successor;
1044
0
    CPpmd_State *s2 = p->FoundState;
1045
0
    p->FoundState = s;
1046
1047
0
    successor = Ppmd8_CreateSuccessors(p, False, NULL, c);
1048
0
    if (!successor)
1049
0
      Ppmd8State_SetSuccessor(s, 0);
1050
0
    else
1051
0
      Ppmd8State_SetSuccessor(s, REF(successor));
1052
0
    p->FoundState = s2;
1053
0
  }
1054
  
1055
0
  {
1056
0
    CPpmd_Void_Ref successor = SUCCESSOR(s);
1057
0
    if (p->OrderFall == 1 && c1 == p->MaxContext)
1058
0
    {
1059
0
      Ppmd8State_SetSuccessor(p->FoundState, successor);
1060
0
      p->Text--;
1061
0
    }
1062
0
    if (successor == 0)
1063
0
      return NULL;
1064
0
    return CTX(successor);
1065
0
  }
1066
0
}
1067
1068
1069
1070
void Ppmd8_UpdateModel(CPpmd8 *p);
1071
Z7_NO_INLINE
1072
void Ppmd8_UpdateModel(CPpmd8 *p)
1073
97.7M
{
1074
97.7M
  CPpmd_Void_Ref maxSuccessor, minSuccessor = SUCCESSOR(p->FoundState);
1075
97.7M
  PPMD8_CTX_PTR c;
1076
97.7M
  unsigned s0, ns, fFreq = p->FoundState->Freq;
1077
97.7M
  Byte flag, fSymbol = p->FoundState->Symbol;
1078
97.7M
  {
1079
97.7M
  CPpmd_State *s = NULL;
1080
97.7M
  if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)
1081
53.6M
  {
1082
    /* Update Freqs in Suffix Context */
1083
1084
53.6M
    c = SUFFIX(p->MinContext);
1085
    
1086
53.6M
    if (c->NumStats == 0)
1087
5.48M
    {
1088
5.48M
      s = ONE_STATE(c);
1089
5.48M
      if (s->Freq < 32)
1090
5.47M
        s->Freq++;
1091
5.48M
    }
1092
48.1M
    else
1093
48.1M
    {
1094
48.1M
      Byte sym = p->FoundState->Symbol;
1095
48.1M
      s = STATS(c);
1096
1097
48.1M
      if (s->Symbol != sym)
1098
45.1M
      {
1099
45.1M
        do
1100
4.76G
        {
1101
        
1102
4.76G
          s++;
1103
4.76G
        }
1104
4.76G
        while (s->Symbol != sym);
1105
        
1106
45.1M
        if (s[0].Freq >= s[-1].Freq)
1107
23.5M
        {
1108
23.5M
          SWAP_STATES(&s[0], &s[-1]);
1109
23.5M
          s--;
1110
23.5M
        }
1111
45.1M
      }
1112
      
1113
48.1M
      if (s->Freq < MAX_FREQ - 9)
1114
44.6M
      {
1115
44.6M
        s->Freq = (Byte)(s->Freq + 2);
1116
44.6M
        c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2);
1117
44.6M
      }
1118
48.1M
    }
1119
53.6M
  }
1120
  
1121
97.7M
  c = p->MaxContext;
1122
97.7M
  if (p->OrderFall == 0 && minSuccessor)
1123
9.11M
  {
1124
9.11M
    PPMD8_CTX_PTR cs = Ppmd8_CreateSuccessors(p, True, s, p->MinContext);
1125
9.11M
    if (!cs)
1126
8
    {
1127
8
      Ppmd8State_SetSuccessor(p->FoundState, 0);
1128
8
      RESTORE_MODEL(c, CTX(minSuccessor));
1129
8
      return;
1130
8
    }
1131
9.11M
    Ppmd8State_SetSuccessor(p->FoundState, REF(cs));
1132
9.11M
    p->MinContext = p->MaxContext = cs;
1133
9.11M
    return;
1134
9.11M
  }
1135
  
1136
1137
1138
1139
88.6M
  {
1140
88.6M
    Byte *text = p->Text;
1141
88.6M
    *text++ = p->FoundState->Symbol;
1142
88.6M
    p->Text = text;
1143
88.6M
    if (text >= p->UnitsStart)
1144
47
    {
1145
47
      RESTORE_MODEL(c, CTX(minSuccessor)); /* check it */
1146
47
      return;
1147
47
    }
1148
88.6M
    maxSuccessor = REF(text);
1149
88.6M
  }
1150
1151
88.6M
  if (!minSuccessor)
1152
301k
  {
1153
301k
    PPMD8_CTX_PTR cs = ReduceOrder(p, s, p->MinContext);
1154
301k
    if (!cs)
1155
0
    {
1156
0
      RESTORE_MODEL(c, NULL);
1157
0
      return;
1158
0
    }
1159
301k
    minSuccessor = REF(cs);
1160
301k
  }
1161
88.3M
  else if ((Byte *)Ppmd8_GetPtr(p, minSuccessor) < p->UnitsStart)
1162
21.2M
  {
1163
21.2M
    PPMD8_CTX_PTR cs = Ppmd8_CreateSuccessors(p, False, s, p->MinContext);
1164
21.2M
    if (!cs)
1165
2
    {
1166
2
      RESTORE_MODEL(c, NULL);
1167
2
      return;
1168
2
    }
1169
21.2M
    minSuccessor = REF(cs);
1170
21.2M
  }
1171
  
1172
88.6M
  if (--p->OrderFall == 0)
1173
27.8M
  {
1174
27.8M
    maxSuccessor = minSuccessor;
1175
27.8M
    p->Text -= (p->MaxContext != p->MinContext);
1176
27.8M
  }
1177
  #ifdef PPMD8_FREEZE_SUPPORT
1178
  else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
1179
  {
1180
    maxSuccessor = minSuccessor;
1181
    RESET_TEXT(0)
1182
    p->OrderFall = 0;
1183
  }
1184
  #endif
1185
88.6M
  }
1186
  
1187
  
1188
  
1189
  
1190
  
1191
  
1192
  
1193
  
1194
  
1195
  
1196
  
1197
  
1198
  
1199
  
1200
  
1201
  
1202
  
1203
  
1204
  
1205
  
1206
  
1207
  
1208
  
1209
  
1210
  
1211
1212
  
1213
  
1214
88.6M
  flag = (Byte)(PPMD8_HiBitsFlag_3(fSymbol));
1215
88.6M
  s0 = p->MinContext->Union2.SummFreq - (ns = p->MinContext->NumStats) - fFreq;
1216
  
1217
177M
  for (; c != p->MinContext; c = SUFFIX(c))
1218
88.3M
  {
1219
88.3M
    unsigned ns1;
1220
88.3M
    UInt32 sum;
1221
    
1222
88.3M
    if ((ns1 = c->NumStats) != 0)
1223
65.9M
    {
1224
65.9M
      if ((ns1 & 1) != 0)
1225
36.3M
      {
1226
        /* Expand for one UNIT */
1227
36.3M
        const unsigned oldNU = (ns1 + 1) >> 1;
1228
36.3M
        const unsigned i = U2I(oldNU);
1229
36.3M
        if (i != U2I((size_t)oldNU + 1))
1230
22.1M
        {
1231
22.1M
          void *ptr = Ppmd8_AllocUnits(p, i + 1);
1232
22.1M
          void *oldPtr;
1233
22.1M
          if (!ptr)
1234
424
          {
1235
424
            RESTORE_MODEL(c, CTX(minSuccessor));
1236
424
            return;
1237
424
          }
1238
22.1M
          oldPtr = STATS(c);
1239
22.1M
          MEM_12_CPY(ptr, oldPtr, oldNU)
1240
22.1M
          Ppmd8_InsertNode(p, oldPtr, i);
1241
22.1M
          c->Union4.Stats = STATS_REF(ptr);
1242
22.1M
        }
1243
36.3M
      }
1244
65.9M
      sum = c->Union2.SummFreq;
1245
      /* max increase of Escape_Freq is 1 here.
1246
         an average increase is 1/3 per symbol */
1247
65.9M
      sum += (UInt32)(unsigned)(3 * ns1 + 1 < ns);
1248
      /* original PPMdH uses 16-bit variable for (sum) here.
1249
         But (sum < ???). Do we need to truncate (sum) to 16-bit */
1250
      // sum = (UInt16)sum;
1251
65.9M
    }
1252
22.3M
    else
1253
22.3M
    {
1254
      
1255
22.3M
      CPpmd_State *s = (CPpmd_State*)Ppmd8_AllocUnits(p, 0);
1256
22.3M
      if (!s)
1257
2
      {
1258
2
        RESTORE_MODEL(c, CTX(minSuccessor));
1259
2
        return;
1260
2
      }
1261
22.3M
      {
1262
22.3M
        unsigned freq = c->Union2.State2.Freq;
1263
        // s = *ONE_STATE(c);
1264
22.3M
        s->Symbol = c->Union2.State2.Symbol;
1265
22.3M
        s->Successor_0 = c->Union4.State4.Successor_0;
1266
22.3M
        s->Successor_1 = c->Union4.State4.Successor_1;
1267
        // Ppmd8State_SetSuccessor(s, c->Union4.Stats);  // call it only for debug purposes to check the order of
1268
                                              // (Successor_0 and Successor_1) in LE/BE.
1269
22.3M
        c->Union4.Stats = REF(s);
1270
22.3M
        if (freq < MAX_FREQ / 4 - 1)
1271
22.3M
          freq <<= 1;
1272
16.8k
        else
1273
16.8k
          freq = MAX_FREQ - 4;
1274
1275
22.3M
        s->Freq = (Byte)freq;
1276
1277
22.3M
        sum = (UInt32)(freq + p->InitEsc + (ns > 2));   // Ppmd8 (> 2)
1278
22.3M
      }
1279
22.3M
    }
1280
1281
88.3M
    {
1282
88.3M
      CPpmd_State *s = STATS(c) + ns1 + 1;
1283
88.3M
      UInt32 cf = 2 * (sum + 6) * (UInt32)fFreq;
1284
88.3M
      UInt32 sf = (UInt32)s0 + sum;
1285
88.3M
      s->Symbol = fSymbol;
1286
88.3M
      c->NumStats = (Byte)(ns1 + 1);
1287
88.3M
      Ppmd8State_SetSuccessor(s, maxSuccessor);
1288
88.3M
      c->Flags |= flag;
1289
88.3M
      if (cf < 6 * sf)
1290
70.8M
      {
1291
70.8M
        cf = (unsigned)1 + (cf > sf) + (cf >= 4 * sf);
1292
70.8M
        sum += 4;
1293
        /* It can add (1, 2, 3) to Escape_Freq */
1294
70.8M
      }
1295
17.5M
      else
1296
17.5M
      {
1297
17.5M
        cf = (unsigned)4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf);
1298
17.5M
        sum += cf;
1299
17.5M
      }
1300
1301
88.3M
      c->Union2.SummFreq = (UInt16)sum;
1302
88.3M
      s->Freq = (Byte)cf;
1303
88.3M
    }
1304
1305
88.3M
  }
1306
88.6M
  p->MaxContext = p->MinContext = CTX(minSuccessor);
1307
88.6M
}
1308
  
1309
1310
1311
Z7_NO_INLINE
1312
static void Ppmd8_Rescale(CPpmd8 *p)
1313
309k
{
1314
309k
  unsigned i, adder, sumFreq, escFreq;
1315
309k
  CPpmd_State *stats = STATS(p->MinContext);
1316
309k
  CPpmd_State *s = p->FoundState;
1317
1318
  /* Sort the list by Freq */
1319
309k
  if (s != stats)
1320
27.5k
  {
1321
27.5k
    CPpmd_State tmp = *s;
1322
27.5k
    do
1323
1.72M
      s[0] = s[-1];
1324
1.72M
    while (--s != stats);
1325
27.5k
    *s = tmp;
1326
27.5k
  }
1327
1328
309k
  sumFreq = s->Freq;
1329
309k
  escFreq = p->MinContext->Union2.SummFreq - sumFreq;
1330
1331
1332
  
1333
  
1334
  
1335
  
1336
309k
  adder = (p->OrderFall != 0);
1337
  
1338
  #ifdef PPMD8_FREEZE_SUPPORT
1339
  adder |= (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE);
1340
  #endif
1341
  
1342
309k
  sumFreq = (sumFreq + 4 + adder) >> 1;
1343
309k
  i = p->MinContext->NumStats;
1344
309k
  s->Freq = (Byte)sumFreq;
1345
  
1346
309k
  do
1347
38.5M
  {
1348
38.5M
    unsigned freq = (++s)->Freq;
1349
38.5M
    escFreq -= freq;
1350
38.5M
    freq = (freq + adder) >> 1;
1351
38.5M
    sumFreq += freq;
1352
38.5M
    s->Freq = (Byte)freq;
1353
38.5M
    if (freq > s[-1].Freq)
1354
12.6M
    {
1355
12.6M
      CPpmd_State tmp = *s;
1356
12.6M
      CPpmd_State *s1 = s;
1357
12.6M
      do
1358
802M
      {
1359
802M
        s1[0] = s1[-1];
1360
802M
      }
1361
802M
      while (--s1 != stats && freq > s1[-1].Freq);
1362
12.6M
      *s1 = tmp;
1363
12.6M
    }
1364
38.5M
  }
1365
38.5M
  while (--i);
1366
  
1367
309k
  if (s->Freq == 0)
1368
74.8k
  {
1369
    /* Remove all items with Freq == 0 */
1370
74.8k
    CPpmd8_Context *mc;
1371
74.8k
    unsigned numStats, numStatsNew, n0, n1;
1372
    
1373
616k
    i = 0; do { i++; } while ((--s)->Freq == 0);
1374
    
1375
    
1376
1377
    
1378
74.8k
    escFreq += i;
1379
74.8k
    mc = p->MinContext;
1380
74.8k
    numStats = mc->NumStats;
1381
74.8k
    numStatsNew = numStats - i;
1382
74.8k
    mc->NumStats = (Byte)(numStatsNew);
1383
74.8k
    n0 = (numStats + 2) >> 1;
1384
    
1385
74.8k
    if (numStatsNew == 0)
1386
15.5k
    {
1387
    
1388
15.5k
      unsigned freq = (2 * (unsigned)stats->Freq + escFreq - 1) / escFreq;
1389
15.5k
      if (freq > MAX_FREQ / 3)
1390
3.74k
        freq = MAX_FREQ / 3;
1391
15.5k
      mc->Flags = (Byte)((mc->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(stats->Symbol));
1392
      
1393
      
1394
      
1395
      
1396
      
1397
15.5k
      s = ONE_STATE(mc);
1398
15.5k
      *s = *stats;
1399
15.5k
      s->Freq = (Byte)freq;
1400
15.5k
      p->FoundState = s;
1401
15.5k
      Ppmd8_InsertNode(p, stats, U2I(n0));
1402
15.5k
      return;
1403
15.5k
    }
1404
1405
59.2k
    n1 = (numStatsNew + 2) >> 1;
1406
59.2k
    if (n0 != n1)
1407
54.0k
      mc->Union4.Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));
1408
59.2k
    {
1409
      // here we are for max order only. So Ppmd8_MakeEscFreq() doesn't use mc->Flags
1410
      // but we still need current (Flags & FLAG_PREV_HIGH), if we will convert context to 1-symbol context later.
1411
      /*
1412
      unsigned flags = HiBits_Prepare((s = STATS(mc))->Symbol);
1413
      i = mc->NumStats;
1414
      do { flags |= HiBits_Prepare((++s)->Symbol); } while (--i);
1415
      mc->Flags = (Byte)((mc->Flags & ~FLAG_SYM_HIGH) + HiBits_Convert_3(flags));
1416
      */
1417
59.2k
    }
1418
59.2k
  }
1419
1420
1421
1422
  
1423
1424
1425
293k
  {
1426
293k
    CPpmd8_Context *mc = p->MinContext;
1427
293k
    mc->Union2.SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));
1428
293k
    mc->Flags |= FLAG_RESCALED;
1429
293k
    p->FoundState = STATS(mc);
1430
293k
  }
1431
293k
}
1432
1433
1434
CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq)
1435
86.4M
{
1436
86.4M
  CPpmd_See *see;
1437
86.4M
  const CPpmd8_Context *mc = p->MinContext;
1438
86.4M
  unsigned numStats = mc->NumStats;
1439
86.4M
  if (numStats != 0xFF)
1440
45.6M
  {
1441
    // (3 <= numStats + 2 <= 256)   (3 <= NS2Indx[3] and NS2Indx[256] === 26)
1442
45.6M
    see = p->See[(size_t)(unsigned)p->NS2Indx[(size_t)numStats + 2] - 3]
1443
45.6M
        + (mc->Union2.SummFreq > 11 * (numStats + 1))
1444
45.6M
        + 2 * (unsigned)(2 * numStats < ((unsigned)SUFFIX(mc)->NumStats + numMasked1))
1445
45.6M
        + mc->Flags;
1446
1447
45.6M
    {
1448
      // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ
1449
45.6M
      const unsigned summ = (UInt16)see->Summ; // & 0xFFFF
1450
45.6M
      const unsigned r = (summ >> see->Shift);
1451
45.6M
      see->Summ = (UInt16)(summ - r);
1452
45.6M
      *escFreq = (UInt32)(r + (r == 0));
1453
45.6M
    }
1454
45.6M
  }
1455
40.8M
  else
1456
40.8M
  {
1457
40.8M
    see = &p->DummySee;
1458
40.8M
    *escFreq = 1;
1459
40.8M
  }
1460
86.4M
  return see;
1461
86.4M
}
1462
1463
 
1464
static void Ppmd8_NextContext(CPpmd8 *p)
1465
26.2M
{
1466
26.2M
  PPMD8_CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
1467
26.2M
  if (p->OrderFall == 0 && (const Byte *)c >= p->UnitsStart)
1468
7.63M
    p->MaxContext = p->MinContext = c;
1469
18.5M
  else
1470
18.5M
    Ppmd8_UpdateModel(p);
1471
26.2M
}
1472
 
1473
1474
void Ppmd8_Update1(CPpmd8 *p)
1475
20.1M
{
1476
20.1M
  CPpmd_State *s = p->FoundState;
1477
20.1M
  unsigned freq = s->Freq;
1478
20.1M
  freq += 4;
1479
20.1M
  p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4);
1480
20.1M
  s->Freq = (Byte)freq;
1481
20.1M
  if (freq > s[-1].Freq)
1482
15.4M
  {
1483
15.4M
    SWAP_STATES(s, &s[-1]);
1484
15.4M
    p->FoundState = --s;
1485
15.4M
    if (freq > MAX_FREQ)
1486
2.11k
      Ppmd8_Rescale(p);
1487
15.4M
  }
1488
20.1M
  Ppmd8_NextContext(p);
1489
20.1M
}
1490
1491
1492
void Ppmd8_Update1_0(CPpmd8 *p)
1493
6.08M
{
1494
6.08M
  CPpmd_State *s = p->FoundState;
1495
6.08M
  CPpmd8_Context *mc = p->MinContext;
1496
6.08M
  unsigned freq = s->Freq;
1497
6.08M
  const unsigned summFreq = mc->Union2.SummFreq;
1498
6.08M
  p->PrevSuccess = (2 * freq >= summFreq); // Ppmd8 (>=)
1499
6.08M
  p->RunLength += (Int32)p->PrevSuccess;
1500
6.08M
  mc->Union2.SummFreq = (UInt16)(summFreq + 4);
1501
6.08M
  freq += 4;
1502
6.08M
  s->Freq = (Byte)freq;
1503
6.08M
  if (freq > MAX_FREQ)
1504
164k
    Ppmd8_Rescale(p);
1505
6.08M
  Ppmd8_NextContext(p);
1506
6.08M
}
1507
1508
1509
/*
1510
void Ppmd8_UpdateBin(CPpmd8 *p)
1511
{
1512
  unsigned freq = p->FoundState->Freq;
1513
  p->FoundState->Freq = (Byte)(freq + (freq < 196)); // Ppmd8 (196)
1514
  p->PrevSuccess = 1;
1515
  p->RunLength++;
1516
  Ppmd8_NextContext(p);
1517
}
1518
*/
1519
1520
void Ppmd8_Update2(CPpmd8 *p)
1521
70.0M
{
1522
70.0M
  CPpmd_State *s = p->FoundState;
1523
70.0M
  unsigned freq = s->Freq;
1524
70.0M
  freq += 4;
1525
70.0M
  p->RunLength = p->InitRL;
1526
70.0M
  p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4);
1527
70.0M
  s->Freq = (Byte)freq;
1528
70.0M
  if (freq > MAX_FREQ)
1529
142k
    Ppmd8_Rescale(p);
1530
70.0M
  Ppmd8_UpdateModel(p);
1531
70.0M
}
1532
1533
/* H->I changes:
1534
  NS2Indx
1535
  GlueCount, and Glue method
1536
  BinSum
1537
  See / EscFreq
1538
  Ppmd8_CreateSuccessors updates more suffix contexts
1539
  Ppmd8_UpdateModel consts.
1540
  PrevSuccess Update
1541
1542
Flags:
1543
  (1 << 2) - the Context was Rescaled
1544
  (1 << 3) - there is symbol in Stats with (sym >= 0x40) in
1545
  (1 << 4) - main symbol of context is (sym >= 0x40)
1546
*/
1547
1548
#undef RESET_TEXT
1549
#undef FLAG_RESCALED
1550
#undef FLAG_PREV_HIGH
1551
#undef HiBits_Prepare
1552
#undef HiBits_Convert_3
1553
#undef HiBits_Convert_4
1554
#undef PPMD8_HiBitsFlag_3
1555
#undef PPMD8_HiBitsFlag_4
1556
#undef RESTORE_MODEL
1557
1558
#undef MAX_FREQ
1559
#undef UNIT_SIZE
1560
#undef U2B
1561
#undef U2I
1562
#undef I2U
1563
1564
#undef REF
1565
#undef STATS_REF
1566
#undef CTX
1567
#undef STATS
1568
#undef ONE_STATE
1569
#undef SUFFIX
1570
#undef NODE
1571
#undef EMPTY_NODE
1572
#undef MEM_12_CPY
1573
#undef SUCCESSOR
1574
#undef SWAP_STATES