Files
Aaru.Compression.Native/ppmd/RangeCoder.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

110 lines
3.0 KiB
C

/*
* RangeCoder.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 "RangeCoder.h"
void InitializePPMdRangeCoder(PPMdRangeCoder *self, PPMdReadFunction *readfunc, void *inputcontext, bool uselow,
int bottom)
{
self->readfunc = readfunc;
self->inputcontext = inputcontext;
self->low = 0;
self->code = 0;
self->range = 0xffffffff;
self->uselow = uselow;
self->bottom = bottom;
for(int i = 0; i < 4; i++) self->code = (self->code << 8) | readfunc(inputcontext);
}
uint32_t PPMdRangeCoderCurrentCount(PPMdRangeCoder *self, uint32_t scale)
{
self->range /= scale;
return (self->code - self->low) / self->range;
}
void RemovePPMdRangeCoderSubRange(PPMdRangeCoder *self, uint32_t lowcount, uint32_t highcount)
{
if(self->uselow)
self->low += self->range * lowcount;
else
self->code -= self->range * lowcount;
self->range *= highcount - lowcount;
NormalizePPMdRangeCoder(self);
}
int NextWeightedBitFromPPMdRangeCoder(PPMdRangeCoder *self, int weight, int size)
{
uint32_t val = PPMdRangeCoderCurrentCount(self, size);
if(val < weight)
{
RemovePPMdRangeCoderSubRange(self, 0, weight);
return 0;
}
else
{
RemovePPMdRangeCoderSubRange(self, weight, size);
return 1;
}
}
int NextWeightedBitFromPPMdRangeCoder2(PPMdRangeCoder *self, int weight, int shift)
{
uint32_t threshold = (self->range >> shift) * weight;
int bit;
if(self->code < threshold) // <= ?
{
bit = 0;
self->range = threshold;
}
else
{
bit = 1;
self->range -= threshold;
self->code -= threshold;
}
NormalizePPMdRangeCoder(self);
return bit;
}
void NormalizePPMdRangeCoder(PPMdRangeCoder *self)
{
for(;;)
{
if((self->low ^ (self->low + self->range)) >= 0x1000000)
{
if(self->range >= self->bottom)
break;
else
self->range = -self->low & (self->bottom - 1);
}
int byte = self->readfunc(self->inputcontext);
self->code = (self->code << 8) | byte;
self->range <<= 8;
self->low <<= 8;
}
}