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

Generated by: LCOV version 1.15