2022-05-27 16:44:42 +02:00
|
|
|
#include "DataFormatter.h"
|
2022-05-26 22:30:59 +02:00
|
|
|
#include "Bases.h"
|
|
|
|
#include <GeneralUtility/BaseConversion.h>
|
|
|
|
#include <StringTools/StringTools.h>
|
2022-05-26 23:22:04 +02:00
|
|
|
#include <GCrypt/Util.h>
|
2022-05-26 22:30:59 +02:00
|
|
|
|
|
|
|
using namespace Leonetienne::GCrypt;
|
|
|
|
using namespace Leonetienne::StringTools;
|
|
|
|
using namespace Leonetienne::GeneralUtility;
|
|
|
|
|
2022-05-27 16:44:42 +02:00
|
|
|
std::string DataFormatter::FormatBlock(
|
2022-05-26 22:30:59 +02:00
|
|
|
const Block& block,
|
|
|
|
const Configuration::IOBASE_FORMAT base
|
|
|
|
) {
|
|
|
|
switch (base) {
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_BYTES:
|
|
|
|
return block.ToByteString();
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_2:
|
|
|
|
return block.ToBinaryString();
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_8:
|
|
|
|
return Bin2CustomBase(
|
|
|
|
block.ToBinaryString(),
|
2022-05-27 02:13:05 +02:00
|
|
|
BASE_8,
|
2022-05-27 03:00:34 +02:00
|
|
|
blockLengthByBase[base]
|
2022-05-26 22:30:59 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_10:
|
|
|
|
return Bin2CustomBase(
|
|
|
|
block.ToBinaryString(),
|
2022-05-27 02:13:05 +02:00
|
|
|
BASE_10,
|
2022-05-27 03:00:34 +02:00
|
|
|
blockLengthByBase[base]
|
2022-05-26 22:30:59 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_16:
|
|
|
|
return block.ToHexString();
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_64:
|
|
|
|
return Bin2CustomBase(
|
|
|
|
block.ToBinaryString(),
|
2022-05-27 02:13:05 +02:00
|
|
|
BASE_64,
|
2022-05-27 03:00:34 +02:00
|
|
|
blockLengthByBase[base]
|
2022-05-26 22:30:59 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_UWU:
|
|
|
|
return Bin2CustomBase(
|
|
|
|
block.ToBinaryString(),
|
|
|
|
BASE_UWU,
|
2022-05-27 03:00:34 +02:00
|
|
|
blockLengthByBase[base],
|
2022-05-26 22:30:59 +02:00
|
|
|
" "
|
|
|
|
);
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_UGH:
|
|
|
|
return Bin2CustomBase(
|
|
|
|
block.ToBinaryString(),
|
|
|
|
BASE_UGH,
|
2022-05-27 03:00:34 +02:00
|
|
|
blockLengthByBase[base],
|
2022-05-26 22:30:59 +02:00
|
|
|
" "
|
|
|
|
);
|
|
|
|
|
|
|
|
default:
|
2022-05-26 23:22:04 +02:00
|
|
|
throw std::invalid_argument("FormatBlock(): Iobase now found! Oh no. Anyway.");
|
2022-05-26 22:30:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-27 16:44:42 +02:00
|
|
|
std::string DataFormatter::FormatBlocks(
|
2022-05-27 03:00:34 +02:00
|
|
|
const std::vector<Block>& blocks,
|
|
|
|
const Configuration::IOBASE_FORMAT base
|
|
|
|
) {
|
|
|
|
std::stringstream ss;
|
|
|
|
|
|
|
|
std::size_t i = 0;
|
|
|
|
for (const Block& block : blocks) {
|
|
|
|
ss << FormatBlock(block, base);
|
|
|
|
|
|
|
|
// If we are dealing with a multichar base, we must append a
|
|
|
|
// seperator (space), but only if its not the last block.
|
|
|
|
if (
|
|
|
|
(base == Configuration::IOBASE_FORMAT::BASE_UWU) ||
|
|
|
|
(base == Configuration::IOBASE_FORMAT::BASE_UGH)
|
|
|
|
) {
|
|
|
|
if (i++ != blocks.size()) {
|
|
|
|
ss << " ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
2022-05-27 16:44:42 +02:00
|
|
|
Block DataFormatter::DecodeFormat(
|
2022-05-26 23:22:04 +02:00
|
|
|
const std::string& str,
|
|
|
|
const Configuration::IOBASE_FORMAT base
|
|
|
|
) {
|
|
|
|
|
|
|
|
Block b;
|
|
|
|
|
|
|
|
switch (base) {
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_BYTES:
|
|
|
|
b.FromByteString(str);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_2:
|
|
|
|
b.FromBinaryString(str);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_8:
|
|
|
|
b.FromBinaryString(
|
|
|
|
CustomBase2Bin(
|
|
|
|
str,
|
|
|
|
BASE_8
|
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_10:
|
|
|
|
b.FromBinaryString(
|
|
|
|
CustomBase2Bin(
|
|
|
|
str,
|
|
|
|
BASE_10
|
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_16:
|
|
|
|
b.FromHexString(str);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_64:
|
|
|
|
b.FromBinaryString(
|
|
|
|
CustomBase2Bin(
|
|
|
|
str,
|
|
|
|
BASE_64
|
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_UWU:
|
|
|
|
b.FromBinaryString(
|
|
|
|
CustomBase2Bin(
|
|
|
|
str,
|
|
|
|
BASE_UWU,
|
|
|
|
" "
|
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_UGH:
|
|
|
|
b.FromBinaryString(
|
|
|
|
CustomBase2Bin(
|
|
|
|
str,
|
|
|
|
BASE_UGH,
|
|
|
|
" "
|
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
throw std::invalid_argument("StringToBlock(): Iobase now found! Oh no. Anyway.");
|
|
|
|
}
|
|
|
|
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
2022-05-27 16:44:42 +02:00
|
|
|
std::vector<Block> DataFormatter::DecodeFormatMultiblock(
|
2022-05-27 03:00:34 +02:00
|
|
|
const std::string& str,
|
|
|
|
const Configuration::IOBASE_FORMAT base
|
|
|
|
) {
|
|
|
|
std::vector<Block> blocks;
|
|
|
|
|
|
|
|
// A block is this many digits wide, in encoding
|
|
|
|
const std::size_t blockWidth = blockLengthByBase[base];
|
|
|
|
|
|
|
|
// How many blocks are we dealing with here?
|
|
|
|
const std::size_t n_blocks = (str.length() / blockWidth) + 1;
|
|
|
|
blocks.reserve(n_blocks);
|
|
|
|
|
|
|
|
// Iterate over the string, and parse all blocks
|
2022-05-31 21:40:13 +02:00
|
|
|
// We now have to differentiate between single-char digit sets (like hex),
|
|
|
|
// and multi-char digit sets (like uwu):
|
2022-05-27 03:00:34 +02:00
|
|
|
switch (base) {
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_BYTES:
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_2:
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_8:
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_10:
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_16:
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_64:
|
|
|
|
// Easy case: Each digit is exactly one char in size.
|
2022-05-27 14:47:26 +02:00
|
|
|
// We can just calculate how many bytes we should read.
|
2022-05-27 03:00:34 +02:00
|
|
|
for (std::size_t i = 0; i < str.length(); i += blockWidth) {
|
|
|
|
|
|
|
|
const std::string subs = str.substr(i, blockWidth);
|
|
|
|
|
2022-05-27 15:34:16 +02:00
|
|
|
Block newBlock = DecodeFormat(
|
2022-05-27 03:00:34 +02:00
|
|
|
subs,
|
|
|
|
base
|
|
|
|
);
|
|
|
|
|
|
|
|
blocks.emplace_back(newBlock);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Configuration::IOBASE_FORMAT::BASE_UWU:
|
2022-05-27 14:47:26 +02:00
|
|
|
case Configuration::IOBASE_FORMAT::BASE_UGH: {
|
|
|
|
// Hard case: Each digit is n digits long. Digits may vary in length.
|
2022-05-27 03:00:34 +02:00
|
|
|
// They are seperated by spaces.
|
|
|
|
// We have to parse them...
|
|
|
|
std::size_t digitsPassed = 0;
|
|
|
|
std::size_t blockStart = 0;
|
|
|
|
for (std::size_t i = 0; i < str.length(); i++) {
|
|
|
|
|
|
|
|
if (str[i] == ' ') {
|
|
|
|
digitsPassed++;
|
|
|
|
|
|
|
|
if (digitsPassed == blockWidth) {
|
|
|
|
const std::string subs = str.substr(
|
2022-05-27 14:47:26 +02:00
|
|
|
blockStart,
|
|
|
|
i - blockStart
|
2022-05-27 03:00:34 +02:00
|
|
|
);
|
|
|
|
|
2022-05-27 15:34:16 +02:00
|
|
|
Block newBlock = DecodeFormat(
|
2022-05-27 03:00:34 +02:00
|
|
|
subs,
|
|
|
|
base
|
|
|
|
);
|
|
|
|
|
|
|
|
blocks.emplace_back(newBlock);
|
|
|
|
|
|
|
|
digitsPassed = 0;
|
|
|
|
blockStart = i+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-27 14:47:26 +02:00
|
|
|
// Here should never be any digits left. A formatted block should ALWAYS be full length.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2022-05-27 16:44:42 +02:00
|
|
|
throw std::invalid_argument("DataFormatter::StringToBlocks() has been passed an unknown base! No switch-case matched!");
|
2022-05-27 03:00:34 +02:00
|
|
|
break;
|
2022-05-27 14:47:26 +02:00
|
|
|
|
2022-05-27 03:00:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return blocks;
|
|
|
|
}
|
|
|
|
|
2022-05-27 16:44:42 +02:00
|
|
|
std::string DataFormatter::Bin2CustomBase(
|
2022-05-26 22:30:59 +02:00
|
|
|
const std::string& bin,
|
|
|
|
const std::vector<std::string>& customSet,
|
2022-05-27 02:13:05 +02:00
|
|
|
const std::size_t minLen,
|
2022-05-26 22:30:59 +02:00
|
|
|
const std::string& seperator
|
|
|
|
) {
|
|
|
|
std::stringstream ss;
|
|
|
|
|
|
|
|
// Translate to custom set
|
|
|
|
const std::vector<std::string> vec_base_custom =
|
2022-05-27 02:13:05 +02:00
|
|
|
Leonetienne::GeneralUtility::BaseConversion::BaseX_2_Y<std::string, std::vector<std::string>>(
|
|
|
|
bin,
|
|
|
|
"01",
|
|
|
|
customSet,
|
|
|
|
minLen
|
|
|
|
);
|
2022-05-26 22:30:59 +02:00
|
|
|
|
|
|
|
// Convert to string
|
|
|
|
for (std::size_t i = 0; i < vec_base_custom.size(); i++) {
|
|
|
|
ss << vec_base_custom[i];
|
|
|
|
|
|
|
|
if (i != vec_base_custom.size() - 1) {
|
|
|
|
ss << seperator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
2022-05-27 16:44:42 +02:00
|
|
|
std::string DataFormatter::CustomBase2Bin(
|
2022-05-26 22:30:59 +02:00
|
|
|
const std::string& in,
|
|
|
|
const std::vector<std::string>& customSet,
|
|
|
|
const std::string& seperator
|
|
|
|
) {
|
|
|
|
// Split input into symbols
|
|
|
|
const std::vector<std::string> in_symbols = StringTools::Split(in, seperator);
|
|
|
|
|
|
|
|
// Translate to binary
|
|
|
|
std::string binary =
|
2022-05-27 02:13:05 +02:00
|
|
|
Leonetienne::GeneralUtility::BaseConversion::BaseX_2_Y<std::vector<std::string>, std::string>(
|
|
|
|
in_symbols,
|
|
|
|
customSet,
|
|
|
|
std::string("01"),
|
|
|
|
Block::BLOCK_SIZE_BITS
|
|
|
|
);
|
2022-05-26 22:30:59 +02:00
|
|
|
|
|
|
|
if (binary.length() != Block::BLOCK_SIZE_BITS) {
|
2022-05-27 16:44:42 +02:00
|
|
|
throw std::invalid_argument("DataFormatter::CustomBase2Bin() received input that doesn't translate to a bitstring of length 512!");
|
2022-05-26 22:30:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return binary;
|
|
|
|
}
|
|
|
|
|