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 % 113 113
Test Date: 2026-02-25 21:00:01 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         929 : 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             929 :     std::size_t n = 0;
      46             929 :     auto it = s.data();
      47             929 :     auto const last = it + s.size();
      48                 : 
      49             929 :     if (!opt.space_as_plus)
      50                 :     {
      51            3754 :         while (it != last)
      52                 :         {
      53            3023 :             char const c = *it;
      54            3023 :             if (allowed(c))
      55                 :             {
      56            2894 :                 ++n;
      57                 :             }
      58                 :             else
      59                 :             {
      60             129 :                 n += 3;
      61                 :             }
      62            3023 :             ++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             198 :         FNT takes_one_char =
      74             396 :             allowed('+') ?
      75             196 :                 (allowed(' ') ?
      76               4 :                      FNT([](CS const& allowed, char c){ return allowed(c) && c != '+'; }) :
      77            1658 :                      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            1670 :         while (it != last)
      82                 :         {
      83            1472 :             char const c = *it;
      84            1472 :             if (takes_one_char(allowed, c))
      85                 :             {
      86            1426 :                 ++n;
      87                 :             }
      88                 :             else
      89                 :             {
      90              46 :                 n += 3;
      91                 :             }
      92            1472 :             ++it;
      93                 :         }
      94                 :     }
      95             929 :     return n;
      96                 : }
      97                 : 
      98                 : //------------------------------------------------
      99                 : 
     100                 : template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
     101                 : std::size_t
     102             570 : 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             570 :     BOOST_ASSERT(!allowed('%'));
     119                 : 
     120             570 :     char const* const hex =
     121             570 :         detail::hexdigs[opt.lower_case];
     122             686 :     auto const encode = [hex](
     123                 :         char*& dest,
     124                 :         unsigned char c) noexcept
     125                 :     {
     126             116 :         *dest++ = '%';
     127             116 :         *dest++ = hex[c>>4];
     128             116 :         *dest++ = hex[c&0xf];
     129                 :     };
     130                 : 
     131             570 :     auto it = s.data();
     132             570 :     auto const end = dest + size;
     133             570 :     auto const last = it + s.size();
     134             570 :     auto const dest0 = dest;
     135             570 :     auto const end3 = end - 3;
     136                 : 
     137             570 :     if (!opt.space_as_plus)
     138                 :     {
     139            1873 :         while(it != last)
     140                 :         {
     141            1519 :             char const c = *it;
     142            1519 :             if (allowed(c))
     143                 :             {
     144            1426 :                 if(dest == end)
     145               3 :                     return dest - dest0;
     146            1423 :                 *dest++ = c;
     147            1423 :                 ++it;
     148            1423 :                 continue;
     149                 :             }
     150              93 :             if (dest > end3)
     151              15 :                 return dest - dest0;
     152              78 :             encode(dest, c);
     153              78 :             ++it;
     154                 :         }
     155             354 :         return dest - dest0;
     156                 :     }
     157                 :     else
     158                 :     {
     159            1640 :         while (it != last)
     160                 :         {
     161            1456 :             char const c = *it;
     162            1456 :             if (c == ' ')
     163                 :             {
     164              27 :                 if(dest == end)
     165               2 :                     return dest - dest0;
     166              25 :                 *dest++ = '+';
     167              25 :                 ++it;
     168              25 :                 continue;
     169                 :             }
     170            2808 :             else if (
     171            1429 :                 allowed(c) &&
     172                 :                 c != '+')
     173                 :             {
     174            1382 :                 if(dest == end)
     175               3 :                     return dest - dest0;
     176            1379 :                 *dest++ = c;
     177            1379 :                 ++it;
     178            1379 :                 continue;
     179                 :             }
     180              47 :             if(dest > end3)
     181               9 :                 return dest - dest0;
     182              38 :             encode(dest, c);
     183              38 :             ++it;
     184                 :         }
     185                 :     }
     186             184 :     return dest - dest0;
     187                 : }
     188                 : 
     189                 : //------------------------------------------------
     190                 : 
     191                 : // unsafe encode just
     192                 : // asserts on the output buffer
     193                 : //
     194                 : template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
     195                 : std::size_t
     196             186 : encode_unsafe(
     197                 :     char* dest,
     198                 :     std::size_t size,
     199                 :     core::string_view s,
     200                 :     CS const& allowed,
     201                 :     encoding_opts opt)
     202                 : {
     203                 :     BOOST_CORE_STATIC_ASSERT(
     204                 :         grammar::is_charset<CS>::value);
     205                 : 
     206                 :     // '%' must be reserved
     207             186 :     BOOST_ASSERT(!allowed('%'));
     208                 : 
     209             186 :     auto it = s.data();
     210             186 :     auto const last = it + s.size();
     211             186 :     auto const end = dest + size;
     212                 :     ignore_unused(end);
     213                 : 
     214             186 :     char const* const hex =
     215             186 :         detail::hexdigs[opt.lower_case];
     216             292 :     auto const encode = [end, hex](
     217                 :         char*& dest,
     218                 :         unsigned char c) noexcept
     219                 :     {
     220              53 :         ignore_unused(end);
     221              53 :         *dest++ = '%';
     222              53 :         BOOST_ASSERT(dest != end);
     223              53 :         *dest++ = hex[c>>4];
     224              53 :         BOOST_ASSERT(dest != end);
     225              53 :         *dest++ = hex[c&0xf];
     226                 :     };
     227                 : 
     228             186 :     auto const dest0 = dest;
     229             186 :     if (!opt.space_as_plus)
     230                 :     {
     231             663 :         while(it != last)
     232                 :         {
     233             490 :             BOOST_ASSERT(dest != end);
     234             490 :             char const c = *it;
     235             490 :             if(allowed(c))
     236                 :             {
     237             445 :                 *dest++ = c;
     238                 :             }
     239                 :             else
     240                 :             {
     241              45 :                 encode(dest, c);
     242                 :             }
     243             490 :             ++it;
     244                 :         }
     245                 :     }
     246                 :     else
     247                 :     {
     248              53 :         while(it != last)
     249                 :         {
     250              40 :             BOOST_ASSERT(dest != end);
     251              40 :             char const c = *it;
     252              40 :             if (c == ' ')
     253                 :             {
     254               9 :                 *dest++ = '+';
     255                 :             }
     256              31 :             else if (
     257              31 :                 allowed(c) &&
     258                 :                 c != '+')
     259                 :             {
     260              23 :                 *dest++ = c;
     261                 :             }
     262                 :             else
     263                 :             {
     264               8 :                 encode(dest, c);
     265                 :             }
     266              40 :             ++it;
     267                 :         }
     268                 :     }
     269             186 :     return dest - dest0;
     270                 : }
     271                 : 
     272                 : //------------------------------------------------
     273                 : 
     274                 : template<
     275                 :     BOOST_URL_CONSTRAINT(string_token::StringToken) StringToken,
     276                 :     BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
     277                 : BOOST_URL_STRTOK_RETURN
     278              28 : encode(
     279                 :     core::string_view s,
     280                 :     CS const& allowed,
     281                 :     encoding_opts opt,
     282                 :     StringToken&& token) noexcept
     283                 : {
     284                 :     BOOST_CORE_STATIC_ASSERT(
     285                 :         grammar::is_charset<CS>::value);
     286                 : 
     287              28 :     auto const n = encoded_size(
     288                 :         s, allowed, opt);
     289              28 :     auto p = token.prepare(n);
     290              28 :     if(n > 0)
     291              26 :         encode_unsafe(
     292                 :             p, n, s, allowed, opt);
     293              28 :     return token.result();
     294                 : }
     295                 : 
     296                 : } // urls
     297                 : } // boost
     298                 : 
     299                 : #endif
        

Generated by: LCOV version 2.3