LCOV - code coverage report
Current view: top level - libs/url/src - ipv6_address.cpp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 125 125 100.0 %
Date: 2024-03-08 17:32:04 Functions: 13 13 100.0 %

          Line data    Source code
       1             : //
       2             : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
       3             : //
       4             : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5             : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6             : //
       7             : // Official repository: https://github.com/boostorg/url
       8             : //
       9             : 
      10             : 
      11             : #include <boost/url/detail/config.hpp>
      12             : #include <boost/url/ipv6_address.hpp>
      13             : #include <boost/url/ipv4_address.hpp>
      14             : #include <boost/url/rfc/ipv6_address_rule.hpp>
      15             : #include <boost/url/detail/except.hpp>
      16             : #include <boost/url/grammar/parse.hpp>
      17             : #include <cstring>
      18             : 
      19             : namespace boost {
      20             : namespace urls {
      21             : 
      22         210 : ipv6_address::
      23             : ipv6_address(
      24         210 :     bytes_type const& bytes) noexcept
      25             : {
      26         210 :     std::memcpy(&addr_,
      27         210 :         bytes.data(), 16);
      28         210 : }
      29             : 
      30           4 : ipv6_address::
      31             : ipv6_address(
      32           4 :     ipv4_address const& addr) noexcept
      33             : {
      34           4 :     auto const v = addr.to_bytes();
      35           4 :     ipv6_address::bytes_type bytes = {
      36             :     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      37           4 :       0xff, 0xff, v[0], v[1], v[2], v[3] } };
      38           4 :     std::memcpy(&addr_, bytes.data(), 16);
      39           4 : }
      40             : 
      41          58 : ipv6_address::
      42             : ipv6_address(
      43          58 :     core::string_view s)
      44             :     : ipv6_address(
      45          58 :         parse_ipv6_address(s
      46          58 :             ).value(BOOST_URL_POS))
      47             : {
      48          57 : }
      49             : 
      50             : core::string_view
      51          14 : ipv6_address::
      52             : to_buffer(
      53             :     char* dest,
      54             :     std::size_t dest_size) const
      55             : {
      56          14 :     if(dest_size < max_str_len)
      57           1 :         detail::throw_length_error();
      58          13 :     auto n = print_impl(dest);
      59          13 :     return core::string_view(dest, n);
      60             : }
      61             : 
      62             : bool
      63           3 : ipv6_address::
      64             : is_loopback() const noexcept
      65             : {
      66           3 :     return *this == loopback();
      67             : }
      68             : 
      69             : bool
      70           3 : ipv6_address::
      71             : is_unspecified() const noexcept
      72             : {
      73           3 :     return *this == ipv6_address();
      74             : }
      75             : 
      76             : bool
      77          56 : ipv6_address::
      78             : is_v4_mapped() const noexcept
      79             : {
      80             :     return
      81         103 :         addr_[ 0] == 0 && addr_[ 1] == 0 &&
      82          31 :         addr_[ 2] == 0 && addr_[ 3] == 0 &&
      83          29 :         addr_[ 4] == 0 && addr_[ 5] == 0 &&
      84          27 :         addr_[ 6] == 0 && addr_[ 7] == 0 &&
      85          25 :         addr_[ 8] == 0 && addr_[ 9] == 0 &&
      86         115 :         addr_[10] == 0xff &&
      87          68 :         addr_[11] == 0xff;
      88             : }
      89             : 
      90             : ipv6_address
      91           5 : ipv6_address::
      92             : loopback() noexcept
      93             : {
      94           5 :     ipv6_address a;
      95           5 :     a.addr_[15] = 1;
      96           5 :     return a;
      97             : }
      98             : 
      99             : std::size_t
     100          51 : ipv6_address::
     101             : print_impl(
     102             :     char* dest) const noexcept
     103             : {
     104             :     auto const count_zeroes =
     105         169 :     []( unsigned char const* first,
     106             :         unsigned char const* const last)
     107             :     {
     108         169 :         std::size_t n = 0;
     109         448 :         while(first != last)
     110             :         {
     111         425 :             if( first[0] != 0 ||
     112         364 :                 first[1] != 0)
     113             :                 break;
     114         279 :             n += 2;
     115         279 :             first += 2;
     116             :         }
     117         169 :         return n;
     118             :     };
     119             :     auto const print_hex =
     120         135 :     []( char* dest,
     121             :         unsigned short v)
     122             :     {
     123         135 :         char const* const dig =
     124             :             "0123456789abcdef";
     125         135 :         if(v >= 0x1000)
     126             :         {
     127          48 :             *dest++ = dig[v>>12];
     128          48 :             v &= 0x0fff;
     129          48 :             *dest++ = dig[v>>8];
     130          48 :             v &= 0x0ff;
     131          48 :             *dest++ = dig[v>>4];
     132          48 :             v &= 0x0f;
     133          48 :             *dest++ = dig[v];
     134             :         }
     135          87 :         else if(v >= 0x100)
     136             :         {
     137           2 :             *dest++ = dig[v>>8];
     138           2 :             v &= 0x0ff;
     139           2 :             *dest++ = dig[v>>4];
     140           2 :             v &= 0x0f;
     141           2 :             *dest++ = dig[v];
     142             :         }
     143          85 :         else if(v >= 0x10)
     144             :         {
     145           1 :             *dest++ = dig[v>>4];
     146           1 :             v &= 0x0f;
     147           1 :             *dest++ = dig[v];
     148             :         }
     149             :         else
     150             :         {
     151          84 :             *dest++ = dig[v];
     152             :         }
     153         135 :         return dest;
     154             :     };
     155          51 :     auto const dest0 = dest;
     156             :     // find longest run of zeroes
     157          51 :     std::size_t best_len = 0;
     158          51 :     int best_pos = -1;
     159          51 :     auto it = addr_.data();
     160             :     auto const v4 =
     161          51 :         is_v4_mapped();
     162          93 :     auto const end = v4 ?
     163           9 :         (it + addr_.size() - 4)
     164          93 :         : it + addr_.size();
     165         220 :     while(it != end)
     166             :     {
     167         169 :         auto n = count_zeroes(
     168             :             it, end);
     169         169 :         if(n == 0)
     170             :         {
     171         111 :             it += 2;
     172         111 :             continue;
     173             :         }
     174          58 :         if(n > best_len)
     175             :         {
     176          52 :             best_pos = static_cast<
     177          52 :                 int>(it - addr_.data());
     178          52 :             best_len = n;
     179             :         }
     180          58 :         it += n;
     181             :     }
     182          51 :     it = addr_.data();
     183          51 :     if(best_pos != 0)
     184             :     {
     185          30 :         unsigned short v =
     186          30 :             (it[0] * 256U) + it[1];
     187          30 :         dest = print_hex(dest, v);
     188          30 :         it += 2;
     189             :     }
     190             :     else
     191             :     {
     192          21 :         *dest++ = ':';
     193          21 :         it += best_len;
     194          21 :         if(it == end)
     195           2 :             *dest++ = ':';
     196             :     }
     197         181 :     while(it != end)
     198             :     {
     199         130 :         *dest++ = ':';
     200         130 :         if(it - addr_.data() ==
     201         130 :             best_pos)
     202             :         {
     203          25 :             it += best_len;
     204          25 :             if(it == end)
     205          15 :                 *dest++ = ':';
     206          25 :             continue;
     207             :         }
     208         105 :         unsigned short v =
     209         105 :             (it[0] * 256U) + it[1];
     210         105 :         dest = print_hex(dest, v);
     211         105 :         it += 2;
     212             :     }
     213          51 :     if(v4)
     214             :     {
     215             :         ipv4_address::bytes_type bytes;
     216           9 :         bytes[0] = it[0];
     217           9 :         bytes[1] = it[1];
     218           9 :         bytes[2] = it[2];
     219           9 :         bytes[3] = it[3];
     220           9 :         ipv4_address a(bytes);
     221           9 :         *dest++ = ':';
     222           9 :         dest += a.print_impl(dest);
     223             :     }
     224          51 :     return dest - dest0;
     225             : }
     226             : 
     227             : void
     228          38 : ipv6_address::
     229             : to_string_impl(
     230             :     string_token::arg& t) const
     231             : {
     232             :     char buf[max_str_len];
     233          38 :     auto const n = print_impl(buf);
     234          38 :     char* dest = t.prepare(n);
     235          38 :     std::memcpy(dest, buf, n);
     236          38 : }
     237             : 
     238             : //------------------------------------------------
     239             : 
     240             : auto
     241         204 : parse_ipv6_address(
     242             :     core::string_view s) noexcept ->
     243             :         system::result<ipv6_address>
     244             : {
     245             :     return grammar::parse(
     246         204 :         s, ipv6_address_rule);
     247             : }
     248             : 
     249             : } // urls
     250             : } // boost
     251             : 

Generated by: LCOV version 1.15