LCOV - code coverage report
Current view: top level - libs/url/src/ipv6_address.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 126 126
Test Date: 2024-08-20 16:05:53 Functions: 100.0 % 13 13

            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           42 :         : 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          204 :     return grammar::parse(
     246          204 :         s, ipv6_address_rule);
     247              : }
     248              : 
     249              : } // urls
     250              : } // boost
     251              : 
        

Generated by: LCOV version 2.1