Skip to content

Instantly share code, notes, and snippets.

@arnobaer
Last active January 13, 2023 11:33
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save arnobaer/973c91a7e8b5088087e20257df3c82d3 to your computer and use it in GitHub Desktop.
Save arnobaer/973c91a7e8b5088087e20257df3c82d3 to your computer and use it in GitHub Desktop.
C++ infinite hex string to bytes (of any junk size)
/*
* hex2bytes - hex string of unlimited length to a continous block of bytes
* Copyright (C) 2018 Bernhard Arnold <bernhard.arnold@cern.ch>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*
* Function template converts hex string of unlimited length to a continous
* block of bytes wrapped by a STL vector.
*
* Examples:
*
* hex2bytes<uint8_t>("a"); // [0xa]
* hex2bytes<uint8_t>("ab"); // [0xab]
* hex2bytes<uint8_t>("abc"); // [0xbc, 0xa]
* hex2bytes<uint8_t>("abcd"); // [0xcd, 0xab]
* hex2bytes<uint8_t>("abcde"); // [0xde, 0xbc, 0xa]
* hex2bytes<uint16_t>("a11bb22cc33dd"); // [0x33dd, 0x22cc, 0x11bb, 0xa]
*
*/
#ifndef _gist_hex2bytes_h
#define _gist_hex2bytes_h
#include <string>
#include <vector>
template<typename T>
std::vector<T> hex2bytes(const std::string& s)
{
constexpr size_t width = sizeof(T) * 2;
std::vector<T> v;
v.reserve((s.size() + width - 1) / width);
for (auto it = s.crbegin(); it < s.crend(); it += width)
{
auto begin = std::min(s.crend(), it + width).base();
auto end = it.base();
std::string slice(begin, end);
T value = std::stoul(slice, 0, 16);
v.push_back(value);
}
return v;
}
#endif
#include "hex2bytes.h"
#include <algorithm>
#include <cassert>
#include <cstdlib>
template<typename T>
void assert_hex2bytes(const std::string& s, const std::vector<T>& ref)
{
auto res = hex2bytes<T>(s);
assert(std::equal(ref.begin(), ref.end(), res.begin()));
}
int main()
{
assert_hex2bytes<uint8_t>("", {});
assert_hex2bytes<uint8_t>("a", {0xa});
assert_hex2bytes<uint8_t>("ab", {0xab});
assert_hex2bytes<uint8_t>("abc", {0xbc, 0xa});
assert_hex2bytes<uint8_t>("abcd", {0xcd, 0xab});
assert_hex2bytes<uint8_t>("abcde", {0xde, 0xbc, 0xa});
assert_hex2bytes<uint8_t>("abcdef", {0xef, 0xcd, 0xab});
assert_hex2bytes<uint16_t>("", {});
assert_hex2bytes<uint16_t>("a", {0xa});
assert_hex2bytes<uint16_t>("ab", {0xab});
assert_hex2bytes<uint16_t>("abc", {0xabc});
assert_hex2bytes<uint16_t>("abcd", {0xabcd});
assert_hex2bytes<uint16_t>("abcde", {0xbcde, 0xa});
assert_hex2bytes<uint16_t>("abcdef", {0xcdef, 0xab});
assert_hex2bytes<uint32_t>("bbbbcccc", {0xbbbbcccc});
assert_hex2bytes<uint32_t>("abbbbcccc", {0xbbbbcccc, 0xa});
assert_hex2bytes<uint32_t>("aabbbbcccc", {0xbbbbcccc, 0xaa});
assert_hex2bytes<uint32_t>("aaabbbbcccc", {0xbbbbcccc, 0xaaa});
assert_hex2bytes<uint32_t>("aaaabbbbcccc", {0xbbbbcccc, 0xaaaa});
assert_hex2bytes<uint64_t>("bbbbccccddddeeee", {0xbbbbccccddddeeee});
assert_hex2bytes<uint64_t>("abbbbccccddddeeee", {0xbbbbccccddddeeee, 0xa});
assert_hex2bytes<uint64_t>("aabbbbccccddddeeee", {0xbbbbccccddddeeee, 0xaa});
assert_hex2bytes<uint64_t>("aaabbbbccccddddeeee", {0xbbbbccccddddeeee, 0xaaa});
assert_hex2bytes<uint64_t>("aaaabbbbccccddddeeee", {0xbbbbccccddddeeee, 0xaaaa});
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment