LCOV - code coverage report
Current view: top level - boost/url/impl - encode.hpp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 98 99 99.0 %
Date: 2024-04-08 19:38:36 Functions: 14 14 100.0 %

          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         487 :     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           0 :         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         158 :     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           1 :         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 1.15