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 :
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 210 : ipv6_address::
23 : ipv6_address(
24 210 : bytes_type const& bytes) noexcept
25 : {
26 210 : std::memcpy(&addr_,
27 210 : bytes.data(), 16);
28 210 : }
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 58 : ipv6_address::
42 : ipv6_address(
43 58 : core::string_view s)
44 : : ipv6_address(
45 58 : parse_ipv6_address(s
46 58 : ).value(BOOST_URL_POS))
47 : {
48 57 : }
49 :
50 : core::string_view
51 14 : ipv6_address::
52 : to_buffer(
53 : char* dest,
54 : std::size_t dest_size) const
55 : {
56 14 : if(dest_size < max_str_len)
57 1 : detail::throw_length_error();
58 13 : auto n = print_impl(dest);
59 13 : 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 56 : ipv6_address::
78 : is_v4_mapped() const noexcept
79 : {
80 : return
81 103 : addr_[ 0] == 0 && addr_[ 1] == 0 &&
82 31 : addr_[ 2] == 0 && addr_[ 3] == 0 &&
83 29 : addr_[ 4] == 0 && addr_[ 5] == 0 &&
84 27 : addr_[ 6] == 0 && addr_[ 7] == 0 &&
85 25 : addr_[ 8] == 0 && addr_[ 9] == 0 &&
86 115 : addr_[10] == 0xff &&
87 68 : 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 : std::size_t
100 51 : ipv6_address::
101 : print_impl(
102 : char* dest) const noexcept
103 : {
104 : auto const count_zeroes =
105 169 : []( unsigned char const* first,
106 : unsigned char const* const last)
107 : {
108 169 : std::size_t n = 0;
109 448 : while(first != last)
110 : {
111 425 : if( first[0] != 0 ||
112 364 : first[1] != 0)
113 : break;
114 279 : n += 2;
115 279 : first += 2;
116 : }
117 169 : return n;
118 : };
119 : auto const print_hex =
120 135 : []( char* dest,
121 : unsigned short v)
122 : {
123 135 : char const* const dig =
124 : "0123456789abcdef";
125 135 : if(v >= 0x1000)
126 : {
127 48 : *dest++ = dig[v>>12];
128 48 : v &= 0x0fff;
129 48 : *dest++ = dig[v>>8];
130 48 : v &= 0x0ff;
131 48 : *dest++ = dig[v>>4];
132 48 : v &= 0x0f;
133 48 : *dest++ = dig[v];
134 : }
135 87 : else if(v >= 0x100)
136 : {
137 2 : *dest++ = dig[v>>8];
138 2 : v &= 0x0ff;
139 2 : *dest++ = dig[v>>4];
140 2 : v &= 0x0f;
141 2 : *dest++ = dig[v];
142 : }
143 85 : else if(v >= 0x10)
144 : {
145 1 : *dest++ = dig[v>>4];
146 1 : v &= 0x0f;
147 1 : *dest++ = dig[v];
148 : }
149 : else
150 : {
151 84 : *dest++ = dig[v];
152 : }
153 135 : return dest;
154 : };
155 51 : auto const dest0 = dest;
156 : // find longest run of zeroes
157 51 : std::size_t best_len = 0;
158 51 : int best_pos = -1;
159 51 : auto it = addr_.data();
160 : auto const v4 =
161 51 : is_v4_mapped();
162 93 : auto const end = v4 ?
163 9 : (it + addr_.size() - 4)
164 93 : : it + addr_.size();
165 220 : while(it != end)
166 : {
167 169 : auto n = count_zeroes(
168 : it, end);
169 169 : if(n == 0)
170 : {
171 111 : it += 2;
172 111 : continue;
173 : }
174 58 : if(n > best_len)
175 : {
176 52 : best_pos = static_cast<
177 52 : int>(it - addr_.data());
178 52 : best_len = n;
179 : }
180 58 : it += n;
181 : }
182 51 : it = addr_.data();
183 51 : if(best_pos != 0)
184 : {
185 30 : unsigned short v =
186 30 : (it[0] * 256U) + it[1];
187 30 : dest = print_hex(dest, v);
188 30 : it += 2;
189 : }
190 : else
191 : {
192 21 : *dest++ = ':';
193 21 : it += best_len;
194 21 : if(it == end)
195 2 : *dest++ = ':';
196 : }
197 181 : while(it != end)
198 : {
199 130 : *dest++ = ':';
200 130 : if(it - addr_.data() ==
201 130 : best_pos)
202 : {
203 25 : it += best_len;
204 25 : if(it == end)
205 15 : *dest++ = ':';
206 25 : continue;
207 : }
208 105 : unsigned short v =
209 105 : (it[0] * 256U) + it[1];
210 105 : dest = print_hex(dest, v);
211 105 : it += 2;
212 : }
213 51 : if(v4)
214 : {
215 : ipv4_address::bytes_type bytes;
216 9 : bytes[0] = it[0];
217 9 : bytes[1] = it[1];
218 9 : bytes[2] = it[2];
219 9 : bytes[3] = it[3];
220 9 : ipv4_address a(bytes);
221 9 : *dest++ = ':';
222 9 : dest += a.print_impl(dest);
223 : }
224 51 : return dest - dest0;
225 : }
226 :
227 : void
228 38 : ipv6_address::
229 : to_string_impl(
230 : string_token::arg& t) const
231 : {
232 : char buf[max_str_len];
233 38 : auto const n = print_impl(buf);
234 38 : char* dest = t.prepare(n);
235 38 : std::memcpy(dest, buf, n);
236 38 : }
237 :
238 : //------------------------------------------------
239 :
240 : auto
241 204 : parse_ipv6_address(
242 : core::string_view s) noexcept ->
243 : system::result<ipv6_address>
244 : {
245 : return grammar::parse(
246 204 : s, ipv6_address_rule);
247 : }
248 :
249 : } // urls
250 : } // boost
251 :
|