fse_decompress.c
311 lines
| 10.9 KiB
| text/x-c
|
CLexer
Gregory Szorc
|
r30434 | /* ****************************************************************** | ||
FSE : Finite State Entropy decoder | ||||
Copyright (C) 2013-2015, Yann Collet. | ||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) | ||||
Redistribution and use in source and binary forms, with or without | ||||
modification, are permitted provided that the following conditions are | ||||
met: | ||||
* Redistributions of source code must retain the above copyright | ||||
notice, this list of conditions and the following disclaimer. | ||||
* Redistributions in binary form must reproduce the above | ||||
copyright notice, this list of conditions and the following disclaimer | ||||
in the documentation and/or other materials provided with the | ||||
distribution. | ||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
You can contact the author at : | ||||
- FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy | ||||
- Public forum : https://groups.google.com/forum/#!forum/lz4c | ||||
****************************************************************** */ | ||||
/* ************************************************************** | ||||
* Includes | ||||
****************************************************************/ | ||||
#include <stdlib.h> /* malloc, free, qsort */ | ||||
#include <string.h> /* memcpy, memset */ | ||||
#include "bitstream.h" | ||||
Gregory Szorc
|
r37513 | #include "compiler.h" | ||
Gregory Szorc
|
r30434 | #define FSE_STATIC_LINKING_ONLY | ||
#include "fse.h" | ||||
Gregory Szorc
|
r37513 | #include "error_private.h" | ||
Gregory Szorc
|
r30434 | |||
/* ************************************************************** | ||||
* Error Management | ||||
****************************************************************/ | ||||
#define FSE_isError ERR_isError | ||||
Gregory Szorc
|
r40157 | #define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ | ||
Gregory Szorc
|
r30434 | |||
/* check and forward error code */ | ||||
Gregory Szorc
|
r44446 | #ifndef CHECK_F | ||
Gregory Szorc
|
r30434 | #define CHECK_F(f) { size_t const e = f; if (FSE_isError(e)) return e; } | ||
Gregory Szorc
|
r44446 | #endif | ||
Gregory Szorc
|
r30434 | |||
/* ************************************************************** | ||||
* Templates | ||||
****************************************************************/ | ||||
/* | ||||
designed to be included | ||||
for type-specific functions (template emulation in C) | ||||
Objective is to write these functions only once, for improved maintenance | ||||
*/ | ||||
/* safety checks */ | ||||
#ifndef FSE_FUNCTION_EXTENSION | ||||
# error "FSE_FUNCTION_EXTENSION must be defined" | ||||
#endif | ||||
#ifndef FSE_FUNCTION_TYPE | ||||
# error "FSE_FUNCTION_TYPE must be defined" | ||||
#endif | ||||
/* Function names */ | ||||
#define FSE_CAT(X,Y) X##Y | ||||
#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y) | ||||
#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y) | ||||
/* Function templates */ | ||||
FSE_DTable* FSE_createDTable (unsigned tableLog) | ||||
{ | ||||
if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX; | ||||
return (FSE_DTable*)malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) ); | ||||
} | ||||
void FSE_freeDTable (FSE_DTable* dt) | ||||
{ | ||||
free(dt); | ||||
} | ||||
size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) | ||||
{ | ||||
void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */ | ||||
FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr); | ||||
U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1]; | ||||
U32 const maxSV1 = maxSymbolValue + 1; | ||||
U32 const tableSize = 1 << tableLog; | ||||
U32 highThreshold = tableSize-1; | ||||
/* Sanity Checks */ | ||||
if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge); | ||||
if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); | ||||
/* Init, lay down lowprob symbols */ | ||||
{ FSE_DTableHeader DTableH; | ||||
DTableH.tableLog = (U16)tableLog; | ||||
DTableH.fastMode = 1; | ||||
{ S16 const largeLimit= (S16)(1 << (tableLog-1)); | ||||
U32 s; | ||||
for (s=0; s<maxSV1; s++) { | ||||
if (normalizedCounter[s]==-1) { | ||||
tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s; | ||||
symbolNext[s] = 1; | ||||
} else { | ||||
if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0; | ||||
symbolNext[s] = normalizedCounter[s]; | ||||
} } } | ||||
memcpy(dt, &DTableH, sizeof(DTableH)); | ||||
} | ||||
/* Spread symbols */ | ||||
{ U32 const tableMask = tableSize-1; | ||||
U32 const step = FSE_TABLESTEP(tableSize); | ||||
U32 s, position = 0; | ||||
for (s=0; s<maxSV1; s++) { | ||||
int i; | ||||
for (i=0; i<normalizedCounter[s]; i++) { | ||||
tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s; | ||||
position = (position + step) & tableMask; | ||||
while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */ | ||||
} } | ||||
if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ | ||||
} | ||||
/* Build Decoding table */ | ||||
{ U32 u; | ||||
for (u=0; u<tableSize; u++) { | ||||
FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol); | ||||
Gregory Szorc
|
r37513 | U32 const nextState = symbolNext[symbol]++; | ||
tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) ); | ||||
Gregory Szorc
|
r30434 | tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize); | ||
} } | ||||
return 0; | ||||
} | ||||
#ifndef FSE_COMMONDEFS_ONLY | ||||
/*-******************************************************* | ||||
* Decompression (Byte symbols) | ||||
*********************************************************/ | ||||
size_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue) | ||||
{ | ||||
void* ptr = dt; | ||||
FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr; | ||||
void* dPtr = dt + 1; | ||||
FSE_decode_t* const cell = (FSE_decode_t*)dPtr; | ||||
DTableH->tableLog = 0; | ||||
DTableH->fastMode = 0; | ||||
cell->newState = 0; | ||||
cell->symbol = symbolValue; | ||||
cell->nbBits = 0; | ||||
return 0; | ||||
} | ||||
size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits) | ||||
{ | ||||
void* ptr = dt; | ||||
FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr; | ||||
void* dPtr = dt + 1; | ||||
FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr; | ||||
const unsigned tableSize = 1 << nbBits; | ||||
const unsigned tableMask = tableSize - 1; | ||||
const unsigned maxSV1 = tableMask+1; | ||||
unsigned s; | ||||
/* Sanity checks */ | ||||
if (nbBits < 1) return ERROR(GENERIC); /* min size */ | ||||
/* Build Decoding Table */ | ||||
DTableH->tableLog = (U16)nbBits; | ||||
DTableH->fastMode = 1; | ||||
for (s=0; s<maxSV1; s++) { | ||||
dinfo[s].newState = 0; | ||||
dinfo[s].symbol = (BYTE)s; | ||||
dinfo[s].nbBits = (BYTE)nbBits; | ||||
} | ||||
return 0; | ||||
} | ||||
Gregory Szorc
|
r37513 | FORCE_INLINE_TEMPLATE size_t FSE_decompress_usingDTable_generic( | ||
Gregory Szorc
|
r30434 | void* dst, size_t maxDstSize, | ||
const void* cSrc, size_t cSrcSize, | ||||
const FSE_DTable* dt, const unsigned fast) | ||||
{ | ||||
BYTE* const ostart = (BYTE*) dst; | ||||
BYTE* op = ostart; | ||||
BYTE* const omax = op + maxDstSize; | ||||
BYTE* const olimit = omax-3; | ||||
BIT_DStream_t bitD; | ||||
FSE_DState_t state1; | ||||
FSE_DState_t state2; | ||||
/* Init */ | ||||
CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize)); | ||||
FSE_initDState(&state1, &bitD, dt); | ||||
FSE_initDState(&state2, &bitD, dt); | ||||
#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD) | ||||
/* 4 symbols per loop */ | ||||
for ( ; (BIT_reloadDStream(&bitD)==BIT_DStream_unfinished) & (op<olimit) ; op+=4) { | ||||
op[0] = FSE_GETSYMBOL(&state1); | ||||
if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ | ||||
BIT_reloadDStream(&bitD); | ||||
op[1] = FSE_GETSYMBOL(&state2); | ||||
if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ | ||||
{ if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } } | ||||
op[2] = FSE_GETSYMBOL(&state1); | ||||
if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ | ||||
BIT_reloadDStream(&bitD); | ||||
op[3] = FSE_GETSYMBOL(&state2); | ||||
} | ||||
/* tail */ | ||||
/* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */ | ||||
while (1) { | ||||
if (op>(omax-2)) return ERROR(dstSize_tooSmall); | ||||
*op++ = FSE_GETSYMBOL(&state1); | ||||
if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) { | ||||
*op++ = FSE_GETSYMBOL(&state2); | ||||
break; | ||||
} | ||||
if (op>(omax-2)) return ERROR(dstSize_tooSmall); | ||||
*op++ = FSE_GETSYMBOL(&state2); | ||||
if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) { | ||||
*op++ = FSE_GETSYMBOL(&state1); | ||||
break; | ||||
} } | ||||
return op-ostart; | ||||
} | ||||
size_t FSE_decompress_usingDTable(void* dst, size_t originalSize, | ||||
const void* cSrc, size_t cSrcSize, | ||||
const FSE_DTable* dt) | ||||
{ | ||||
const void* ptr = dt; | ||||
const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; | ||||
const U32 fastMode = DTableH->fastMode; | ||||
/* select fast mode (static) */ | ||||
if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1); | ||||
return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0); | ||||
} | ||||
Gregory Szorc
|
r30822 | size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog) | ||
Gregory Szorc
|
r30434 | { | ||
const BYTE* const istart = (const BYTE*)cSrc; | ||||
const BYTE* ip = istart; | ||||
short counting[FSE_MAX_SYMBOL_VALUE+1]; | ||||
unsigned tableLog; | ||||
unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE; | ||||
Gregory Szorc
|
r30822 | /* normal FSE decoding mode */ | ||
size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize); | ||||
if (FSE_isError(NCountLength)) return NCountLength; | ||||
//if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */ | ||||
if (tableLog > maxLog) return ERROR(tableLog_tooLarge); | ||||
ip += NCountLength; | ||||
cSrcSize -= NCountLength; | ||||
CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) ); | ||||
Gregory Szorc
|
r30434 | |||
Gregory Szorc
|
r30822 | return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace); /* always return, even if it is an error code */ | ||
} | ||||
Gregory Szorc
|
r30434 | |||
Gregory Szorc
|
r30822 | typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)]; | ||
Gregory Szorc
|
r30434 | |||
Gregory Szorc
|
r30822 | size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize) | ||
{ | ||||
DTable_max_t dt; /* Static analyzer seems unable to understand this table will be properly initialized later */ | ||||
return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, dt, FSE_MAX_TABLELOG); | ||||
Gregory Szorc
|
r30434 | } | ||
#endif /* FSE_COMMONDEFS_ONLY */ | ||||