File indexing completed on 2025-03-09 04:13:31

0001 /* Ppmd8.c -- PPMdI codec
0002 2010-03-24 : Igor Pavlov : Public domain
0003 This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */
0004 
0005 #include "Precomp.h"
0006 
0007 #include <memory.h>
0008 
0009 #include "Ppmd8.h"
0010 
0011 const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
0012 static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
0013 
0014 #define MAX_FREQ 124
0015 #define UNIT_SIZE 12
0016 
0017 #define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
0018 #define U2I(nu) (p->Units2Indx[(nu) - 1])
0019 #define I2U(indx) (p->Indx2Units[indx])
0020 
0021 #ifdef PPMD_32BIT
0022   #define REF(ptr) (ptr)
0023 #else
0024   #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))
0025 #endif
0026 
0027 #define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))
0028 
0029 #define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref))
0030 #define STATS(ctx) Ppmd8_GetStats(p, ctx)
0031 #define ONE_STATE(ctx) Ppmd8Context_OneState(ctx)
0032 #define SUFFIX(ctx) CTX((ctx)->Suffix)
0033 
0034 typedef CPpmd8_Context * CTX_PTR;
0035 
0036 struct CPpmd8_Node_;
0037 
0038 typedef
0039   #ifdef PPMD_32BIT
0040     struct CPpmd8_Node_ *
0041   #else
0042     UInt32
0043   #endif
0044   CPpmd8_Node_Ref;
0045 
0046 typedef struct CPpmd8_Node_
0047 {
0048   UInt32 Stamp;
0049   CPpmd8_Node_Ref Next;
0050   UInt32 NU;
0051 } CPpmd8_Node;
0052 
0053 #ifdef PPMD_32BIT
0054   #define NODE(ptr) (ptr)
0055 #else
0056   #define NODE(offs) ((CPpmd8_Node *)(p->Base + (offs)))
0057 #endif
0058 
0059 #define EMPTY_NODE 0xFFFFFFFF
0060 
0061 void Ppmd8_Construct(CPpmd8 *p)
0062 {
0063   unsigned i, k, m;
0064 
0065   p->Base = 0;
0066 
0067   for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)
0068   {
0069     unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);
0070     do { p->Units2Indx[k++] = (Byte)i; } while(--step);
0071     p->Indx2Units[i] = (Byte)k;
0072   }
0073 
0074   p->NS2BSIndx[0] = (0 << 1);
0075   p->NS2BSIndx[1] = (1 << 1);
0076   memset(p->NS2BSIndx + 2, (2 << 1), 9);
0077   memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);
0078 
0079   for (i = 0; i < 5; i++)
0080     p->NS2Indx[i] = (Byte)i;
0081   for (m = i, k = 1; i < 260; i++)
0082   {
0083     p->NS2Indx[i] = (Byte)m;
0084     if (--k == 0)
0085       k = (++m) - 4;
0086   }
0087 }
0088 
0089 void Ppmd8_Free(CPpmd8 *p, ISzAlloc *alloc)
0090 {
0091   alloc->Free(alloc, p->Base);
0092   p->Size = 0;
0093   p->Base = 0;
0094 }
0095 
0096 Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAlloc *alloc)
0097 {
0098   if (p->Base == 0 || p->Size != size)
0099   {
0100     Ppmd8_Free(p, alloc);
0101     p->AlignOffset =
0102       #ifdef PPMD_32BIT
0103         (4 - size) & 3;
0104       #else
0105         4 - (size & 3);
0106       #endif
0107     if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size)) == 0)
0108       return False;
0109     p->Size = size;
0110   }
0111   return True;
0112 }
0113 
0114 static void InsertNode(CPpmd8 *p, void *node, unsigned indx)
0115 {
0116   ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE;
0117   ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx];
0118   ((CPpmd8_Node *)node)->NU = I2U(indx);
0119   p->FreeList[indx] = REF(node);
0120   p->Stamps[indx]++;
0121 }
0122 
0123 static void *RemoveNode(CPpmd8 *p, unsigned indx)
0124 {
0125   CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]);
0126   p->FreeList[indx] = node->Next;
0127   p->Stamps[indx]--;
0128   return node;
0129 }
0130 
0131 static void SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx)
0132 {
0133   unsigned i, nu = I2U(oldIndx) - I2U(newIndx);
0134   ptr = (Byte *)ptr + U2B(I2U(newIndx));
0135   if (I2U(i = U2I(nu)) != nu)
0136   {
0137     unsigned k = I2U(--i);
0138     InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);
0139   }
0140   InsertNode(p, ptr, i);
0141 }
0142 
0143 static void GlueFreeBlocks(CPpmd8 *p)
0144 {
0145   CPpmd8_Node_Ref head = 0;
0146   CPpmd8_Node_Ref *prev = &head;
0147   unsigned i;
0148 
0149   p->GlueCount = 1 << 13;
0150   memset(p->Stamps, 0, sizeof(p->Stamps));
0151   
0152   /* Order-0 context is always at top UNIT, so we don't need guard NODE at the end.
0153      All blocks up to p->LoUnit can be free, so we need guard NODE at LoUnit. */
0154   if (p->LoUnit != p->HiUnit)
0155     ((CPpmd8_Node *)p->LoUnit)->Stamp = 0;
0156 
0157   /* Glue free blocks */
0158   for (i = 0; i < PPMD_NUM_INDEXES; i++)
0159   {
0160     CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i];
0161     p->FreeList[i] = 0;
0162     while (next != 0)
0163     {
0164       CPpmd8_Node *node = NODE(next);
0165       if (node->NU != 0)
0166       {
0167         CPpmd8_Node *node2;
0168         *prev = next;
0169         prev = &(node->Next);
0170         while ((node2 = node + node->NU)->Stamp == EMPTY_NODE)
0171         {
0172           node->NU += node2->NU;
0173           node2->NU = 0;
0174         }
0175       }
0176       next = node->Next;
0177     }
0178   }
0179   *prev = 0;
0180   
0181   /* Fill lists of free blocks */
0182   while (head != 0)
0183   {
0184     CPpmd8_Node *node = NODE(head);
0185     unsigned nu;
0186     head = node->Next;
0187     nu = node->NU;
0188     if (nu == 0)
0189       continue;
0190     for (; nu > 128; nu -= 128, node += 128)
0191       InsertNode(p, node, PPMD_NUM_INDEXES - 1);
0192     if (I2U(i = U2I(nu)) != nu)
0193     {
0194       unsigned k = I2U(--i);
0195       InsertNode(p, node + k, nu - k - 1);
0196     }
0197     InsertNode(p, node, i);
0198   }
0199 }
0200 
0201 static void *AllocUnitsRare(CPpmd8 *p, unsigned indx)
0202 {
0203   unsigned i;
0204   void *retVal;
0205   if (p->GlueCount == 0)
0206   {
0207     GlueFreeBlocks(p);
0208     if (p->FreeList[indx] != 0)
0209       return RemoveNode(p, indx);
0210   }
0211   i = indx;
0212   do
0213   {
0214     if (++i == PPMD_NUM_INDEXES)
0215     {
0216       UInt32 numBytes = U2B(I2U(indx));
0217       p->GlueCount--;
0218       return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL);
0219     }
0220   }
0221   while (p->FreeList[i] == 0);
0222   retVal = RemoveNode(p, i);
0223   SplitBlock(p, retVal, i, indx);
0224   return retVal;
0225 }
0226 
0227 static void *AllocUnits(CPpmd8 *p, unsigned indx)
0228 {
0229   UInt32 numBytes;
0230   if (p->FreeList[indx] != 0)
0231     return RemoveNode(p, indx);
0232   numBytes = U2B(I2U(indx));
0233   if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit))
0234   {
0235     void *retVal = p->LoUnit;
0236     p->LoUnit += numBytes;
0237     return retVal;
0238   }
0239   return AllocUnitsRare(p, indx);
0240 }
0241 
0242 #define MyMem12Cpy(dest, src, num) \
0243   { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \
0244     do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); }
0245 
0246 static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
0247 {
0248   unsigned i0 = U2I(oldNU);
0249   unsigned i1 = U2I(newNU);
0250   if (i0 == i1)
0251     return oldPtr;
0252   if (p->FreeList[i1] != 0)
0253   {
0254     void *ptr = RemoveNode(p, i1);
0255     MyMem12Cpy(ptr, oldPtr, newNU);
0256     InsertNode(p, oldPtr, i0);
0257     return ptr;
0258   }
0259   SplitBlock(p, oldPtr, i0, i1);
0260   return oldPtr;
0261 }
0262 
0263 static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu)
0264 {
0265   InsertNode(p, ptr, U2I(nu));
0266 }
0267 
0268 static void SpecialFreeUnit(CPpmd8 *p, void *ptr)
0269 {
0270   if ((Byte *)ptr != p->UnitsStart)
0271     InsertNode(p, ptr, 0);
0272   else
0273   {
0274     #ifdef PPMD8_FREEZE_SUPPORT
0275     *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts */
0276     #endif
0277     p->UnitsStart += UNIT_SIZE;
0278   }
0279 }
0280 
0281 static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu)
0282 {
0283   unsigned indx = U2I(nu);
0284   void *ptr;
0285   if ((Byte *)oldPtr > p->UnitsStart + 16 * 1024 || REF(oldPtr) > p->FreeList[indx])
0286     return oldPtr;
0287   ptr = RemoveNode(p, indx);
0288   MyMem12Cpy(ptr, oldPtr, nu);
0289   if ((Byte*)oldPtr != p->UnitsStart)
0290     InsertNode(p, oldPtr, indx);
0291   else
0292     p->UnitsStart += U2B(I2U(indx));
0293   return ptr;
0294 }
0295 
0296 static void ExpandTextArea(CPpmd8 *p)
0297 {
0298   UInt32 count[PPMD_NUM_INDEXES];
0299   unsigned i;
0300   memset(count, 0, sizeof(count));
0301   if (p->LoUnit != p->HiUnit)
0302     ((CPpmd8_Node *)p->LoUnit)->Stamp = 0;
0303   
0304   {
0305     CPpmd8_Node *node = (CPpmd8_Node *)p->UnitsStart;
0306     for (; node->Stamp == EMPTY_NODE; node += node->NU)
0307     {
0308       node->Stamp = 0;
0309       count[U2I(node->NU)]++;
0310     }
0311     p->UnitsStart = (Byte *)node;
0312   }
0313   
0314   for (i = 0; i < PPMD_NUM_INDEXES; i++)
0315   {
0316     CPpmd8_Node_Ref *next = (CPpmd8_Node_Ref *)&p->FreeList[i];
0317     while (count[i] != 0)
0318     {
0319       CPpmd8_Node *node = NODE(*next);
0320       while (node->Stamp == 0)
0321       {
0322         *next = node->Next;
0323         node = NODE(*next);
0324         p->Stamps[i]--;
0325         if (--count[i] == 0)
0326           break;
0327       }
0328       next = &node->Next;
0329     }
0330   }
0331 }
0332 
0333 #define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16)))
0334 
0335 static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
0336 {
0337   (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF);
0338   (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);
0339 }
0340 
0341 #define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); }
0342 
0343 static void RestartModel(CPpmd8 *p)
0344 {
0345   unsigned i, k, m, r;
0346 
0347   memset(p->FreeList, 0, sizeof(p->FreeList));
0348   memset(p->Stamps, 0, sizeof(p->Stamps));
0349   RESET_TEXT(0);
0350   p->HiUnit = p->Text + p->Size;
0351   p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;
0352   p->GlueCount = 0;
0353 
0354   p->OrderFall = p->MaxOrder;
0355   p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;
0356   p->PrevSuccess = 0;
0357 
0358   p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */
0359   p->MinContext->Suffix = 0;
0360   p->MinContext->NumStats = 255;
0361   p->MinContext->Flags = 0;
0362   p->MinContext->SummFreq = 256 + 1;
0363   p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */
0364   p->LoUnit += U2B(256 / 2);
0365   p->MinContext->Stats = REF(p->FoundState);
0366   for (i = 0; i < 256; i++)
0367   {
0368     CPpmd_State *s = &p->FoundState[i];
0369     s->Symbol = (Byte)i;
0370     s->Freq = 1;
0371     SetSuccessor(s, 0);
0372   }
0373 
0374   for (i = m = 0; m < 25; m++)
0375   {
0376     while (p->NS2Indx[i] == m)
0377       i++;
0378     for (k = 0; k < 8; k++)
0379     {
0380       UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 1));
0381       UInt16 *dest = p->BinSumm[m] + k;
0382       for (r = 0; r < 64; r += 8)
0383         dest[r] = val;
0384     }
0385   }
0386 
0387   for (i = m = 0; m < 24; m++)
0388   {
0389     while (p->NS2Indx[i + 3] == m + 3)
0390       i++;
0391     for (k = 0; k < 32; k++)
0392     {
0393       CPpmd_See *s = &p->See[m][k];
0394       s->Summ = (UInt16)((2 * i + 5) << (s->Shift = PPMD_PERIOD_BITS - 4));
0395       s->Count = 7;
0396     }
0397   }
0398 }
0399 
0400 void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod)
0401 {
0402   p->MaxOrder = maxOrder;
0403   p->RestoreMethod = restoreMethod;
0404   RestartModel(p);
0405   p->DummySee.Shift = PPMD_PERIOD_BITS;
0406   p->DummySee.Summ = 0; /* unused */
0407   p->DummySee.Count = 64; /* unused */
0408 }
0409 
0410 static void Refresh(CPpmd8 *p, CTX_PTR ctx, unsigned oldNU, unsigned scale)
0411 {
0412   unsigned i = ctx->NumStats, escFreq, sumFreq, flags;
0413   CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1);
0414   ctx->Stats = REF(s);
0415   #ifdef PPMD8_FREEZE_SUPPORT
0416   /* fixed over Shkarin's code. Fixed code is not compatible with original code for some files in FREEZE mode. */
0417   scale |= (ctx->SummFreq >= ((UInt32)1 << 15));
0418   #endif
0419   flags = (ctx->Flags & (0x10 + 0x04 * scale)) + 0x08 * (s->Symbol >= 0x40);
0420   escFreq = ctx->SummFreq - s->Freq;
0421   sumFreq = (s->Freq = (Byte)((s->Freq + scale) >> scale));
0422   do
0423   {
0424     escFreq -= (++s)->Freq;
0425     sumFreq += (s->Freq = (Byte)((s->Freq + scale) >> scale));
0426     flags |= 0x08 * (s->Symbol >= 0x40);
0427   }
0428   while (--i);
0429   ctx->SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale));
0430   ctx->Flags = (Byte)flags;
0431 }
0432 
0433 static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)
0434 {
0435   CPpmd_State tmp = *t1;
0436   *t1 = *t2;
0437   *t2 = tmp;
0438 }
0439 
0440 static CPpmd_Void_Ref CutOff(CPpmd8 *p, CTX_PTR ctx, unsigned order)
0441 {
0442   int i;
0443   unsigned tmp;
0444   CPpmd_State *s;
0445   
0446   if (!ctx->NumStats)
0447   {
0448     s = ONE_STATE(ctx);
0449     if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart)
0450     {
0451       if (order < p->MaxOrder)
0452         SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1));
0453       else
0454         SetSuccessor(s, 0);
0455       if (SUCCESSOR(s) || order <= 9) /* O_BOUND */
0456         return REF(ctx);
0457     }
0458     SpecialFreeUnit(p, ctx);
0459     return 0;
0460   }
0461 
0462   ctx->Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), tmp = ((unsigned)ctx->NumStats + 2) >> 1));
0463 
0464   for (s = STATS(ctx) + (i = ctx->NumStats); s >= STATS(ctx); s--)
0465     if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) < p->UnitsStart)
0466     {
0467       CPpmd_State *s2 = STATS(ctx) + (i--);
0468       SetSuccessor(s, 0);
0469       SwapStates(s, s2);
0470     }
0471     else if (order < p->MaxOrder)
0472       SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1));
0473     else
0474       SetSuccessor(s, 0);
0475     
0476   if (i != ctx->NumStats && order)
0477   {
0478     ctx->NumStats = (Byte)i;
0479     s = STATS(ctx);
0480     if (i < 0)
0481     {
0482       FreeUnits(p, s, tmp);
0483       SpecialFreeUnit(p, ctx);
0484       return 0;
0485     }
0486     if (i == 0)
0487     {
0488       ctx->Flags = (ctx->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40);
0489       *ONE_STATE(ctx) = *s;
0490       FreeUnits(p, s, tmp);
0491       ONE_STATE(ctx)->Freq = (Byte)((unsigned)ONE_STATE(ctx)->Freq + 11) >> 3;
0492     }
0493     else
0494       Refresh(p, ctx, tmp, ctx->SummFreq > 16 * i);
0495   }
0496   return REF(ctx);
0497 }
0498 
0499 #ifdef PPMD8_FREEZE_SUPPORT
0500 static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, CTX_PTR ctx, unsigned order)
0501 {
0502   CPpmd_State *s;
0503   if (!ctx->NumStats)
0504   {
0505     s = ONE_STATE(ctx);
0506     if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder)
0507       SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1));
0508     else
0509       SetSuccessor(s, 0);
0510     /* Suffix context can be removed already, since different (high-order)
0511        Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */
0512     if (!SUCCESSOR(s) && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF))
0513     {
0514       FreeUnits(p, ctx, 1);
0515       return 0;
0516     }
0517     else
0518       return REF(ctx);
0519   }
0520 
0521   for (s = STATS(ctx) + ctx->NumStats; s >= STATS(ctx); s--)
0522     if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder)
0523       SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1));
0524     else
0525       SetSuccessor(s, 0);
0526   
0527   return REF(ctx);
0528 }
0529 #endif
0530 
0531 static UInt32 GetUsedMemory(const CPpmd8 *p)
0532 {
0533   UInt32 v = 0;
0534   unsigned i;
0535   for (i = 0; i < PPMD_NUM_INDEXES; i++)
0536     v += p->Stamps[i] * I2U(i);
0537   return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v);
0538 }
0539 
0540 #ifdef PPMD8_FREEZE_SUPPORT
0541   #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor)
0542 #else
0543   #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1)
0544 #endif
0545 
0546 static void RestoreModel(CPpmd8 *p, CTX_PTR c1
0547     #ifdef PPMD8_FREEZE_SUPPORT
0548     , CTX_PTR fSuccessor
0549     #endif
0550     )
0551 {
0552   CTX_PTR c;
0553   CPpmd_State *s;
0554   RESET_TEXT(0);
0555   for (c = p->MaxContext; c != c1; c = SUFFIX(c))
0556     if (--(c->NumStats) == 0)
0557     {
0558       s = STATS(c);
0559       c->Flags = (c->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40);
0560       *ONE_STATE(c) = *s;
0561       SpecialFreeUnit(p, s);
0562       ONE_STATE(c)->Freq = (ONE_STATE(c)->Freq + 11) >> 3;
0563     }
0564     else
0565       Refresh(p, c, (c->NumStats+3) >> 1, 0);
0566  
0567   for (; c != p->MinContext; c = SUFFIX(c))
0568     if (!c->NumStats)
0569       ONE_STATE(c)->Freq -= ONE_STATE(c)->Freq >> 1;
0570     else if ((c->SummFreq += 4) > 128 + 4 * c->NumStats)
0571       Refresh(p, c, (c->NumStats + 2) >> 1, 1);
0572 
0573   #ifdef PPMD8_FREEZE_SUPPORT
0574   if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
0575   {
0576     p->MaxContext = fSuccessor;
0577     p->GlueCount += !(p->Stamps[1] & 1);
0578   }
0579   else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE)
0580   {
0581     while (p->MaxContext->Suffix)
0582       p->MaxContext = SUFFIX(p->MaxContext);
0583     RemoveBinContexts(p, p->MaxContext, 0);
0584     p->RestoreMethod++;
0585     p->GlueCount = 0;
0586     p->OrderFall = p->MaxOrder;
0587   }
0588   else
0589   #endif
0590   if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1))
0591     RestartModel(p);
0592   else
0593   {
0594     while (p->MaxContext->Suffix)
0595       p->MaxContext = SUFFIX(p->MaxContext);
0596     do
0597     {
0598       CutOff(p, p->MaxContext, 0);
0599       ExpandTextArea(p);
0600     }
0601     while (GetUsedMemory(p) > 3 * (p->Size >> 2));
0602     p->GlueCount = 0;
0603     p->OrderFall = p->MaxOrder;
0604   }
0605 }
0606 
0607 static CTX_PTR CreateSuccessors(CPpmd8 *p, Bool skip, CPpmd_State *s1, CTX_PTR c)
0608 {
0609   CPpmd_State upState;
0610   Byte flags;
0611   CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);
0612   /* fixed over Shkarin's code. Maybe it could work without + 1 too. */
0613   CPpmd_State *ps[PPMD8_MAX_ORDER + 1];
0614   unsigned numPs = 0;
0615   
0616   if (!skip)
0617     ps[numPs++] = p->FoundState;
0618   
0619   while (c->Suffix)
0620   {
0621     CPpmd_Void_Ref successor;
0622     CPpmd_State *s;
0623     c = SUFFIX(c);
0624     if (s1)
0625     {
0626       s = s1;
0627       s1 = NULL;
0628     }
0629     else if (c->NumStats != 0)
0630     {
0631       for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++);
0632       if (s->Freq < MAX_FREQ - 9)
0633       {
0634         s->Freq++;
0635         c->SummFreq++;
0636       }
0637     }
0638     else
0639     {
0640       s = ONE_STATE(c);
0641       s->Freq += (!SUFFIX(c)->NumStats & (s->Freq < 24));
0642     }
0643     successor = SUCCESSOR(s);
0644     if (successor != upBranch)
0645     {
0646       c = CTX(successor);
0647       if (numPs == 0)
0648         return c;
0649       break;
0650     }
0651     ps[numPs++] = s;
0652   }
0653   
0654   upState.Symbol = *(const Byte *)Ppmd8_GetPtr(p, upBranch);
0655   SetSuccessor(&upState, upBranch + 1);
0656   flags = 0x10 * (p->FoundState->Symbol >= 0x40) + 0x08 * (upState.Symbol >= 0x40);
0657 
0658   if (c->NumStats == 0)
0659     upState.Freq = ONE_STATE(c)->Freq;
0660   else
0661   {
0662     UInt32 cf, s0;
0663     CPpmd_State *s;
0664     for (s = STATS(c); s->Symbol != upState.Symbol; s++);
0665     cf = s->Freq - 1;
0666     s0 = c->SummFreq - c->NumStats - cf;
0667     upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0)));
0668   }
0669 
0670   do
0671   {
0672     /* Create Child */
0673     CTX_PTR c1; /* = AllocContext(p); */
0674     if (p->HiUnit != p->LoUnit)
0675       c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE);
0676     else if (p->FreeList[0] != 0)
0677       c1 = (CTX_PTR)RemoveNode(p, 0);
0678     else
0679     {
0680       c1 = (CTX_PTR)AllocUnitsRare(p, 0);
0681       if (!c1)
0682         return NULL;
0683     }
0684     c1->NumStats = 0;
0685     c1->Flags = flags;
0686     *ONE_STATE(c1) = upState;
0687     c1->Suffix = REF(c);
0688     SetSuccessor(ps[--numPs], REF(c1));
0689     c = c1;
0690   }
0691   while (numPs != 0);
0692   
0693   return c;
0694 }
0695 
0696 static CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, CTX_PTR c)
0697 {
0698   CPpmd_State *s = NULL;
0699   CTX_PTR c1 = c;
0700   CPpmd_Void_Ref upBranch = REF(p->Text);
0701   
0702   #ifdef PPMD8_FREEZE_SUPPORT
0703   /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */
0704   CPpmd_State *ps[PPMD8_MAX_ORDER + 1];
0705   unsigned numPs = 0;
0706   ps[numPs++] = p->FoundState;
0707   #endif
0708 
0709   SetSuccessor(p->FoundState, upBranch);
0710   p->OrderFall++;
0711 
0712   for (;;)
0713   {
0714     if (s1)
0715     {
0716       c = SUFFIX(c);
0717       s = s1;
0718       s1 = NULL;
0719     }
0720     else
0721     {
0722       if (!c->Suffix)
0723       {
0724         #ifdef PPMD8_FREEZE_SUPPORT
0725         if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
0726         {
0727           do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs);
0728           RESET_TEXT(1);
0729           p->OrderFall = 1;
0730         }
0731         #endif
0732         return c;
0733       }
0734       c = SUFFIX(c);
0735       if (c->NumStats)
0736       {
0737         if ((s = STATS(c))->Symbol != p->FoundState->Symbol)
0738           do { s++; } while (s->Symbol != p->FoundState->Symbol);
0739         if (s->Freq < MAX_FREQ - 9)
0740         {
0741           s->Freq += 2;
0742           c->SummFreq += 2;
0743         }
0744       }
0745       else
0746       {
0747         s = ONE_STATE(c);
0748         s->Freq += (s->Freq < 32);
0749       }
0750     }
0751     if (SUCCESSOR(s))
0752       break;
0753     #ifdef PPMD8_FREEZE_SUPPORT
0754     ps[numPs++] = s;
0755     #endif
0756     SetSuccessor(s, upBranch);
0757     p->OrderFall++;
0758   }
0759   
0760   #ifdef PPMD8_FREEZE_SUPPORT
0761   if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
0762   {
0763     c = CTX(SUCCESSOR(s));
0764     do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs);
0765     RESET_TEXT(1);
0766     p->OrderFall = 1;
0767     return c;
0768   }
0769   else
0770   #endif
0771   if (SUCCESSOR(s) <= upBranch)
0772   {
0773     CTX_PTR successor;
0774     CPpmd_State *s1 = p->FoundState;
0775     p->FoundState = s;
0776 
0777     successor = CreateSuccessors(p, False, NULL, c);
0778     if (successor == NULL)
0779       SetSuccessor(s, 0);
0780     else
0781       SetSuccessor(s, REF(successor));
0782     p->FoundState = s1;
0783   }
0784   
0785   if (p->OrderFall == 1 && c1 == p->MaxContext)
0786   {
0787     SetSuccessor(p->FoundState, SUCCESSOR(s));
0788     p->Text--;
0789   }
0790   if (SUCCESSOR(s) == 0)
0791     return NULL;
0792   return CTX(SUCCESSOR(s));
0793 }
0794 
0795 static void UpdateModel(CPpmd8 *p)
0796 {
0797   CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState);
0798   CTX_PTR c;
0799   unsigned s0, ns, fFreq = p->FoundState->Freq;
0800   Byte flag, fSymbol = p->FoundState->Symbol;
0801   CPpmd_State *s = NULL;
0802   
0803   if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)
0804   {
0805     c = SUFFIX(p->MinContext);
0806     
0807     if (c->NumStats == 0)
0808     {
0809       s = ONE_STATE(c);
0810       if (s->Freq < 32)
0811         s->Freq++;
0812     }
0813     else
0814     {
0815       s = STATS(c);
0816       if (s->Symbol != p->FoundState->Symbol)
0817       {
0818         do { s++; } while (s->Symbol != p->FoundState->Symbol);
0819         if (s[0].Freq >= s[-1].Freq)
0820         {
0821           SwapStates(&s[0], &s[-1]);
0822           s--;
0823         }
0824       }
0825       if (s->Freq < MAX_FREQ - 9)
0826       {
0827         s->Freq += 2;
0828         c->SummFreq += 2;
0829       }
0830     }
0831   }
0832   
0833   c = p->MaxContext;
0834   if (p->OrderFall == 0 && fSuccessor)
0835   {
0836     CTX_PTR cs = CreateSuccessors(p, True, s, p->MinContext);
0837     if (cs == 0)
0838     {
0839       SetSuccessor(p->FoundState, 0);
0840       RESTORE_MODEL(c, CTX(fSuccessor));
0841     }
0842     else
0843     {
0844       SetSuccessor(p->FoundState, REF(cs));
0845       p->MaxContext = cs;
0846     }
0847     return;
0848   }
0849   
0850   *p->Text++ = p->FoundState->Symbol;
0851   successor = REF(p->Text);
0852   if (p->Text >= p->UnitsStart)
0853   {
0854     RESTORE_MODEL(c, CTX(fSuccessor)); /* check it */
0855     return;
0856   }
0857   
0858   if (!fSuccessor)
0859   {
0860     CTX_PTR cs = ReduceOrder(p, s, p->MinContext);
0861     if (cs == NULL)
0862     {
0863       RESTORE_MODEL(c, 0);
0864       return;
0865     }
0866     fSuccessor = REF(cs);
0867   }
0868   else if ((Byte *)Ppmd8_GetPtr(p, fSuccessor) < p->UnitsStart)
0869   {
0870     CTX_PTR cs = CreateSuccessors(p, False, s, p->MinContext);
0871     if (cs == NULL)
0872     {
0873       RESTORE_MODEL(c, 0);
0874       return;
0875     }
0876     fSuccessor = REF(cs);
0877   }
0878   
0879   if (--p->OrderFall == 0)
0880   {
0881     successor = fSuccessor;
0882     p->Text -= (p->MaxContext != p->MinContext);
0883   }
0884   #ifdef PPMD8_FREEZE_SUPPORT
0885   else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
0886   {
0887     successor = fSuccessor;
0888     RESET_TEXT(0);
0889     p->OrderFall = 0;
0890   }
0891   #endif
0892   
0893   s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - fFreq;
0894   flag = 0x08 * (fSymbol >= 0x40);
0895   
0896   for (; c != p->MinContext; c = SUFFIX(c))
0897   {
0898     unsigned ns1;
0899     UInt32 cf, sf;
0900     if ((ns1 = c->NumStats) != 0)
0901     {
0902       if ((ns1 & 1) != 0)
0903       {
0904         /* Expand for one UNIT */
0905         unsigned oldNU = (ns1 + 1) >> 1;
0906         unsigned i = U2I(oldNU);
0907         if (i != U2I(oldNU + 1))
0908         {
0909           void *ptr = AllocUnits(p, i + 1);
0910           void *oldPtr;
0911           if (!ptr)
0912           {
0913             RESTORE_MODEL(c, CTX(fSuccessor));
0914             return;
0915           }
0916           oldPtr = STATS(c);
0917           MyMem12Cpy(ptr, oldPtr, oldNU);
0918           InsertNode(p, oldPtr, i);
0919           c->Stats = STATS_REF(ptr);
0920         }
0921       }
0922       c->SummFreq = (UInt16)(c->SummFreq + (3 * ns1 + 1 < ns));
0923     }
0924     else
0925     {
0926       CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0);
0927       if (!s)
0928       {
0929         RESTORE_MODEL(c, CTX(fSuccessor));
0930         return;
0931       }
0932       *s = *ONE_STATE(c);
0933       c->Stats = REF(s);
0934       if (s->Freq < MAX_FREQ / 4 - 1)
0935         s->Freq <<= 1;
0936       else
0937         s->Freq = MAX_FREQ - 4;
0938       c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 2));
0939     }
0940     cf = 2 * fFreq * (c->SummFreq + 6);
0941     sf = (UInt32)s0 + c->SummFreq;
0942     if (cf < 6 * sf)
0943     {
0944       cf = 1 + (cf > sf) + (cf >= 4 * sf);
0945       c->SummFreq += 4;
0946     }
0947     else
0948     {
0949       cf = 4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf);
0950       c->SummFreq = (UInt16)(c->SummFreq + cf);
0951     }
0952     {
0953       CPpmd_State *s = STATS(c) + ns1 + 1;
0954       SetSuccessor(s, successor);
0955       s->Symbol = fSymbol;
0956       s->Freq = (Byte)cf;
0957       c->Flags |= flag;
0958       c->NumStats = (Byte)(ns1 + 1);
0959     }
0960   }
0961   p->MaxContext = p->MinContext = CTX(fSuccessor);
0962 }
0963   
0964 static void Rescale(CPpmd8 *p)
0965 {
0966   unsigned i, adder, sumFreq, escFreq;
0967   CPpmd_State *stats = STATS(p->MinContext);
0968   CPpmd_State *s = p->FoundState;
0969   {
0970     CPpmd_State tmp = *s;
0971     for (; s != stats; s--)
0972       s[0] = s[-1];
0973     *s = tmp;
0974   }
0975   escFreq = p->MinContext->SummFreq - s->Freq;
0976   s->Freq += 4;
0977   adder = (p->OrderFall != 0
0978       #ifdef PPMD8_FREEZE_SUPPORT
0979       || p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE
0980       #endif
0981       );
0982   s->Freq = (Byte)((s->Freq + adder) >> 1);
0983   sumFreq = s->Freq;
0984   
0985   i = p->MinContext->NumStats;
0986   do
0987   {
0988     escFreq -= (++s)->Freq;
0989     s->Freq = (Byte)((s->Freq + adder) >> 1);
0990     sumFreq += s->Freq;
0991     if (s[0].Freq > s[-1].Freq)
0992     {
0993       CPpmd_State *s1 = s;
0994       CPpmd_State tmp = *s1;
0995       do
0996         s1[0] = s1[-1];
0997       while (--s1 != stats && tmp.Freq > s1[-1].Freq);
0998       *s1 = tmp;
0999     }
1000   }
1001   while (--i);
1002   
1003   if (s->Freq == 0)
1004   {
1005     unsigned numStats = p->MinContext->NumStats;
1006     unsigned n0, n1;
1007     do { i++; } while ((--s)->Freq == 0);
1008     escFreq += i;
1009     p->MinContext->NumStats = (Byte)(p->MinContext->NumStats - i);
1010     if (p->MinContext->NumStats == 0)
1011     {
1012       CPpmd_State tmp = *stats;
1013       tmp.Freq = (Byte)((2 * tmp.Freq + escFreq - 1) / escFreq);
1014       if (tmp.Freq > MAX_FREQ / 3)
1015         tmp.Freq = MAX_FREQ / 3;
1016       InsertNode(p, stats, U2I((numStats + 2) >> 1));
1017       p->MinContext->Flags = (p->MinContext->Flags & 0x10) + 0x08 * (tmp.Symbol >= 0x40);
1018       *(p->FoundState = ONE_STATE(p->MinContext)) = tmp;
1019       return;
1020     }
1021     n0 = (numStats + 2) >> 1;
1022     n1 = (p->MinContext->NumStats + 2) >> 1;
1023     if (n0 != n1)
1024       p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));
1025     p->MinContext->Flags &= ~0x08;
1026     p->MinContext->Flags |= 0x08 * ((s = STATS(p->MinContext))->Symbol >= 0x40);
1027     i = p->MinContext->NumStats;
1028     do { p->MinContext->Flags |= 0x08*((++s)->Symbol >= 0x40); } while (--i);
1029   }
1030   p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));
1031   p->MinContext->Flags |= 0x4;
1032   p->FoundState = STATS(p->MinContext);
1033 }
1034 
1035 CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq)
1036 {
1037   CPpmd_See *see;
1038   if (p->MinContext->NumStats != 0xFF)
1039   {
1040     see = p->See[p->NS2Indx[p->MinContext->NumStats + 2] - 3] +
1041         (p->MinContext->SummFreq > 11 * ((unsigned)p->MinContext->NumStats + 1)) +
1042         2 * (2 * (unsigned)p->MinContext->NumStats <
1043         ((unsigned)SUFFIX(p->MinContext)->NumStats + numMasked1)) +
1044         p->MinContext->Flags;
1045     {
1046       unsigned r = (see->Summ >> see->Shift);
1047       see->Summ = (UInt16)(see->Summ - r);
1048       *escFreq = r + (r == 0);
1049     }
1050   }
1051   else
1052   {
1053     see = &p->DummySee;
1054     *escFreq = 1;
1055   }
1056   return see;
1057 }
1058 
1059 static void NextContext(CPpmd8 *p)
1060 {
1061   CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
1062   if (p->OrderFall == 0 && (Byte *)c >= p->UnitsStart)
1063     p->MinContext = p->MaxContext = c;
1064   else
1065   {
1066     UpdateModel(p);
1067     p->MinContext = p->MaxContext;
1068   }
1069 }
1070 
1071 void Ppmd8_Update1(CPpmd8 *p)
1072 {
1073   CPpmd_State *s = p->FoundState;
1074   s->Freq += 4;
1075   p->MinContext->SummFreq += 4;
1076   if (s[0].Freq > s[-1].Freq)
1077   {
1078     SwapStates(&s[0], &s[-1]);
1079     p->FoundState = --s;
1080     if (s->Freq > MAX_FREQ)
1081       Rescale(p);
1082   }
1083   NextContext(p);
1084 }
1085 
1086 void Ppmd8_Update1_0(CPpmd8 *p)
1087 {
1088   p->PrevSuccess = (2 * p->FoundState->Freq >= p->MinContext->SummFreq);
1089   p->RunLength += p->PrevSuccess;
1090   p->MinContext->SummFreq += 4;
1091   if ((p->FoundState->Freq += 4) > MAX_FREQ)
1092     Rescale(p);
1093   NextContext(p);
1094 }
1095 
1096 void Ppmd8_UpdateBin(CPpmd8 *p)
1097 {
1098   p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 196));
1099   p->PrevSuccess = 1;
1100   p->RunLength++;
1101   NextContext(p);
1102 }
1103 
1104 void Ppmd8_Update2(CPpmd8 *p)
1105 {
1106   p->MinContext->SummFreq += 4;
1107   if ((p->FoundState->Freq += 4) > MAX_FREQ)
1108     Rescale(p);
1109   p->RunLength = p->InitRL;
1110   UpdateModel(p);
1111   p->MinContext = p->MaxContext;
1112 }
1113 
1114 /* H->I changes:
1115   NS2Indx
1116   GlewCount, and Glue method
1117   BinSum
1118   See / EscFreq
1119   CreateSuccessors updates more suffix contexts
1120   UpdateModel consts.
1121   PrevSuccess Update
1122 */