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