Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:53:28

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/detail/encode.hpp>
0014 #include <boost/url/detail/except.hpp>
0015 #include <boost/url/encoding_opts.hpp>
0016 #include <boost/url/grammar/charset.hpp>
0017 #include <boost/url/grammar/hexdig_chars.hpp>
0018 #include <boost/url/grammar/type_traits.hpp>
0019 #include <boost/assert.hpp>
0020 #include <boost/static_assert.hpp>
0021 
0022 namespace boost {
0023 namespace urls {
0024 
0025 //------------------------------------------------
0026 
0027 template<class CharSet>
0028 std::size_t
0029 encoded_size(
0030     core::string_view s,
0031     CharSet const& unreserved,
0032     encoding_opts opt) noexcept
0033 {
0034 /*  If you get a compile error here, it
0035     means that the value you passed does
0036     not meet the requirements stated in
0037     the documentation.
0038 */
0039     static_assert(
0040         grammar::is_charset<CharSet>::value,
0041         "Type requirements not met");
0042 
0043     std::size_t n = 0;
0044     auto it = s.data();
0045     auto const last = it + s.size();
0046 
0047     if(! opt.space_as_plus ||
0048         unreserved(' '))
0049     {
0050         while(it != last)
0051         {
0052             if(unreserved(*it))
0053                 n += 1;
0054             else
0055                 n += 3;
0056             ++it;
0057         }
0058     }
0059     else
0060     {
0061         while(it != last)
0062         {
0063             auto c = *it;
0064             if(unreserved(c))
0065                 ++n;
0066             else if(c == ' ')
0067                 ++n;
0068             else
0069                 n += 3;
0070             ++it;
0071         }
0072     }
0073     return n;
0074 }
0075 
0076 //------------------------------------------------
0077 
0078 template<class CharSet>
0079 std::size_t
0080 encode(
0081     char* dest,
0082     std::size_t size,
0083     core::string_view s,
0084     CharSet const& unreserved,
0085     encoding_opts opt)
0086 {
0087 /*  If you get a compile error here, it
0088     means that the value you passed does
0089     not meet the requirements stated in
0090     the documentation.
0091 */
0092     static_assert(
0093         grammar::is_charset<CharSet>::value,
0094         "Type requirements not met");
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<class CharSet>
0173 std::size_t
0174 encode_unsafe(
0175     char* dest,
0176     std::size_t size,
0177     core::string_view s,
0178     CharSet const& unreserved,
0179     encoding_opts opt)
0180 {
0181     // '%' must be reserved
0182     BOOST_ASSERT(! unreserved('%'));
0183 
0184     auto it = s.data();
0185     auto const last = it + s.size();
0186     auto const end = dest + size;
0187     ignore_unused(end);
0188 
0189     char const* const hex =
0190         detail::hexdigs[opt.lower_case];
0191     auto const encode = [end, hex](
0192         char*& dest,
0193         unsigned char c) noexcept
0194     {
0195         ignore_unused(end);
0196         *dest++ = '%';
0197         BOOST_ASSERT(dest != end);
0198         *dest++ = hex[c>>4];
0199         BOOST_ASSERT(dest != end);
0200         *dest++ = hex[c&0xf];
0201     };
0202 
0203     auto const dest0 = dest;
0204     if(! opt.space_as_plus)
0205     {
0206         while(it != last)
0207         {
0208             BOOST_ASSERT(dest != end);
0209             if(unreserved(*it))
0210                 *dest++ = *it++;
0211             else
0212                 encode(dest, *it++);
0213         }
0214     }
0215     else
0216     {
0217         // VFALCO space is usually reserved,
0218         // and we depend on this for an
0219         // optimization. if this assert
0220         // goes off we can split the loop
0221         // below into two versions.
0222         BOOST_ASSERT(! unreserved(' '));
0223 
0224         while(it != last)
0225         {
0226             BOOST_ASSERT(dest != end);
0227             if(unreserved(*it))
0228             {
0229                 *dest++ = *it++;
0230             }
0231             else if(*it == ' ')
0232             {
0233                 *dest++ = '+';
0234                 ++it;
0235             }
0236             else
0237             {
0238                 encode(dest, *it++);
0239             }
0240         }
0241     }
0242     return dest - dest0;
0243 }
0244 
0245 //------------------------------------------------
0246 
0247 template<
0248     class StringToken,
0249     class CharSet>
0250 BOOST_URL_STRTOK_RETURN
0251 encode(
0252     core::string_view s,
0253     CharSet const& unreserved,
0254     encoding_opts opt,
0255     StringToken&& token) noexcept
0256 {
0257 /*  If you get a compile error here, it
0258     means that the value you passed does
0259     not meet the requirements stated in
0260     the documentation.
0261 */
0262     static_assert(
0263         grammar::is_charset<CharSet>::value,
0264         "Type requirements not met");
0265 
0266     auto const n = encoded_size(
0267         s, unreserved, opt);
0268     auto p = token.prepare(n);
0269     if(n > 0)
0270         encode_unsafe(
0271             p, n, s, unreserved, opt);
0272     return token.result();
0273 }
0274 
0275 } // urls
0276 } // boost
0277 
0278 #endif