GCC Code Coverage Report


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