Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:52:41

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/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& unreserved,
0034     encoding_opts opt) noexcept
0035 {
0036 /*  If you get a compile error here, it
0037     means that the value you passed does
0038     not meet the requirements stated in
0039     the documentation.
0040 */
0041     BOOST_STATIC_ASSERT(
0042         grammar::is_charset<CS>::value);
0043 
0044     std::size_t n = 0;
0045     auto it = s.data();
0046     auto const last = it + s.size();
0047 
0048     if(! opt.space_as_plus ||
0049         unreserved(' '))
0050     {
0051         while(it != last)
0052         {
0053             if(unreserved(*it))
0054                 n += 1;
0055             else
0056                 n += 3;
0057             ++it;
0058         }
0059     }
0060     else
0061     {
0062         while(it != last)
0063         {
0064             auto c = *it;
0065             if(unreserved(c))
0066                 ++n;
0067             else if(c == ' ')
0068                 ++n;
0069             else
0070                 n += 3;
0071             ++it;
0072         }
0073     }
0074     return n;
0075 }
0076 
0077 //------------------------------------------------
0078 
0079 template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
0080 std::size_t
0081 encode(
0082     char* dest,
0083     std::size_t size,
0084     core::string_view s,
0085     CS const& unreserved,
0086     encoding_opts opt)
0087 {
0088 /*  If you get a compile error here, it
0089     means that the value you passed does
0090     not meet the requirements stated in
0091     the documentation.
0092 */
0093     BOOST_STATIC_ASSERT(
0094         grammar::is_charset<CS>::value);
0095 
0096     // '%' must be reserved
0097     BOOST_ASSERT(! unreserved('%'));
0098 
0099     char const* const hex =
0100         detail::hexdigs[opt.lower_case];
0101     auto const encode = [hex](
0102         char*& dest,
0103         unsigned char c) noexcept
0104     {
0105         *dest++ = '%';
0106         *dest++ = hex[c>>4];
0107         *dest++ = hex[c&0xf];
0108     };
0109 
0110     auto it = s.data();
0111     auto const end = dest + size;
0112     auto const last = it + s.size();
0113     auto const dest0 = dest;
0114     auto const end3 = end - 3;
0115 
0116     if(! opt.space_as_plus)
0117     {
0118         while(it != last)
0119         {
0120             if(unreserved(*it))
0121             {
0122                 if(dest == end)
0123                     return dest - dest0;
0124                 *dest++ = *it++;
0125                 continue;
0126             }
0127             if(dest > end3)
0128                 return dest - dest0;
0129             encode(dest, *it++);
0130         }
0131         return dest - dest0;
0132     }
0133     else if(! unreserved(' '))
0134     {
0135         // VFALCO space is usually reserved,
0136         // and we depend on this for an
0137         // optimization. if this assert
0138         // goes off we can split the loop
0139         // below into two versions.
0140         BOOST_ASSERT(! unreserved(' '));
0141 
0142         while(it != last)
0143         {
0144             if(unreserved(*it))
0145             {
0146                 if(dest == end)
0147                     return dest - dest0;
0148                 *dest++ = *it++;
0149                 continue;
0150             }
0151             if(*it == ' ')
0152             {
0153                 if(dest == end)
0154                     return dest - dest0;
0155                 *dest++ = '+';
0156                 ++it;
0157                 continue;
0158             }
0159             if(dest > end3)
0160                 return dest - dest0;
0161             encode(dest, *it++);
0162         }
0163     }
0164     return dest - dest0;
0165 }
0166 
0167 //------------------------------------------------
0168 
0169 // unsafe encode just
0170 // asserts on the output buffer
0171 //
0172 template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
0173 std::size_t
0174 encode_unsafe(
0175     char* dest,
0176     std::size_t size,
0177     core::string_view s,
0178     CS const& unreserved,
0179     encoding_opts opt)
0180 {
0181     BOOST_STATIC_ASSERT(
0182         grammar::is_charset<CS>::value);
0183 
0184     // '%' must be reserved
0185     BOOST_ASSERT(! unreserved('%'));
0186 
0187     auto it = s.data();
0188     auto const last = it + s.size();
0189     auto const end = dest + size;
0190     ignore_unused(end);
0191 
0192     char const* const hex =
0193         detail::hexdigs[opt.lower_case];
0194     auto const encode = [end, hex](
0195         char*& dest,
0196         unsigned char c) noexcept
0197     {
0198         ignore_unused(end);
0199         *dest++ = '%';
0200         BOOST_ASSERT(dest != end);
0201         *dest++ = hex[c>>4];
0202         BOOST_ASSERT(dest != end);
0203         *dest++ = hex[c&0xf];
0204     };
0205 
0206     auto const dest0 = dest;
0207     if(! opt.space_as_plus)
0208     {
0209         while(it != last)
0210         {
0211             BOOST_ASSERT(dest != end);
0212             if(unreserved(*it))
0213                 *dest++ = *it++;
0214             else
0215                 encode(dest, *it++);
0216         }
0217     }
0218     else
0219     {
0220         // VFALCO space is usually reserved,
0221         // and we depend on this for an
0222         // optimization. if this assert
0223         // goes off we can split the loop
0224         // below into two versions.
0225         BOOST_ASSERT(! unreserved(' '));
0226 
0227         while(it != last)
0228         {
0229             BOOST_ASSERT(dest != end);
0230             if(unreserved(*it))
0231             {
0232                 *dest++ = *it++;
0233             }
0234             else if(*it == ' ')
0235             {
0236                 *dest++ = '+';
0237                 ++it;
0238             }
0239             else
0240             {
0241                 encode(dest, *it++);
0242             }
0243         }
0244     }
0245     return dest - dest0;
0246 }
0247 
0248 //------------------------------------------------
0249 
0250 template<
0251     BOOST_URL_CONSTRAINT(string_token::StringToken) StringToken,
0252     BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
0253 BOOST_URL_STRTOK_RETURN
0254 encode(
0255     core::string_view s,
0256     CS const& unreserved,
0257     encoding_opts opt,
0258     StringToken&& token) noexcept
0259 {
0260     BOOST_STATIC_ASSERT(
0261         grammar::is_charset<CS>::value);
0262 
0263     auto const n = encoded_size(
0264         s, unreserved, opt);
0265     auto p = token.prepare(n);
0266     if(n > 0)
0267         encode_unsafe(
0268             p, n, s, unreserved, opt);
0269     return token.result();
0270 }
0271 
0272 } // urls
0273 } // boost
0274 
0275 #endif