LCOV - code coverage report
Current view: top level - url/rfc/impl - ipv6_address_rule.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 111 111
Test Date: 2026-02-25 21:00:01 Functions: 100.0 % 2 2

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

Generated by: LCOV version 2.3