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

Generated by: LCOV version 2.3