#include "message_parser.hpp"
#include <iomanip>
enum class ParserState
{
DEFAULT,
ESCAPE,
HEX_VALUE_0,
HEX_VALUE_1,
};
int parseHexDigit(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
else
return -1;
}
std::pair<std::vector<char>, int> parseString(const char* str)
{
std::vector<char> data;
int hex_char = 0;
ParserState state = ParserState::DEFAULT;
for (const char* c = str; *c != '\0'; ++c) {
switch (state)
{
case ParserState::DEFAULT:
if (*c == '\\') {
state = ParserState::ESCAPE;
} else {
data.push_back(*c);
}
break;
case ParserState::ESCAPE:
switch (*c)
{
case '\\':
data.push_back('\\');
state = ParserState::DEFAULT;
break;
case '0':
data.push_back('\0');
state = ParserState::DEFAULT;
break;
case 'n':
data.push_back('\n');
state = ParserState::DEFAULT;
break;
case 'x':
state = ParserState::HEX_VALUE_0;
break;
default:
return std::make_pair(data, static_cast<int>(c - str));
}
break;
case ParserState::HEX_VALUE_0:
hex_char = parseHexDigit(*c);
if (hex_char < 0) return std::make_pair(data, static_cast<int>(c - str));
state = ParserState::HEX_VALUE_1;
break;
case ParserState::HEX_VALUE_1:
{
int digit = parseHexDigit(*c);
if (digit < 0) return std::make_pair(data, static_cast<int>(c - str));
hex_char = (hex_char << 4) | digit;
data.push_back(static_cast<char>(hex_char));
state = ParserState::DEFAULT;
break;
}
}
}
return std::make_pair(data, -1);
}
std::ostream& printEscapedString(std::ostream& stream, const char* buffer, size_t len)
{
auto flags = stream.flags(std::ios::hex);
auto fill = stream.fill('0');
for (size_t i = 0; i < len; ++i) {
char c = buffer[i];
if (std::isprint(c)) {
stream << c;
} else {
if (c == '\0')
stream << "\\0";
else if (c == '\n')
stream << "\\n";
else
stream << "\\x" << std::setw(2) << +static_cast<unsigned char>(c);
}
}
stream.setf(flags);
stream.fill(fill);
return stream;
}
std::ostream& printBuffer(std::ostream& stream, const char* buffer, size_t len)
{
constexpr size_t ROW = 16;
auto flags = stream.flags(std::ios::hex);
auto fill = stream.fill('0');
for (unsigned long i = 0; i < len; i += ROW) {
if (i != 0) stream << '\n';
unsigned long j = 0;
for (j = 0; j < ROW && (i+j) < len; ++j) {
if (j != 0) stream << ' ';
stream << std::setw(2) << +static_cast<unsigned char>(buffer[i+j]);
}
for (; j < ROW; ++j) stream << " ..";
stream << ' ';
for (j = 0; j < ROW && (i+j) < len; ++j) {
char c = buffer[i+j];
if (std::isprint(c)) {
stream << c;
} else {
if (c == '\0')
stream << "\\0";
else if (c == '\n')
stream << "\\n";
else
stream << "\\x" << std::setw(2) << +static_cast<unsigned char>(c);
}
}
}
stream.setf(flags);
stream.fill(fill);
return stream;
}