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   65 maybe_octet( 34   61 maybe_octet(
35   unsigned char const* p) noexcept 35   unsigned char const* p) noexcept
36   { 36   {
HITCBC 37   65 unsigned short word = 37   61 unsigned short word =
38   static_cast<unsigned short>( 38   static_cast<unsigned short>(
HITCBC 39   65 p[0]) * 256 + 39   61 p[0]) * 256 +
40   static_cast<unsigned short>( 40   static_cast<unsigned short>(
HITCBC 41   65 p[1]); 41   61 p[1]);
HITCBC 42   65 if(word > 0x255) 42   61 if(word > 0x255)
HITCBC 43   7 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   346 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   346 int n = 8; // words needed 62   352 int n = 8; // words needed
HITCBC 63   346 int b = -1; // value of n 63   352 int b = -1; // value of n
64   // when '::' seen 64   // when '::' seen
HITCBC 65   346 bool c = false; // need colon 65   352 bool c = false; // need colon
HITCBC 66   346 auto prev = it; 66   352 auto prev = it;
67   ipv6_address::bytes_type bytes; 67   ipv6_address::bytes_type bytes;
HITCBC 68   346 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   1746 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   1654 if(*it == ':') 83   1668 if(*it == ':')
84   { 84   {
HITCBC 85   1129 ++it; 85   1135 ++it;
HITCBC 86   1129 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   1124 if(*it == ':') 92   1130 if(*it == ':')
93   { 93   {
HITCBC 94   205 if(b == -1) 94   210 if(b == -1)
95   { 95   {
96   // first "::" 96   // first "::"
HITCBC 97   202 ++it; 97   207 ++it;
HITCBC 98   202 --n; 98   207 --n;
HITCBC 99   202 b = n; 99   207 b = n;
HITCBC 100   202 if(n == 0) 100   207 if(n == 0)
HITCBC 101   2 break; 101   2 break;
HITCBC 102   200 c = false; 102   205 c = false;
HITCBC 103   200 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   919 if(c) 109   920 if(c)
110   { 110   {
HITCBC 111   913 prev = it; 111   914 prev = it;
HITCBC 112   913 rv = grammar::parse( 112   914 rv = grammar::parse(
113   it, end, 113   it, end,
114   detail::h16_rule); 114   detail::h16_rule);
HITCBC 115   913 if(! rv) 115   914 if(! rv)
HITCBC 116   5 return rv.error(); 116   5 return rv.error();
HITCBC 117   908 bytes[2*(8-n)+0] = rv->hi; 117   909 bytes[2*(8-n)+0] = rv->hi;
HITCBC 118   908 bytes[2*(8-n)+1] = rv->lo; 118   909 bytes[2*(8-n)+1] = rv->lo;
HITCBC 119   908 --n; 119   909 --n;
HITCBC 120   908 if(n == 0) 120   909 if(n == 0)
HITCBC 121   96 break; 121   96 break;
HITCBC 122   812 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   525 if(*it == '.') 128   533 if(*it == '.')
129   { 129   {
HITCBC 130   75 if(b == -1 && n > 1) 130   81 if(b == -1 && n > 1)
131   { 131   {
132   // not enough h16 132   // not enough h16
HITCBC 133   10 BOOST_URL_CONSTEXPR_RETURN_EC( 133   11 BOOST_URL_CONSTEXPR_RETURN_EC(
134   grammar::error::invalid); 134   grammar::error::invalid);
135   } 135   }
HITGNC   136 + 70 if(! c)
  137 + {
  138 + // missing h16 before "."
HITGNC   139 + 9 BOOST_URL_CONSTEXPR_RETURN_EC(
  140 + grammar::error::invalid);
  141 + }
HITCBC 136   65 if(! detail::maybe_octet( 142   61 if(! detail::maybe_octet(
HITCBC 137   65 &bytes[2*(7-n)])) 143   61 &bytes[2*(7-n)]))
138   { 144   {
139   // invalid octet 145   // invalid octet
HITCBC 140   10 BOOST_URL_CONSTEXPR_RETURN_EC( 146   6 BOOST_URL_CONSTEXPR_RETURN_EC(
141   grammar::error::invalid); 147   grammar::error::invalid);
142   } 148   }
143   // rewind the h16 and 149   // rewind the h16 and
144   // parse it as ipv4 150   // parse it as ipv4
HITCBC 145   55 it = prev; 151   55 it = prev;
HITCBC 146   55 auto rv1 = grammar::parse( 152   55 auto rv1 = grammar::parse(
147   it, end, ipv4_address_rule); 153   it, end, ipv4_address_rule);
HITCBC 148   55 if(! rv1) 154   55 if(! rv1)
HITCBC 149   22 return rv1.error(); 155   22 return rv1.error();
HITCBC 150   33 auto v4 = *rv1; 156   33 auto v4 = *rv1;
151   auto const b4 = 157   auto const b4 =
HITCBC 152   33 v4.to_bytes(); 158   33 v4.to_bytes();
HITCBC 153   33 bytes[2*(7-n)+0] = b4[0]; 159   33 bytes[2*(7-n)+0] = b4[0];
HITCBC 154   33 bytes[2*(7-n)+1] = b4[1]; 160   33 bytes[2*(7-n)+1] = b4[1];
HITCBC 155   33 bytes[2*(7-n)+2] = b4[2]; 161   33 bytes[2*(7-n)+2] = b4[2];
HITCBC 156   33 bytes[2*(7-n)+3] = b4[3]; 162   33 bytes[2*(7-n)+3] = b4[3];
HITCBC 157   33 --n; 163   33 --n;
HITCBC 158   33 break; 164   33 break;
159   } 165   }
160   auto d = 166   auto d =
HITCBC 161   450 grammar::hexdig_value(*it); 167   452 grammar::hexdig_value(*it);
HITCBC 162   450 if( b != -1 && 168   452 if( b != -1 &&
163   d < 0) 169   d < 0)
164   { 170   {
165   // ends in "::" 171   // ends in "::"
HITCBC 166   41 break; 172   41 break;
167   } 173   }
HITCBC 168   409 if(! c) 174   411 if(! c)
169   { 175   {
HITCBC 170   405 prev = it; 176   407 prev = it;
HITCBC 171   405 rv = grammar::parse( 177   407 rv = grammar::parse(
172   it, end, 178   it, end,
173   detail::h16_rule); 179   detail::h16_rule);
HITCBC 174   405 if(! rv) 180   407 if(! rv)
HITCBC 175   16 return rv.error(); 181   16 return rv.error();
HITCBC 176   389 bytes[2*(8-n)+0] = rv->hi; 182   391 bytes[2*(8-n)+0] = rv->hi;
HITCBC 177   389 bytes[2*(8-n)+1] = rv->lo; 183   391 bytes[2*(8-n)+1] = rv->lo;
HITCBC 178   389 --n; 184   391 --n;
HITCBC 179   389 if(n == 0) 185   391 if(n == 0)
HITCBC 180   1 break; 186   1 break;
HITCBC 181   388 c = true; 187   390 c = true;
HITCBC 182   388 continue; 188   390 continue;
183   } 189   }
184   // ':' divides a word 190   // ':' divides a word
HITCBC 185   4 BOOST_URL_CONSTEXPR_RETURN_EC( 191   4 BOOST_URL_CONSTEXPR_RETURN_EC(
186   grammar::error::invalid); 192   grammar::error::invalid);
HITCBC 187   1400 } 193   1408 }
HITCBC 188   259 if(b == -1) 194   259 if(b == -1)
HITCBC 189   95 return ipv6_address{bytes}; 195   95 return ipv6_address{bytes};
HITCBC 190   164 if(b == n) 196   164 if(b == n)
191   { 197   {
192   // "::" last 198   // "::" last
HITCBC 193   35 auto const i = 199   35 auto const i =
HITCBC 194   35 2 * (7 - n); 200   35 2 * (7 - n);
HITCBC 195   35 std::memset( 201   35 std::memset(
HITCBC 196   35 &bytes[i], 202   35 &bytes[i],
HITCBC 197   35 0, 16 - i); 203   35 0, 16 - i);
198   } 204   }
HITCBC 199   129 else if(b == 7) 205   129 else if(b == 7)
200   { 206   {
201   // "::" first 207   // "::" first
HITCBC 202   52 auto const i = 208   52 auto const i =
HITCBC 203   52 2 * (b - n); 209   52 2 * (b - n);
HITCBC 204   104 std::memmove( 210   104 std::memmove(
HITCBC 205   52 &bytes[16 - i], 211   52 &bytes[16 - i],
HITCBC 206   52 &bytes[2], 212   52 &bytes[2],
207   i); 213   i);
HITCBC 208   52 std::memset( 214   52 std::memset(
HITCBC 209   52 &bytes[0], 215   52 &bytes[0],
HITCBC 210   52 0, 16 - i); 216   52 0, 16 - i);
211   } 217   }
212   else 218   else
213   { 219   {
214   // "::" in middle 220   // "::" in middle
HITCBC 215   77 auto const i0 = 221   77 auto const i0 =
HITCBC 216   77 2 * (7 - b); 222   77 2 * (7 - b);
HITCBC 217   77 auto const i1 = 223   77 auto const i1 =
HITCBC 218   77 2 * (b - n); 224   77 2 * (b - n);
HITCBC 219   154 std::memmove( 225   154 std::memmove(
HITCBC 220   77 &bytes[16 - i1], 226   77 &bytes[16 - i1],
HITCBC 221   77 &bytes[i0 + 2], 227   77 &bytes[i0 + 2],
222   i1); 228   i1);
HITCBC 223   77 std::memset( 229   77 std::memset(
HITCBC 224   77 &bytes[i0], 230   77 &bytes[i0],
HITCBC 225   77 0, 16 - (i0 + i1)); 231   77 0, 16 - (i0 + i1));
226   } 232   }
HITCBC 227   164 return ipv6_address{bytes}; 233   164 return ipv6_address{bytes};
228   } 234   }
229   235  
230   } // urls 236   } // urls
231   } // boost 237   } // boost
232   238  
233   239  
234   #endif 240   #endif