Coverage Report

Created: 2026-06-30 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/libsolutil/CommonData.cpp
Line
Count
Source
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
/** @file CommonData.cpp
19
 * @author Gav Wood <i@gavwood.com>
20
 * @date 2014
21
 */
22
23
#include <libsolutil/Assertions.h>
24
#include <libsolutil/CommonData.h>
25
#include <libsolutil/Exceptions.h>
26
#include <libsolutil/FixedHash.h>
27
#include <libsolutil/Keccak256.h>
28
#include <libsolutil/StringUtils.h>
29
30
#include <boost/algorithm/string.hpp>
31
32
using namespace solidity;
33
using namespace solidity::util;
34
35
namespace
36
{
37
38
static char const* upperHexChars = "0123456789ABCDEF";
39
static char const* lowerHexChars = "0123456789abcdef";
40
41
}
42
43
std::string solidity::util::toHex(uint8_t _data, HexCase _case)
44
0
{
45
0
  assertThrow(_case != HexCase::Mixed, BadHexCase, "Mixed case can only be used for byte arrays.");
46
47
0
  char const* chars = _case == HexCase::Upper ? upperHexChars : lowerHexChars;
48
49
0
  return std::string{
50
0
    chars[(unsigned(_data) / 16) & 0xf],
51
0
    chars[unsigned(_data) & 0xf]
52
0
  };
53
0
}
54
55
std::string solidity::util::toHex(bytes const& _data, HexPrefix _prefix, HexCase _case)
56
3.66M
{
57
3.66M
  std::string ret(_data.size() * 2 + (_prefix == HexPrefix::Add ? 2 : 0), 0);
58
59
3.66M
  size_t i = 0;
60
3.66M
  if (_prefix == HexPrefix::Add)
61
996k
  {
62
996k
    ret[i++] = '0';
63
996k
    ret[i++] = 'x';
64
996k
  }
65
66
  // Mixed case will be handled inside the loop.
67
3.66M
  char const* chars = _case == HexCase::Upper ? upperHexChars : lowerHexChars;
68
3.66M
  size_t rix = _data.size() - 1;
69
3.66M
  for (uint8_t c: _data)
70
53.7M
  {
71
    // switch hex case every four hexchars
72
53.7M
    if (_case == HexCase::Mixed)
73
0
      chars = (rix-- & 2) == 0 ? lowerHexChars : upperHexChars;
74
75
53.7M
    ret[i++] = chars[(static_cast<size_t>(c) >> 4ul) & 0xfu];
76
53.7M
    ret[i++] = chars[c & 0xfu];
77
53.7M
  }
78
3.66M
  assertThrow(i == ret.size(), Exception, "");
79
80
3.66M
  return ret;
81
3.66M
}
82
83
int solidity::util::fromHex(char _i, WhenError _throw)
84
16.2M
{
85
16.2M
  if (_i >= '0' && _i <= '9')
86
15.9M
    return _i - '0';
87
300k
  if (_i >= 'a' && _i <= 'f')
88
3.46k
    return _i - 'a' + 10;
89
296k
  if (_i >= 'A' && _i <= 'F')
90
296k
    return _i - 'A' + 10;
91
0
  if (_throw == WhenError::Throw)
92
0
    assertThrow(false, BadHexCharacter, std::to_string(_i));
93
0
  else
94
0
    return -1;
95
0
}
96
97
bytes solidity::util::fromHex(std::string const& _s, WhenError _throw)
98
367k
{
99
367k
  if (_s.empty())
100
0
    return {};
101
102
367k
  unsigned s = (_s.size() >= 2 && _s[0] == '0' && _s[1] == 'x') ? 2 : 0;
103
367k
  std::vector<uint8_t> ret;
104
367k
  ret.reserve((_s.size() - s + 1) / 2);
105
106
367k
  if (_s.size() % 2)
107
1
  {
108
1
    int h = fromHex(_s[s++], _throw);
109
1
    if (h != -1)
110
1
      ret.push_back(static_cast<uint8_t>(h));
111
0
    else
112
0
      return bytes();
113
1
  }
114
8.49M
  for (unsigned i = s; i < _s.size(); i += 2)
115
8.13M
  {
116
8.13M
    int h = fromHex(_s[i], _throw);
117
8.13M
    int l = fromHex(_s[i + 1], _throw);
118
8.13M
    if (h != -1 && l != -1)
119
8.13M
      ret.push_back(static_cast<uint8_t>(h * 16 + l));
120
0
    else
121
0
      return bytes();
122
8.13M
  }
123
367k
  return ret;
124
367k
}
125
126
127
bool solidity::util::passesAddressChecksum(std::string const& _str, bool _strict)
128
86
{
129
86
  std::string s = _str.substr(0, 2) == "0x" ? _str : "0x" + _str;
130
131
86
  if (s.length() != 42)
132
0
    return false;
133
134
86
  if (!_strict && (
135
0
    s.find_first_of("abcdef") == std::string::npos ||
136
0
    s.find_first_of("ABCDEF") == std::string::npos
137
0
  ))
138
0
    return true;
139
140
86
  return s == solidity::util::getChecksummedAddress(s);
141
86
}
142
143
std::string solidity::util::getChecksummedAddress(std::string const& _addr)
144
110
{
145
110
  std::string s = _addr.substr(0, 2) == "0x" ? _addr.substr(2) : _addr;
146
110
  assertThrow(s.length() == 40, InvalidAddress, "");
147
110
  assertThrow(s.find_first_not_of("0123456789abcdefABCDEF") == std::string::npos, InvalidAddress, "");
148
149
110
  h256 hash = keccak256(boost::algorithm::to_lower_copy(s, std::locale::classic()));
150
151
110
  std::string ret = "0x";
152
4.51k
  for (unsigned i = 0; i < 40; ++i)
153
4.40k
  {
154
4.40k
    char addressCharacter = s[i];
155
4.40k
    uint8_t nibble = hash[i / 2u] >> (4u * (1u - (i % 2u))) & 0xf;
156
4.40k
    if (nibble >= 8)
157
2.19k
      ret += toUpper(addressCharacter);
158
2.20k
    else
159
2.20k
      ret += toLower(addressCharacter);
160
4.40k
  }
161
110
  return ret;
162
110
}
163
164
bool solidity::util::isValidHex(std::string_view const _string)
165
7.02M
{
166
7.02M
  if (_string.substr(0, 2) != "0x")
167
0
    return false;
168
7.02M
  if (_string.find_first_not_of("0123456789abcdefABCDEF", 2) != std::string::npos)
169
0
    return false;
170
7.02M
  return true;
171
7.02M
}
172
173
bool solidity::util::isValidDecimal(std::string_view const _string)
174
25.5M
{
175
25.5M
  if (_string.empty())
176
0
    return false;
177
25.5M
  if (_string == "0")
178
4.73M
    return true;
179
  // No leading zeros
180
20.8M
  if (_string.front() == '0')
181
7.02M
    return false;
182
13.8M
  if (_string.find_first_not_of("0123456789") != std::string::npos)
183
204
    return false;
184
13.8M
  return true;
185
13.8M
}
186
187
std::string solidity::util::formatAsStringOrNumber(std::string const& _value)
188
3.27k
{
189
3.27k
  assertThrow(_value.length() <= 32, StringTooLong, "String to be formatted longer than 32 bytes.");
190
191
3.27k
  for (auto const& c: _value)
192
26.8k
    if (c <= 0x1f || c >= 0x7f || c == '"')
193
1.97k
      return "0x" + h256(_value, h256::AlignLeft).hex();
194
195
1.30k
  return escapeAndQuoteString(_value);
196
3.27k
}
197
198
199
std::string solidity::util::escapeAndQuoteString(std::string const& _input)
200
358k
{
201
358k
  std::string out;
202
203
358k
  for (char c: _input)
204
4.40M
    if (c == '\\')
205
1.08k
      out += "\\\\";
206
4.40M
    else if (c == '"')
207
16.2k
      out += "\\\"";
208
4.38M
    else if (c == '\n')
209
99
      out += "\\n";
210
4.38M
    else if (c == '\r')
211
341
      out += "\\r";
212
4.38M
    else if (c == '\t')
213
1.95k
      out += "\\t";
214
4.38M
    else if (!isPrint(c))
215
61.4k
    {
216
61.4k
      std::ostringstream o;
217
61.4k
      o << "\\x" << std::hex << std::setfill('0') << std::setw(2) << (unsigned)(unsigned char)(c);
218
61.4k
      out += o.str();
219
61.4k
    }
220
4.32M
    else
221
4.32M
      out += c;
222
223
358k
  return "\"" + std::move(out) + "\"";
224
358k
}