File indexing completed on 2026-08-08 09:08:01
0001
0002
0003
0004
0005
0006
0007
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
0038
0039
0040
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
0068
0069
0070
0071
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
0110
0111
0112
0113
0114 BOOST_CORE_STATIC_ASSERT(
0115 grammar::is_charset<CS>::value);
0116
0117
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
0192
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
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 }
0297 }
0298
0299 #endif