Added huffman encoding utility

This commit is contained in:
Jordan Sherer 2018-07-12 18:02:54 -04:00
parent 705244786e
commit 707f577f31
3 changed files with 151 additions and 29 deletions

View File

@ -1050,6 +1050,16 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
ui->tableWidgetCalls->addAction(clearActionSep);
ui->tableWidgetCalls->addAction(clearActionAll);
// TESTING :P
qint64 a = QDateTime::currentSecsSinceEpoch();
qDebug() << a << Varicode::pack64bits(a) << Varicode::unpack64bits(Varicode::pack64bits(a));
qDebug() << a << Varicode::bitsToStr(Varicode::intToBits(a)) << Varicode::bitsToInt(Varicode::strToBits(Varicode::bitsToStr(Varicode::intToBits(a))));
auto input = "HELLO BRAVE NEW WORLD!";
auto encoded = Varicode::huffEncode(input);
auto decoded = Varicode::huffDecode(encoded);
qDebug() << input << Varicode::bitsToStr(encoded) << decoded;
// this must be the last statement of constructor
if (!m_valid) throw std::runtime_error {"Fatal initialization exception"};
}

View File

@ -1,6 +1,8 @@
/**
* (C) 2018 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved
**/
#include <QDebug>
#include <QMap>
#include "varicode.h"
@ -10,6 +12,56 @@ QString grid_pattern = {R"((?<grid>[A-R]{2}[0-9]{2})+)"};
QString callsign_pattern1 = {R"((?<callsign>[A-Z0-9/]{2,}))"};
QString callsign_pattern2 = {R"((?<callsign>(\d|[A-Z])+\/?((\d|[A-Z]){3,})(\/(\d|[A-Z])+)?(\/(\d|[A-Z])+)?))"};
QMap<QChar, QString> huff = {
// char code weight
{' ' , "001" }, // 1300
{'E' , "000" }, // 1270.2
{'T' , "1100" }, // 905.6
{'A' , "1010" }, // 816.7
{'O' , "0111" }, // 750.7
{'I' , "0101" }, // 696.6
{'N' , "0100" }, // 674.9
{'S' , "11111" }, // 632.7
{'H' , "11110" }, // 609.4
{'R' , "11101" }, // 598.7
{'D' , "10111" }, // 425.3
{'L' , "10110" }, // 402.5
{'C' , "111001" }, // 278.2
{'U' , "111000" }, // 275.8
{'M' , "110111" }, // 240.6
{'W' , "110110" }, // 236.0
{'F' , "110100" }, // 222.8
{'G' , "100111" }, // 201.5
{'Q' , "100110" }, // 200
{'Y' , "011010" }, // 197.4
{'P' , "011001" }, // 192.9
{'B' , "011000" }, // 149.2
{'!' , "0110111" }, // 100
{'.' , "1000000" }, // 100
{'0' , "1000001" }, // 100
{'1' , "1000010" }, // 100
{'2' , "1000011" }, // 100
{'3' , "1000100" }, // 100
{'4' , "1000101" }, // 100
{'5' , "1000110" }, // 100
{'6' , "1000111" }, // 100
{'7' , "1001000" }, // 100
{'8' , "1001001" }, // 100
{'9' , "1001010" }, // 100
{'?' , "1001011" }, // 100
{'^' , "1101010" }, // 100 <- shift
{'V' , "0110110" }, // 97.8
{'K' , "11010111" }, // 77.2
{'J' , "1101011010" }, // 15.3
{'X' , "1101011001" }, // 15.0
{'Z' , "11010110110" }, // 7.4
{':' , "11010110000" }, // 5
{'+' , "110101100011" }, // 5
{'-' , "110101101110" }, // 5
{'/' , "110101101111" }, // 5
{'\x04' , "110101100010" }, // 1 <- eot
};
QStringList Varicode::parseCallsigns(QString const &input){
QStringList callsigns;
QRegularExpression re(callsign_pattern2);
@ -47,11 +99,63 @@ QStringList Varicode::parseGrids(const QString &input){
return grids;
}
QVector<bool> Varicode::intToBits(qint64 value, int expected){
QVector<bool> Varicode::huffEncode(QString const& text){
QVector<bool> out;
foreach(auto ch, text){
if(!huff.contains(ch)){
continue;
}
out += strToBits(huff[ch]);
}
return out;
}
QString Varicode::huffDecode(QVector<bool> const& bitvec){
QString out;
QString bits = bitsToStr(bitvec);
// TODO: jsherer - this is naive...
while(bits.length() > 0){
bool found = false;
foreach(auto key, huff.keys()){
if(bits.startsWith(huff[key])){
out.append(key);
bits = bits.mid(huff[key].length());
found = true;
}
}
if(!found){
break;
}
}
return out;
}
QVector<bool> Varicode::strToBits(QString const& bitvec){
QVector<bool> bits;
foreach(auto ch, bitvec){
bits.append(ch == '1');
}
return bits;
}
QString Varicode::bitsToStr(QVector<bool> const& bitvec){
QString bits;
foreach(auto bit, bitvec){
bits.append(bit ? "1" : "0");
}
return bits;
}
QVector<bool> Varicode::intToBits(quint64 value, int expected){
QVector<bool> bits;
while(value){
bits.prepend((bool) value & 1);
bits.prepend((bool)(value & 1));
value = value >> 1;
}
@ -64,32 +168,33 @@ QVector<bool> Varicode::intToBits(qint64 value, int expected){
return bits;
}
qint64 Varicode::bitsToInt(QVector<bool> const value){
qint64 v = 0;
quint64 Varicode::bitsToInt(QVector<bool> const value){
quint64 v = 0;
foreach(bool bit, value){
v = (v << 1) + (int)(bit);
}
return v;
}
qint8 Varicode::unpack5bits(QString const& value){
quint8 Varicode::unpack5bits(QString const& value){
return alphabet.indexOf(value.at(0));
}
QString Varicode::pack5bits(qint8 packed){
QString Varicode::pack5bits(quint8 packed){
return alphabet.at(packed % nalphabet);
}
qint16 Varicode::unpack16bits(QString const& value){
quint16 Varicode::unpack16bits(QString const& value){
int a = alphabet.indexOf(value.at(0));
int b = alphabet.indexOf(value.at(1));
int c = alphabet.indexOf(value.at(2));
return (nalphabet*nalphabet) * a + nalphabet*b + c;
}
QString Varicode::pack16bits(qint16 packed){
QString Varicode::pack16bits(quint16 packed){
QString out;
qint16 tmp = packed / (nalphabet*nalphabet);
quint16 tmp = packed / (nalphabet*nalphabet);
out.append(alphabet.at(tmp));
tmp = (packed - (tmp * (nalphabet*nalphabet))) / nalphabet;
@ -98,25 +203,27 @@ QString Varicode::pack16bits(qint16 packed){
tmp = packed % nalphabet;
out.append(alphabet.at(tmp));
return out;
}
qint32 Varicode::unpack32bits(QString const& value){
return (qint32)unpack16bits(value.left(3)) << 16 | unpack16bits(value.right(3));
quint32 Varicode::unpack32bits(QString const& value){
return (quint32)(unpack16bits(value.left(3))) << 16 | unpack16bits(value.right(3));
}
QString Varicode::pack32bits(qint32 packed){
qint16 a = (packed & 0xFFFF0000) >> 16;
qint16 b = packed & 0xFFFF;
QString Varicode::pack32bits(quint32 packed){
quint16 a = (packed & 0xFFFF0000) >> 16;
quint16 b = packed & 0xFFFF;
return pack16bits(a) + pack16bits(b);
}
qint64 Varicode::unpack64bits(QString const& value){
return (qint64)unpack16bits(value.left(6)) << 32 | unpack16bits(value.right(6));
quint64 Varicode::unpack64bits(QString const& value){
return (quint64)(unpack32bits(value.left(6))) << 32 | unpack32bits(value.right(6));
}
QString Varicode::pack64bits(qint64 packed){
qint32 a = (packed & 0xFFFFFFFF00000000) >> 32;
qint32 b = packed & 0xFFFFFFFF;
QString Varicode::pack64bits(quint64 packed){
quint32 a = (packed & 0xFFFFFFFF00000000) >> 32;
quint32 b = packed & 0xFFFFFFFF;
return pack32bits(a) + pack32bits(b);
}

View File

@ -20,21 +20,26 @@ public:
static QStringList parseCallsigns(QString const &input);
static QStringList parseGrids(QString const &input);
static QVector<bool> huffEncode(QString const& text);
static QString huffDecode(QVector<bool> const& bitvec);
QVector<bool> intToBits(qint64 value, int expected=0);
qint64 bitsToInt(QVector<bool> const value);
static QVector<bool> strToBits(QString const& bitvec);
static QString bitsToStr(QVector<bool> const& bitvec);
qint8 unpack5bits(QString const& value);
QString pack5bits(qint8 packed);
static QVector<bool> intToBits(quint64 value, int expected=0);
static quint64 bitsToInt(QVector<bool> const value);
qint16 unpack16bits(QString const& value);
QString pack16bits(qint16 packed);
static quint8 unpack5bits(QString const& value);
static QString pack5bits(quint8 packed);
qint32 unpack32bits(QString const& value);
QString pack32bits(qint32 packed);
static quint16 unpack16bits(QString const& value);
static QString pack16bits(quint16 packed);
qint64 unpack64bits(QString const& value);
QString pack64bits(qint64 packed);
static quint32 unpack32bits(QString const& value);
static QString pack32bits(quint32 packed);
static quint64 unpack64bits(QString const& value);
static QString pack64bits(quint64 packed);
};
#endif // VARICODE_H