LCOV - code coverage report
Current view: top level - url/impl - encode.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 100.0 % 112 112
Test Date: 2026-03-02 22:26:03 Functions: 66.7 % 54 36 18

           TLA  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_ENCODE_HPP
      11                 : #define BOOST_URL_IMPL_ENCODE_HPP
      12                 : 
      13                 : #include <boost/url/grammar/token_rule.hpp>
      14                 : #include <boost/assert.hpp>
      15                 : #include <boost/core/detail/static_assert.hpp>
      16                 : #include <boost/url/detail/encode.hpp>
      17                 : #include <boost/url/detail/except.hpp>
      18                 : #include <boost/url/encoding_opts.hpp>
      19                 : #include <boost/url/grammar/charset.hpp>
      20                 : #include <boost/url/grammar/hexdig_chars.hpp>
      21                 : #include <boost/url/grammar/string_token.hpp>
      22                 : #include <boost/url/grammar/type_traits.hpp>
      23                 : 
      24                 : namespace boost {
      25                 : namespace urls {
      26                 : 
      27                 : //------------------------------------------------
      28                 : 
      29                 : template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
      30                 : std::size_t
      31 HIT        5523 : encoded_size(
      32                 :     core::string_view s,
      33                 :     CS const& allowed,
      34                 :     encoding_opts opt) noexcept
      35                 : {
      36                 :     /*
      37                 :         If you get a compilation error here, it
      38                 :         means that the value you passed does
      39                 :         not meet the requirements stated in
      40                 :         the documentation.
      41                 :     */
      42                 :     BOOST_CORE_STATIC_ASSERT(
      43                 :         grammar::is_charset<CS>::value);
      44                 : 
      45            5523 :     std::size_t n = 0;
      46            5523 :     auto it = s.data();
      47            5523 :     auto const last = it + s.size();
      48                 : 
      49            5523 :     if (!opt.space_as_plus)
      50                 :     {
      51           25592 :         while (it != last)
      52                 :         {
      53           22571 :             char const c = *it;
      54           22571 :             if (allowed(c))
      55                 :             {
      56           19533 :                 ++n;
      57                 :             }
      58                 :             else
      59                 :             {
      60            3038 :                 n += 3;
      61                 :             }
      62           22571 :             ++it;
      63                 :         }
      64                 :     }
      65                 :     else
      66                 :     {
      67                 :         // '+' is always encoded (thus
      68                 :         // spending 3 chars) even if
      69                 :         // allowed because "%2B" and
      70                 :         // "+" have different meanings
      71                 :         // when space as plus is enabled
      72                 :         using FNT = bool (*)(CS const& allowed, char);
      73            2502 :         FNT takes_one_char =
      74            5004 :             allowed('+') ?
      75            2500 :                 (allowed(' ') ?
      76               4 :                      FNT([](CS const& allowed, char c){ return allowed(c) && c != '+'; }) :
      77           22612 :                      FNT([](CS const& allowed, char c){ return (allowed(c) || c == ' ') && c != '+'; })) :
      78               2 :                 (allowed(' ') ?
      79               4 :                      FNT([](CS const& allowed, char c){ return allowed(c); }) :
      80               4 :                      FNT([](CS const& allowed, char c){ return allowed(c) || c == ' '; }));
      81           22624 :         while (it != last)
      82                 :         {
      83           20122 :             char const c = *it;
      84           20122 :             if (takes_one_char(allowed, c))
      85                 :             {
      86           16975 :                 ++n;
      87                 :             }
      88                 :             else
      89                 :             {
      90            3147 :                 n += 3;
      91                 :             }
      92           20122 :             ++it;
      93                 :         }
      94                 :     }
      95            5523 :     return n;
      96                 : }
      97                 : 
      98                 : //------------------------------------------------
      99                 : 
     100                 : template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
     101                 : std::size_t
     102           21818 : encode(
     103                 :     char* dest,
     104                 :     std::size_t size,
     105                 :     core::string_view s,
     106                 :     CS const& allowed,
     107                 :     encoding_opts opt)
     108                 : {
     109                 : /*  If you get a compilation error here, it
     110                 :     means that the value you passed does
     111                 :     not meet the requirements stated in
     112                 :     the documentation.
     113                 : */
     114                 :     BOOST_CORE_STATIC_ASSERT(
     115                 :         grammar::is_charset<CS>::value);
     116                 : 
     117                 :     // '%' must be reserved
     118           21818 :     BOOST_ASSERT(!allowed('%'));
     119                 : 
     120           21818 :     char const* const hex =
     121           21818 :         detail::hexdigs[opt.lower_case];
     122          266468 :     auto const encode = [hex](
     123                 :         char*& dest,
     124                 :         unsigned char c) noexcept
     125                 :     {
     126          244650 :         *dest++ = '%';
     127          244650 :         *dest++ = hex[c>>4];
     128          244650 :         *dest++ = hex[c&0xf];
     129                 :     };
     130                 : 
     131           21818 :     auto it = s.data();
     132           21818 :     auto const end = dest + size;
     133           21818 :     auto const last = it + s.size();
     134           21818 :     auto const dest0 = dest;
     135                 : 
     136           21818 :     if (!opt.space_as_plus)
     137                 :     {
     138         1303128 :         while(it != last)
     139                 :         {
     140         1294002 :             char const c = *it;
     141         1294002 :             if (allowed(c))
     142                 :             {
     143         1048403 :                 if(dest == end)
     144            6102 :                     return dest - dest0;
     145         1042301 :                 *dest++ = c;
     146         1042301 :                 ++it;
     147         1042301 :                 continue;
     148                 :             }
     149          245599 :             if (end - dest < 3)
     150            4088 :                 return dest - dest0;
     151          241511 :             encode(dest, c);
     152          241511 :             ++it;
     153                 :         }
     154            9126 :         return dest - dest0;
     155                 :     }
     156                 :     else
     157                 :     {
     158           22594 :         while (it != last)
     159                 :         {
     160           20106 :             char const c = *it;
     161           20106 :             if (c == ' ')
     162                 :             {
     163             262 :                 if(dest == end)
     164               2 :                     return dest - dest0;
     165             260 :                 *dest++ = '+';
     166             260 :                 ++it;
     167             260 :                 continue;
     168                 :             }
     169           36537 :             else if (
     170           19844 :                 allowed(c) &&
     171                 :                 c != '+')
     172                 :             {
     173           16696 :                 if(dest == end)
     174               3 :                     return dest - dest0;
     175           16693 :                 *dest++ = c;
     176           16693 :                 ++it;
     177           16693 :                 continue;
     178                 :             }
     179            3148 :             if(end - dest < 3)
     180               9 :                 return dest - dest0;
     181            3139 :             encode(dest, c);
     182            3139 :             ++it;
     183                 :         }
     184                 :     }
     185            2488 :     return dest - dest0;
     186                 : }
     187                 : 
     188                 : //------------------------------------------------
     189                 : 
     190                 : // unsafe encode just
     191                 : // asserts on the output buffer
     192                 : //
     193                 : template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
     194                 : std::size_t
     195            1569 : encode_unsafe(
     196                 :     char* dest,
     197                 :     std::size_t size,
     198                 :     core::string_view s,
     199                 :     CS const& allowed,
     200                 :     encoding_opts opt)
     201                 : {
     202                 :     BOOST_CORE_STATIC_ASSERT(
     203                 :         grammar::is_charset<CS>::value);
     204                 : 
     205                 :     // '%' must be reserved
     206            1569 :     BOOST_ASSERT(!allowed('%'));
     207                 : 
     208            1569 :     auto it = s.data();
     209            1569 :     auto const last = it + s.size();
     210            1569 :     auto const end = dest + size;
     211                 :     ignore_unused(end);
     212                 : 
     213            1569 :     char const* const hex =
     214            1569 :         detail::hexdigs[opt.lower_case];
     215            2955 :     auto const encode = [end, hex](
     216                 :         char*& dest,
     217                 :         unsigned char c) noexcept
     218                 :     {
     219             693 :         ignore_unused(end);
     220             693 :         *dest++ = '%';
     221             693 :         BOOST_ASSERT(dest != end);
     222             693 :         *dest++ = hex[c>>4];
     223             693 :         BOOST_ASSERT(dest != end);
     224             693 :         *dest++ = hex[c&0xf];
     225                 :     };
     226                 : 
     227            1569 :     auto const dest0 = dest;
     228            1569 :     if (!opt.space_as_plus)
     229                 :     {
     230            8140 :         while(it != last)
     231                 :         {
     232            6584 :             BOOST_ASSERT(dest != end);
     233            6584 :             char const c = *it;
     234            6584 :             if(allowed(c))
     235                 :             {
     236            5899 :                 *dest++ = c;
     237                 :             }
     238                 :             else
     239                 :             {
     240             685 :                 encode(dest, c);
     241                 :             }
     242            6584 :             ++it;
     243                 :         }
     244                 :     }
     245                 :     else
     246                 :     {
     247              53 :         while(it != last)
     248                 :         {
     249              40 :             BOOST_ASSERT(dest != end);
     250              40 :             char const c = *it;
     251              40 :             if (c == ' ')
     252                 :             {
     253               9 :                 *dest++ = '+';
     254                 :             }
     255              31 :             else if (
     256              31 :                 allowed(c) &&
     257                 :                 c != '+')
     258                 :             {
     259              23 :                 *dest++ = c;
     260                 :             }
     261                 :             else
     262                 :             {
     263               8 :                 encode(dest, c);
     264                 :             }
     265              40 :             ++it;
     266                 :         }
     267                 :     }
     268            1569 :     return dest - dest0;
     269                 : }
     270                 : 
     271                 : //------------------------------------------------
     272                 : 
     273                 : template<
     274                 :     BOOST_URL_CONSTRAINT(string_token::StringToken) StringToken,
     275                 :     BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
     276                 : BOOST_URL_STRTOK_RETURN
     277              28 : encode(
     278                 :     core::string_view s,
     279                 :     CS const& allowed,
     280                 :     encoding_opts opt,
     281                 :     StringToken&& token)
     282                 : {
     283                 :     BOOST_CORE_STATIC_ASSERT(
     284                 :         grammar::is_charset<CS>::value);
     285                 : 
     286              28 :     auto const n = encoded_size(
     287                 :         s, allowed, opt);
     288              28 :     auto p = token.prepare(n);
     289              28 :     if(n > 0)
     290              26 :         encode_unsafe(
     291                 :             p, n, s, allowed, opt);
     292              28 :     return token.result();
     293                 : }
     294                 : 
     295                 : } // urls
     296                 : } // boost
     297                 : 
     298                 : #endif
        

Generated by: LCOV version 2.3