2020-11-10 00:58:19 +01:00
|
|
|
#include "common/garmin.h"
|
2020-01-21 21:50:13 +01:00
|
|
|
#include "huffmantable.h"
|
|
|
|
|
2021-09-20 21:43:17 +02:00
|
|
|
using namespace Garmin;
|
2021-04-10 15:27:40 +02:00
|
|
|
using namespace IMG;
|
|
|
|
|
2020-01-21 21:50:13 +01:00
|
|
|
static inline quint32 readVUint32(const quint8 *buffer, quint32 bytes)
|
|
|
|
{
|
|
|
|
quint32 val = 0;
|
|
|
|
|
2021-10-22 22:04:46 +02:00
|
|
|
for (quint32 i = 0; i < bytes; i++)
|
|
|
|
val |= ((quint32)*(buffer + i)) << (i * 8);
|
2020-01-21 21:50:13 +01:00
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2020-11-10 00:58:19 +01:00
|
|
|
bool HuffmanTable::load(const RGNFile *rgn, SubFile::Handle &rgnHdl)
|
2020-01-21 21:50:13 +01:00
|
|
|
{
|
2020-11-10 00:58:19 +01:00
|
|
|
if (!_buffer.load(rgn, rgnHdl))
|
2020-01-21 21:50:13 +01:00
|
|
|
return false;
|
|
|
|
|
2021-10-22 22:04:46 +02:00
|
|
|
_aclBits = (quint8)_buffer.at(0) & 0x0F;
|
|
|
|
_huffman = (quint8)_buffer.at(0) & 0x10;
|
|
|
|
_symBits = (quint8)_buffer.at(1);
|
|
|
|
_symBytes = bs(_symBits);
|
|
|
|
_bsrchEntries = (quint8)_buffer.at(2);
|
|
|
|
_symbolBits = (quint8)_buffer.at(3);
|
|
|
|
_symbolBytes = bs(_symbolBits);
|
|
|
|
_aclEntryBytes = _symbolBytes + 1;
|
|
|
|
_indexBytes = vs(_buffer.at(4));
|
2021-10-23 07:41:27 +02:00
|
|
|
_bsrchEntryBytes = _symBytes + _indexBytes + 1;
|
2021-10-23 17:28:06 +02:00
|
|
|
_bsrchTable = (const quint8*)(_buffer.constData()) + 4 + _indexBytes;
|
2021-10-22 22:04:46 +02:00
|
|
|
_aclTable = _bsrchTable + _bsrchEntryBytes * _bsrchEntries;
|
|
|
|
_huffmanTable = _aclTable + (_aclEntryBytes << _aclBits);
|
2020-01-21 21:50:13 +01:00
|
|
|
|
2021-10-23 22:53:10 +02:00
|
|
|
return (_symBits <= 32 && _symbolBits <= 32);
|
2020-01-21 21:50:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
quint32 HuffmanTable::symbol(quint32 data, quint8 &size) const
|
|
|
|
{
|
2021-10-22 22:04:46 +02:00
|
|
|
quint32 lo, hi;
|
2021-10-23 17:28:06 +02:00
|
|
|
const quint8 *tp;
|
2020-01-21 21:50:13 +01:00
|
|
|
|
|
|
|
|
2021-10-22 22:04:46 +02:00
|
|
|
if (!_aclBits) {
|
|
|
|
hi = _bsrchEntries - 1;
|
|
|
|
lo = 0;
|
2020-01-21 21:50:13 +01:00
|
|
|
} else {
|
2021-10-22 22:04:46 +02:00
|
|
|
quint32 offset = _aclEntryBytes * (data >> (32 - _aclBits));
|
|
|
|
tp = _aclTable + offset;
|
2020-01-21 21:50:13 +01:00
|
|
|
|
2021-10-22 22:04:46 +02:00
|
|
|
if (*tp & 1) {
|
2020-01-21 21:50:13 +01:00
|
|
|
size = *tp >> 1;
|
2021-10-22 22:04:46 +02:00
|
|
|
return readVUint32(tp + 1, _symbolBytes);;
|
2020-01-21 21:50:13 +01:00
|
|
|
}
|
|
|
|
|
2021-10-22 22:04:46 +02:00
|
|
|
lo = *tp >> 1;
|
|
|
|
hi = *(tp + 1);
|
2020-01-21 21:50:13 +01:00
|
|
|
}
|
|
|
|
|
2021-10-22 22:04:46 +02:00
|
|
|
tp = _bsrchTable + (lo * _bsrchEntryBytes);
|
|
|
|
data >>= 32 - _symBits;
|
2020-01-21 21:50:13 +01:00
|
|
|
|
2021-10-22 22:04:46 +02:00
|
|
|
while (lo < hi) {
|
2021-10-23 17:28:06 +02:00
|
|
|
const quint8 *prev = tp;
|
2021-10-22 22:04:46 +02:00
|
|
|
quint32 m = (lo + 1 + hi) >> 1;
|
|
|
|
tp = _bsrchTable + (m * _bsrchEntryBytes);
|
|
|
|
quint32 nd = readVUint32(tp, _symBytes);
|
2020-01-21 21:50:13 +01:00
|
|
|
|
|
|
|
if (data <= nd) {
|
|
|
|
if (data == nd)
|
2021-10-22 22:04:46 +02:00
|
|
|
lo = m;
|
2020-01-21 21:50:13 +01:00
|
|
|
else
|
|
|
|
tp = prev;
|
|
|
|
|
2021-10-22 22:04:46 +02:00
|
|
|
hi = m - (data < nd);
|
|
|
|
m = lo;
|
2020-01-21 21:50:13 +01:00
|
|
|
}
|
2021-10-22 22:04:46 +02:00
|
|
|
lo = m;
|
2020-01-21 21:50:13 +01:00
|
|
|
}
|
|
|
|
|
2021-10-22 22:04:46 +02:00
|
|
|
quint32 i = readVUint32(tp, _symBytes);
|
|
|
|
tp = tp + _symBytes;
|
2020-01-21 21:50:13 +01:00
|
|
|
size = *tp;
|
|
|
|
|
2021-10-22 22:04:46 +02:00
|
|
|
if (!_huffman)
|
|
|
|
return readVUint32(tp + 1, _symbolBytes);
|
2020-01-21 21:50:13 +01:00
|
|
|
else {
|
2021-10-22 22:04:46 +02:00
|
|
|
quint32 bi = readVUint32(tp + 1, _indexBytes);
|
|
|
|
quint32 ci = (data - i) >> (_symBits - size);
|
|
|
|
quint32 si = (ci + bi) * _symbolBits;
|
|
|
|
quint32 sbi = si & 7;
|
|
|
|
quint32 shift = 8 - sbi;
|
2021-10-23 07:41:27 +02:00
|
|
|
tp = _huffmanTable + (si >> 3);
|
2021-10-22 22:04:46 +02:00
|
|
|
|
2021-10-23 22:53:10 +02:00
|
|
|
if (shift < _symbolBits) {
|
|
|
|
quint32 val = readVUint32(tp + 1, bs(_symbolBits - shift));
|
|
|
|
return (val << shift) | (*tp >> sbi);
|
|
|
|
} else
|
|
|
|
return (*tp >> sbi);
|
2021-10-22 22:04:46 +02:00
|
|
|
}
|
2020-01-21 21:50:13 +01:00
|
|
|
}
|