Files
Aaru.Compression.Native/ppmd/VariantI.c
Natalia Portillo 12a4d684f5 Add support for various ZIP compression methods
- Implement Deflate64 decompression in zip/deflate64.h and zip/deflate64.c.
- Add ZIP Implode decompression functionality in zip/implode.h and zip/implode.c.
- Introduce ZIP Reduce decompression in zip/reduce.h and zip/reduce.c.
- Implement ZIP Shrink decompression in zip/shrink.h and zip/shrink.c.
- Create a unified ZIP interface in zip/zip.h and zip/zip.c to handle multiple compression methods including PPMd, WavPack, and WinZip JPEG.
- Ensure all new functions adhere to the Aaru Data Preservation Suite licensing and documentation standards.
2026-04-15 00:52:22 +01:00

887 lines
28 KiB
C

/*
* VariantI.c
*
* Copyright (c) 2017-present, MacPaw Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "VariantI.h"
#include <string.h>
#define UP_FREQ 5
#define O_BOUND 9
static void RestartModel(PPMdModelVariantI *self);
static void UpdateModel(PPMdModelVariantI *self, PPMdContext *mincontext);
static PPMdContext *CreateSuccessors(PPMdModelVariantI *self, bool skip, PPMdState *p1, PPMdContext *mincontext);
static PPMdContext *ReduceOrder(PPMdModelVariantI *self, PPMdState *state, PPMdContext *startcontext);
static void RestoreModel(PPMdModelVariantI *self, PPMdContext *currcontext, PPMdContext *mincontext,
PPMdContext *FSuccessor);
static void ShrinkContext(PPMdContext *self, int newlastindex, bool scale, PPMdModelVariantI *model);
static PPMdContext *CutOffContext(PPMdContext *self, int order, PPMdModelVariantI *model);
static PPMdContext *RemoveBinConts(PPMdContext *self, int order, PPMdModelVariantI *model);
static void DecodeBinSymbolVariantI(PPMdContext *self, PPMdModelVariantI *model);
static void DecodeSymbol1VariantI(PPMdContext *self, PPMdModelVariantI *model);
static void DecodeSymbol2VariantI(PPMdContext *self, PPMdModelVariantI *model);
static void RescalePPMdContextVariantI(PPMdContext *self, PPMdModelVariantI *model);
void StartPPMdModelVariantI(PPMdModelVariantI *self, PPMdReadFunction *readfunc, void *inputcontext,
PPMdSubAllocatorVariantI *alloc, int maxorder, int restoration)
{
InitializePPMdRangeCoder(&self->core.coder, readfunc, inputcontext, true, 0x8000);
if(maxorder < 2) // TODO: solid mode
{
memset(self->core.CharMask, 0, sizeof(self->core.CharMask));
self->core.OrderFall = self->MaxOrder;
for(PPMdContext *pc = self->MaxContext; pc->Suffix; pc = PPMdContextSuffix(pc, &self->core))
self->core.OrderFall--;
return;
}
self->alloc = alloc;
self->core.alloc = &alloc->core;
self->core.RescalePPMdContext = (void *)RescalePPMdContextVariantI;
self->MaxOrder = maxorder;
self->MRMethod = restoration;
self->core.EscCount = 1;
self->NS2BSIndx[0] = 2 * 0;
self->NS2BSIndx[1] = 2 * 1;
for(int i = 2; i < 11; i++) self->NS2BSIndx[i] = 2 * 2;
for(int i = 11; i < 256; i++) self->NS2BSIndx[i] = 2 * 3;
for(int i = 0; i < UP_FREQ; i++) self->QTable[i] = i;
int m = UP_FREQ, k = 1, step = 1;
for(int i = UP_FREQ; i < 260; i++)
{
self->QTable[i] = m;
if(!--k)
{
m++;
step++;
k = step;
}
}
self->DummySEE2Cont.Summ = 0xaf8f;
// self->DummySEE2Cont.Shift=0xac;
self->DummySEE2Cont.Count = 0x84;
self->DummySEE2Cont.Shift = PERIOD_BITS;
self->endofstream = false;
RestartModel(self);
}
static void RestartModel(PPMdModelVariantI *self)
{
InitSubAllocator(self->core.alloc);
memset(self->core.CharMask, 0, sizeof(self->core.CharMask));
self->core.PrevSuccess = 0;
self->core.OrderFall = self->MaxOrder;
self->core.RunLength = self->core.InitRL = -((self->MaxOrder < 12) ? self->MaxOrder : 12) - 1;
self->MaxContext = NewPPMdContext(&self->core);
self->MaxContext->LastStateIndex = 255;
self->MaxContext->SummFreq = 257;
self->MaxContext->States = AllocUnits(self->core.alloc, 256 / 2);
PPMdState *maxstates = PPMdContextStates(self->MaxContext, &self->core);
for(int i = 0; i < 256; i++)
{
maxstates[i].Symbol = i;
maxstates[i].Freq = 1;
maxstates[i].Successor = 0;
}
static const uint16_t InitBinEsc[8] = {0x3cdd, 0x1f3f, 0x59bf, 0x48f3, 0x64a1, 0x5abc, 0x6632, 0x6051};
int i = 0;
for(int m = 0; m < 25; m++)
{
while(self->QTable[i] == m) i++;
for(int k = 0; k < 8; k++) self->BinSumm[m][k] = BIN_SCALE - InitBinEsc[k] / (i + 1);
for(int k = 8; k < 64; k += 8) memcpy(&self->BinSumm[m][k], &self->BinSumm[m][0], 8 * sizeof(uint16_t));
}
i = 0;
for(int m = 0; m < 24; m++)
{
while(self->QTable[i + 3] == m + 3) i++;
for(int k = 0; k < 32; k++) self->SEE2Cont[m][k] = MakeSEE2(2 * i + 5, 7);
}
}
int NextPPMdVariantIByte(PPMdModelVariantI *self)
{
if(self->endofstream) return -1;
PPMdContext *mincontext = self->MaxContext;
if(mincontext->LastStateIndex != 0)
DecodeSymbol1VariantI(mincontext, self);
else
DecodeBinSymbolVariantI(mincontext, self);
while(!self->core.FoundState)
{
do
{
self->core.OrderFall++;
mincontext = PPMdContextSuffix(mincontext, &self->core);
if(!mincontext)
{
self->endofstream = true;
return -1;
}
} while(mincontext->LastStateIndex == self->core.LastMaskIndex);
DecodeSymbol2VariantI(mincontext, self);
}
uint8_t byte = self->core.FoundState->Symbol;
if(self->core.OrderFall == 0 &&
(uint8_t *)PPMdStateSuccessor(self->core.FoundState, &self->core) >= self->alloc->UnitsStart)
{
self->MaxContext = PPMdStateSuccessor(self->core.FoundState, &self->core);
// PrefetchData(MaxContext)
}
else
{
UpdateModel(self, mincontext);
// PrefetchData(MaxContext)
if(self->core.EscCount == 0) ClearPPMdModelMask(&self->core);
}
return byte;
}
static void UpdateModel(PPMdModelVariantI *self, PPMdContext *mincontext)
{
PPMdState fs = *self->core.FoundState;
PPMdState *state = NULL;
PPMdContext *currcontext = self->MaxContext;
if(fs.Freq < MAX_FREQ / 4 && mincontext->Suffix)
{
PPMdContext *context = PPMdContextSuffix(mincontext, &self->core);
if(context->LastStateIndex != 0)
{
state = PPMdContextStates(context, &self->core);
if(state->Symbol != fs.Symbol)
{
do state++;
while(state->Symbol != fs.Symbol);
if(state[0].Freq >= state[-1].Freq)
{
SWAP(state[0], state[-1]);
state--;
}
}
if(state->Freq < MAX_FREQ - 9)
{
state->Freq += 2;
context->SummFreq += 2;
}
}
else
{
state = PPMdContextOneState(context);
if(state->Freq < 32) state->Freq++;
}
}
if(self->core.OrderFall == 0 && fs.Successor)
{
PPMdContext *newsuccessor = CreateSuccessors(self, true, state, mincontext);
SetPPMdStateSuccessorPointer(self->core.FoundState, newsuccessor, &self->core);
if(!newsuccessor) goto RESTART_MODEL;
self->MaxContext = newsuccessor;
return;
}
*self->alloc->pText++ = fs.Symbol;
PPMdContext *Successor = (PPMdContext *)self->alloc->pText;
if(self->alloc->pText >= self->alloc->UnitsStart) goto RESTART_MODEL;
if(fs.Successor)
{
if((uint8_t *)PPMdStateSuccessor(&fs, &self->core) < self->alloc->UnitsStart)
{
SetPPMdStateSuccessorPointer(&fs, CreateSuccessors(self, false, state, mincontext), &self->core);
}
}
else
{
SetPPMdStateSuccessorPointer(&fs, ReduceOrder(self, state, mincontext), &self->core);
}
if(!fs.Successor) goto RESTART_MODEL;
if(--self->core.OrderFall == 0)
{
Successor = PPMdStateSuccessor(&fs, &self->core);
if(self->MaxContext != mincontext) self->alloc->pText--;
}
else if(self->MRMethod > MRM_FREEZE)
{
Successor = PPMdStateSuccessor(&fs, &self->core);
self->alloc->pText = self->alloc->HeapStart;
self->core.OrderFall = 0;
}
int minnum = mincontext->LastStateIndex + 1;
int s0 = mincontext->SummFreq - minnum - (fs.Freq - 1);
uint8_t flag = fs.Symbol >= 0x40 ? 8 : 0;
for(; currcontext != mincontext; currcontext = PPMdContextSuffix(currcontext, &self->core))
{
int currnum = currcontext->LastStateIndex + 1;
if(currnum != 1)
{
if((currnum & 1) == 0)
{
uint32_t states = ExpandUnits(self->core.alloc, currcontext->States, currnum >> 1);
if(!states) goto RESTART_MODEL;
currcontext->States = states;
}
if(3 * currnum - 1 < minnum) currcontext->SummFreq++;
}
else
{
PPMdState *states = OffsetToPointer(self->core.alloc, AllocUnits(self->core.alloc, 1));
if(!states) goto RESTART_MODEL;
states[0] = *(PPMdContextOneState(currcontext));
SetPPMdContextStatesPointer(currcontext, states, &self->core);
if(states[0].Freq < MAX_FREQ / 4 - 1)
states[0].Freq *= 2;
else
states[0].Freq = MAX_FREQ - 4;
currcontext->SummFreq = states[0].Freq + self->core.InitEsc + (minnum > 3 ? 1 : 0);
}
unsigned int cf = 2 * fs.Freq * (currcontext->SummFreq + 6);
unsigned int sf = s0 + currcontext->SummFreq;
unsigned int freq;
if(cf < 6 * sf)
{
if(cf >= 4 * sf)
freq = 3;
else if(cf > sf)
freq = 2;
else
freq = 1;
currcontext->SummFreq += 4;
}
else
{
if(cf > 15 * sf)
freq = 7;
else if(cf > 12 * sf)
freq = 6;
else if(cf > 9 * sf)
freq = 5;
else
freq = 4;
currcontext->SummFreq += freq;
}
currcontext->LastStateIndex++;
PPMdState *currstates = PPMdContextStates(currcontext, &self->core);
PPMdState *new = &currstates[currcontext->LastStateIndex];
SetPPMdStateSuccessorPointer(new, Successor, &self->core);
new->Symbol = fs.Symbol;
new->Freq = freq;
currcontext->Flags |= flag;
}
self->MaxContext = PPMdStateSuccessor(&fs, &self->core);
return;
RESTART_MODEL:
RestoreModel(self, currcontext, mincontext, PPMdStateSuccessor(&fs, &self->core));
}
static PPMdContext *CreateSuccessors(PPMdModelVariantI *self, bool skip, PPMdState *state, PPMdContext *context)
{
PPMdContext *upbranch = PPMdStateSuccessor(self->core.FoundState, &self->core);
PPMdState *statelist[MAX_O];
uint8_t sym = self->core.FoundState->Symbol;
int n = 0;
if(!skip)
{
statelist[n++] = self->core.FoundState;
if(!context->Suffix) goto skip;
}
if(state)
{
context = PPMdContextSuffix(context, &self->core);
if(PPMdStateSuccessor(state, &self->core) != upbranch)
{
context = PPMdStateSuccessor(state, &self->core);
goto skip;
}
statelist[n++] = state;
if(!context->Suffix) goto skip;
}
do
{
context = PPMdContextSuffix(context, &self->core);
if(context->LastStateIndex != 0)
{
state = PPMdContextStates(context, &self->core);
while(state->Symbol != sym) state++;
if(state->Freq < MAX_FREQ - 9)
{
state->Freq++;
context->SummFreq++;
}
}
else
{
state = PPMdContextOneState(context);
state->Freq += (!PPMdContextSuffix(context, &self->core)->LastStateIndex & (state->Freq < 24));
}
if(PPMdStateSuccessor(state, &self->core) != upbranch)
{
context = PPMdStateSuccessor(state, &self->core);
break;
}
statelist[n++] = state;
} while(context->Suffix);
skip:
if(n == 0) return context;
PPMdContext ct;
uint8_t newsym = *(uint8_t *)upbranch;
ct.LastStateIndex = 0;
ct.Flags = 0;
if(sym >= 0x40) ct.Flags |= 0x10;
if(newsym >= 0x40) ct.Flags |= 0x08;
PPMdState *onestate = PPMdContextOneState(&ct);
onestate->Symbol = newsym;
SetPPMdStateSuccessorPointer(onestate, (PPMdContext *)(((uint8_t *)upbranch) + 1), &self->core);
if(context->LastStateIndex != 0)
{
state = PPMdContextStates(context, &self->core);
while(state->Symbol != newsym) state++;
int cf = state->Freq - 1;
int s0 = context->SummFreq - context->LastStateIndex - cf;
if(2 * cf <= s0)
{
if(5 * cf > s0)
onestate->Freq = 2;
else
onestate->Freq = 1;
}
else
onestate->Freq = 1 + ((cf + 2 * s0 - 3) / s0);
}
else
onestate->Freq = PPMdContextOneState(context)->Freq;
for(int i = n - 1; i >= 0; i--)
{
PPMdContext *newcontext = (PPMdContext *)OffsetToPointer(self->core.alloc, AllocContext(self->core.alloc));
if(!newcontext) return NULL;
memcpy(newcontext, &ct, 8);
SetPPMdContextSuffixPointer(newcontext, context, &self->core);
SetPPMdStateSuccessorPointer(statelist[i], newcontext, &self->core);
context = newcontext;
}
return context;
}
static PPMdContext *ReduceOrder(PPMdModelVariantI *self, PPMdState *state, PPMdContext *startcontext)
{
PPMdState *statelist[MAX_O];
PPMdContext *context = startcontext, *upbranch = (PPMdContext *)self->alloc->pText;
uint8_t sym = self->core.FoundState->Symbol;
int n = 0;
statelist[n++] = self->core.FoundState;
self->core.OrderFall++;
if(state)
{
context = PPMdContextSuffix(context, &self->core);
if(state->Successor) goto skip;
statelist[n++] = state;
self->core.OrderFall++;
}
for(;;)
{
if(!context->Suffix)
{
if(self->MRMethod > MRM_FREEZE)
{
for(int i = 0; i < n; i++) SetPPMdStateSuccessorPointer(statelist[i], context, &self->core);
self->alloc->pText = self->alloc->HeapStart + 1;
self->core.OrderFall = 1;
}
else
{
for(int i = 0; i < n; i++) SetPPMdStateSuccessorPointer(statelist[i], upbranch, &self->core);
}
return context;
}
context = PPMdContextSuffix(context, &self->core);
if(context->LastStateIndex)
{
state = PPMdContextStates(context, &self->core);
while(state->Symbol != sym) state++;
if(state->Freq < MAX_FREQ - 9)
{
state->Freq += 2;
context->SummFreq += 2;
}
}
else
{
state = PPMdContextOneState(context);
if(state->Freq < 32) state->Freq++;
}
if(state->Successor) break;
statelist[n++] = state;
self->core.OrderFall++;
}
skip:
if(self->MRMethod > MRM_FREEZE)
{
PPMdContext *successor = PPMdStateSuccessor(state, &self->core);
for(int i = 0; i < n; i++) SetPPMdStateSuccessorPointer(statelist[i], successor, &self->core);
self->alloc->pText = self->alloc->HeapStart + 1;
self->core.OrderFall = 1;
return successor;
}
else
{
for(int i = 0; i < n; i++) SetPPMdStateSuccessorPointer(statelist[i], upbranch, &self->core);
}
if(PPMdStateSuccessor(state, &self->core) <= upbranch)
{
PPMdState *tmp = self->core.FoundState;
self->core.FoundState = state;
SetPPMdStateSuccessorPointer(state, CreateSuccessors(self, false, NULL, context), &self->core);
self->core.FoundState = tmp;
}
if(self->core.OrderFall == 1 && startcontext == self->MaxContext)
{
self->core.FoundState->Successor = state->Successor;
self->alloc->pText--;
}
return PPMdStateSuccessor(state, &self->core);
}
static void RestoreModel(PPMdModelVariantI *self, PPMdContext *currcontext, PPMdContext *mincontext,
PPMdContext *FSuccessor)
{
self->alloc->pText = self->alloc->HeapStart;
PPMdContext *context = self->MaxContext;
while(context != currcontext)
{
if(context->LastStateIndex == 1)
{
PPMdState state = *(PPMdContextStates(context, &self->core));
SpecialFreeUnitVariantI(self->alloc, context->States);
state.Freq = (state.Freq + 11) >> 3;
*(PPMdContextOneState(context)) = state;
context->LastStateIndex = 0;
context->Flags &= 0x10;
if(state.Symbol >= 0x40) context->Flags += 0x08;
}
else
{
ShrinkContext(context, context->LastStateIndex - 1, false, self);
}
context = PPMdContextSuffix(context, &self->core);
}
while(context != mincontext)
{
if(!context->LastStateIndex)
{
PPMdContextOneState(context)->Freq = (PPMdContextOneState(context)->Freq + 1) >> 1;
}
else
{
context->SummFreq += 4;
if(context->SummFreq > 128 + 4 * context->LastStateIndex)
ShrinkContext(context, context->LastStateIndex, true, self);
}
context = PPMdContextSuffix(context, &self->core);
}
if(self->MRMethod > MRM_FREEZE)
{
self->MaxContext = FSuccessor;
if(!(self->alloc->BList[1].Stamp & 1)) self->alloc->GlueCount++;
}
else if(self->MRMethod == MRM_FREEZE)
{
while(self->MaxContext->Suffix) self->MaxContext = PPMdContextSuffix(self->MaxContext, &self->core);
RemoveBinConts(self->MaxContext, 0, self);
self->MRMethod = self->MRMethod + 1;
self->alloc->GlueCount = 0;
self->core.OrderFall = self->MaxOrder;
}
else if(self->MRMethod == MRM_RESTART || GetUsedMemoryVariantI(self->alloc) < (self->alloc->SubAllocatorSize >> 1))
{
RestartModel(self);
self->core.EscCount = 0;
}
else
{
while(self->MaxContext->Suffix) self->MaxContext = PPMdContextSuffix(self->MaxContext, &self->core);
do
{
CutOffContext(self->MaxContext, 0, self);
ExpandTextAreaVariantI(self->alloc);
} while(GetUsedMemoryVariantI(self->alloc) > 3 * (self->alloc->SubAllocatorSize >> 2));
self->alloc->GlueCount = 0;
self->core.OrderFall = self->MaxOrder;
}
}
static void ShrinkContext(PPMdContext *self, int newlastindex, bool scale, PPMdModelVariantI *model)
{
self->States =
ShrinkUnits(model->core.alloc, self->States, (self->LastStateIndex + 2) >> 1, (newlastindex + 2) >> 1);
self->LastStateIndex = newlastindex;
if(scale)
self->Flags &= 0x14;
else
self->Flags &= 0x10;
PPMdState *states = PPMdContextStates(self, &model->core);
int escfreq = self->SummFreq;
self->SummFreq = 0;
for(int i = 0; i <= self->LastStateIndex; i++)
{
escfreq -= states[i].Freq;
if(scale) states[i].Freq = (states[i].Freq + 1) >> 1;
self->SummFreq += states[i].Freq;
if(states[i].Symbol >= 0x40) self->Flags |= 0x08;
}
if(scale) escfreq = (escfreq + 1) >> 1;
self->SummFreq += escfreq;
}
static PPMdContext *CutOffContext(PPMdContext *self, int order, PPMdModelVariantI *model)
{
if(self->LastStateIndex == 0)
{
PPMdState *onestate = PPMdContextOneState(self);
if((uint8_t *)PPMdStateSuccessor(onestate, &model->core) >= model->alloc->UnitsStart)
{
if(order < model->MaxOrder)
{
// PrefetchData(p->Successor);
SetPPMdStateSuccessorPointer(
onestate, CutOffContext(PPMdStateSuccessor(onestate, &model->core), order + 1, model),
&model->core);
}
else
onestate->Successor = 0;
if(!onestate->Successor && order > O_BOUND)
{
SpecialFreeUnitVariantI(model->alloc, PointerToOffset(model->core.alloc, self));
return NULL;
}
return self;
}
else
{
SpecialFreeUnitVariantI(model->alloc, PointerToOffset(model->core.alloc, self));
return NULL;
}
}
// PrefetchData(self->States);
int oldnum = (self->LastStateIndex + 2) >> 1;
self->States = MoveUnitsUpVariantI(model->alloc, self->States, oldnum);
int n = self->LastStateIndex;
PPMdState *states = PPMdContextStates(self, &model->core);
for(int i = n; i >= 0; i--)
{
if((uint8_t *)PPMdStateSuccessor(&states[i], &model->core) < model->alloc->UnitsStart)
{
states[i].Successor = 0;
SWAP(states[i], states[n]);
n--;
}
else if(order < model->MaxOrder)
{
// PrefetchData(state->Successor);
SetPPMdStateSuccessorPointer(&states[i],
CutOffContext(PPMdStateSuccessor(&states[i], &model->core), order + 1, model),
&model->core);
}
else
states[i].Successor = 0;
}
if(n != self->LastStateIndex && order)
{
if(n < 0)
{
FreeUnits(model->core.alloc, self->States, oldnum);
SpecialFreeUnitVariantI(model->alloc, PointerToOffset(model->core.alloc, self));
return NULL;
}
else if(n == 0)
{
PPMdState state = *(PPMdContextStates(self, &model->core));
FreeUnits(model->core.alloc, self->States, oldnum);
state.Freq = (state.Freq + 11) >> 3;
*(PPMdContextOneState(self)) = state;
self->LastStateIndex = 0;
self->Flags &= 0x10;
if(state.Symbol >= 0x40) self->Flags += 0x08;
}
else
ShrinkContext(self, n, self->SummFreq > 16 * n, model);
}
return self;
}
static PPMdContext *RemoveBinConts(PPMdContext *self, int order, PPMdModelVariantI *model)
{
if(self->LastStateIndex == 0)
{
PPMdState *state = PPMdContextOneState(self);
if((uint8_t *)PPMdStateSuccessor(state, &model->core) >= model->alloc->UnitsStart && order < model->MaxOrder)
{
// PrefetchData(onestate->Successor);
SetPPMdStateSuccessorPointer(
state, RemoveBinConts(PPMdStateSuccessor(state, &model->core), order + 1, model), &model->core);
}
else
state->Successor = 0;
if(!state->Successor)
{
PPMdContext *suffix = PPMdContextSuffix(self, &model->core);
if(suffix->LastStateIndex == 0 || suffix->Flags == 0xff)
{
FreeUnits(model->core.alloc, PointerToOffset(model->core.alloc, self), 1);
return NULL;
}
}
return self;
}
// PrefetchData(self->States);
PPMdState *states = PPMdContextStates(self, &model->core);
for(int i = self->LastStateIndex; i >= 0; i--)
{
if((uint8_t *)PPMdStateSuccessor(&states[i], &model->core) >= model->alloc->UnitsStart &&
order < model->MaxOrder)
{
// PrefetchData(states[i].Successor);
SetPPMdStateSuccessorPointer(&states[i],
RemoveBinConts(PPMdStateSuccessor(&states[i], &model->core), order + 1, model),
&model->core);
}
else
states[i].Successor = 0;
}
return self;
}
static void DecodeBinSymbolVariantI(PPMdContext *self, PPMdModelVariantI *model)
{
PPMdState *rs = PPMdContextOneState(self);
uint8_t index =
model->NS2BSIndx[PPMdContextSuffix(self, &model->core)->LastStateIndex] + model->core.PrevSuccess + self->Flags;
uint16_t *bs = &model->BinSumm[model->QTable[rs->Freq - 1]][index + ((model->core.RunLength >> 26) & 0x20)];
PPMdDecodeBinSymbol(self, &model->core, bs, 196, false);
}
static void DecodeSymbol1VariantI(PPMdContext *self, PPMdModelVariantI *model)
{ PPMdDecodeSymbol1(self, &model->core, true); }
static void DecodeSymbol2VariantI(PPMdContext *self, PPMdModelVariantI *model)
{
SEE2Context *see;
// uint8_t *pb=(uint8_t *)PPMdContextStates(self);
// unsigned int t=2*self->LastStateIndex;
// PrefetchData(pb);
// PrefetchData(pb+t);
// PrefetchData(pb+2*t);
// PrefetchData(pb+3*t);
if(self->LastStateIndex != 255)
{
int n = PPMdContextSuffix(self, &model->core)->LastStateIndex;
see = &model->SEE2Cont[model->QTable[self->LastStateIndex + 2] - 3]
[(self->SummFreq > 11 * (self->LastStateIndex + 1) ? 1 : 0) +
(2 * self->LastStateIndex < n + model->core.LastMaskIndex ? 2 : 0) + self->Flags];
model->core.scale = GetSEE2Mean(see);
}
else
{
model->core.scale = 1;
see = &model->DummySEE2Cont;
}
PPMdDecodeSymbol2(self, &model->core, see);
}
static void RescalePPMdContextVariantI(PPMdContext *self, PPMdModelVariantI *model)
{
PPMdState *states = PPMdContextStates(self, &model->core);
int n = self->LastStateIndex + 1;
// Bump frequency of found state
model->core.FoundState->Freq += 4;
// Divide all frequencies and sort list
int escfreq = self->SummFreq + 4;
int adder = (model->core.OrderFall != 0 || model->MRMethod > MRM_FREEZE ? 1 : 0);
self->SummFreq = 0;
for(int i = 0; i < n; i++)
{
escfreq -= states[i].Freq;
states[i].Freq = (states[i].Freq + adder) >> 1;
self->SummFreq += states[i].Freq;
// Keep states sorted by decreasing frequency
if(i > 0 && states[i].Freq > states[i - 1].Freq)
{
// If not sorted, move current state upwards until list is sorted
PPMdState tmp = states[i];
int j = i - 1;
while(j > 0 && tmp.Freq > states[j - 1].Freq) j--;
memmove(&states[j + 1], &states[j], sizeof(PPMdState) * (i - j));
states[j] = tmp;
}
}
// TODO: add better sorting stage here.
// Drop states whose frequency has fallen to 0
if(states[n - 1].Freq == 0)
{
int numzeros = 1;
while(numzeros < n && states[n - 1 - numzeros].Freq == 0) numzeros++;
escfreq += numzeros;
self->LastStateIndex -= numzeros;
if(self->LastStateIndex == 0)
{
PPMdState tmp = states[0];
tmp.Freq = (2 * tmp.Freq + escfreq - 1) / escfreq;
if(tmp.Freq > MAX_FREQ / 3) tmp.Freq = MAX_FREQ / 3;
FreeUnits(model->core.alloc, self->States, (n + 1) >> 1);
model->core.FoundState = PPMdContextOneState(self);
*model->core.FoundState = tmp;
self->Flags = (self->Flags & 0x10) + 0x08 * (tmp.Symbol >= 0x40);
return;
}
self->States = ShrinkUnits(model->core.alloc, self->States, (n + 1) >> 1, (self->LastStateIndex + 2) >> 1);
PPMdState *states = PPMdContextStates(self, &model->core);
self->Flags &= ~0x08;
for(int i = 0; i <= self->LastStateIndex; i++)
if(states[i].Symbol >= 0x40) self->Flags |= 0x08;
}
self->SummFreq += (escfreq + 1) >> 1;
self->Flags |= 0x04;
// The found state is the first one to breach the limit, thus it is the largest and also first
model->core.FoundState = PPMdContextStates(self, &model->core);
}