Strutils: add hex-decoding helper

This will be used to allow entering hex bytes in XML files, for HID
descriptor support on Windows.
This commit is contained in:
James Turner 2020-03-31 10:09:47 +01:00
parent 454df4872a
commit e9e2053c64
3 changed files with 75 additions and 0 deletions

View File

@ -897,6 +897,69 @@ std::string encodeHex(const unsigned char* rawBytes, unsigned int length)
return hex;
}
std::vector<uint8_t> decodeHex(const std::string& input)
{
std::vector<uint8_t> result;
char* ptr = const_cast<char*>(input.data());
const char* end = ptr + input.length();
bool highNibble = true;
uint8_t b = 0;
while (ptr != end) {
const char c = *ptr;
char val = 0;
if (c == '0') {
val = 0;
if ((ptr + 1) < end) {
const auto peek = *(ptr + 1);
if (peek == 'x') {
// tolerate 0x prefixing
highNibble = true;
ptr += 2; // skip both bytes
continue;
}
}
} else if (isdigit(c)) {
val = c - '0';
} else if ((c >= 'A') && (c <= 'F')) {
val = c - 'A' + 10;
} else if ((c >= 'a') && (c <= 'f')) {
val = c - 'a' + 10;
} else {
// any other input: newline, space, tab, comma...
if (!highNibble) {
// allow a single digit to work, if we have spacing
highNibble = true;
result.push_back(b >> 4);
}
++ptr;
continue;
}
if (highNibble) {
highNibble = false;
b = val << 4;
} else {
highNibble = true;
b |= val;
result.push_back(b);
}
++ptr;
}
// watch for trailing single digit
// this is reqquired so a stirng ending in 0x3 is decoded.
if (!highNibble) {
result.push_back(b >> 4);
}
return result;
}
// Write an octal backslash-escaped respresentation of 'val' to 'buf'.
//
// At least 4 write positions must be available at 'buf'. The result is *not*

View File

@ -33,6 +33,7 @@
#include <vector>
#include <type_traits>
#include <cstdlib>
#include <cstdint>
typedef std::vector < std::string > string_list;
@ -304,6 +305,9 @@ namespace simgear {
std::string encodeHex(const unsigned char* rawBytes, unsigned int length);
std::vector<uint8_t> decodeHex(const std::string& input);
/**
* Backslash-escape a string for C/C++ string literal syntax.
*

View File

@ -730,6 +730,13 @@ void test_formatGeod()
}
void testDecodeHex()
{
const auto decoded = simgear::strutils::decodeHex("01 0xff,0xcd \n\t99 0xcD abcdef\n\r0x1 0x2 0x3");
vector<uint8_t> data1 = {0x1, 0xff, 0xcd, 0x99, 0xcd, 0xAB, 0xCD,0xEF, 1, 2, 3};
SG_VERIFY(decoded == data1);
}
int main(int argc, char* argv[])
{
test_strip();
@ -753,6 +760,7 @@ int main(int argc, char* argv[])
test_parseGeod();
test_formatGeod();
test_iequals();
testDecodeHex();
return EXIT_SUCCESS;
}