Coverage Report

Created: 2022-08-24 06:40

/src/solidity/libsolutil/CommonData.cpp
Line
Count
Source (jump to first uncovered line)
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 std;
33
using namespace solidity;
34
using namespace solidity::util;
35
36
namespace
37
{
38
39
static char const* upperHexChars = "0123456789ABCDEF";
40
static char const* lowerHexChars = "0123456789abcdef";
41
42
}
43
44
string solidity::util::toHex(uint8_t _data, HexCase _case)
45
0
{
46
0
  assertThrow(_case != HexCase::Mixed, BadHexCase, "Mixed case can only be used for byte arrays.");
47
48
0
  char const* chars = _case == HexCase::Upper ? upperHexChars : lowerHexChars;
49
50
0
  return std::string{
51
0
    chars[(unsigned(_data) / 16) & 0xf],
52
0
    chars[unsigned(_data) & 0xf]
53
0
  };
54
0
}
55
56
string solidity::util::toHex(bytes const& _data, HexPrefix _prefix, HexCase _case)
57
1.24M
{
58
1.24M
  std::string ret(_data.size() * 2 + (_prefix == HexPrefix::Add ? 2 : 0), 0);
59
60
1.24M
  size_t i = 0;
61
1.24M
  if (_prefix == HexPrefix::Add)
62
0
  {
63
0
    ret[i++] = '0';
64
0
    ret[i++] = 'x';
65
0
  }
66
67
  // Mixed case will be handled inside the loop.
68
1.24M
  char const* chars = _case == HexCase::Upper ? upperHexChars : lowerHexChars;
69
1.24M
  size_t rix = _data.size() - 1;
70
1.24M
  for (uint8_t c: _data)
71
36.1M
  {
72
    // switch hex case every four hexchars
73
36.1M
    if (_case == HexCase::Mixed)
74
0
      chars = (rix-- & 2) == 0 ? lowerHexChars : upperHexChars;
75
76
36.1M
    ret[i++] = chars[(static_cast<size_t>(c) >> 4ul) & 0xfu];
77
36.1M
    ret[i++] = chars[c & 0xfu];
78
36.1M
  }
79
1.24M
  assertThrow(i == ret.size(), Exception, "");
80
81
1.24M
  return ret;
82
1.24M
}
83
84
int solidity::util::fromHex(char _i, WhenError _throw)
85
4.56M
{
86
4.56M
  if (_i >= '0' && _i <= '9')
87
4.56M
    return _i - '0';
88
0
  if (_i >= 'a' && _i <= 'f')
89
0
    return _i - 'a' + 10;
90
0
  if (_i >= 'A' && _i <= 'F')
91
0
    return _i - 'A' + 10;
92
0
  if (_throw == WhenError::Throw)
93
0
    assertThrow(false, BadHexCharacter, to_string(_i));
94
0
  else
95
0
    return -1;
96
0
}
97
98
bytes solidity::util::fromHex(std::string const& _s, WhenError _throw)
99
114k
{
100
114k
  if (_s.empty())
101
0
    return {};
102
103
114k
  unsigned s = (_s.size() >= 2 && _s[0] == '0' && _s[1] == 'x') ? 2 : 0;
104
114k
  std::vector<uint8_t> ret;
105
114k
  ret.reserve((_s.size() - s + 1) / 2);
106
107
114k
  if (_s.size() % 2)
108
0
  {
109
0
    int h = fromHex(_s[s++], _throw);
110
0
    if (h != -1)
111
0
      ret.push_back(static_cast<uint8_t>(h));
112
0
    else
113
0
      return bytes();
114
0
  }
115
2.39M
  for (unsigned i = s; i < _s.size(); i += 2)
116
2.28M
  {
117
2.28M
    int h = fromHex(_s[i], _throw);
118
2.28M
    int l = fromHex(_s[i + 1], _throw);
119
2.28M
    if (h != -1 && l != -1)
120
2.28M
      ret.push_back(static_cast<uint8_t>(h * 16 + l));
121
0
    else
122
0
      return bytes();
123
2.28M
  }
124
114k
  return ret;
125
114k
}
126
127
128
bool solidity::util::passesAddressChecksum(string const& _str, bool _strict)
129
0
{
130
0
  string s = _str.substr(0, 2) == "0x" ? _str : "0x" + _str;
131
132
0
  if (s.length() != 42)
133
0
    return false;
134
135
0
  if (!_strict && (
136
0
    s.find_first_of("abcdef") == string::npos ||
137
0
    s.find_first_of("ABCDEF") == string::npos
138
0
  ))
139
0
    return true;
140
141
0
  return s == solidity::util::getChecksummedAddress(s);
142
0
}
143
144
string solidity::util::getChecksummedAddress(string const& _addr)
145
0
{
146
0
  string s = _addr.substr(0, 2) == "0x" ? _addr.substr(2) : _addr;
147
0
  assertThrow(s.length() == 40, InvalidAddress, "");
148
0
  assertThrow(s.find_first_not_of("0123456789abcdefABCDEF") == string::npos, InvalidAddress, "");
149
150
0
  h256 hash = keccak256(boost::algorithm::to_lower_copy(s, std::locale::classic()));
151
152
0
  string ret = "0x";
153
0
  for (unsigned i = 0; i < 40; ++i)
154
0
  {
155
0
    char addressCharacter = s[i];
156
0
    uint8_t nibble = hash[i / 2u] >> (4u * (1u - (i % 2u))) & 0xf;
157
0
    if (nibble >= 8)
158
0
      ret += toUpper(addressCharacter);
159
0
    else
160
0
      ret += toLower(addressCharacter);
161
0
  }
162
0
  return ret;
163
0
}
164
165
bool solidity::util::isValidHex(string const& _string)
166
182M
{
167
182M
  if (_string.substr(0, 2) != "0x")
168
0
    return false;
169
182M
  if (_string.find_first_not_of("0123456789abcdefABCDEF", 2) != string::npos)
170
0
    return false;
171
182M
  return true;
172
182M
}
173
174
bool solidity::util::isValidDecimal(string const& _string)
175
286M
{
176
286M
  if (_string.empty())
177
0
    return false;
178
286M
  if (_string == "0")
179
47.7M
    return true;
180
  // No leading zeros
181
238M
  if (_string.front() == '0')
182
182M
    return false;
183
56.4M
  if (_string.find_first_not_of("0123456789") != string::npos)
184
0
    return false;
185
56.4M
  return true;
186
56.4M
}
187
188
string solidity::util::formatAsStringOrNumber(string const& _value)
189
0
{
190
0
  assertThrow(_value.length() <= 32, StringTooLong, "String to be formatted longer than 32 bytes.");
191
192
0
  for (auto const& c: _value)
193
0
    if (c <= 0x1f || c >= 0x7f || c == '"')
194
0
      return "0x" + h256(_value, h256::AlignLeft).hex();
195
196
0
  return escapeAndQuoteString(_value);
197
0
}
198
199
200
string solidity::util::escapeAndQuoteString(string const& _input)
201
0
{
202
0
  string out;
203
204
0
  for (char c: _input)
205
0
    if (c == '\\')
206
0
      out += "\\\\";
207
0
    else if (c == '"')
208
0
      out += "\\\"";
209
0
    else if (c == '\n')
210
0
      out += "\\n";
211
0
    else if (c == '\r')
212
0
      out += "\\r";
213
0
    else if (c == '\t')
214
0
      out += "\\t";
215
0
    else if (!isPrint(c))
216
0
    {
217
0
      ostringstream o;
218
0
      o << "\\x" << std::hex << setfill('0') << setw(2) << (unsigned)(unsigned char)(c);
219
0
      out += o.str();
220
0
    }
221
0
    else
222
0
      out += c;
223
224
0
  return "\"" + std::move(out) + "\"";
225
0
}