Files
Aaru.Compression.Native/ppmd/VariantH.c
Natalia Portillo 1228eea822 Add RAR compression algorithms
- Introduced a new header file `vm.h` for the RAR 3.0 virtual machine, defining its architecture, instruction set, and API.
- Implemented the core functionality for executing RAR decompression filters.
- Added test cases for RAR formats 1.5, 2.0, 3.0, and 5.0, verifying decompression and CRC checks.
- Included necessary binary test data files for RAR formats in the test directory.
- Updated CMake configuration to include new test files and data.
2026-04-15 02:59:40 +01:00

426 lines
14 KiB
C

/*
* VariantH.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, see <http://www.gnu.org/licenses/>.
*/
#include "VariantH.h"
#include <string.h>
static void RestartModel(PPMdModelVariantH *self);
static void UpdateModel(PPMdModelVariantH *self);
static PPMdContext *CreateSuccessors(PPMdModelVariantH *self, bool skip, PPMdState *state);
static void DecodeBinSymbolVariantH(PPMdContext *self, PPMdModelVariantH *model);
static void DecodeSymbol1VariantH(PPMdContext *self, PPMdModelVariantH *model);
static void DecodeSymbol2VariantH(PPMdContext *self, PPMdModelVariantH *model);
void StartPPMdModelVariantH(PPMdModelVariantH *self, PPMdReadFunction *readfunc, void *inputcontext,
PPMdSubAllocatorVariantH *alloc, int maxorder, bool sevenzip)
{
RestartPPMdVariantHRangeCoder(self, readfunc, inputcontext, sevenzip);
self->alloc = alloc;
self->core.alloc = &alloc->core;
self->core.RescalePPMdContext = RescalePPMdContext;
self->MaxOrder = maxorder;
self->SevenZip = sevenzip;
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 < 3; i++) self->NS2Indx[i] = i;
int m = 3, k = 1, step = 1;
for(int i = 3; i < 256; i++)
{
self->NS2Indx[i] = m;
if(!--k)
{
m++;
step++;
k = step;
}
}
memset(self->HB2Flag, 0, 0x40);
memset(self->HB2Flag + 0x40, 0x08, 0x100 - 0x40);
self->DummySEE2Cont.Shift = PERIOD_BITS;
RestartModel(self);
}
void RestartPPMdVariantHRangeCoder(PPMdModelVariantH *self, PPMdReadFunction *readfunc, void *inputcontext,
bool sevenzip)
{
if(sevenzip)
{
readfunc(inputcontext);
InitializePPMdRangeCoder(&self->core.coder, readfunc, inputcontext, false, 0);
}
else
InitializePPMdRangeCoder(&self->core.coder, readfunc, inputcontext, true, 0x8000);
}
static void RestartModel(PPMdModelVariantH *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 = self->MinContext = 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;
}
self->core.FoundState = PPMdContextStates(self->MaxContext, &self->core);
static const uint16_t InitBinEsc[8] = {0x3cdd, 0x1f3f, 0x59bf, 0x48f3, 0x64a1, 0x5abc, 0x6632, 0x6051};
for(int i = 0; i < 128; i++)
for(int k = 0; k < 8; k++)
for(int m = 0; m < 64; m += 8) self->BinSumm[i][k + m] = BIN_SCALE - InitBinEsc[k] / (i + 2);
for(int i = 0; i < 25; i++)
for(int k = 0; k < 16; k++) self->SEE2Cont[i][k] = MakeSEE2(5 * i + 10, 4);
}
int NextPPMdVariantHByte(PPMdModelVariantH *self)
{
if(!self->MinContext) return -1;
if(self->MinContext->LastStateIndex != 0)
DecodeSymbol1VariantH(self->MinContext, self);
else
DecodeBinSymbolVariantH(self->MinContext, self);
while(!self->core.FoundState)
{
do
{
self->core.OrderFall++;
self->MinContext = PPMdContextSuffix(self->MinContext, &self->core);
if(!self->MinContext) return -1;
} while(self->MinContext->LastStateIndex == self->core.LastMaskIndex);
DecodeSymbol2VariantH(self->MinContext, self);
}
uint8_t byte = self->core.FoundState->Symbol;
if(self->core.OrderFall == 0 &&
(uint8_t *)PPMdStateSuccessor(self->core.FoundState, &self->core) > self->alloc->pText)
{
self->MinContext = self->MaxContext = PPMdStateSuccessor(self->core.FoundState, &self->core);
}
else
{
UpdateModel(self);
if(self->core.EscCount == 0) ClearPPMdModelMask(&self->core);
}
return byte;
}
static void UpdateModel(PPMdModelVariantH *self)
{
PPMdState fs = *self->core.FoundState;
PPMdState *state = NULL;
if(fs.Freq < MAX_FREQ / 4 && self->MinContext->Suffix)
{
PPMdContext *context = PPMdContextSuffix(self->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)
{
self->MinContext = self->MaxContext = CreateSuccessors(self, true, state);
SetPPMdStateSuccessorPointer(self->core.FoundState, self->MinContext, &self->core);
if(!self->MinContext) goto RESTART_MODEL;
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->pText)
{
SetPPMdStateSuccessorPointer(&fs, CreateSuccessors(self, false, state), &self->core);
if(!fs.Successor) goto RESTART_MODEL;
}
if(--self->core.OrderFall == 0)
{
Successor = PPMdStateSuccessor(&fs, &self->core);
if(self->MaxContext != self->MinContext) self->alloc->pText--;
}
}
else
{
SetPPMdStateSuccessorPointer(self->core.FoundState, Successor, &self->core);
SetPPMdStateSuccessorPointer(&fs, self->MinContext, &self->core);
}
int minnum = self->MinContext->LastStateIndex + 1;
int s0 = self->MinContext->SummFreq - minnum - (fs.Freq - 1);
for(PPMdContext *currcontext = self->MaxContext; currcontext != self->MinContext;
currcontext = PPMdContextSuffix(currcontext, &self->core))
{
int currnum = currcontext->LastStateIndex + 1;
if(currnum != 1)
{
if((currnum & 1) == 0)
{
currcontext->States = ExpandUnits(self->core.alloc, currcontext->States, currnum >> 1);
if(!currcontext->States) goto RESTART_MODEL;
}
if(4 * currnum <= minnum && currcontext->SummFreq <= 8 * currnum) currcontext->SummFreq += 2;
if(2 * currnum < 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 += 3;
}
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;
}
PPMdState *currstates = PPMdContextStates(currcontext, &self->core);
PPMdState *newstate = &currstates[currnum];
SetPPMdStateSuccessorPointer(newstate, Successor, &self->core);
newstate->Symbol = fs.Symbol;
newstate->Freq = freq;
currcontext->LastStateIndex = currnum;
}
self->MaxContext = self->MinContext = PPMdStateSuccessor(&fs, &self->core);
return;
RESTART_MODEL:
RestartModel(self);
self->core.EscCount = 0;
}
static PPMdContext *CreateSuccessors(PPMdModelVariantH *self, bool skip, PPMdState *state)
{
PPMdContext *context = self->MinContext, *upbranch = PPMdStateSuccessor(self->core.FoundState, &self->core);
PPMdState *statelist[MAX_O];
int n = 0;
if(!skip)
{
statelist[n++] = self->core.FoundState;
if(!context->Suffix) goto skip_label;
}
if(state)
{
context = PPMdContextSuffix(context, &self->core);
if(PPMdStateSuccessor(state, &self->core) != upbranch)
{
context = PPMdStateSuccessor(state, &self->core);
goto skip_label;
}
statelist[n++] = state;
if(!context->Suffix) goto skip_label;
}
do
{
context = PPMdContextSuffix(context, &self->core);
if(context->LastStateIndex != 0)
{
state = PPMdContextStates(context, &self->core);
while(state->Symbol != self->core.FoundState->Symbol) state++;
}
else
state = PPMdContextOneState(context);
if(PPMdStateSuccessor(state, &self->core) != upbranch)
{
context = PPMdStateSuccessor(state, &self->core);
break;
}
statelist[n++] = state;
} while(context->Suffix);
skip_label:
if(n == 0) return context;
PPMdState upstate;
upstate.Symbol = *(uint8_t *)upbranch;
SetPPMdStateSuccessorPointer(&upstate, (PPMdContext *)(((uint8_t *)upbranch) + 1), &self->core);
if(context->LastStateIndex != 0)
{
state = PPMdContextStates(context, &self->core);
while(state->Symbol != upstate.Symbol) state++;
int cf = state->Freq - 1;
int s0 = context->SummFreq - context->LastStateIndex - 1 - cf;
if(2 * cf <= s0)
{
if(5 * cf > s0)
upstate.Freq = 2;
else
upstate.Freq = 1;
}
else
upstate.Freq = 1 + ((2 * cf + 3 * s0 - 1) / (2 * s0));
}
else
upstate.Freq = PPMdContextOneState(context)->Freq;
for(int i = n - 1; i >= 0; i--)
{
context = NewPPMdContextAsChildOf(&self->core, context, statelist[i], &upstate);
if(!context) return NULL;
}
return context;
}
static void DecodeBinSymbolVariantH(PPMdContext *self, PPMdModelVariantH *model)
{
PPMdState *rs = PPMdContextOneState(self);
model->HiBitsFlag = model->HB2Flag[model->core.FoundState->Symbol];
uint16_t *bs =
&model->BinSumm[rs->Freq - 1][model->core.PrevSuccess +
model->NS2BSIndx[PPMdContextSuffix(self, &model->core)->LastStateIndex] +
model->HiBitsFlag + 2 * model->HB2Flag[rs->Symbol] +
((model->core.RunLength >> 26) & 0x20)];
PPMdDecodeBinSymbol(self, &model->core, bs, 128, model->SevenZip);
}
static void DecodeSymbol1VariantH(PPMdContext *self, PPMdModelVariantH *model)
{
int lastsym = PPMdDecodeSymbol1(self, &model->core, false);
if(lastsym >= 0) { model->HiBitsFlag = model->HB2Flag[lastsym]; }
}
static void DecodeSymbol2VariantH(PPMdContext *self, PPMdModelVariantH *model)
{
int diff = self->LastStateIndex - model->core.LastMaskIndex;
SEE2Context *see;
if(self->LastStateIndex != 255)
{
see =
&model
->SEE2Cont[model->NS2Indx[diff - 1]]
[+(diff < PPMdContextSuffix(self, &model->core)->LastStateIndex - self->LastStateIndex ? 1
: 0) +
(self->SummFreq < 11 * (self->LastStateIndex + 1) ? 2 : 0) +
(model->core.LastMaskIndex + 1 > diff ? 4 : 0) + model->HiBitsFlag];
model->core.scale = GetSEE2Mean(see);
}
else
{
model->core.scale = 1;
see = &model->DummySEE2Cont;
}
PPMdDecodeSymbol2(self, &model->core, see);
}