GCC Code Coverage Report


Directory: libs/url/
File: src/ipv6_address.cpp
Date: 2025-11-10 19:06:22
Exec Total Coverage
Lines: 130 130 100.0%
Functions: 14 14 100.0%
Branches: 58 66 87.9%

Line Branch Exec Source
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/url
8 //
9
10
11 #include <boost/url/detail/config.hpp>
12 #include <boost/url/ipv6_address.hpp>
13 #include <boost/url/ipv4_address.hpp>
14 #include <boost/url/rfc/ipv6_address_rule.hpp>
15 #include <boost/url/detail/except.hpp>
16 #include <boost/url/grammar/parse.hpp>
17 #include <cstring>
18
19 namespace boost {
20 namespace urls {
21
22 226 ipv6_address::
23 ipv6_address(
24 226 bytes_type const& bytes) noexcept
25 {
26 226 std::memcpy(&addr_,
27 226 bytes.data(), 16);
28 226 }
29
30 4 ipv6_address::
31 ipv6_address(
32 4 ipv4_address const& addr) noexcept
33 {
34 4 auto const v = addr.to_bytes();
35 4 ipv6_address::bytes_type bytes = {
36 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37 4 0xff, 0xff, v[0], v[1], v[2], v[3] } };
38 4 std::memcpy(&addr_, bytes.data(), 16);
39 4 }
40
41 60 ipv6_address::
42 ipv6_address(
43 60 core::string_view s)
44 : ipv6_address(
45 60 parse_ipv6_address(s
46
2/2
✓ Branch 2 taken 59 times.
✓ Branch 3 taken 1 times.
60 ).value(BOOST_URL_POS))
47 {
48 59 }
49
50 core::string_view
51 27 ipv6_address::
52 to_buffer(
53 char* dest,
54 std::size_t dest_size) const
55 {
56
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 26 times.
27 if(dest_size < max_str_len)
57 1 detail::throw_length_error();
58 26 auto n = print_impl(dest);
59 26 return core::string_view(dest, n);
60 }
61
62 bool
63 3 ipv6_address::
64 is_loopback() const noexcept
65 {
66 3 return *this == loopback();
67 }
68
69 bool
70 3 ipv6_address::
71 is_unspecified() const noexcept
72 {
73 3 return *this == ipv6_address();
74 }
75
76 bool
77 70 ipv6_address::
78 is_v4_mapped() const noexcept
79 {
80 return
81
2/2
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 16 times.
119 addr_[ 0] == 0 && addr_[ 1] == 0 &&
82
3/4
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 31 times.
✓ Branch 5 taken 2 times.
33 addr_[ 2] == 0 && addr_[ 3] == 0 &&
83
3/4
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 2 times.
31 addr_[ 4] == 0 && addr_[ 5] == 0 &&
84
3/4
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 2 times.
29 addr_[ 6] == 0 && addr_[ 7] == 0 &&
85
3/4
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25 times.
✓ Branch 5 taken 2 times.
27 addr_[ 8] == 0 && addr_[ 9] == 0 &&
86
4/4
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 21 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 13 times.
131 addr_[10] == 0xff &&
87
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
82 addr_[11] == 0xff;
88 }
89
90 ipv6_address
91 5 ipv6_address::
92 loopback() noexcept
93 {
94 5 ipv6_address a;
95 5 a.addr_[15] = 1;
96 5 return a;
97 }
98
99 void
100 1 ipv6_address::
101 write_ostream(
102 std::ostream& os) const
103 {
104 char buf[ipv6_address::max_str_len];
105
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 auto const s = to_buffer(buf, sizeof(buf));
106
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 os << s;
107 1 }
108
109 std::size_t
110 65 ipv6_address::
111 print_impl(
112 char* dest) const noexcept
113 {
114 auto const count_zeroes =
115 207 []( unsigned char const* first,
116 unsigned char const* const last)
117 {
118 207 std::size_t n = 0;
119
2/2
✓ Branch 0 taken 549 times.
✓ Branch 1 taken 25 times.
574 while(first != last)
120 {
121
2/2
✓ Branch 0 taken 476 times.
✓ Branch 1 taken 73 times.
549 if( first[0] != 0 ||
122
2/2
✓ Branch 0 taken 367 times.
✓ Branch 1 taken 109 times.
476 first[1] != 0)
123 break;
124 367 n += 2;
125 367 first += 2;
126 }
127 207 return n;
128 };
129 auto const print_hex =
130 159 []( char* dest,
131 unsigned short v)
132 {
133 159 char const* const dig =
134 "0123456789abcdef";
135
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 99 times.
159 if(v >= 0x1000)
136 {
137 60 *dest++ = dig[v>>12];
138 60 v &= 0x0fff;
139 60 *dest++ = dig[v>>8];
140 60 v &= 0x0ff;
141 60 *dest++ = dig[v>>4];
142 60 v &= 0x0f;
143 60 *dest++ = dig[v];
144 }
145
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 97 times.
99 else if(v >= 0x100)
146 {
147 2 *dest++ = dig[v>>8];
148 2 v &= 0x0ff;
149 2 *dest++ = dig[v>>4];
150 2 v &= 0x0f;
151 2 *dest++ = dig[v];
152 }
153
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 96 times.
97 else if(v >= 0x10)
154 {
155 1 *dest++ = dig[v>>4];
156 1 v &= 0x0f;
157 1 *dest++ = dig[v];
158 }
159 else
160 {
161 96 *dest++ = dig[v];
162 }
163 159 return dest;
164 };
165 65 auto const dest0 = dest;
166 // find longest run of zeroes
167 65 std::size_t best_len = 0;
168 65 int best_pos = -1;
169 65 auto it = addr_.data();
170 auto const v4 =
171 65 is_v4_mapped();
172
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 56 times.
65 auto const end = v4 ?
173 18 (it + addr_.size() - 4)
174 112 : it + addr_.size();
175
2/2
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 65 times.
272 while(it != end)
176 {
177 207 auto n = count_zeroes(
178 it, end);
179
2/2
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 72 times.
207 if(n == 0)
180 {
181 135 it += 2;
182 135 continue;
183 }
184
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 6 times.
72 if(n > best_len)
185 {
186 66 best_pos = static_cast<
187 66 int>(it - addr_.data());
188 66 best_len = n;
189 }
190 72 it += n;
191 }
192 65 it = addr_.data();
193
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 23 times.
65 if(best_pos != 0)
194 {
195 42 unsigned short v =
196 42 (it[0] * 256U) + it[1];
197 42 dest = print_hex(dest, v);
198 42 it += 2;
199 }
200 else
201 {
202 23 *dest++ = ':';
203 23 it += best_len;
204
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
23 if(it == end)
205 4 *dest++ = ':';
206 }
207
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 65 times.
219 while(it != end)
208 {
209 154 *dest++ = ':';
210 154 if(it - addr_.data() ==
211
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 117 times.
154 best_pos)
212 {
213 37 it += best_len;
214
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 22 times.
37 if(it == end)
215 15 *dest++ = ':';
216 37 continue;
217 }
218 117 unsigned short v =
219 117 (it[0] * 256U) + it[1];
220 117 dest = print_hex(dest, v);
221 117 it += 2;
222 }
223
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 56 times.
65 if(v4)
224 {
225 ipv4_address::bytes_type bytes;
226 9 bytes[0] = it[0];
227 9 bytes[1] = it[1];
228 9 bytes[2] = it[2];
229 9 bytes[3] = it[3];
230 9 ipv4_address a(bytes);
231 9 *dest++ = ':';
232 9 dest += a.print_impl(dest);
233 }
234 65 return dest - dest0;
235 }
236
237 void
238 39 ipv6_address::
239 to_string_impl(
240 string_token::arg& t) const
241 {
242 char buf[max_str_len];
243 39 auto const n = print_impl(buf);
244
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 char* dest = t.prepare(n);
245 39 std::memcpy(dest, buf, n);
246 39 }
247
248 //------------------------------------------------
249
250 auto
251 172 parse_ipv6_address(
252 core::string_view s) noexcept ->
253 system::result<ipv6_address>
254 {
255 172 return grammar::parse(
256 172 s, ipv6_address_rule);
257 }
258
259 } // urls
260 } // boost
261
262