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 | #ifndef BOOST_URL_RFC_IMPL_IPV6_ADDRESS_RULE_IPP | ||
11 | #define BOOST_URL_RFC_IMPL_IPV6_ADDRESS_RULE_IPP | ||
12 | |||
13 | #include <boost/url/detail/config.hpp> | ||
14 | #include <boost/url/rfc/ipv6_address_rule.hpp> | ||
15 | #include <boost/url/rfc/ipv4_address_rule.hpp> | ||
16 | #include <boost/url/rfc/detail/h16_rule.hpp> | ||
17 | #include <boost/url/grammar/charset.hpp> | ||
18 | #include <boost/url/grammar/hexdig_chars.hpp> | ||
19 | #include <boost/url/grammar/parse.hpp> | ||
20 | #include <boost/assert.hpp> | ||
21 | #include <cstring> | ||
22 | |||
23 | namespace boost { | ||
24 | namespace urls { | ||
25 | |||
26 | namespace detail { | ||
27 | |||
28 | // return `true` if the hex | ||
29 | // word could be 0..255 if | ||
30 | // interpreted as decimal | ||
31 | static | ||
32 | bool | ||
33 | 65 | maybe_octet( | |
34 | unsigned char const* p) noexcept | ||
35 | { | ||
36 | 65 | unsigned short word = | |
37 | static_cast<unsigned short>( | ||
38 | 65 | p[0]) * 256 + | |
39 | static_cast<unsigned short>( | ||
40 | 65 | p[1]); | |
41 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 58 times.
|
65 | if(word > 0x255) |
42 | 7 | return false; | |
43 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 57 times.
|
58 | if(((word >> 4) & 0xf) > 9) |
44 | 1 | return false; | |
45 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 55 times.
|
57 | if((word & 0xf) > 9) |
46 | 2 | return false; | |
47 | 55 | return true; | |
48 | } | ||
49 | |||
50 | } // detail | ||
51 | |||
52 | auto | ||
53 | 288 | ipv6_address_rule_t:: | |
54 | parse( | ||
55 | char const*& it, | ||
56 | char const* const end | ||
57 | ) const noexcept -> | ||
58 | system::result<ipv6_address> | ||
59 | { | ||
60 | 288 | int n = 8; // words needed | |
61 | 288 | int b = -1; // value of n | |
62 | // when '::' seen | ||
63 | 288 | bool c = false; // need colon | |
64 | 288 | auto prev = it; | |
65 | ipv6_address::bytes_type bytes; | ||
66 | 288 | system::result<detail::h16_rule_t::value_type> rv; | |
67 | for(;;) | ||
68 | { | ||
69 |
2/2✓ Branch 0 taken 91 times.
✓ Branch 1 taken 1233 times.
|
1324 | if(it == end) |
70 | { | ||
71 |
2/2✓ Branch 0 taken 83 times.
✓ Branch 1 taken 8 times.
|
91 | if(b != -1) |
72 | { | ||
73 | // end in "::" | ||
74 | 83 | break; | |
75 | } | ||
76 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | BOOST_ASSERT(n > 0); |
77 | // not enough words | ||
78 | 8 | BOOST_URL_RETURN_EC( | |
79 | grammar::error::invalid); | ||
80 | } | ||
81 |
2/2✓ Branch 0 taken 794 times.
✓ Branch 1 taken 439 times.
|
1233 | if(*it == ':') |
82 | { | ||
83 | 794 | ++it; | |
84 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 789 times.
|
794 | if(it == end) |
85 | { | ||
86 | // expected ':' | ||
87 | 5 | BOOST_URL_RETURN_EC( | |
88 | grammar::error::invalid); | ||
89 | } | ||
90 |
2/2✓ Branch 0 taken 186 times.
✓ Branch 1 taken 603 times.
|
789 | if(*it == ':') |
91 | { | ||
92 |
2/2✓ Branch 0 taken 183 times.
✓ Branch 1 taken 3 times.
|
186 | if(b == -1) |
93 | { | ||
94 | // first "::" | ||
95 | 183 | ++it; | |
96 | 183 | --n; | |
97 | 183 | b = n; | |
98 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 181 times.
|
183 | if(n == 0) |
99 | 2 | break; | |
100 | 181 | c = false; | |
101 | 181 | continue; | |
102 | } | ||
103 | // extra "::" found | ||
104 | 3 | BOOST_URL_RETURN_EC( | |
105 | grammar::error::invalid); | ||
106 | } | ||
107 |
2/2✓ Branch 0 taken 597 times.
✓ Branch 1 taken 6 times.
|
603 | if(c) |
108 | { | ||
109 | 597 | prev = it; | |
110 | rv = grammar::parse( | ||
111 | it, end, | ||
112 | 597 | detail::h16_rule); | |
113 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 592 times.
|
597 | if(! rv) |
114 | 5 | return rv.error(); | |
115 | 592 | bytes[2*(8-n)+0] = rv->hi; | |
116 | 592 | bytes[2*(8-n)+1] = rv->lo; | |
117 | 592 | --n; | |
118 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 541 times.
|
592 | if(n == 0) |
119 | 51 | break; | |
120 | 541 | continue; | |
121 | } | ||
122 | // expected h16 | ||
123 | 6 | BOOST_URL_RETURN_EC( | |
124 | grammar::error::invalid); | ||
125 | } | ||
126 |
2/2✓ Branch 0 taken 75 times.
✓ Branch 1 taken 364 times.
|
439 | if(*it == '.') |
127 | { | ||
128 |
4/4✓ Branch 0 taken 15 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 5 times.
|
75 | if(b == -1 && n > 1) |
129 | { | ||
130 | // not enough h16 | ||
131 | 10 | BOOST_URL_RETURN_EC( | |
132 | grammar::error::invalid); | ||
133 | } | ||
134 |
2/2✓ Branch 1 taken 10 times.
✓ Branch 2 taken 55 times.
|
65 | if(! detail::maybe_octet( |
135 | 65 | &bytes[2*(7-n)])) | |
136 | { | ||
137 | // invalid octet | ||
138 | 10 | BOOST_URL_RETURN_EC( | |
139 | grammar::error::invalid); | ||
140 | } | ||
141 | // rewind the h16 and | ||
142 | // parse it as ipv4 | ||
143 | 55 | it = prev; | |
144 | auto rv1 = grammar::parse( | ||
145 | 55 | it, end, ipv4_address_rule); | |
146 |
2/2✓ Branch 1 taken 22 times.
✓ Branch 2 taken 33 times.
|
55 | if(! rv1) |
147 | 22 | return rv1.error(); | |
148 | 33 | auto v4 = *rv1; | |
149 | auto const b4 = | ||
150 | 33 | v4.to_bytes(); | |
151 | 33 | bytes[2*(7-n)+0] = b4[0]; | |
152 | 33 | bytes[2*(7-n)+1] = b4[1]; | |
153 | 33 | bytes[2*(7-n)+2] = b4[2]; | |
154 | 33 | bytes[2*(7-n)+3] = b4[3]; | |
155 | 33 | --n; | |
156 | 33 | break; | |
157 | } | ||
158 | auto d = | ||
159 | 364 | grammar::hexdig_value(*it); | |
160 |
4/4✓ Branch 0 taken 170 times.
✓ Branch 1 taken 194 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 145 times.
|
364 | if( b != -1 && |
161 | d < 0) | ||
162 | { | ||
163 | // ends in "::" | ||
164 | 25 | break; | |
165 | } | ||
166 |
2/2✓ Branch 0 taken 335 times.
✓ Branch 1 taken 4 times.
|
339 | if(! c) |
167 | { | ||
168 | 335 | prev = it; | |
169 | rv = grammar::parse( | ||
170 | it, end, | ||
171 | 335 | detail::h16_rule); | |
172 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 315 times.
|
335 | if(! rv) |
173 | 20 | return rv.error(); | |
174 | 315 | bytes[2*(8-n)+0] = rv->hi; | |
175 | 315 | bytes[2*(8-n)+1] = rv->lo; | |
176 | 315 | --n; | |
177 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 314 times.
|
315 | if(n == 0) |
178 | 1 | break; | |
179 | 314 | c = true; | |
180 | 314 | continue; | |
181 | } | ||
182 | // ':' divides a word | ||
183 | 4 | BOOST_URL_RETURN_EC( | |
184 | grammar::error::invalid); | ||
185 | 1036 | } | |
186 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 145 times.
|
195 | if(b == -1) |
187 | 50 | return ipv6_address{bytes}; | |
188 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 111 times.
|
145 | if(b == n) |
189 | { | ||
190 | // "::" last | ||
191 | 34 | auto const i = | |
192 | 34 | 2 * (7 - n); | |
193 | 34 | std::memset( | |
194 | 34 | &bytes[i], | |
195 | 34 | 0, 16 - i); | |
196 | } | ||
197 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 66 times.
|
111 | else if(b == 7) |
198 | { | ||
199 | // "::" first | ||
200 | 45 | auto const i = | |
201 | 45 | 2 * (b - n); | |
202 | 90 | std::memmove( | |
203 | 45 | &bytes[16 - i], | |
204 | 45 | &bytes[2], | |
205 | i); | ||
206 | 45 | std::memset( | |
207 | 45 | &bytes[0], | |
208 | 45 | 0, 16 - i); | |
209 | } | ||
210 | else | ||
211 | { | ||
212 | // "::" in middle | ||
213 | 66 | auto const i0 = | |
214 | 66 | 2 * (7 - b); | |
215 | 66 | auto const i1 = | |
216 | 66 | 2 * (b - n); | |
217 | 132 | std::memmove( | |
218 | 66 | &bytes[16 - i1], | |
219 | 66 | &bytes[i0 + 2], | |
220 | i1); | ||
221 | 66 | std::memset( | |
222 | 66 | &bytes[i0], | |
223 | 66 | 0, 16 - (i0 + i1)); | |
224 | } | ||
225 | 145 | return ipv6_address{bytes}; | |
226 | } | ||
227 | |||
228 | } // urls | ||
229 | } // boost | ||
230 | |||
231 | #endif | ||
232 |