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 % 99 99
Test Date: 2024-08-20 16:05:53 Functions: 100.0 % 14 14

            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/detail/encode.hpp>
      14              : #include <boost/url/detail/except.hpp>
      15              : #include <boost/url/encoding_opts.hpp>
      16              : #include <boost/url/grammar/charset.hpp>
      17              : #include <boost/url/grammar/hexdig_chars.hpp>
      18              : #include <boost/url/grammar/type_traits.hpp>
      19              : #include <boost/assert.hpp>
      20              : #include <boost/static_assert.hpp>
      21              : 
      22              : namespace boost {
      23              : namespace urls {
      24              : 
      25              : //------------------------------------------------
      26              : 
      27              : template<class CharSet>
      28              : std::size_t
      29          855 : encoded_size(
      30              :     core::string_view s,
      31              :     CharSet const& unreserved,
      32              :     encoding_opts opt) noexcept
      33              : {
      34              : /*  If you get a compile error here, it
      35              :     means that the value you passed does
      36              :     not meet the requirements stated in
      37              :     the documentation.
      38              : */
      39              :     static_assert(
      40              :         grammar::is_charset<CharSet>::value,
      41              :         "Type requirements not met");
      42              : 
      43          855 :     std::size_t n = 0;
      44          855 :     auto it = s.data();
      45          855 :     auto const last = it + s.size();
      46              : 
      47          877 :     if(! opt.space_as_plus ||
      48           22 :         unreserved(' '))
      49              :     {
      50         4748 :         while(it != last)
      51              :         {
      52         3915 :             if(unreserved(*it))
      53         3764 :                 n += 1;
      54              :             else
      55          151 :                 n += 3;
      56         3915 :             ++it;
      57              :         }
      58              :     }
      59              :     else
      60              :     {
      61           66 :         while(it != last)
      62              :         {
      63           44 :             auto c = *it;
      64           44 :             if(unreserved(c))
      65           26 :                 ++n;
      66           18 :             else if(c == ' ')
      67            9 :                 ++n;
      68              :             else
      69            9 :                 n += 3;
      70           44 :             ++it;
      71              :         }
      72              :     }
      73          855 :     return n;
      74              : }
      75              : 
      76              : //------------------------------------------------
      77              : 
      78              : template<class CharSet>
      79              : std::size_t
      80          543 : encode(
      81              :     char* dest,
      82              :     std::size_t size,
      83              :     core::string_view s,
      84              :     CharSet const& unreserved,
      85              :     encoding_opts opt)
      86              : {
      87              : /*  If you get a compile error here, it
      88              :     means that the value you passed does
      89              :     not meet the requirements stated in
      90              :     the documentation.
      91              : */
      92              :     static_assert(
      93              :         grammar::is_charset<CharSet>::value,
      94              :         "Type requirements not met");
      95              : 
      96              :     // '%' must be reserved
      97          543 :     BOOST_ASSERT(! unreserved('%'));
      98              : 
      99          543 :     char const* const hex =
     100          543 :         detail::hexdigs[opt.lower_case];
     101          653 :     auto const encode = [hex](
     102              :         char*& dest,
     103              :         unsigned char c) noexcept
     104              :     {
     105          110 :         *dest++ = '%';
     106          110 :         *dest++ = hex[c>>4];
     107          110 :         *dest++ = hex[c&0xf];
     108              :     };
     109              : 
     110          543 :     auto it = s.data();
     111          543 :     auto const end = dest + size;
     112          543 :     auto const last = it + s.size();
     113          543 :     auto const dest0 = dest;
     114          543 :     auto const end3 = end - 3;
     115              : 
     116          543 :     if(! opt.space_as_plus)
     117              :     {
     118         3286 :         while(it != last)
     119              :         {
     120         2787 :             if(unreserved(*it))
     121              :             {
     122         2668 :                 if(dest == end)
     123            3 :                     return dest - dest0;
     124         2665 :                 *dest++ = *it++;
     125         2665 :                 continue;
     126              :             }
     127          119 :             if(dest > end3)
     128           15 :                 return dest - dest0;
     129          104 :             encode(dest, *it++);
     130              :         }
     131          499 :         return dest - dest0;
     132              :     }
     133           26 :     else if(! unreserved(' '))
     134              :     {
     135              :         // VFALCO space is usually reserved,
     136              :         // and we depend on this for an
     137              :         // optimization. if this assert
     138              :         // goes off we can split the loop
     139              :         // below into two versions.
     140           26 :         BOOST_ASSERT(! unreserved(' '));
     141              : 
     142           52 :         while(it != last)
     143              :         {
     144           40 :             if(unreserved(*it))
     145              :             {
     146           16 :                 if(dest == end)
     147            3 :                     return dest - dest0;
     148           13 :                 *dest++ = *it++;
     149           13 :                 continue;
     150              :             }
     151           24 :             if(*it == ' ')
     152              :             {
     153            9 :                 if(dest == end)
     154            2 :                     return dest - dest0;
     155            7 :                 *dest++ = '+';
     156            7 :                 ++it;
     157            7 :                 continue;
     158              :             }
     159           15 :             if(dest > end3)
     160            9 :                 return dest - dest0;
     161            6 :             encode(dest, *it++);
     162              :         }
     163              :     }
     164           12 :     return dest - dest0;
     165              : }
     166              : 
     167              : //------------------------------------------------
     168              : 
     169              : // unsafe encode just
     170              : // asserts on the output buffer
     171              : //
     172              : template<class CharSet>
     173              : std::size_t
     174          175 : encode_unsafe(
     175              :     char* dest,
     176              :     std::size_t size,
     177              :     core::string_view s,
     178              :     CharSet const& unreserved,
     179              :     encoding_opts opt)
     180              : {
     181              :     // '%' must be reserved
     182          175 :     BOOST_ASSERT(! unreserved('%'));
     183              : 
     184          175 :     auto it = s.data();
     185          175 :     auto const last = it + s.size();
     186          175 :     auto const end = dest + size;
     187              :     ignore_unused(end);
     188              : 
     189          175 :     char const* const hex =
     190          175 :         detail::hexdigs[opt.lower_case];
     191          359 :     auto const encode = [end, hex](
     192              :         char*& dest,
     193              :         unsigned char c) noexcept
     194              :     {
     195           46 :         ignore_unused(end);
     196           46 :         *dest++ = '%';
     197           46 :         BOOST_ASSERT(dest != end);
     198           46 :         *dest++ = hex[c>>4];
     199           46 :         BOOST_ASSERT(dest != end);
     200           46 :         *dest++ = hex[c&0xf];
     201              :     };
     202              : 
     203          175 :     auto const dest0 = dest;
     204          175 :     if(! opt.space_as_plus)
     205              :     {
     206          605 :         while(it != last)
     207              :         {
     208          439 :             BOOST_ASSERT(dest != end);
     209          439 :             if(unreserved(*it))
     210          396 :                 *dest++ = *it++;
     211              :             else
     212           43 :                 encode(dest, *it++);
     213              :         }
     214              :     }
     215              :     else
     216              :     {
     217              :         // VFALCO space is usually reserved,
     218              :         // and we depend on this for an
     219              :         // optimization. if this assert
     220              :         // goes off we can split the loop
     221              :         // below into two versions.
     222            9 :         BOOST_ASSERT(! unreserved(' '));
     223              : 
     224           37 :         while(it != last)
     225              :         {
     226           28 :             BOOST_ASSERT(dest != end);
     227           28 :             if(unreserved(*it))
     228              :             {
     229           20 :                 *dest++ = *it++;
     230              :             }
     231            8 :             else if(*it == ' ')
     232              :             {
     233            5 :                 *dest++ = '+';
     234            5 :                 ++it;
     235              :             }
     236              :             else
     237              :             {
     238            3 :                 encode(dest, *it++);
     239              :             }
     240              :         }
     241              :     }
     242          175 :     return dest - dest0;
     243              : }
     244              : 
     245              : //------------------------------------------------
     246              : 
     247              : template<
     248              :     class StringToken,
     249              :     class CharSet>
     250              : BOOST_URL_STRTOK_RETURN
     251           24 : encode(
     252              :     core::string_view s,
     253              :     CharSet const& unreserved,
     254              :     encoding_opts opt,
     255              :     StringToken&& token) noexcept
     256              : {
     257              : /*  If you get a compile error here, it
     258              :     means that the value you passed does
     259              :     not meet the requirements stated in
     260              :     the documentation.
     261              : */
     262              :     static_assert(
     263              :         grammar::is_charset<CharSet>::value,
     264              :         "Type requirements not met");
     265              : 
     266           24 :     auto const n = encoded_size(
     267              :         s, unreserved, opt);
     268           24 :     auto p = token.prepare(n);
     269           24 :     if(n > 0)
     270           22 :         encode_unsafe(
     271              :             p, n, s, unreserved, opt);
     272           24 :     return token.result();
     273              : }
     274              : 
     275              : } // urls
     276              : } // boost
     277              : 
     278              : #endif
        

Generated by: LCOV version 2.1