100.00% Lines (113/113) 100.00% Functions (2/2)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3   // Copyright (c) 2024 Alan de Freitas (alandefreitas@gmail.com) 3   // Copyright (c) 2024 Alan de Freitas (alandefreitas@gmail.com)
4   // 4   //
5   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7   // 7   //
8   // Official repository: https://github.com/boostorg/url 8   // Official repository: https://github.com/boostorg/url
9   // 9   //
10   10  
11   #ifndef BOOST_URL_RFC_IMPL_IPV6_ADDRESS_RULE_HPP 11   #ifndef BOOST_URL_RFC_IMPL_IPV6_ADDRESS_RULE_HPP
12   #define BOOST_URL_RFC_IMPL_IPV6_ADDRESS_RULE_HPP 12   #define BOOST_URL_RFC_IMPL_IPV6_ADDRESS_RULE_HPP
13   13  
14   #include <boost/url/detail/config.hpp> 14   #include <boost/url/detail/config.hpp>
15   #include <boost/url/rfc/ipv4_address_rule.hpp> 15   #include <boost/url/rfc/ipv4_address_rule.hpp>
16   #include <boost/url/rfc/detail/h16_rule.hpp> 16   #include <boost/url/rfc/detail/h16_rule.hpp>
17   #include <boost/url/grammar/charset.hpp> 17   #include <boost/url/grammar/charset.hpp>
18   #include <boost/url/grammar/hexdig_chars.hpp> 18   #include <boost/url/grammar/hexdig_chars.hpp>
19   #include <boost/url/grammar/error.hpp> 19   #include <boost/url/grammar/error.hpp>
20   #include <boost/url/grammar/parse.hpp> 20   #include <boost/url/grammar/parse.hpp>
21   #include <boost/assert.hpp> 21   #include <boost/assert.hpp>
22   #include <cstring> 22   #include <cstring>
23   23  
24   namespace boost { 24   namespace boost {
25   namespace urls { 25   namespace urls {
26   26  
27   namespace detail { 27   namespace detail {
28   28  
29   // return `true` if the hex 29   // return `true` if the hex
30   // word could be 0..255 if 30   // word could be 0..255 if
31   // interpreted as decimal 31   // interpreted as decimal
32   BOOST_URL_CXX20_CONSTEXPR_OR_INLINE 32   BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
33   bool 33   bool
HITCBC 34   61 maybe_octet( 34   61 maybe_octet(
35   unsigned char const* p) noexcept 35   unsigned char const* p) noexcept
36   { 36   {
HITCBC 37   61 unsigned short word = 37   61 unsigned short word =
38   static_cast<unsigned short>( 38   static_cast<unsigned short>(
HITCBC 39   61 p[0]) * 256 + 39   61 p[0]) * 256 +
40   static_cast<unsigned short>( 40   static_cast<unsigned short>(
HITCBC 41   61 p[1]); 41   61 p[1]);
HITCBC 42   61 if(word > 0x255) 42   61 if(word > 0x255)
HITCBC 43   3 return false; 43   3 return false;
HITCBC 44   58 if(((word >> 4) & 0xf) > 9) 44   58 if(((word >> 4) & 0xf) > 9)
HITCBC 45   1 return false; 45   1 return false;
HITCBC 46   57 if((word & 0xf) > 9) 46   57 if((word & 0xf) > 9)
HITCBC 47   2 return false; 47   2 return false;
HITCBC 48   55 return true; 48   55 return true;
49   } 49   }
50   50  
51   } // detail 51   } // detail
52   52  
53   BOOST_URL_CXX20_CONSTEXPR_OR_INLINE 53   BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
54   auto 54   auto
HITCBC 55   352 implementation_defined::ipv6_address_rule_t:: 55   352 implementation_defined::ipv6_address_rule_t::
56   parse( 56   parse(
57   char const*& it, 57   char const*& it,
58   char const* const end 58   char const* const end
59   ) const noexcept -> 59   ) const noexcept ->
60   system::result<ipv6_address> 60   system::result<ipv6_address>
61   { 61   {
HITCBC 62   352 int n = 8; // words needed 62   352 int n = 8; // words needed
HITCBC 63   352 int b = -1; // value of n 63   352 int b = -1; // value of n
64   // when '::' seen 64   // when '::' seen
HITCBC 65   352 bool c = false; // need colon 65   352 bool c = false; // need colon
HITCBC 66   352 auto prev = it; 66   352 auto prev = it;
67   ipv6_address::bytes_type bytes; 67   ipv6_address::bytes_type bytes;
HITCBC 68   352 system::result<detail::h16_rule_t::value_type> rv; 68   352 system::result<detail::h16_rule_t::value_type> rv;
69   for(;;) 69   for(;;)
70   { 70   {
HITCBC 71   1760 if(it == end) 71   1760 if(it == end)
72   { 72   {
HITCBC 73   92 if(b != -1) 73   92 if(b != -1)
74   { 74   {
75   // end in "::" 75   // end in "::"
HITCBC 76   86 break; 76   86 break;
77   } 77   }
HITCBC 78   6 BOOST_ASSERT(n > 0); 78   6 BOOST_ASSERT(n > 0);
79   // not enough words 79   // not enough words
HITCBC 80   6 BOOST_URL_CONSTEXPR_RETURN_EC( 80   6 BOOST_URL_CONSTEXPR_RETURN_EC(
81   grammar::error::invalid); 81   grammar::error::invalid);
82   } 82   }
HITCBC 83   1668 if(*it == ':') 83   1668 if(*it == ':')
84   { 84   {
HITCBC 85   1135 ++it; 85   1135 ++it;
HITCBC 86   1135 if(it == end) 86   1135 if(it == end)
87   { 87   {
88   // expected ':' 88   // expected ':'
HITCBC 89   5 BOOST_URL_CONSTEXPR_RETURN_EC( 89   5 BOOST_URL_CONSTEXPR_RETURN_EC(
90   grammar::error::invalid); 90   grammar::error::invalid);
91   } 91   }
HITCBC 92   1130 if(*it == ':') 92   1130 if(*it == ':')
93   { 93   {
HITCBC 94   210 if(b == -1) 94   210 if(b == -1)
95   { 95   {
96   // first "::" 96   // first "::"
HITCBC 97   207 ++it; 97   207 ++it;
HITCBC 98   207 --n; 98   207 --n;
HITCBC 99   207 b = n; 99   207 b = n;
HITCBC 100   207 if(n == 0) 100   207 if(n == 0)
HITCBC 101   2 break; 101   2 break;
HITCBC 102   205 c = false; 102   205 c = false;
HITCBC 103   205 continue; 103   205 continue;
104   } 104   }
105   // extra "::" found 105   // extra "::" found
HITCBC 106   3 BOOST_URL_CONSTEXPR_RETURN_EC( 106   3 BOOST_URL_CONSTEXPR_RETURN_EC(
107   grammar::error::invalid); 107   grammar::error::invalid);
108   } 108   }
HITCBC 109   920 if(c) 109   920 if(c)
110   { 110   {
HITCBC 111   914 prev = it; 111   914 prev = it;
HITCBC 112   914 rv = grammar::parse( 112   914 rv = grammar::parse(
113   it, end, 113   it, end,
114   detail::h16_rule); 114   detail::h16_rule);
HITCBC 115   914 if(! rv) 115   914 if(! rv)
HITCBC 116   5 return rv.error(); 116   5 return rv.error();
HITCBC 117   909 bytes[2*(8-n)+0] = rv->hi; 117   909 bytes[2*(8-n)+0] = rv->hi;
HITCBC 118   909 bytes[2*(8-n)+1] = rv->lo; 118   909 bytes[2*(8-n)+1] = rv->lo;
HITCBC 119   909 --n; 119   909 --n;
HITCBC 120   909 if(n == 0) 120   909 if(n == 0)
HITCBC 121   96 break; 121   96 break;
HITCBC 122   813 continue; 122   813 continue;
123   } 123   }
124   // expected h16 124   // expected h16
HITCBC 125   6 BOOST_URL_CONSTEXPR_RETURN_EC( 125   6 BOOST_URL_CONSTEXPR_RETURN_EC(
126   grammar::error::invalid); 126   grammar::error::invalid);
127   } 127   }
HITCBC 128   533 if(*it == '.') 128   533 if(*it == '.')
129   { 129   {
HITCBC 130   81 if(b == -1 && n > 1) 130   81 if(b == -1 && n > 1)
131   { 131   {
132   // not enough h16 132   // not enough h16
HITCBC 133   11 BOOST_URL_CONSTEXPR_RETURN_EC( 133   11 BOOST_URL_CONSTEXPR_RETURN_EC(
134   grammar::error::invalid); 134   grammar::error::invalid);
135   } 135   }
HITCBC 136   70 if(! c) 136   70 if(! c)
137   { 137   {
138   // missing h16 before "." 138   // missing h16 before "."
HITCBC 139   9 BOOST_URL_CONSTEXPR_RETURN_EC( 139   9 BOOST_URL_CONSTEXPR_RETURN_EC(
140   grammar::error::invalid); 140   grammar::error::invalid);
141   } 141   }
HITCBC 142   61 if(! detail::maybe_octet( 142   61 if(! detail::maybe_octet(
HITCBC 143   61 &bytes[2*(7-n)])) 143   61 &bytes[2*(7-n)]))
144   { 144   {
145   // invalid octet 145   // invalid octet
HITCBC 146   6 BOOST_URL_CONSTEXPR_RETURN_EC( 146   6 BOOST_URL_CONSTEXPR_RETURN_EC(
147   grammar::error::invalid); 147   grammar::error::invalid);
148   } 148   }
149   // rewind the h16 and 149   // rewind the h16 and
150   // parse it as ipv4 150   // parse it as ipv4
HITCBC 151   55 it = prev; 151   55 it = prev;
HITCBC 152   55 auto rv1 = grammar::parse( 152   55 auto rv1 = grammar::parse(
153   it, end, ipv4_address_rule); 153   it, end, ipv4_address_rule);
HITCBC 154   55 if(! rv1) 154   55 if(! rv1)
HITCBC 155   22 return rv1.error(); 155   22 return rv1.error();
HITCBC 156   33 auto v4 = *rv1; 156   33 auto v4 = *rv1;
157   auto const b4 = 157   auto const b4 =
HITCBC 158   33 v4.to_bytes(); 158   33 v4.to_bytes();
HITCBC 159   33 bytes[2*(7-n)+0] = b4[0]; 159   33 bytes[2*(7-n)+0] = b4[0];
HITCBC 160   33 bytes[2*(7-n)+1] = b4[1]; 160   33 bytes[2*(7-n)+1] = b4[1];
HITCBC 161   33 bytes[2*(7-n)+2] = b4[2]; 161   33 bytes[2*(7-n)+2] = b4[2];
HITCBC 162   33 bytes[2*(7-n)+3] = b4[3]; 162   33 bytes[2*(7-n)+3] = b4[3];
HITCBC 163   33 --n; 163   33 --n;
HITCBC 164   33 break; 164   33 break;
165   } 165   }
166   auto d = 166   auto d =
HITCBC 167   452 grammar::hexdig_value(*it); 167   452 grammar::hexdig_value(*it);
HITCBC 168   452 if( b != -1 && 168   452 if( b != -1 &&
169   d < 0) 169   d < 0)
170   { 170   {
171   // ends in "::" 171   // ends in "::"
HITCBC 172   41 break; 172   41 break;
173   } 173   }
HITCBC 174   411 if(! c) 174   411 if(! c)
175   { 175   {
HITCBC 176   407 prev = it; 176   407 prev = it;
HITCBC 177   407 rv = grammar::parse( 177   407 rv = grammar::parse(
178   it, end, 178   it, end,
179   detail::h16_rule); 179   detail::h16_rule);
HITCBC 180   407 if(! rv) 180   407 if(! rv)
HITCBC 181   16 return rv.error(); 181   16 return rv.error();
HITCBC 182   391 bytes[2*(8-n)+0] = rv->hi; 182   391 bytes[2*(8-n)+0] = rv->hi;
HITCBC 183   391 bytes[2*(8-n)+1] = rv->lo; 183   391 bytes[2*(8-n)+1] = rv->lo;
HITCBC 184   391 --n; 184   391 --n;
HITCBC 185   391 if(n == 0) 185   391 if(n == 0)
HITCBC 186   1 break; 186   1 break;
HITCBC 187   390 c = true; 187   390 c = true;
HITCBC 188   390 continue; 188   390 continue;
189   } 189   }
190   // ':' divides a word 190   // ':' divides a word
HITCBC 191   4 BOOST_URL_CONSTEXPR_RETURN_EC( 191   4 BOOST_URL_CONSTEXPR_RETURN_EC(
192   grammar::error::invalid); 192   grammar::error::invalid);
HITCBC 193   1408 } 193   1408 }
HITCBC 194   259 if(b == -1) 194   259 if(b == -1)
HITCBC 195   95 return ipv6_address{bytes}; 195   95 return ipv6_address{bytes};
HITCBC 196   164 if(b == n) 196   164 if(b == n)
197   { 197   {
198   // "::" last 198   // "::" last
HITCBC 199   35 auto const i = 199   35 auto const i =
HITCBC 200   35 2 * (7 - n); 200   35 2 * (7 - n);
HITCBC 201   35 std::memset( 201   35 std::memset(
HITCBC 202   35 &bytes[i], 202   35 &bytes[i],
HITCBC 203   35 0, 16 - i); 203   35 0, 16 - i);
204   } 204   }
HITCBC 205   129 else if(b == 7) 205   129 else if(b == 7)
206   { 206   {
207   // "::" first 207   // "::" first
HITCBC 208   52 auto const i = 208   52 auto const i =
HITCBC 209   52 2 * (b - n); 209   52 2 * (b - n);
HITCBC 210   104 std::memmove( 210   104 std::memmove(
HITCBC 211   52 &bytes[16 - i], 211   52 &bytes[16 - i],
HITCBC 212   52 &bytes[2], 212   52 &bytes[2],
213   i); 213   i);
HITCBC 214   52 std::memset( 214   52 std::memset(
HITCBC 215   52 &bytes[0], 215   52 &bytes[0],
HITCBC 216   52 0, 16 - i); 216   52 0, 16 - i);
217   } 217   }
218   else 218   else
219   { 219   {
220   // "::" in middle 220   // "::" in middle
HITCBC 221   77 auto const i0 = 221   77 auto const i0 =
HITCBC 222   77 2 * (7 - b); 222   77 2 * (7 - b);
HITCBC 223   77 auto const i1 = 223   77 auto const i1 =
HITCBC 224   77 2 * (b - n); 224   77 2 * (b - n);
HITCBC 225   154 std::memmove( 225   154 std::memmove(
HITCBC 226   77 &bytes[16 - i1], 226   77 &bytes[16 - i1],
HITCBC 227   77 &bytes[i0 + 2], 227   77 &bytes[i0 + 2],
228   i1); 228   i1);
HITCBC 229   77 std::memset( 229   77 std::memset(
HITCBC 230   77 &bytes[i0], 230   77 &bytes[i0],
HITCBC 231   77 0, 16 - (i0 + i1)); 231   77 0, 16 - (i0 + i1));
232   } 232   }
HITCBC 233   164 return ipv6_address{bytes}; 233   164 return ipv6_address{bytes};
234   } 234   }
235   235  
236   } // urls 236   } // urls
237   } // boost 237   } // boost
238   238  
239   239  
240   #endif 240   #endif