diff --git a/mainwindow.cpp b/mainwindow.cpp index 2e017d3..8a580ba 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -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"}; } diff --git a/varicode.cpp b/varicode.cpp index cb90bd8..2f497d3 100644 --- a/varicode.cpp +++ b/varicode.cpp @@ -1,6 +1,8 @@ /** * (C) 2018 Jordan Sherer - All Rights Reserved **/ +#include +#include #include "varicode.h" @@ -10,6 +12,56 @@ QString grid_pattern = {R"((?[A-R]{2}[0-9]{2})+)"}; QString callsign_pattern1 = {R"((?[A-Z0-9/]{2,}))"}; QString callsign_pattern2 = {R"((?(\d|[A-Z])+\/?((\d|[A-Z]){3,})(\/(\d|[A-Z])+)?(\/(\d|[A-Z])+)?))"}; +QMap 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 Varicode::intToBits(qint64 value, int expected){ +QVector Varicode::huffEncode(QString const& text){ + QVector out; + + foreach(auto ch, text){ + if(!huff.contains(ch)){ + continue; + } + out += strToBits(huff[ch]); + } + + return out; +} + +QString Varicode::huffDecode(QVector 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 Varicode::strToBits(QString const& bitvec){ + QVector bits; + foreach(auto ch, bitvec){ + bits.append(ch == '1'); + } + return bits; +} + +QString Varicode::bitsToStr(QVector const& bitvec){ + QString bits; + foreach(auto bit, bitvec){ + bits.append(bit ? "1" : "0"); + } + return bits; +} + +QVector Varicode::intToBits(quint64 value, int expected){ QVector bits; while(value){ - bits.prepend((bool) value & 1); + bits.prepend((bool)(value & 1)); value = value >> 1; } @@ -64,32 +168,33 @@ QVector Varicode::intToBits(qint64 value, int expected){ return bits; } -qint64 Varicode::bitsToInt(QVector const value){ - qint64 v = 0; +quint64 Varicode::bitsToInt(QVector 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); } diff --git a/varicode.h b/varicode.h index ca5b8e0..1970400 100644 --- a/varicode.h +++ b/varicode.h @@ -20,21 +20,26 @@ public: static QStringList parseCallsigns(QString const &input); static QStringList parseGrids(QString const &input); + static QVector huffEncode(QString const& text); + static QString huffDecode(QVector const& bitvec); - QVector intToBits(qint64 value, int expected=0); - qint64 bitsToInt(QVector const value); + static QVector strToBits(QString const& bitvec); + static QString bitsToStr(QVector const& bitvec); - qint8 unpack5bits(QString const& value); - QString pack5bits(qint8 packed); + static QVector intToBits(quint64 value, int expected=0); + static quint64 bitsToInt(QVector 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