LCOV - code coverage report
Current view: top level - boost/url/impl/encode.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 113 113
Test Date: 2025-11-10 19:06:20 Functions: 66.7 % 54 36

            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          877 : 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          877 :     std::size_t n = 0;
      46          877 :     auto it = s.data();
      47          877 :     auto const last = it + s.size();
      48              : 
      49          877 :     if (!opt.space_as_plus)
      50              :     {
      51         3310 :         while (it != last)
      52              :         {
      53         2625 :             char const c = *it;
      54         2625 :             if (allowed(c))
      55              :             {
      56         2501 :                 ++n;
      57              :             }
      58              :             else
      59              :             {
      60          124 :                 n += 3;
      61              :             }
      62         2625 :             ++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          192 :         FNT takes_one_char =
      74          384 :             allowed('+') ?
      75          190 :                 (allowed(' ') ?
      76            4 :                      FNT([](CS const& allowed, char c){ return allowed(c) && c != '+'; }) :
      77         1620 :                      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         1632 :         while (it != last)
      82              :         {
      83         1440 :             char const c = *it;
      84         1440 :             if (takes_one_char(allowed, c))
      85              :             {
      86         1394 :                 ++n;
      87              :             }
      88              :             else
      89              :             {
      90           46 :                 n += 3;
      91              :             }
      92         1440 :             ++it;
      93              :         }
      94              :     }
      95          877 :     return n;
      96              : }
      97              : 
      98              : //------------------------------------------------
      99              : 
     100              : template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
     101              : std::size_t
     102          560 : 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          560 :     BOOST_ASSERT(!allowed('%'));
     119              : 
     120          560 :     char const* const hex =
     121          560 :         detail::hexdigs[opt.lower_case];
     122          675 :     auto const encode = [hex](
     123              :         char*& dest,
     124              :         unsigned char c) noexcept
     125              :     {
     126          115 :         *dest++ = '%';
     127          115 :         *dest++ = hex[c>>4];
     128          115 :         *dest++ = hex[c&0xf];
     129              :     };
     130              : 
     131          560 :     auto it = s.data();
     132          560 :     auto const end = dest + size;
     133          560 :     auto const last = it + s.size();
     134          560 :     auto const dest0 = dest;
     135          560 :     auto const end3 = end - 3;
     136              : 
     137          560 :     if (!opt.space_as_plus)
     138              :     {
     139         1831 :         while(it != last)
     140              :         {
     141         1481 :             char const c = *it;
     142         1481 :             if (allowed(c))
     143              :             {
     144         1389 :                 if(dest == end)
     145            3 :                     return dest - dest0;
     146         1386 :                 *dest++ = c;
     147         1386 :                 ++it;
     148         1386 :                 continue;
     149              :             }
     150           92 :             if (dest > end3)
     151           15 :                 return dest - dest0;
     152           77 :             encode(dest, c);
     153           77 :             ++it;
     154              :         }
     155          350 :         return dest - dest0;
     156              :     }
     157              :     else
     158              :     {
     159         1602 :         while (it != last)
     160              :         {
     161         1424 :             char const c = *it;
     162         1424 :             if (c == ' ')
     163              :             {
     164           25 :                 if(dest == end)
     165            2 :                     return dest - dest0;
     166           23 :                 *dest++ = '+';
     167           23 :                 ++it;
     168           23 :                 continue;
     169              :             }
     170         2748 :             else if (
     171         1399 :                 allowed(c) &&
     172              :                 c != '+')
     173              :             {
     174         1352 :                 if(dest == end)
     175            3 :                     return dest - dest0;
     176         1349 :                 *dest++ = c;
     177         1349 :                 ++it;
     178         1349 :                 continue;
     179              :             }
     180           47 :             if(dest > end3)
     181            9 :                 return dest - dest0;
     182           38 :             encode(dest, c);
     183           38 :             ++it;
     184              :         }
     185              :     }
     186          178 :     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          181 : 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          181 :     BOOST_ASSERT(!allowed('%'));
     208              : 
     209          181 :     auto it = s.data();
     210          181 :     auto const last = it + s.size();
     211          181 :     auto const end = dest + size;
     212              :     ignore_unused(end);
     213              : 
     214          181 :     char const* const hex =
     215          181 :         detail::hexdigs[opt.lower_case];
     216          283 :     auto const encode = [end, hex](
     217              :         char*& dest,
     218              :         unsigned char c) noexcept
     219              :     {
     220           51 :         ignore_unused(end);
     221           51 :         *dest++ = '%';
     222           51 :         BOOST_ASSERT(dest != end);
     223           51 :         *dest++ = hex[c>>4];
     224           51 :         BOOST_ASSERT(dest != end);
     225           51 :         *dest++ = hex[c&0xf];
     226              :     };
     227              : 
     228          181 :     auto const dest0 = dest;
     229          181 :     if (!opt.space_as_plus)
     230              :     {
     231          623 :         while(it != last)
     232              :         {
     233          455 :             BOOST_ASSERT(dest != end);
     234          455 :             char const c = *it;
     235          455 :             if(allowed(c))
     236              :             {
     237          412 :                 *dest++ = c;
     238              :             }
     239              :             else
     240              :             {
     241           43 :                 encode(dest, c);
     242              :             }
     243          455 :             ++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          181 :     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.1