Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-08 09:08:01

0001 //
0002 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/url
0008 //
0009 
0010 #ifndef BOOST_URL_IMPL_ENCODE_HPP
0011 #define BOOST_URL_IMPL_ENCODE_HPP
0012 
0013 #include "boost/url/grammar/token_rule.hpp"
0014 #include <boost/assert.hpp>
0015 #include <boost/core/detail/static_assert.hpp>
0016 #include <boost/url/detail/encode.hpp>
0017 #include <boost/url/detail/except.hpp>
0018 #include <boost/url/encoding_opts.hpp>
0019 #include <boost/url/grammar/charset.hpp>
0020 #include <boost/url/grammar/hexdig_chars.hpp>
0021 #include <boost/url/grammar/string_token.hpp>
0022 #include <boost/url/grammar/type_traits.hpp>
0023 
0024 namespace boost {
0025 namespace urls {
0026 
0027 //------------------------------------------------
0028 
0029 template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
0030 std::size_t
0031 encoded_size(
0032     core::string_view s,
0033     CS const& allowed,
0034     encoding_opts opt) noexcept
0035 {
0036     /*
0037         If you get a compilation error here, it
0038         means that the value you passed does
0039         not meet the requirements stated in
0040         the documentation.
0041     */
0042     BOOST_CORE_STATIC_ASSERT(
0043         grammar::is_charset<CS>::value);
0044 
0045     std::size_t n = 0;
0046     auto it = s.data();
0047     auto const last = it + s.size();
0048 
0049     if (!opt.space_as_plus)
0050     {
0051         while (it != last)
0052         {
0053             char const c = *it;
0054             if (allowed(c))
0055             {
0056                 ++n;
0057             }
0058             else
0059             {
0060                 n += 3;
0061             }
0062             ++it;
0063         }
0064     }
0065     else
0066     {
0067         // '+' is always encoded (thus
0068         // spending 3 chars) even if
0069         // allowed because "%2B" and
0070         // "+" have different meanings
0071         // when space as plus is enabled
0072         using FNT = bool (*)(CS const& allowed, char);
0073         FNT takes_one_char =
0074             allowed('+') ?
0075                 (allowed(' ') ?
0076                      FNT([](CS const& allowed, char c){ return allowed(c) && c != '+'; }) :
0077                      FNT([](CS const& allowed, char c){ return (allowed(c) || c == ' ') && c != '+'; })) :
0078                 (allowed(' ') ?
0079                      FNT([](CS const& allowed, char c){ return allowed(c); }) :
0080                      FNT([](CS const& allowed, char c){ return allowed(c) || c == ' '; }));
0081         while (it != last)
0082         {
0083             char const c = *it;
0084             if (takes_one_char(allowed, c))
0085             {
0086                 ++n;
0087             }
0088             else
0089             {
0090                 n += 3;
0091             }
0092             ++it;
0093         }
0094     }
0095     return n;
0096 }
0097 
0098 //------------------------------------------------
0099 
0100 template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
0101 std::size_t
0102 encode(
0103     char* dest,
0104     std::size_t size,
0105     core::string_view s,
0106     CS const& allowed,
0107     encoding_opts opt)
0108 {
0109 /*  If you get a compilation error here, it
0110     means that the value you passed does
0111     not meet the requirements stated in
0112     the documentation.
0113 */
0114     BOOST_CORE_STATIC_ASSERT(
0115         grammar::is_charset<CS>::value);
0116 
0117     // '%' must be reserved
0118     BOOST_ASSERT(!allowed('%'));
0119 
0120     char const* const hex =
0121         detail::hexdigs[opt.lower_case];
0122     auto const encode = [hex](
0123         char*& dest,
0124         unsigned char c) noexcept
0125     {
0126         *dest++ = '%';
0127         *dest++ = hex[c>>4];
0128         *dest++ = hex[c&0xf];
0129     };
0130 
0131     auto it = s.data();
0132     auto const end = dest + size;
0133     auto const last = it + s.size();
0134     auto const dest0 = dest;
0135     auto const end3 = end - 3;
0136 
0137     if (!opt.space_as_plus)
0138     {
0139         while(it != last)
0140         {
0141             char const c = *it;
0142             if (allowed(c))
0143             {
0144                 if(dest == end)
0145                     return dest - dest0;
0146                 *dest++ = c;
0147                 ++it;
0148                 continue;
0149             }
0150             if (dest > end3)
0151                 return dest - dest0;
0152             encode(dest, c);
0153             ++it;
0154         }
0155         return dest - dest0;
0156     }
0157     else
0158     {
0159         while (it != last)
0160         {
0161             char const c = *it;
0162             if (c == ' ')
0163             {
0164                 if(dest == end)
0165                     return dest - dest0;
0166                 *dest++ = '+';
0167                 ++it;
0168                 continue;
0169             }
0170             else if (
0171                 allowed(c) &&
0172                 c != '+')
0173             {
0174                 if(dest == end)
0175                     return dest - dest0;
0176                 *dest++ = c;
0177                 ++it;
0178                 continue;
0179             }
0180             if(dest > end3)
0181                 return dest - dest0;
0182             encode(dest, c);
0183             ++it;
0184         }
0185     }
0186     return dest - dest0;
0187 }
0188 
0189 //------------------------------------------------
0190 
0191 // unsafe encode just
0192 // asserts on the output buffer
0193 //
0194 template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
0195 std::size_t
0196 encode_unsafe(
0197     char* dest,
0198     std::size_t size,
0199     core::string_view s,
0200     CS const& allowed,
0201     encoding_opts opt)
0202 {
0203     BOOST_CORE_STATIC_ASSERT(
0204         grammar::is_charset<CS>::value);
0205 
0206     // '%' must be reserved
0207     BOOST_ASSERT(!allowed('%'));
0208 
0209     auto it = s.data();
0210     auto const last = it + s.size();
0211     auto const end = dest + size;
0212     ignore_unused(end);
0213 
0214     char const* const hex =
0215         detail::hexdigs[opt.lower_case];
0216     auto const encode = [end, hex](
0217         char*& dest,
0218         unsigned char c) noexcept
0219     {
0220         ignore_unused(end);
0221         *dest++ = '%';
0222         BOOST_ASSERT(dest != end);
0223         *dest++ = hex[c>>4];
0224         BOOST_ASSERT(dest != end);
0225         *dest++ = hex[c&0xf];
0226     };
0227 
0228     auto const dest0 = dest;
0229     if (!opt.space_as_plus)
0230     {
0231         while(it != last)
0232         {
0233             BOOST_ASSERT(dest != end);
0234             char const c = *it;
0235             if(allowed(c))
0236             {
0237                 *dest++ = c;
0238             }
0239             else
0240             {
0241                 encode(dest, c);
0242             }
0243             ++it;
0244         }
0245     }
0246     else
0247     {
0248         while(it != last)
0249         {
0250             BOOST_ASSERT(dest != end);
0251             char const c = *it;
0252             if (c == ' ')
0253             {
0254                 *dest++ = '+';
0255             }
0256             else if (
0257                 allowed(c) &&
0258                 c != '+')
0259             {
0260                 *dest++ = c;
0261             }
0262             else
0263             {
0264                 encode(dest, c);
0265             }
0266             ++it;
0267         }
0268     }
0269     return dest - dest0;
0270 }
0271 
0272 //------------------------------------------------
0273 
0274 template<
0275     BOOST_URL_CONSTRAINT(string_token::StringToken) StringToken,
0276     BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
0277 BOOST_URL_STRTOK_RETURN
0278 encode(
0279     core::string_view s,
0280     CS const& allowed,
0281     encoding_opts opt,
0282     StringToken&& token) noexcept
0283 {
0284     BOOST_CORE_STATIC_ASSERT(
0285         grammar::is_charset<CS>::value);
0286 
0287     auto const n = encoded_size(
0288         s, allowed, opt);
0289     auto p = token.prepare(n);
0290     if(n > 0)
0291         encode_unsafe(
0292             p, n, s, allowed, opt);
0293     return token.result();
0294 }
0295 
0296 } // urls
0297 } // boost
0298 
0299 #endif