// // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/url // #ifndef BOOST_URL_DETAIL_ENCODE_HPP #define BOOST_URL_DETAIL_ENCODE_HPP #include #include #include #include #include namespace boost { namespace urls { namespace detail { constexpr char const* const hexdigs[] = { "0123456789ABCDEF", "0123456789abcdef" }; //------------------------------------------------ // re-encode is to percent-encode a // string that can already contain // escapes. Characters not in the // unreserved set are escaped, and // escapes are passed through unchanged. // template std::size_t re_encoded_size_unsafe( string_view s, CharSet const& unreserved, encoding_opts opt) noexcept { std::size_t n = 0; auto const end = s.end(); auto it = s.begin(); if(opt.space_as_plus) { while(it != end) { if(*it != '%') { if( unreserved(*it) || *it == ' ') n += 1; else n += 3; ++it; } else { BOOST_ASSERT(end - it >= 3); BOOST_ASSERT( grammar::hexdig_value( it[1]) >= 0); BOOST_ASSERT( grammar::hexdig_value( it[2]) >= 0); n += 3; it += 3; } } } else { while(it != end) { if(*it != '%') { if(unreserved(*it)) n += 1; else n += 3; ++it; } else { BOOST_ASSERT(end - it >= 3); BOOST_ASSERT( grammar::hexdig_value( it[1]) >= 0); BOOST_ASSERT( grammar::hexdig_value( it[2]) >= 0); n += 3; it += 3; } } } return n; } // unchecked // returns decoded size template std::size_t re_encode_unsafe( char*& dest_, char const* const end, string_view s, CharSet const& unreserved, encoding_opts opt) noexcept { char const* const hex = detail::hexdigs[opt.lower_case]; auto const encode = [end, hex]( char*& dest, unsigned char c) noexcept { ignore_unused(end); *dest++ = '%'; BOOST_ASSERT(dest != end); *dest++ = hex[c>>4]; BOOST_ASSERT(dest != end); *dest++ = hex[c&0xf]; }; ignore_unused(end); auto dest = dest_; auto const dest0 = dest; auto const last = s.end(); std::size_t dn = 0; auto it = s.begin(); if(opt.space_as_plus) { while(it != last) { BOOST_ASSERT(dest != end); if(*it != '%') { if(*it == ' ') { *dest++ = '+'; } else if(unreserved(*it)) { *dest++ = *it; } else { encode(dest, *it); dn += 2; } ++it; } else { *dest++ = *it++; BOOST_ASSERT(dest != end); *dest++ = *it++; BOOST_ASSERT(dest != end); *dest++ = *it++; dn += 2; } } } else { while(it != last) { BOOST_ASSERT(dest != end); if(*it != '%') { if(unreserved(*it)) { *dest++ = *it; } else { encode(dest, *it); dn += 2; } ++it; } else { *dest++ = *it++; BOOST_ASSERT(dest != end); *dest++ = *it++; BOOST_ASSERT(dest != end); *dest++ = *it++; dn += 2; } } } dest_ = dest; return dest - dest0 - dn; } } // detail } // urls } // boost #endif