Electroneum
hex.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017-Present, Electroneum
2 // Copyright (c) 2017-2019, The Monero Project
3 //
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without modification, are
7 // permitted provided that the following conditions are met:
8 //
9 // 1. Redistributions of source code must retain the above copyright notice, this list of
10 // conditions and the following disclaimer.
11 //
12 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
13 // of conditions and the following disclaimer in the documentation and/or other
14 // materials provided with the distribution.
15 //
16 // 3. Neither the name of the copyright holder nor the names of its contributors may be
17 // used to endorse or promote products derived from this software without specific
18 // prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 #include "hex.h"
31 
32 #include <iterator>
33 #include <limits>
34 #include <ostream>
35 #include <stdexcept>
36 
37 namespace epee
38 {
39  namespace
40  {
41  template<typename T>
42  void write_hex(T&& out, const span<const std::uint8_t> src)
43  {
44  static constexpr const char hex[] = u8"0123456789abcdef";
45  static_assert(sizeof(hex) == 17, "bad string size");
46  for (const std::uint8_t byte : src)
47  {
48  *out = hex[byte >> 4];
49  ++out;
50  *out = hex[byte & 0x0F];
51  ++out;
52  }
53  }
54  }
55 
56  template<typename T>
57  T to_hex::convert(const span<const std::uint8_t> src)
58  {
59  if (std::numeric_limits<std::size_t>::max() / 2 < src.size())
60  throw std::range_error("hex_view::to_string exceeded maximum size");
61 
62  T out{};
63  out.resize(src.size() * 2);
64  to_hex::buffer_unchecked((char*)out.data(), src); // can't see the non const version in wipeable_string??
65  return out;
66  }
67 
68  std::string to_hex::string(const span<const std::uint8_t> src) { return convert<std::string>(src); }
69  epee::wipeable_string to_hex::wipeable_string(const span<const std::uint8_t> src) { return convert<epee::wipeable_string>(src); }
70 
71  void to_hex::buffer(std::ostream& out, const span<const std::uint8_t> src)
72  {
73  write_hex(std::ostreambuf_iterator<char>{out}, src);
74  }
75 
76  void to_hex::formatted(std::ostream& out, const span<const std::uint8_t> src)
77  {
78  out.put('<');
79  buffer(out, src);
80  out.put('>');
81  }
82 
83  void to_hex::buffer_unchecked(char* out, const span<const std::uint8_t> src) noexcept
84  {
85  return write_hex(out, src);
86  }
87 
88  std::vector<uint8_t> from_hex::vector(boost::string_ref src)
89  {
90  // should we include a specific character
91  auto include = [](char input) {
92  // we ignore spaces and colons
93  return !std::isspace(input) && input != ':';
94  };
95 
96  // the number of relevant characters to decode
97  auto count = std::count_if(src.begin(), src.end(), include);
98 
99  // this must be a multiple of two, otherwise we have a truncated input
100  if (count % 2) {
101  throw std::length_error{ "Invalid hexadecimal input length" };
102  }
103 
104  std::vector<uint8_t> result;
105  result.reserve(count / 2);
106 
107  // the data to work with (std::string is always null-terminated)
108  auto data = src.data();
109 
110  // convert a single hex character to an unsigned integer
111  auto char_to_int = [](const char *input) {
112  switch (std::tolower(*input)) {
113  case '0': return 0;
114  case '1': return 1;
115  case '2': return 2;
116  case '3': return 3;
117  case '4': return 4;
118  case '5': return 5;
119  case '6': return 6;
120  case '7': return 7;
121  case '8': return 8;
122  case '9': return 9;
123  case 'a': return 10;
124  case 'b': return 11;
125  case 'c': return 12;
126  case 'd': return 13;
127  case 'e': return 14;
128  case 'f': return 15;
129  default: throw std::range_error{ "Invalid hexadecimal input" };
130  }
131  };
132 
133  // keep going until we reach the end
134  while (data[0] != '\0') {
135  // skip unwanted characters
136  if (!include(data[0])) {
137  ++data;
138  continue;
139  }
140 
141  // convert two matching characters to int
142  auto high = char_to_int(data++);
143  auto low = char_to_int(data++);
144 
145  result.push_back(high << 4 | low);
146  }
147 
148  return result;
149  }
150 }
const uint32_t T[512]
::std::string string
Definition: gtest-port.h:1097
unsigned char uint8_t
Definition: stdint.h:124
static epee::wipeable_string wipeable_string(const span< const std::uint8_t > src)
Definition: hex.cpp:69
mdb_size_t count(MDB_cursor *cur)
static std::vector< uint8_t > vector(boost::string_ref src)
Definition: hex.cpp:88
static void buffer(std::ostream &out, const span< const std::uint8_t > src)
Append src as hex to out.
Definition: hex.cpp:71
static std::string string(const span< const std::uint8_t > src)
Definition: hex.cpp:68
std::string hex(difficulty_type v)
Definition: difficulty.cpp:254
static void formatted(std::ostream &out, const span< const std::uint8_t > src)
Append < + src + > as hex to out.
Definition: hex.cpp:76
unsigned char u8
Definition: chacha_private.h:9