LCOV - code coverage report
Current view: top level - libs/url/src/rfc/ipv6_address_rule.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 111 111
Test Date: 2024-08-19 20:08:54 Functions: 100.0 % 2 2

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

Generated by: LCOV version 2.1