Skip to content

Commit

Permalink
Adds hex_to_string helper function to format_utils. (#707)
Browse files Browse the repository at this point in the history
* Adds hex_to_string helper function to format_utils.

* Adds format utils test.

* Fix whitespace.

* Change API to return nonnegative integer.
Fix review comment.
  • Loading branch information
balazsracz authored Apr 23, 2023
1 parent d5062f6 commit b9207af
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 0 deletions.
51 changes: 51 additions & 0 deletions src/utils/format_utils.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,57 @@ string string_to_hex(const string &arg)
return ret;
}

static uint8_t get_nibble(char b)
{
if ('0' <= b && b <= '9')
{
return b - '0';
}
if ('a' <= b && b <= 'f')
{
return b - 'a' + 10;
}
if ('A' <= b && b <= 'F')
{
return b - 'A' + 10;
}
return 0xff;
}

size_t hex_to_string(
const char *input, size_t len, string *output, bool ignore_nonhex)
{
uint8_t b = 0; // current byte
bool next_high = true; // next nibble is high of the byte
for (size_t ofs = 0; ofs < len; ++ofs)
{
uint8_t nib = get_nibble(input[ofs]);
if (nib == 0xff)
{
if (!ignore_nonhex)
{
return ofs;
}
continue;
}
b |= nib & 0xf;
if (next_high)
{
b <<= 4;
next_high = false;
continue;
}
else
{
output->push_back(b);
b = 0;
next_high = true;
continue;
}
}
return len;
}

string mac_to_string(uint8_t mac[6], char colon)
{
string ret;
Expand Down
35 changes: 35 additions & 0 deletions src/utils/format_utils.cxxtest
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "utils/format_utils.hxx"

#include "utils/test_main.hxx"

TEST(HexToString, basic)
{
string input = "303132";
string output;
EXPECT_EQ(6u, hex_to_string(input.data(), input.size(), &output));
EXPECT_EQ("012", output);

output = "xx";
EXPECT_EQ(6u, hex_to_string(input.data(), input.size(), &output));
EXPECT_EQ("xx012", output);

output.clear();
input = "0A0BfC";
EXPECT_EQ(6u, hex_to_string(input.data(), input.size(), &output));
EXPECT_EQ("\x0a\x0b\xfc", output);

output.clear();
input = "30.31.32";
EXPECT_EQ(2u, hex_to_string(input.data(), input.size(), &output));
EXPECT_EQ("0", output);

output.clear();
EXPECT_EQ(8u, hex_to_string(input.data(), input.size(), &output, true));
EXPECT_EQ("012", output);

output.clear();
input = "303132F";
EXPECT_EQ(7u, hex_to_string(input.data(), input.size(), &output));
// lost one nibble, this is ok according to the contract
EXPECT_EQ("012", output);
}
15 changes: 15 additions & 0 deletions src/utils/format_utils.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,21 @@ string int64_to_string_hex(int64_t value, unsigned padding = 0);
/// original data.
string string_to_hex(const string& arg);

/// Converts hex bytes to binary representation.
///
/// @param input points to the input hexadecimal string
/// @param len how many bytes are there
/// @param output parsed byte data will be appended here
/// @param ignore_nonhex if true, jumps over all nonhex characters. If false,
/// stops at the first nonhex character.
///
/// @return number of ascii bytes consumed from the input. For example 0 if the
/// first byte was not hex and ignore_nonhex=false. If the number of hex digits
/// is not even, there will be data loss.
///
size_t hex_to_string(
const char *input, size_t len, string *output, bool ignore_nonhex = false);

/// Formats a MAC address to string. Works both for Ethernet addresses as well
/// as for OpenLCB node IDs.
///
Expand Down

0 comments on commit b9207af

Please sign in to comment.