From e9e2053c64fe40ef8e4d724bb39aa4371a9d4bb3 Mon Sep 17 00:00:00 2001 From: James Turner Date: Tue, 31 Mar 2020 10:09:47 +0100 Subject: [PATCH] Strutils: add hex-decoding helper This will be used to allow entering hex bytes in XML files, for HID descriptor support on Windows. --- simgear/misc/strutils.cxx | 63 ++++++++++++++++++++++++++++++++++ simgear/misc/strutils.hxx | 4 +++ simgear/misc/strutils_test.cxx | 8 +++++ 3 files changed, 75 insertions(+) diff --git a/simgear/misc/strutils.cxx b/simgear/misc/strutils.cxx index 208f422c..2509601e 100644 --- a/simgear/misc/strutils.cxx +++ b/simgear/misc/strutils.cxx @@ -897,6 +897,69 @@ std::string encodeHex(const unsigned char* rawBytes, unsigned int length) return hex; } +std::vector decodeHex(const std::string& input) +{ + std::vector result; + char* ptr = const_cast(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* diff --git a/simgear/misc/strutils.hxx b/simgear/misc/strutils.hxx index a289b657..07c065c7 100644 --- a/simgear/misc/strutils.hxx +++ b/simgear/misc/strutils.hxx @@ -33,6 +33,7 @@ #include #include #include +#include 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 decodeHex(const std::string& input); + /** * Backslash-escape a string for C/C++ string literal syntax. * diff --git a/simgear/misc/strutils_test.cxx b/simgear/misc/strutils_test.cxx index cb371c47..d1c6f522 100644 --- a/simgear/misc/strutils_test.cxx +++ b/simgear/misc/strutils_test.cxx @@ -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 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; }