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:
@@ -897,6 +897,69 @@ std::string encodeHex(const unsigned char* rawBytes, unsigned int length)
|
|||||||
return hex;
|
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'.
|
// Write an octal backslash-escaped respresentation of 'val' to 'buf'.
|
||||||
//
|
//
|
||||||
// At least 4 write positions must be available at 'buf'. The result is *not*
|
// At least 4 write positions must be available at 'buf'. The result is *not*
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
typedef std::vector < std::string > string_list;
|
typedef std::vector < std::string > string_list;
|
||||||
|
|
||||||
@@ -304,6 +305,9 @@ namespace simgear {
|
|||||||
|
|
||||||
std::string encodeHex(const unsigned char* rawBytes, unsigned int length);
|
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.
|
* Backslash-escape a string for C/C++ string literal syntax.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
test_strip();
|
test_strip();
|
||||||
@@ -753,6 +760,7 @@ int main(int argc, char* argv[])
|
|||||||
test_parseGeod();
|
test_parseGeod();
|
||||||
test_formatGeod();
|
test_formatGeod();
|
||||||
test_iequals();
|
test_iequals();
|
||||||
|
testDecodeHex();
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user