mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-09-23 06:53:43 +00:00
- Adds missing includes, removes some unused ones. - Removes unused Windows.h and shellapi.h includes. - Uses / as path separator. This is portable and should still work fine on Windows.
451 lines
11 KiB
C++
451 lines
11 KiB
C++
#include <climits>
|
|
|
|
#include "PrefixCode.h"
|
|
|
|
struct XADCodeTreeNode
|
|
{
|
|
int branches[2];
|
|
};
|
|
|
|
struct XADCodeTableEntry
|
|
{
|
|
uint32_t length;
|
|
int32_t value;
|
|
};
|
|
|
|
static inline XADCodeTreeNode *NodePointer(XADPrefixCode *self, int node) { return &self->tree[node]; }
|
|
static inline int Branch(XADPrefixCode *self, int node, int bit) { return NodePointer(self, node)->branches[bit]; }
|
|
static inline void SetBranch(XADPrefixCode *self, int node, int bit, int nextnode) { NodePointer(self, node)->branches[bit] = nextnode; }
|
|
|
|
static inline int LeftBranch(XADPrefixCode *self, int node) { return Branch(self, node, 0); }
|
|
static inline int RightBranch(XADPrefixCode *self, int node) { return Branch(self, node, 1); }
|
|
static inline void SetLeftBranch(XADPrefixCode *self, int node, int nextnode) { SetBranch(self, node, 0, nextnode); }
|
|
static inline void SetRightBranch(XADPrefixCode *self, int node, int nextnode) { SetBranch(self, node, 1, nextnode); }
|
|
|
|
static inline int LeafValue(XADPrefixCode *self, int node) { return LeftBranch(self, node); }
|
|
static inline void SetLeafValue(XADPrefixCode *self, int node, int value) { SetLeftBranch(self, node, value); SetRightBranch(self, node, value); }
|
|
|
|
static inline void SetEmptyNode(XADPrefixCode *self, int node) { SetLeftBranch(self, node, -1); SetRightBranch(self, node, -2); }
|
|
|
|
static inline bool IsInvalidNode(XADPrefixCode *self, int node) { return node < 0; }
|
|
static inline bool IsOpenBranch(XADPrefixCode *self, int node, int bit) { return IsInvalidNode(self, Branch(self, node, bit)); }
|
|
static inline bool IsEmptyNode(XADPrefixCode *self, int node) { return LeftBranch(self, node) == -1 && RightBranch(self, node) == -2; }
|
|
static inline bool IsLeafNode(XADPrefixCode *self, int node) { return LeftBranch(self, node) == RightBranch(self, node); }
|
|
|
|
static inline int NewNode(XADPrefixCode *self)
|
|
{
|
|
self->tree.resize(self->numentries + 1);
|
|
SetEmptyNode(self, self->numentries);
|
|
return self->numentries++;
|
|
}
|
|
|
|
bool CSInputNextSymbolUsingCode(CSInputBuffer *buf, XADPrefixCode *code, int &outSymbol)
|
|
{
|
|
if (!code->table1)
|
|
code->_makeTable();
|
|
|
|
unsigned int bits;
|
|
if (!CSInputPeekBitString(buf, code->tablesize, bits))
|
|
return false;
|
|
|
|
int length = code->table1[bits].length;
|
|
int value = code->table1[bits].value;
|
|
|
|
if (length < 0)
|
|
return false;
|
|
|
|
if (length <= code->tablesize)
|
|
{
|
|
if (!CSInputSkipPeekedBits(buf, length))
|
|
return false;
|
|
outSymbol = value;
|
|
return true;
|
|
}
|
|
|
|
if (!CSInputSkipPeekedBits(buf, code->tablesize))
|
|
return false;
|
|
|
|
int node = value;
|
|
while (!IsLeafNode(code, node))
|
|
{
|
|
unsigned int bit;
|
|
if (!CSInputNextBit(buf, bit))
|
|
return false;
|
|
|
|
if (IsOpenBranch(code, node, bit))
|
|
return false;
|
|
node = Branch(code, node, bit);
|
|
}
|
|
outSymbol = LeafValue(code, node);
|
|
return true;
|
|
}
|
|
|
|
bool CSInputNextSymbolUsingCodeLE(CSInputBuffer *buf, XADPrefixCode *code, int &outSymbol)
|
|
{
|
|
if (!code->table2)
|
|
code->_makeTableLE();
|
|
|
|
unsigned int bits;
|
|
if (!CSInputPeekBitStringLE(buf, code->tablesize, bits))
|
|
return false;
|
|
|
|
int length = code->table2[bits].length;
|
|
int value = code->table2[bits].value;
|
|
|
|
if (length < 0)
|
|
return false;
|
|
|
|
if (length <= code->tablesize)
|
|
{
|
|
if (!CSInputSkipPeekedBitsLE(buf, length))
|
|
return false;
|
|
outSymbol = value;
|
|
return true;
|
|
}
|
|
|
|
if (!CSInputSkipPeekedBitsLE(buf, code->tablesize))
|
|
return false;
|
|
|
|
int node = value;
|
|
while (!IsLeafNode(code, node))
|
|
{
|
|
unsigned int bit;
|
|
if (!CSInputNextBitLE(buf, bit))
|
|
return false;
|
|
|
|
if (IsOpenBranch(code, node, bit))
|
|
return false;
|
|
node = Branch(code, node, bit);
|
|
}
|
|
outSymbol = LeafValue(code, node);
|
|
return true;
|
|
}
|
|
|
|
/*int CSInputNextSymbolUsingCode(CSInputBuffer *buf,XADPrefixCode *code)
|
|
{
|
|
int node=0;
|
|
while(!IsLeafNode(code,node))
|
|
{
|
|
int bit=CSInputNextBit(buf);
|
|
if(IsOpenBranch(code,node,bit)) [NSException raise:XADInvalidPrefixCodeException format:@"Invalid prefix code in bitstream"];
|
|
node=Branch(code,node,bit);
|
|
}
|
|
return LeafValue(code,node);
|
|
}
|
|
|
|
int CSInputNextSymbolUsingCodeLE(CSInputBuffer *buf,XADPrefixCode *code)
|
|
{
|
|
int node=0;
|
|
while(!IsLeafNode(code,node))
|
|
{
|
|
int bit=CSInputNextBitLE(buf);
|
|
if(IsOpenBranch(code,node,bit)) [NSException raise:XADInvalidPrefixCodeException format:@"Invalid prefix code in bitstream"];
|
|
node=Branch(code,node,bit);
|
|
}
|
|
return LeafValue(code,node);
|
|
}*/
|
|
|
|
|
|
XADPrefixCode *XADPrefixCode::prefixCode()
|
|
{
|
|
XADPrefixCode *self = new XADPrefixCode();
|
|
self->init();
|
|
return self;
|
|
}
|
|
|
|
XADPrefixCode *XADPrefixCode::prefixCodeWithLengths(const int *lengths, int numsymbols, int maxlength, bool zeros)
|
|
{
|
|
XADPrefixCode *self = prefixCode();
|
|
if (!self->initWithLengths(lengths, numsymbols, maxlength, zeros))
|
|
{
|
|
delete self;
|
|
self = nullptr;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
void XADPrefixCode::init()
|
|
{
|
|
tree.resize(1);
|
|
SetEmptyNode(this, 0);
|
|
numentries = 1;
|
|
minlength = INT_MAX;
|
|
maxlength = INT_MIN;
|
|
isstatic = false;
|
|
|
|
table1 = table2 = NULL;
|
|
}
|
|
|
|
bool XADPrefixCode::initWithLengths(const int *lengths, int numsymbols, int maxcodelength, bool zeros)
|
|
{
|
|
int code = 0, symbolsleft = numsymbols;
|
|
|
|
for (int length = 1; length <= maxcodelength; length++)
|
|
{
|
|
for (int i = 0; i < numsymbols; i++)
|
|
{
|
|
if (lengths[i] != length)
|
|
continue;
|
|
|
|
// Instead of reversing to get a low-bit-first code, we shift and use high-bit-first.
|
|
if (zeros)
|
|
{
|
|
if (!this->addValueHighBitFirst(i, code, length))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (!this->addValueHighBitFirst(i, ~code, length))
|
|
return false;
|
|
}
|
|
code++;
|
|
if (--symbolsleft == 0)
|
|
return true; // early exit if all codes have been handled
|
|
}
|
|
code <<= 1;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
XADPrefixCode::XADPrefixCode()
|
|
: numentries(0)
|
|
, minlength(0)
|
|
, maxlength(0)
|
|
, isstatic(false)
|
|
, currnode(0)
|
|
, tablesize(0)
|
|
, table1(nullptr)
|
|
, table2(nullptr)
|
|
{
|
|
}
|
|
|
|
XADPrefixCode::~XADPrefixCode()
|
|
{
|
|
delete[] table1;
|
|
delete[] table2;
|
|
}
|
|
|
|
bool XADPrefixCode::addValueHighBitFirst(int value, uint32_t code, int length)
|
|
{
|
|
return this->addValueHighBitFirst(value, code, length, length);
|
|
}
|
|
|
|
bool XADPrefixCode::addValueHighBitFirst(int value, uint32_t code, int length, int repeatpos)
|
|
{
|
|
if (isstatic)
|
|
return false;
|
|
|
|
delete[] table1;
|
|
delete[] table2;
|
|
table1 = table2 = NULL;
|
|
|
|
if (length > maxlength) maxlength = length;
|
|
if (length < minlength) minlength = length;
|
|
|
|
repeatpos = length - 1 - repeatpos;
|
|
if (repeatpos == 0 || (repeatpos >= 0 && (((code >> (repeatpos - 1)) & 3) == 0 || ((code >> (repeatpos - 1)) & 3) == 3)))
|
|
return false;
|
|
|
|
int lastnode = 0;
|
|
for (int bitpos = length - 1; bitpos >= 0; bitpos--)
|
|
{
|
|
int bit = (code >> bitpos) & 1;
|
|
|
|
if (IsLeafNode(this, lastnode))
|
|
return false;
|
|
|
|
if (bitpos == repeatpos)
|
|
{
|
|
if (!IsOpenBranch(this, lastnode, bit))
|
|
return false;
|
|
|
|
int repeatnode = NewNode(this);
|
|
int nextnode = NewNode(this);
|
|
|
|
SetBranch(this, lastnode, bit, repeatnode);
|
|
SetBranch(this, repeatnode, bit, repeatnode);
|
|
SetBranch(this, repeatnode, bit ^ 1, nextnode);
|
|
lastnode = nextnode;
|
|
|
|
bitpos++; // terminating bit already handled, skip it
|
|
}
|
|
else
|
|
{
|
|
if (IsOpenBranch(this, lastnode, bit))
|
|
SetBranch(this, lastnode, bit, NewNode(this));
|
|
lastnode = Branch(this, lastnode, bit);
|
|
}
|
|
|
|
}
|
|
|
|
if (!IsEmptyNode(this, lastnode))
|
|
return false;
|
|
SetLeafValue(this, lastnode, value);
|
|
|
|
return true;
|
|
}
|
|
|
|
static uint32_t Reverse32(uint32_t val)
|
|
{
|
|
val = ((val >> 1) & 0x55555555) | ((val & 0x55555555) << 1);
|
|
val = ((val >> 2) & 0x33333333) | ((val & 0x33333333) << 2);
|
|
val = ((val >> 4) & 0x0F0F0F0F) | ((val & 0x0F0F0F0F) << 4);
|
|
val = ((val >> 8) & 0x00FF00FF) | ((val & 0x00FF00FF) << 8);
|
|
return (val >> 16) | (val << 16);
|
|
}
|
|
|
|
static uint32_t ReverseN(uint32_t val, int length)
|
|
{
|
|
return Reverse32(val) >> (32 - length);
|
|
}
|
|
|
|
bool XADPrefixCode::addValueLowBitFirst(int value, uint32_t code, int length)
|
|
{
|
|
return this->addValueHighBitFirst(value, ReverseN(code, length), length, length);
|
|
}
|
|
|
|
bool XADPrefixCode::addValueLowBitFirst(int value, uint32_t code, int length, int repeatpos)
|
|
{
|
|
return this->addValueHighBitFirst(value, ReverseN(code, length), length, repeatpos);
|
|
}
|
|
|
|
void XADPrefixCode::startBuildingTree()
|
|
{
|
|
currnode = 0;
|
|
stack.resize(0);
|
|
}
|
|
|
|
void XADPrefixCode::startZeroBranch()
|
|
{
|
|
int newNode = NewNode(this);
|
|
SetBranch(this, currnode, 0, newNode);
|
|
this->_pushNode();
|
|
currnode = newNode;
|
|
}
|
|
|
|
void XADPrefixCode::startOneBranch()
|
|
{
|
|
int newNode = NewNode(this);
|
|
SetBranch(this, currnode, 1, newNode);
|
|
this->_pushNode();
|
|
currnode = newNode;
|
|
}
|
|
|
|
void XADPrefixCode::finishBranches()
|
|
{
|
|
this->_popNode();
|
|
}
|
|
|
|
void XADPrefixCode::makeLeafWithValue(int value)
|
|
{
|
|
SetLeafValue(this, currnode, value);
|
|
this->_popNode();
|
|
}
|
|
|
|
void XADPrefixCode::_pushNode()
|
|
{
|
|
stack.push_back(currnode);
|
|
}
|
|
|
|
void XADPrefixCode::_popNode()
|
|
{
|
|
if (stack.size() == 0) return; // the final pop will underflow the stack otherwise
|
|
int num = stack.back();
|
|
stack.pop_back();
|
|
currnode = num;
|
|
}
|
|
|
|
static void MakeTable(XADPrefixCode *code, int node, XADCodeTableEntry *table, int depth, int maxdepth)
|
|
{
|
|
int currtablesize = 1 << (maxdepth - depth);
|
|
|
|
if (IsLeafNode(code, node))
|
|
{
|
|
for (int i = 0; i < currtablesize; i++)
|
|
{
|
|
table[i].length = depth;
|
|
table[i].value = LeafValue(code, node);
|
|
}
|
|
}
|
|
else if (IsInvalidNode(code, node))
|
|
{
|
|
for (int i = 0; i < currtablesize; i++) table[i].length = -1;
|
|
}
|
|
else
|
|
{
|
|
if (depth == maxdepth)
|
|
{
|
|
table[0].length = maxdepth + 1;
|
|
table[0].value = node;
|
|
}
|
|
else
|
|
{
|
|
MakeTable(code, LeftBranch(code, node), table, depth + 1, maxdepth);
|
|
MakeTable(code, RightBranch(code, node), table + currtablesize / 2, depth + 1, maxdepth);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void MakeTableLE(XADPrefixCode *code, int node, XADCodeTableEntry *table, int depth, int maxdepth)
|
|
{
|
|
int currtablesize = 1 << (maxdepth - depth);
|
|
int currstride = 1 << depth;
|
|
|
|
if (IsLeafNode(code, node))
|
|
{
|
|
for (int i = 0; i < currtablesize; i++)
|
|
{
|
|
table[i*currstride].length = depth;
|
|
table[i*currstride].value = LeafValue(code, node);
|
|
}
|
|
}
|
|
else if (IsInvalidNode(code, node))
|
|
{
|
|
for (int i = 0; i < currtablesize; i++) table[i*currstride].length = -1;
|
|
}
|
|
else
|
|
{
|
|
if (depth == maxdepth)
|
|
{
|
|
table[0].length = maxdepth + 1;
|
|
table[0].value = node;
|
|
}
|
|
else
|
|
{
|
|
MakeTableLE(code, LeftBranch(code, node), table, depth + 1, maxdepth);
|
|
MakeTableLE(code, RightBranch(code, node), table + currstride, depth + 1, maxdepth);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define TableMaxSize 10
|
|
|
|
void XADPrefixCode::_makeTable()
|
|
{
|
|
if (table1) return;
|
|
|
|
if (maxlength < minlength) tablesize = TableMaxSize; // no code lengths recorded
|
|
else if (maxlength >= TableMaxSize) tablesize = TableMaxSize;
|
|
else tablesize = maxlength;
|
|
|
|
table1 = new XADCodeTableEntry[1 << tablesize];
|
|
|
|
MakeTable(this, 0, table1, 0, tablesize);
|
|
}
|
|
|
|
void XADPrefixCode::_makeTableLE()
|
|
{
|
|
if (table2) return;
|
|
|
|
if (maxlength < minlength) tablesize = TableMaxSize; // no code lengths recorded
|
|
else if (maxlength >= TableMaxSize) tablesize = TableMaxSize;
|
|
else tablesize = maxlength;
|
|
|
|
table2 = new XADCodeTableEntry[1 << tablesize];
|
|
|
|
MakeTableLE(this, 0, table2, 0, tablesize);
|
|
}
|