include/boost/url/rfc/impl/ipv6_address_rule.hpp

100.0% Lines (111/111) 100.0% Functions (2/2) 98.1% Branches (53/54)
include/boost/url/rfc/impl/ipv6_address_rule.hpp
Line Branch Hits Source Code
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 // Copyright (c) 2024 Alan de Freitas (alandefreitas@gmail.com)
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/boostorg/url
9 //
10
11 #ifndef BOOST_URL_RFC_IMPL_IPV6_ADDRESS_RULE_HPP
12 #define BOOST_URL_RFC_IMPL_IPV6_ADDRESS_RULE_HPP
13
14 #include <boost/url/detail/config.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/error.hpp>
20 #include <boost/url/grammar/parse.hpp>
21 #include <boost/assert.hpp>
22 #include <cstring>
23
24 namespace boost {
25 namespace urls {
26
27 namespace detail {
28
29 inline BOOST_URL_CXX20_CONSTEXPR
30 bool
31 65 maybe_octet(
32 unsigned char const* p) noexcept
33 {
34 65 unsigned short word =
35 static_cast<unsigned short>(
36 65 p[0]) * 256 +
37 static_cast<unsigned short>(
38 65 p[1]);
39
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 58 times.
65 if(word > 0x255)
40 7 return false;
41
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 57 times.
58 if(((word >> 4) & 0xf) > 9)
42 1 return false;
43
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 55 times.
57 if((word & 0xf) > 9)
44 2 return false;
45 55 return true;
46 }
47
48 } // detail
49
50 inline BOOST_URL_CXX20_CONSTEXPR
51 auto
52 292 implementation_defined::ipv6_address_rule_t::
53 parse(
54 char const*& it,
55 char const* const end
56 ) const noexcept ->
57 system::result<ipv6_address>
58 {
59 292 int n = 8;
60 292 int b = -1;
61 292 bool c = false;
62 292 auto prev = it;
63 ipv6_address::bytes_type bytes;
64 292 system::result<detail::h16_rule_t::value_type> rv;
65 for(;;)
66 {
67
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 1267 times.
1358 if(it == end)
68 {
69
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 6 times.
91 if(b != -1)
70 {
71 85 break;
72 }
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 BOOST_ASSERT(n > 0);
74 6 BOOST_URL_CONSTEXPR_RETURN_EC(
75 grammar::error::invalid);
76 }
77
2/2
✓ Branch 0 taken 804 times.
✓ Branch 1 taken 463 times.
1267 if(*it == ':')
78 {
79 804 ++it;
80
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 799 times.
804 if(it == end)
81 {
82 5 BOOST_URL_CONSTEXPR_RETURN_EC(
83 grammar::error::invalid);
84 }
85
2/2
✓ Branch 0 taken 196 times.
✓ Branch 1 taken 603 times.
799 if(*it == ':')
86 {
87
2/2
✓ Branch 0 taken 193 times.
✓ Branch 1 taken 3 times.
196 if(b == -1)
88 {
89 193 ++it;
90 193 --n;
91 193 b = n;
92
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 191 times.
193 if(n == 0)
93 2 break;
94 191 c = false;
95 191 continue;
96 }
97 3 BOOST_URL_CONSTEXPR_RETURN_EC(
98 grammar::error::invalid);
99 }
100
2/2
✓ Branch 0 taken 597 times.
✓ Branch 1 taken 6 times.
603 if(c)
101 {
102 597 prev = it;
103 597 rv = grammar::parse(
104 it, end,
105 detail::h16_rule);
106
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 592 times.
597 if(! rv)
107 5 return rv.error();
108 592 bytes[2*(8-n)+0] = rv->hi;
109 592 bytes[2*(8-n)+1] = rv->lo;
110 592 --n;
111
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 541 times.
592 if(n == 0)
112 51 break;
113 541 continue;
114 }
115 6 BOOST_URL_CONSTEXPR_RETURN_EC(
116 grammar::error::invalid);
117 }
118
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 388 times.
463 if(*it == '.')
119 {
120
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)
121 {
122 10 BOOST_URL_CONSTEXPR_RETURN_EC(
123 grammar::error::invalid);
124 }
125
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 55 times.
65 if(! detail::maybe_octet(
126 65 &bytes[2*(7-n)]))
127 {
128 10 BOOST_URL_CONSTEXPR_RETURN_EC(
129 grammar::error::invalid);
130 }
131 55 it = prev;
132 55 auto rv1 = grammar::parse(
133 it, end, ipv4_address_rule);
134
2/2
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 33 times.
55 if(! rv1)
135 22 return rv1.error();
136 33 auto v4 = *rv1;
137 auto const b4 =
138 33 v4.to_bytes();
139 33 bytes[2*(7-n)+0] = b4[0];
140 33 bytes[2*(7-n)+1] = b4[1];
141 33 bytes[2*(7-n)+2] = b4[2];
142 33 bytes[2*(7-n)+3] = b4[3];
143 33 --n;
144 33 break;
145 }
146 auto d =
147 388 grammar::hexdig_value(*it);
148
4/4
✓ Branch 0 taken 188 times.
✓ Branch 1 taken 200 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 155 times.
388 if( b != -1 &&
149 d < 0)
150 {
151 33 break;
152 }
153
2/2
✓ Branch 0 taken 351 times.
✓ Branch 1 taken 4 times.
355 if(! c)
154 {
155 351 prev = it;
156 351 rv = grammar::parse(
157 it, end,
158 detail::h16_rule);
159
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 335 times.
351 if(! rv)
160 16 return rv.error();
161 335 bytes[2*(8-n)+0] = rv->hi;
162 335 bytes[2*(8-n)+1] = rv->lo;
163 335 --n;
164
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 334 times.
335 if(n == 0)
165 1 break;
166 334 c = true;
167 334 continue;
168 }
169 4 BOOST_URL_CONSTEXPR_RETURN_EC(
170 grammar::error::invalid);
171 1066 }
172
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 155 times.
205 if(b == -1)
173 50 return ipv6_address{bytes};
174
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 121 times.
155 if(b == n)
175 {
176 34 auto const i =
177 34 2 * (7 - n);
178 34 std::memset(
179 34 &bytes[i],
180 34 0, 16 - i);
181 }
182
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 76 times.
121 else if(b == 7)
183 {
184 45 auto const i =
185 45 2 * (b - n);
186 90 std::memmove(
187 45 &bytes[16 - i],
188 45 &bytes[2],
189 i);
190 45 std::memset(
191 45 &bytes[0],
192 45 0, 16 - i);
193 }
194 else
195 {
196 76 auto const i0 =
197 76 2 * (7 - b);
198 76 auto const i1 =
199 76 2 * (b - n);
200 152 std::memmove(
201 76 &bytes[16 - i1],
202 76 &bytes[i0 + 2],
203 i1);
204 76 std::memset(
205 76 &bytes[i0],
206 76 0, 16 - (i0 + i1));
207 }
208 155 return ipv6_address{bytes};
209 }
210
211 } // urls
212 } // boost
213
214
215 #endif
216