src/ipv6_address.cpp

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