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