Home | History | Annotate | Line # | Download | only in libarchive
      1 /* Ppmd7.c -- PPMdH codec
      2 2010-03-12 : Igor Pavlov : Public domain
      3 This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
      4 
      5 #include "archive_platform.h"
      6 
      7 #include <stdlib.h>
      8 
      9 #include "archive_ppmd7_private.h"
     10 
     11 #ifdef PPMD_32BIT
     12   #define Ppmd7_GetPtr(p, ptr) (ptr)
     13   #define Ppmd7_GetContext(p, ptr) (ptr)
     14   #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats)
     15 #else
     16   #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs)))
     17   #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs)))
     18   #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats)))
     19 #endif
     20 
     21 #define Ppmd7_GetBinSumm(p) \
     22     &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \
     23     p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \
     24     (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \
     25     2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \
     26     ((p->RunLength >> 26) & 0x20)]
     27 
     28 #define kTopValue (1 << 24)
     29 #define MAX_FREQ 124
     30 #define UNIT_SIZE 12
     31 
     32 #define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
     33 #define U2I(nu) (p->Units2Indx[(nu) - 1])
     34 #define I2U(indx) (p->Indx2Units[indx])
     35 
     36 #ifdef PPMD_32BIT
     37   #define REF(ptr) (ptr)
     38 #else
     39   #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))
     40 #endif
     41 
     42 #define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))
     43 
     44 #define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
     45 #define STATS(ctx) Ppmd7_GetStats(p, ctx)
     46 #define ONE_STATE(ctx) Ppmd7Context_OneState(ctx)
     47 #define SUFFIX(ctx) CTX((ctx)->Suffix)
     48 
     49 static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
     50 static const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
     51 
     52 typedef CPpmd7_Context * CTX_PTR;
     53 
     54 struct CPpmd7_Node_;
     55 
     56 typedef
     57   #ifdef PPMD_32BIT
     58     struct CPpmd7_Node_ *
     59   #else
     60     UInt32
     61   #endif
     62   CPpmd7_Node_Ref;
     63 
     64 typedef struct CPpmd7_Node_
     65 {
     66   UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */
     67   UInt16 NU;
     68   CPpmd7_Node_Ref Next; /* must be at offset >= 4 */
     69   CPpmd7_Node_Ref Prev;
     70 } CPpmd7_Node;
     71 
     72 #ifdef PPMD_32BIT
     73   #define NODE(ptr) (ptr)
     74 #else
     75   #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs)))
     76 #endif
     77 
     78 static void Ppmd7_Update1(CPpmd7 *p);
     79 static void Ppmd7_Update1_0(CPpmd7 *p);
     80 static void Ppmd7_Update2(CPpmd7 *p);
     81 static void Ppmd7_UpdateBin(CPpmd7 *p);
     82 static CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked,
     83                                     UInt32 *scale);
     84 
     85 /* ----------- Base ----------- */
     86 
     87 static void Ppmd7_Construct(CPpmd7 *p)
     88 {
     89   unsigned i, k, m;
     90 
     91   p->Base = 0;
     92 
     93   for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)
     94   {
     95     unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);
     96     do { p->Units2Indx[k++] = (Byte)i; } while(--step);
     97     p->Indx2Units[i] = (Byte)k;
     98   }
     99 
    100   p->NS2BSIndx[0] = (0 << 1);
    101   p->NS2BSIndx[1] = (1 << 1);
    102   memset(p->NS2BSIndx + 2, (2 << 1), 9);
    103   memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);
    104 
    105   for (i = 0; i < 3; i++)
    106     p->NS2Indx[i] = (Byte)i;
    107   for (m = i, k = 1; i < 256; i++)
    108   {
    109     p->NS2Indx[i] = (Byte)m;
    110     if (--k == 0)
    111       k = (++m) - 2;
    112   }
    113 
    114   memset(p->HB2Flag, 0, 0x40);
    115   memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40);
    116 }
    117 
    118 static void Ppmd7_Free(CPpmd7 *p)
    119 {
    120   free(p->Base);
    121   p->Size = 0;
    122   p->Base = 0;
    123 }
    124 
    125 static Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size)
    126 {
    127   if (p->Base == 0 || p->Size != size)
    128   {
    129     /* RestartModel() below assumes that p->Size >= UNIT_SIZE
    130        (see the calculation of m->MinContext). */
    131     if (size < UNIT_SIZE) {
    132       return False;
    133     }
    134     Ppmd7_Free(p);
    135     p->AlignOffset =
    136       #ifdef PPMD_32BIT
    137         (4 - size) & 3;
    138       #else
    139         4 - (size & 3);
    140       #endif
    141     if ((p->Base = malloc(p->AlignOffset + size
    142         #ifndef PPMD_32BIT
    143         + UNIT_SIZE
    144         #endif
    145         )) == 0)
    146       return False;
    147     p->Size = size;
    148   }
    149   return True;
    150 }
    151 
    152 static void InsertNode(CPpmd7 *p, void *node, unsigned indx)
    153 {
    154   *((CPpmd_Void_Ref *)node) = p->FreeList[indx];
    155   p->FreeList[indx] = REF(node);
    156 }
    157 
    158 static void *RemoveNode(CPpmd7 *p, unsigned indx)
    159 {
    160   CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]);
    161   p->FreeList[indx] = *node;
    162   return node;
    163 }
    164 
    165 static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx)
    166 {
    167   unsigned i, nu = I2U(oldIndx) - I2U(newIndx);
    168   ptr = (Byte *)ptr + U2B(I2U(newIndx));
    169   if (I2U(i = U2I(nu)) != nu)
    170   {
    171     unsigned k = I2U(--i);
    172     InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);
    173   }
    174   InsertNode(p, ptr, i);
    175 }
    176 
    177 static void GlueFreeBlocks(CPpmd7 *p)
    178 {
    179   #ifdef PPMD_32BIT
    180   CPpmd7_Node headItem;
    181   CPpmd7_Node_Ref head = &headItem;
    182   #else
    183   CPpmd7_Node_Ref head = p->AlignOffset + p->Size;
    184   #endif
    185 
    186   CPpmd7_Node_Ref n = head;
    187   unsigned i;
    188 
    189   p->GlueCount = 255;
    190 
    191   /* create doubly-linked list of free blocks */
    192   for (i = 0; i < PPMD_NUM_INDEXES; i++)
    193   {
    194     UInt16 nu = I2U(i);
    195     CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i];
    196     p->FreeList[i] = 0;
    197     while (next != 0)
    198     {
    199       CPpmd7_Node *node = NODE(next);
    200       node->Next = n;
    201       n = NODE(n)->Prev = next;
    202       next = *(const CPpmd7_Node_Ref *)node;
    203       node->Stamp = 0;
    204       node->NU = (UInt16)nu;
    205     }
    206   }
    207   NODE(head)->Stamp = 1;
    208   NODE(head)->Next = n;
    209   NODE(n)->Prev = head;
    210   if (p->LoUnit != p->HiUnit)
    211     ((CPpmd7_Node *)p->LoUnit)->Stamp = 1;
    212 
    213   /* Glue free blocks */
    214   while (n != head)
    215   {
    216     CPpmd7_Node *node = NODE(n);
    217     UInt32 nu = (UInt32)node->NU;
    218     for (;;)
    219     {
    220       CPpmd7_Node *node2 = NODE(n) + nu;
    221       nu += node2->NU;
    222       if (node2->Stamp != 0 || nu >= 0x10000)
    223         break;
    224       NODE(node2->Prev)->Next = node2->Next;
    225       NODE(node2->Next)->Prev = node2->Prev;
    226       node->NU = (UInt16)nu;
    227     }
    228     n = node->Next;
    229   }
    230 
    231   /* Fill lists of free blocks */
    232   for (n = NODE(head)->Next; n != head;)
    233   {
    234     CPpmd7_Node *node = NODE(n);
    235     unsigned nu;
    236     CPpmd7_Node_Ref next = node->Next;
    237     for (nu = node->NU; nu > 128; nu -= 128, node += 128)
    238       InsertNode(p, node, PPMD_NUM_INDEXES - 1);
    239     if (I2U(i = U2I(nu)) != nu)
    240     {
    241       unsigned k = I2U(--i);
    242       InsertNode(p, node + k, nu - k - 1);
    243     }
    244     InsertNode(p, node, i);
    245     n = next;
    246   }
    247 }
    248 
    249 static void *AllocUnitsRare(CPpmd7 *p, unsigned indx)
    250 {
    251   unsigned i;
    252   void *retVal;
    253   if (p->GlueCount == 0)
    254   {
    255     GlueFreeBlocks(p);
    256     if (p->FreeList[indx] != 0)
    257       return RemoveNode(p, indx);
    258   }
    259   i = indx;
    260   do
    261   {
    262     if (++i == PPMD_NUM_INDEXES)
    263     {
    264       UInt32 numBytes = U2B(I2U(indx));
    265       p->GlueCount--;
    266       return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL);
    267     }
    268   }
    269   while (p->FreeList[i] == 0);
    270   retVal = RemoveNode(p, i);
    271   SplitBlock(p, retVal, i, indx);
    272   return retVal;
    273 }
    274 
    275 static void *AllocUnits(CPpmd7 *p, unsigned indx)
    276 {
    277   UInt32 numBytes;
    278   if (p->FreeList[indx] != 0)
    279     return RemoveNode(p, indx);
    280   numBytes = U2B(I2U(indx));
    281   if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit))
    282   {
    283     void *retVal = p->LoUnit;
    284     p->LoUnit += numBytes;
    285     return retVal;
    286   }
    287   return AllocUnitsRare(p, indx);
    288 }
    289 
    290 #define MyMem12Cpy(dest, src, num) do {					\
    291 	UInt32 *d = (UInt32 *)dest;					\
    292 	const UInt32 *s = (const UInt32 *)src;				\
    293 	UInt32 n = num;							\
    294 	do {								\
    295 		d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3;	\
    296 	} while(--n);							\
    297 } while (0)
    298 
    299 static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
    300 {
    301   unsigned i0 = U2I(oldNU);
    302   unsigned i1 = U2I(newNU);
    303   if (i0 == i1)
    304     return oldPtr;
    305   if (p->FreeList[i1] != 0)
    306   {
    307     void *ptr = RemoveNode(p, i1);
    308     MyMem12Cpy(ptr, oldPtr, newNU);
    309     InsertNode(p, oldPtr, i0);
    310     return ptr;
    311   }
    312   SplitBlock(p, oldPtr, i0, i1);
    313   return oldPtr;
    314 }
    315 
    316 #define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16)))
    317 
    318 static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
    319 {
    320   (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF);
    321   (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);
    322 }
    323 
    324 static void RestartModel(CPpmd7 *p)
    325 {
    326   unsigned i, k, m;
    327 
    328   memset(p->FreeList, 0, sizeof(p->FreeList));
    329   p->Text = p->Base + p->AlignOffset;
    330   p->HiUnit = p->Text + p->Size;
    331   p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;
    332   p->GlueCount = 0;
    333 
    334   p->OrderFall = p->MaxOrder;
    335   p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;
    336   p->PrevSuccess = 0;
    337 
    338   p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */
    339   p->MinContext->Suffix = 0;
    340   p->MinContext->NumStats = 256;
    341   p->MinContext->SummFreq = 256 + 1;
    342   p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */
    343   p->LoUnit += U2B(256 / 2);
    344   p->MinContext->Stats = REF(p->FoundState);
    345   for (i = 0; i < 256; i++)
    346   {
    347     CPpmd_State *s = &p->FoundState[i];
    348     s->Symbol = (Byte)i;
    349     s->Freq = 1;
    350     SetSuccessor(s, 0);
    351   }
    352 
    353   for (i = 0; i < 128; i++)
    354     for (k = 0; k < 8; k++)
    355     {
    356       UInt16 *dest = p->BinSumm[i] + k;
    357       UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2));
    358       for (m = 0; m < 64; m += 8)
    359         dest[m] = val;
    360     }
    361 
    362   for (i = 0; i < 25; i++)
    363     for (k = 0; k < 16; k++)
    364     {
    365       CPpmd_See *s = &p->See[i][k];
    366       s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4));
    367       s->Count = 4;
    368     }
    369 }
    370 
    371 static void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder)
    372 {
    373   p->MaxOrder = maxOrder;
    374   RestartModel(p);
    375   p->DummySee.Shift = PPMD_PERIOD_BITS;
    376   p->DummySee.Summ = 0; /* unused */
    377   p->DummySee.Count = 64; /* unused */
    378 }
    379 
    380 static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip)
    381 {
    382   CPpmd_State upState;
    383   CTX_PTR c = p->MinContext;
    384   CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);
    385   CPpmd_State *ps[PPMD7_MAX_ORDER];
    386   unsigned numPs = 0;
    387 
    388   if (!skip)
    389     ps[numPs++] = p->FoundState;
    390 
    391   while (c->Suffix)
    392   {
    393     CPpmd_Void_Ref successor;
    394     CPpmd_State *s;
    395     c = SUFFIX(c);
    396     if (c->NumStats != 1)
    397     {
    398       for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++);
    399     }
    400     else
    401       s = ONE_STATE(c);
    402     successor = SUCCESSOR(s);
    403     if (successor != upBranch)
    404     {
    405       c = CTX(successor);
    406       if (numPs == 0)
    407         return c;
    408       break;
    409     }
    410     ps[numPs++] = s;
    411   }
    412 
    413   upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch);
    414   SetSuccessor(&upState, upBranch + 1);
    415 
    416   if (c->NumStats == 1)
    417     upState.Freq = ONE_STATE(c)->Freq;
    418   else
    419   {
    420     UInt32 cf, s0;
    421     CPpmd_State *s;
    422     for (s = STATS(c); s->Symbol != upState.Symbol; s++);
    423     cf = s->Freq - 1;
    424     s0 = c->SummFreq - c->NumStats - cf;
    425     upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))));
    426   }
    427 
    428   while (numPs != 0)
    429   {
    430     /* Create Child */
    431     CTX_PTR c1; /* = AllocContext(p); */
    432     if (p->HiUnit != p->LoUnit)
    433       c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE);
    434     else if (p->FreeList[0] != 0)
    435       c1 = (CTX_PTR)RemoveNode(p, 0);
    436     else
    437     {
    438       c1 = (CTX_PTR)AllocUnitsRare(p, 0);
    439       if (!c1)
    440         return NULL;
    441     }
    442     c1->NumStats = 1;
    443     *ONE_STATE(c1) = upState;
    444     c1->Suffix = REF(c);
    445     SetSuccessor(ps[--numPs], REF(c1));
    446     c = c1;
    447   }
    448 
    449   return c;
    450 }
    451 
    452 static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)
    453 {
    454   CPpmd_State tmp = *t1;
    455   *t1 = *t2;
    456   *t2 = tmp;
    457 }
    458 
    459 static void UpdateModel(CPpmd7 *p)
    460 {
    461   CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState);
    462   CTX_PTR c;
    463   unsigned s0, ns;
    464 
    465   if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)
    466   {
    467     c = SUFFIX(p->MinContext);
    468 
    469     if (c->NumStats == 1)
    470     {
    471       CPpmd_State *s = ONE_STATE(c);
    472       if (s->Freq < 32)
    473         s->Freq++;
    474     }
    475     else
    476     {
    477       CPpmd_State *s = STATS(c);
    478       if (s->Symbol != p->FoundState->Symbol)
    479       {
    480         do { s++; } while (s->Symbol != p->FoundState->Symbol);
    481         if (s[0].Freq >= s[-1].Freq)
    482         {
    483           SwapStates(&s[0], &s[-1]);
    484           s--;
    485         }
    486       }
    487       if (s->Freq < MAX_FREQ - 9)
    488       {
    489         s->Freq += 2;
    490         c->SummFreq += 2;
    491       }
    492     }
    493   }
    494 
    495   if (p->OrderFall == 0)
    496   {
    497     p->MinContext = p->MaxContext = CreateSuccessors(p, True);
    498     if (p->MinContext == 0)
    499     {
    500       RestartModel(p);
    501       return;
    502     }
    503     SetSuccessor(p->FoundState, REF(p->MinContext));
    504     return;
    505   }
    506 
    507   *p->Text++ = p->FoundState->Symbol;
    508   successor = REF(p->Text);
    509   if (p->Text >= p->UnitsStart)
    510   {
    511     RestartModel(p);
    512     return;
    513   }
    514 
    515   if (fSuccessor)
    516   {
    517     if (fSuccessor <= successor)
    518     {
    519       CTX_PTR cs = CreateSuccessors(p, False);
    520       if (cs == NULL)
    521       {
    522         RestartModel(p);
    523         return;
    524       }
    525       fSuccessor = REF(cs);
    526     }
    527     if (--p->OrderFall == 0)
    528     {
    529       successor = fSuccessor;
    530       p->Text -= (p->MaxContext != p->MinContext);
    531     }
    532   }
    533   else
    534   {
    535     SetSuccessor(p->FoundState, successor);
    536     fSuccessor = REF(p->MinContext);
    537   }
    538 
    539   s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1);
    540 
    541   for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c))
    542   {
    543     unsigned ns1;
    544     UInt32 cf, sf;
    545     if ((ns1 = c->NumStats) != 1)
    546     {
    547       if ((ns1 & 1) == 0)
    548       {
    549         /* Expand for one UNIT */
    550         unsigned oldNU = ns1 >> 1;
    551         unsigned i = U2I(oldNU);
    552         if (i != U2I(oldNU + 1))
    553         {
    554           void *ptr = AllocUnits(p, i + 1);
    555           void *oldPtr;
    556           if (!ptr)
    557           {
    558             RestartModel(p);
    559             return;
    560           }
    561           oldPtr = STATS(c);
    562           MyMem12Cpy(ptr, oldPtr, oldNU);
    563           InsertNode(p, oldPtr, i);
    564           c->Stats = STATS_REF(ptr);
    565         }
    566       }
    567       c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1)));
    568     }
    569     else
    570     {
    571       CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0);
    572       if (!s)
    573       {
    574         RestartModel(p);
    575         return;
    576       }
    577       *s = *ONE_STATE(c);
    578       c->Stats = REF(s);
    579       if (s->Freq < MAX_FREQ / 4 - 1)
    580         s->Freq <<= 1;
    581       else
    582         s->Freq = MAX_FREQ - 4;
    583       c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3));
    584     }
    585     cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6);
    586     sf = (UInt32)s0 + c->SummFreq;
    587     if (cf < 6 * sf)
    588     {
    589       cf = 1 + (cf > sf) + (cf >= 4 * sf);
    590       c->SummFreq += 3;
    591     }
    592     else
    593     {
    594       cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf);
    595       c->SummFreq = (UInt16)(c->SummFreq + cf);
    596     }
    597     {
    598       CPpmd_State *s = STATS(c) + ns1;
    599       SetSuccessor(s, successor);
    600       s->Symbol = p->FoundState->Symbol;
    601       s->Freq = (Byte)cf;
    602       c->NumStats = (UInt16)(ns1 + 1);
    603     }
    604   }
    605   p->MaxContext = p->MinContext = CTX(fSuccessor);
    606 }
    607 
    608 static void Rescale(CPpmd7 *p)
    609 {
    610   unsigned i, adder, sumFreq, escFreq;
    611   CPpmd_State *stats = STATS(p->MinContext);
    612   CPpmd_State *s = p->FoundState;
    613   {
    614     CPpmd_State tmp = *s;
    615     for (; s != stats; s--)
    616       s[0] = s[-1];
    617     *s = tmp;
    618   }
    619   escFreq = p->MinContext->SummFreq - s->Freq;
    620   s->Freq += 4;
    621   adder = (p->OrderFall != 0);
    622   s->Freq = (Byte)((s->Freq + adder) >> 1);
    623   sumFreq = s->Freq;
    624 
    625   i = p->MinContext->NumStats - 1;
    626   do
    627   {
    628     escFreq -= (++s)->Freq;
    629     s->Freq = (Byte)((s->Freq + adder) >> 1);
    630     sumFreq += s->Freq;
    631     if (s[0].Freq > s[-1].Freq)
    632     {
    633       CPpmd_State *s1 = s;
    634       CPpmd_State tmp = *s1;
    635       do
    636         s1[0] = s1[-1];
    637       while (--s1 != stats && tmp.Freq > s1[-1].Freq);
    638       *s1 = tmp;
    639     }
    640   }
    641   while (--i);
    642 
    643   if (s->Freq == 0)
    644   {
    645     unsigned numStats = p->MinContext->NumStats;
    646     unsigned n0, n1;
    647     do { i++; } while ((--s)->Freq == 0);
    648     escFreq += i;
    649     p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i);
    650     if (p->MinContext->NumStats == 1)
    651     {
    652       CPpmd_State tmp = *stats;
    653       do
    654       {
    655         tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1));
    656         escFreq >>= 1;
    657       }
    658       while (escFreq > 1);
    659       InsertNode(p, stats, U2I(((numStats + 1) >> 1)));
    660       *(p->FoundState = ONE_STATE(p->MinContext)) = tmp;
    661       return;
    662     }
    663     n0 = (numStats + 1) >> 1;
    664     n1 = (p->MinContext->NumStats + 1) >> 1;
    665     if (n0 != n1)
    666       p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));
    667   }
    668   p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));
    669   p->FoundState = STATS(p->MinContext);
    670 }
    671 
    672 static CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq)
    673 {
    674   CPpmd_See *see;
    675   unsigned nonMasked = p->MinContext->NumStats - numMasked;
    676   if (p->MinContext->NumStats != 256)
    677   {
    678     see = p->See[p->NS2Indx[nonMasked - 1]] +
    679         (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) +
    680         2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) +
    681         4 * (numMasked > nonMasked) +
    682         p->HiBitsFlag;
    683     {
    684       unsigned r = (see->Summ >> see->Shift);
    685       see->Summ = (UInt16)(see->Summ - r);
    686       *escFreq = r + (r == 0);
    687     }
    688   }
    689   else
    690   {
    691     see = &p->DummySee;
    692     *escFreq = 1;
    693   }
    694   return see;
    695 }
    696 
    697 static void NextContext(CPpmd7 *p)
    698 {
    699   CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
    700   if (p->OrderFall == 0 && (Byte *)c > p->Text)
    701     p->MinContext = p->MaxContext = c;
    702   else
    703     UpdateModel(p);
    704 }
    705 
    706 static void Ppmd7_Update1(CPpmd7 *p)
    707 {
    708   CPpmd_State *s = p->FoundState;
    709   s->Freq += 4;
    710   p->MinContext->SummFreq += 4;
    711   if (s[0].Freq > s[-1].Freq)
    712   {
    713     SwapStates(&s[0], &s[-1]);
    714     p->FoundState = --s;
    715     if (s->Freq > MAX_FREQ)
    716       Rescale(p);
    717   }
    718   NextContext(p);
    719 }
    720 
    721 static void Ppmd7_Update1_0(CPpmd7 *p)
    722 {
    723   p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq);
    724   p->RunLength += p->PrevSuccess;
    725   p->MinContext->SummFreq += 4;
    726   if ((p->FoundState->Freq += 4) > MAX_FREQ)
    727     Rescale(p);
    728   NextContext(p);
    729 }
    730 
    731 static void Ppmd7_UpdateBin(CPpmd7 *p)
    732 {
    733   p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0));
    734   p->PrevSuccess = 1;
    735   p->RunLength++;
    736   NextContext(p);
    737 }
    738 
    739 static void Ppmd7_Update2(CPpmd7 *p)
    740 {
    741   p->MinContext->SummFreq += 4;
    742   if ((p->FoundState->Freq += 4) > MAX_FREQ)
    743     Rescale(p);
    744   p->RunLength = p->InitRL;
    745   UpdateModel(p);
    746 }
    747 
    748 /* ---------- Decode ---------- */
    749 
    750 static Bool Ppmd_RangeDec_Init(CPpmd7z_RangeDec *p)
    751 {
    752   unsigned i;
    753   p->Low = p->Bottom = 0;
    754   p->Range = 0xFFFFFFFF;
    755   for (i = 0; i < 4; i++)
    756     p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
    757   return (p->Code < 0xFFFFFFFF);
    758 }
    759 
    760 static Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p)
    761 {
    762   if (p->Stream->Read((void *)p->Stream) != 0)
    763     return False;
    764   return Ppmd_RangeDec_Init(p);
    765 }
    766 
    767 static Bool PpmdRAR_RangeDec_Init(CPpmd7z_RangeDec *p)
    768 {
    769   if (!Ppmd_RangeDec_Init(p))
    770     return False;
    771   p->Bottom = 0x8000;
    772   return True;
    773 }
    774 
    775 static UInt32 Range_GetThreshold(void *pp, UInt32 total)
    776 {
    777   CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
    778   return (p->Code - p->Low) / (p->Range /= total);
    779 }
    780 
    781 static void Range_Normalize(CPpmd7z_RangeDec *p)
    782 {
    783   while (1)
    784   {
    785     if((p->Low ^ (p->Low + p->Range)) >= kTopValue)
    786     {
    787       if(p->Range >= p->Bottom)
    788         break;
    789       else
    790         p->Range = ((uint32_t)(-(int32_t)p->Low)) & (p->Bottom - 1);
    791     }
    792     p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
    793     p->Range <<= 8;
    794     p->Low <<= 8;
    795   }
    796 }
    797 
    798 static void Range_Decode_7z(void *pp, UInt32 start, UInt32 size)
    799 {
    800   CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
    801   p->Code -= start * p->Range;
    802   p->Range *= size;
    803   Range_Normalize(p);
    804 }
    805 
    806 static void Range_Decode_RAR(void *pp, UInt32 start, UInt32 size)
    807 {
    808   CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
    809   p->Low += start * p->Range;
    810   p->Range *= size;
    811   Range_Normalize(p);
    812 }
    813 
    814 static UInt32 Range_DecodeBit_7z(void *pp, UInt32 size0)
    815 {
    816   CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
    817   UInt32 newBound = (p->Range >> 14) * size0;
    818   UInt32 symbol;
    819   if (p->Code < newBound)
    820   {
    821     symbol = 0;
    822     p->Range = newBound;
    823   }
    824   else
    825   {
    826     symbol = 1;
    827     p->Code -= newBound;
    828     p->Range -= newBound;
    829   }
    830   Range_Normalize(p);
    831   return symbol;
    832 }
    833 
    834 static UInt32 Range_DecodeBit_RAR(void *pp, UInt32 size0)
    835 {
    836   CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
    837   UInt32 bit, value = p->p.GetThreshold(p, PPMD_BIN_SCALE);
    838   if(value < size0)
    839   {
    840     bit = 0;
    841     p->p.Decode(p, 0, size0);
    842   }
    843   else
    844   {
    845     bit = 1;
    846     p->p.Decode(p, size0, PPMD_BIN_SCALE - size0);
    847   }
    848   return bit;
    849 }
    850 
    851 static void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p)
    852 {
    853   p->p.GetThreshold = Range_GetThreshold;
    854   p->p.Decode = Range_Decode_7z;
    855   p->p.DecodeBit = Range_DecodeBit_7z;
    856 }
    857 
    858 static void PpmdRAR_RangeDec_CreateVTable(CPpmd7z_RangeDec *p)
    859 {
    860   p->p.GetThreshold = Range_GetThreshold;
    861   p->p.Decode = Range_Decode_RAR;
    862   p->p.DecodeBit = Range_DecodeBit_RAR;
    863 }
    864 
    865 #define MASK(sym) ((signed char *)charMask)[sym]
    866 
    867 static int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc)
    868 {
    869   size_t charMask[256 / sizeof(size_t)];
    870   if (p->MinContext->NumStats != 1)
    871   {
    872     CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
    873     unsigned i;
    874     UInt32 count, hiCnt;
    875     if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq))
    876     {
    877       Byte symbol;
    878       rc->Decode(rc, 0, s->Freq);
    879       p->FoundState = s;
    880       symbol = s->Symbol;
    881       Ppmd7_Update1_0(p);
    882       return symbol;
    883     }
    884     p->PrevSuccess = 0;
    885     i = p->MinContext->NumStats - 1;
    886     do
    887     {
    888       if ((hiCnt += (++s)->Freq) > count)
    889       {
    890         Byte symbol;
    891         rc->Decode(rc, hiCnt - s->Freq, s->Freq);
    892         p->FoundState = s;
    893         symbol = s->Symbol;
    894         Ppmd7_Update1(p);
    895         return symbol;
    896       }
    897     }
    898     while (--i);
    899     if (count >= p->MinContext->SummFreq)
    900       return -2;
    901     p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];
    902     rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt);
    903     PPMD_SetAllBitsIn256Bytes(charMask);
    904     MASK(s->Symbol) = 0;
    905     i = p->MinContext->NumStats - 1;
    906     do { MASK((--s)->Symbol) = 0; } while (--i);
    907   }
    908   else
    909   {
    910     UInt16 *prob = Ppmd7_GetBinSumm(p);
    911     if (rc->DecodeBit(rc, *prob) == 0)
    912     {
    913       Byte symbol;
    914       *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
    915       symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;
    916       Ppmd7_UpdateBin(p);
    917       return symbol;
    918     }
    919     *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
    920     p->InitEsc = PPMD7_kExpEscape[*prob >> 10];
    921     PPMD_SetAllBitsIn256Bytes(charMask);
    922     MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;
    923     p->PrevSuccess = 0;
    924   }
    925   for (;;)
    926   {
    927     CPpmd_State *ps[256], *s;
    928     UInt32 freqSum, count, hiCnt;
    929     CPpmd_See *see;
    930     unsigned i, num, numMasked = p->MinContext->NumStats;
    931     do
    932     {
    933       p->OrderFall++;
    934       if (!p->MinContext->Suffix)
    935         return -1;
    936       p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);
    937     }
    938     while (p->MinContext->NumStats == numMasked);
    939     hiCnt = 0;
    940     s = Ppmd7_GetStats(p, p->MinContext);
    941     i = 0;
    942     num = p->MinContext->NumStats - numMasked;
    943     do
    944     {
    945       int k = (int)(MASK(s->Symbol));
    946       hiCnt += (s->Freq & k);
    947       ps[i] = s++;
    948       i -= k;
    949     }
    950     while (i != num);
    951 
    952     see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);
    953     freqSum += hiCnt;
    954     count = rc->GetThreshold(rc, freqSum);
    955 
    956     if (count < hiCnt)
    957     {
    958       Byte symbol;
    959       CPpmd_State **pps = ps;
    960       for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++);
    961       s = *pps;
    962       rc->Decode(rc, hiCnt - s->Freq, s->Freq);
    963       Ppmd_See_Update(see);
    964       p->FoundState = s;
    965       symbol = s->Symbol;
    966       Ppmd7_Update2(p);
    967       return symbol;
    968     }
    969     if (count >= freqSum)
    970       return -2;
    971     rc->Decode(rc, hiCnt, freqSum - hiCnt);
    972     see->Summ = (UInt16)(see->Summ + freqSum);
    973     do { MASK(ps[--i]->Symbol) = 0; } while (i != 0);
    974   }
    975 }
    976 
    977 /* ---------- Encode ---------- Ppmd7Enc.c */
    978 
    979 #define kTopValue (1 << 24)
    980 
    981 static void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p)
    982 {
    983   p->Low = 0;
    984   p->Range = 0xFFFFFFFF;
    985   p->Cache = 0;
    986   p->CacheSize = 1;
    987 }
    988 
    989 static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p)
    990 {
    991   if ((UInt32)p->Low < (UInt32)0xFF000000 || (unsigned)(p->Low >> 32) != 0)
    992   {
    993     Byte temp = p->Cache;
    994     do
    995     {
    996       p->Stream->Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32)));
    997       temp = 0xFF;
    998     }
    999     while(--p->CacheSize != 0);
   1000     p->Cache = (Byte)((UInt32)p->Low >> 24);
   1001   }
   1002   p->CacheSize++;
   1003   p->Low = ((UInt32)p->Low << 8) & 0xFFFFFFFF;
   1004 }
   1005 
   1006 static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total)
   1007 {
   1008   p->Low += (UInt64)start * (UInt64)(p->Range /= total);
   1009   p->Range *= size;
   1010   while (p->Range < kTopValue)
   1011   {
   1012     p->Range <<= 8;
   1013     RangeEnc_ShiftLow(p);
   1014   }
   1015 }
   1016 
   1017 static void RangeEnc_EncodeBit_0(CPpmd7z_RangeEnc *p, UInt32 size0)
   1018 {
   1019   p->Range = (p->Range >> 14) * size0;
   1020   while (p->Range < kTopValue)
   1021   {
   1022     p->Range <<= 8;
   1023     RangeEnc_ShiftLow(p);
   1024   }
   1025 }
   1026 
   1027 static void RangeEnc_EncodeBit_1(CPpmd7z_RangeEnc *p, UInt32 size0)
   1028 {
   1029   UInt32 newBound = (p->Range >> 14) * size0;
   1030   p->Low += newBound;
   1031   p->Range -= newBound;
   1032   while (p->Range < kTopValue)
   1033   {
   1034     p->Range <<= 8;
   1035     RangeEnc_ShiftLow(p);
   1036   }
   1037 }
   1038 
   1039 static void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p)
   1040 {
   1041   unsigned i;
   1042   for (i = 0; i < 5; i++)
   1043     RangeEnc_ShiftLow(p);
   1044 }
   1045 
   1046 
   1047 #define MASK(sym) ((signed char *)charMask)[sym]
   1048 
   1049 static void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol)
   1050 {
   1051   size_t charMask[256 / sizeof(size_t)];
   1052   if (p->MinContext->NumStats != 1)
   1053   {
   1054     CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
   1055     UInt32 sum;
   1056     unsigned i;
   1057     if (s->Symbol == symbol)
   1058     {
   1059       RangeEnc_Encode(rc, 0, s->Freq, p->MinContext->SummFreq);
   1060       p->FoundState = s;
   1061       Ppmd7_Update1_0(p);
   1062       return;
   1063     }
   1064     p->PrevSuccess = 0;
   1065     sum = s->Freq;
   1066     i = p->MinContext->NumStats - 1;
   1067     do
   1068     {
   1069       if ((++s)->Symbol == symbol)
   1070       {
   1071         RangeEnc_Encode(rc, sum, s->Freq, p->MinContext->SummFreq);
   1072         p->FoundState = s;
   1073         Ppmd7_Update1(p);
   1074         return;
   1075       }
   1076       sum += s->Freq;
   1077     }
   1078     while (--i);
   1079 
   1080     p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];
   1081     PPMD_SetAllBitsIn256Bytes(charMask);
   1082     MASK(s->Symbol) = 0;
   1083     i = p->MinContext->NumStats - 1;
   1084     do { MASK((--s)->Symbol) = 0; } while (--i);
   1085     RangeEnc_Encode(rc, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq);
   1086   }
   1087   else
   1088   {
   1089     UInt16 *prob = Ppmd7_GetBinSumm(p);
   1090     CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);
   1091     if (s->Symbol == symbol)
   1092     {
   1093       RangeEnc_EncodeBit_0(rc, *prob);
   1094       *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
   1095       p->FoundState = s;
   1096       Ppmd7_UpdateBin(p);
   1097       return;
   1098     }
   1099     else
   1100     {
   1101       RangeEnc_EncodeBit_1(rc, *prob);
   1102       *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
   1103       p->InitEsc = PPMD7_kExpEscape[*prob >> 10];
   1104       PPMD_SetAllBitsIn256Bytes(charMask);
   1105       MASK(s->Symbol) = 0;
   1106       p->PrevSuccess = 0;
   1107     }
   1108   }
   1109   for (;;)
   1110   {
   1111     UInt32 escFreq;
   1112     CPpmd_See *see;
   1113     CPpmd_State *s;
   1114     UInt32 sum;
   1115     unsigned i, numMasked = p->MinContext->NumStats;
   1116     do
   1117     {
   1118       p->OrderFall++;
   1119       if (!p->MinContext->Suffix)
   1120         return; /* EndMarker (symbol = -1) */
   1121       p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);
   1122     }
   1123     while (p->MinContext->NumStats == numMasked);
   1124 
   1125     see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq);
   1126     s = Ppmd7_GetStats(p, p->MinContext);
   1127     sum = 0;
   1128     i = p->MinContext->NumStats;
   1129     do
   1130     {
   1131       int cur = s->Symbol;
   1132       if (cur == symbol)
   1133       {
   1134         UInt32 low = sum;
   1135         CPpmd_State *s1 = s;
   1136         do
   1137         {
   1138           sum += (s->Freq & (int)(MASK(s->Symbol)));
   1139           s++;
   1140         }
   1141         while (--i);
   1142         RangeEnc_Encode(rc, low, s1->Freq, sum + escFreq);
   1143         Ppmd_See_Update(see);
   1144         p->FoundState = s1;
   1145         Ppmd7_Update2(p);
   1146         return;
   1147       }
   1148       sum += (s->Freq & (int)(MASK(cur)));
   1149       MASK(cur) = 0;
   1150       s++;
   1151     }
   1152     while (--i);
   1153 
   1154     RangeEnc_Encode(rc, sum, escFreq, sum + escFreq);
   1155     see->Summ = (UInt16)(see->Summ + sum + escFreq);
   1156   }
   1157 }
   1158 
   1159 const IPpmd7 __archive_ppmd7_functions =
   1160 {
   1161   &Ppmd7_Construct,
   1162   &Ppmd7_Alloc,
   1163   &Ppmd7_Free,
   1164   &Ppmd7_Init,
   1165   &Ppmd7z_RangeDec_CreateVTable,
   1166   &PpmdRAR_RangeDec_CreateVTable,
   1167   &Ppmd7z_RangeDec_Init,
   1168   &PpmdRAR_RangeDec_Init,
   1169   &Ppmd7_DecodeSymbol,
   1170   &Ppmd7z_RangeEnc_Init,
   1171   &Ppmd7z_RangeEnc_FlushData,
   1172   &Ppmd7_EncodeSymbol
   1173 };
   1174