GCC Code Coverage Report


Directory: libs/url/
File: libs/url/src/rfc/ipv6_address_rule.cpp
Date: 2024-02-29 20:02:56
Exec Total Coverage
Lines: 111 111 100.0%
Functions: 2 2 100.0%
Branches: 53 54 98.1%

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 "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 5 times.
✓ Branch 1 taken 60 times.
65 if(word > 0x255)
42 5 return false;
43
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 57 times.
60 if(((word >> 4) & 0xf) > 9)
44 3 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