• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

libbitcoin / libbitcoin-system / 36510886465

29 Sep 2026 02:04AM UTC coverage: 97.923% (+0.4%) from 97.518%
36510886465

push

github

web-flow
Merge pull request #2024 from evoskuil/tls

Add primitives required for TLS1.3.

1479 of 1484 new or added lines in 27 files covered. (99.66%)

14 existing lines in 7 files now uncovered.

18525 of 18918 relevant lines covered (97.92%)

1824283.41 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.68
/src/unicode/conversion.cpp
1
/**
2
 * Copyright (c) 2011-2026 libbitcoin developers
3
 *
4
 * This file is part of libbitcoin.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU Affero General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Affero General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
#include <bitcoin/system/unicode/conversion.hpp>
20

21
#include <bitcoin/system/define.hpp>
22

23
namespace libbitcoin {
24
namespace system {
25

26
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
27

28
// Surrogates and values above the unicode range are not code points.
29
constexpr bool is_code_point(char32_t point) NOEXCEPT
30
{
31
    return point <= 0x0010ffff && (point < 0x0000d800 || point > 0x0000dfff);
2,709,630 ✔
32
}
33

34
// Decode one code point from UTF8 (char), UTF16 or UTF32 (by char size).
35
// False if the sequence is truncated, overlong, or not a code point.
36
template <typename Char>
37
static bool decode(char32_t& point, const std::basic_string<Char>& in,
5,334,271 ✔
38
    size_t& offset) NOEXCEPT
39
{
40
    if constexpr (sizeof(Char) == sizeof(uint8_t))
41
    {
42
        const auto lead = static_cast<uint8_t>(in.at(offset++));
2,793,425 ✔
43
        if (lead < 0x80)
2,793,425 ✔
44
        {
45
            point = lead;
2,624,631 ✔
46
            return true;
2,624,631 ✔
47
        }
48

49
        size_t trail{};
50
        char32_t minimum{};
51
        if ((lead & 0xe0) == 0xc0)
168,794 ✔
52
        {
53
            trail = 1;
54
            minimum = 0x00000080;
55
            point = lead & 0x1f;
5,394 ✔
56
        }
57
        else if ((lead & 0xf0) == 0xe0)
163,400 ✔
58
        {
59
            trail = 2;
60
            minimum = 0x00000800;
61
            point = lead & 0x0f;
163,361 ✔
62
        }
63
        else if ((lead & 0xf8) == 0xf0)
39 ✔
64
        {
65
            trail = 3;
66
            minimum = 0x00010000;
67
            point = lead & 0x07;
36 ✔
68
        }
69
        else
70
        {
71
            return false;
72
        }
73

74
        if (in.size() - offset < trail)
168,791 ✔
75
            return false;
76

77
        for (; is_nonzero(trail); --trail)
501,005 ✔
78
        {
79
            const auto next = static_cast<uint8_t>(in.at(offset++));
332,218 ✔
80
            if ((next & 0xc0) != 0x80)
332,218 ✔
81
                return false;
82

83
            point = (point << 6) | (next & 0x3f);
332,217 ✔
84
        }
85

86
        return point >= minimum && is_code_point(point);
168,787 ✔
87
    }
88
    else if constexpr (sizeof(Char) == sizeof(uint16_t))
89
    {
90
        const char32_t high = static_cast<uint16_t>(in.at(offset++));
91
        if (high < 0xd800 || high > 0xdfff)
92
        {
93
            point = high;
94
            return true;
95
        }
96

97
        if (high > 0xdbff || offset == in.size())
98
            return false;
99

100
        const char32_t low = static_cast<uint16_t>(in.at(offset++));
101
        if (low < 0xdc00 || low > 0xdfff)
102
            return false;
103

104
        point = 0x00010000 + ((high - 0xd800) << 10) + (low - 0xdc00);
105
        return true;
106
    }
107
    else
108
    {
109
        point = static_cast<char32_t>(in.at(offset++));
2,540,846 ✔
110
        return is_code_point(point);
2,540,846 ✔
111
    }
112
}
113

114
// Encode one code point as UTF8 (char), UTF16 or UTF32 (by char size).
115
template <typename Char>
116
static void encode(std::basic_string<Char>& out, char32_t point) NOEXCEPT
5,334,252 ✔
117
{
118
    const auto put = [&](char32_t value) NOEXCEPT
5,334,252 ✔
119
    {
120
        out.push_back(static_cast<Char>(value));
5,220,383 ✔
121
    };
122

123
    if constexpr (sizeof(Char) == sizeof(uint8_t))
124
    {
125
        if (point < 0x00000080)
2,540,765 ✔
126
        {
127
            put(point);
128
        }
129
        else if (point < 0x00000800)
113,869 ✔
130
        {
131
            put(0xc0 | (point >> 6));
2,848 ✔
132
            put(0x80 | (point & 0x3f));
2,848 ✔
133
        }
134
        else if (point < 0x00010000)
111,021 ✔
135
        {
136
            put(0xe0 | (point >> 12));
110,987 ✔
137
            put(0x80 | ((point >> 6) & 0x3f));
110,987 ✔
138
            put(0x80 | (point & 0x3f));
110,987 ✔
139
        }
140
        else
141
        {
142
            put(0xf0 | (point >> 18));
34 ✔
143
            put(0x80 | ((point >> 12) & 0x3f));
34 ✔
144
            put(0x80 | ((point >> 6) & 0x3f));
34 ✔
145
            put(0x80 | (point & 0x3f));
34 ✔
146
        }
147
    }
148
    else if constexpr (sizeof(Char) == sizeof(uint16_t))
149
    {
150
        if (point < 0x00010000)
151
        {
152
            put(point);
153
        }
154
        else
155
        {
156
            const auto value = point - 0x00010000;
157
            put(0xd800 + (value >> 10));
158
            put(0xdc00 + (value & 0x03ff));
159
        }
160
    }
161
    else
162
    {
163
        put(point);
164
    }
165
}
5,334,252 ✔
166

167
// Empty if any sequence is invalid (no replacement or skipping).
168
template <typename CharOut, typename CharIn>
169
static std::basic_string<CharOut> to_utf(
197,540 ✔
170
    const std::basic_string<CharIn>& in) NOEXCEPT
171
{
172
    std::basic_string<CharOut> out{};
173
    out.reserve(in.size());
197,540 ✔
174

175
    char32_t point{};
197,540 ✔
176
    for (size_t offset{}; offset < in.size();)
5,531,792 ✔
177
    {
178
        if (!decode(point, in, offset))
5,334,271 ✔
179
            return {};
19 ✔
180

181
        encode(out, point);
5,334,252 ✔
182
    }
183

184
    return out;
197,521 ✔
185
}
186

187
template <typename CharOut, typename CharIn>
188
static std::vector<std::basic_string<CharOut>> to_utf(
38 ✔
189
    const std::vector<std::basic_string<CharIn>>& in) NOEXCEPT
190
{
191
    std::vector<std::basic_string<CharOut>> out(in.size());
38 ✔
192
    std::transform(in.begin(), in.end(), out.begin(),
38 ✔
193
        [](const std::basic_string<CharIn>& word) NOEXCEPT
194
        {
195
            return to_utf<CharOut>(word);
47,480 ✔
196
        });
197

198
    return out;
38 ✔
UNCOV
199
}
×
200

201
// char32_t is the only 1:1 char encoding.
202
std::string to_utf8(char32_t point) NOEXCEPT
50 ✔
203
{
204
    return to_utf8(std::u32string{ point });
100 ✔
205
}
206

207
std::string to_utf8(const std::wstring& text) NOEXCEPT
11 ✔
208
{
209
    return to_utf<char>(text);
11 ✔
210
}
211

212
std::string to_utf8(const std::u32string& text) NOEXCEPT
72,957 ✔
213
{
214
    return to_utf<char>(text);
72,957 ✔
215
}
216

217
std::wstring to_utf16(const std::string& text) NOEXCEPT
20 ✔
218
{
219
    return to_utf<wchar_t>(text);
20 ✔
220
}
221

222
std::wstring to_utf16(const std::u32string& text) NOEXCEPT
4 ✔
223
{
224
    return to_utf<wchar_t>(text);
4 ✔
225
}
226

227
std::u32string to_utf32(const std::string& text) NOEXCEPT
77,065 ✔
228
{
229
    return to_utf<char32_t>(text);
77,065 ✔
230
}
231

232
std::u32string to_utf32(const std::wstring& text) NOEXCEPT
3 ✔
233
{
234
    return to_utf<char32_t>(text);
3 ✔
235
}
236

237
string_list to_utf8(const wstring_list& text) NOEXCEPT
2 ✔
238
{
239
    return to_utf<char>(text);
2 ✔
240
}
241

242
string_list to_utf8(const u32string_list& text) NOEXCEPT
3 ✔
243
{
244
    return to_utf<char>(text);
3 ✔
245
}
246

247
wstring_list to_utf16(const string_list& text) NOEXCEPT
14 ✔
248
{
249
    return to_utf<wchar_t>(text);
14 ✔
250
}
251

252
wstring_list to_utf16(const u32string_list& text) NOEXCEPT
3 ✔
253
{
254
    return to_utf<wchar_t>(text);
3 ✔
255
}
256

257
u32string_list to_utf32(const string_list& text) NOEXCEPT
15 ✔
258
{
259
    return to_utf<char32_t>(text);
15 ✔
260
}
261

262
u32string_list to_utf32(const wstring_list& text) NOEXCEPT
1 ✔
263
{
264
    return to_utf<char32_t>(text);
1 ✔
265
}
266

267
BC_POP_WARNING()
268

269
} // namespace system
270
} // namespace libbitcoin
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc