Line data Source code
1 : // 2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) 3 : // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com) 4 : // 5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying 6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 : // 8 : // Official repository: https://github.com/boostorg/url 9 : // 10 : 11 : #ifndef BOOST_URL_DETAIL_ENCODE_HPP 12 : #define BOOST_URL_DETAIL_ENCODE_HPP 13 : 14 : #include <boost/url/encoding_opts.hpp> 15 : #include <boost/url/pct_string_view.hpp> 16 : #include <boost/url/grammar/hexdig_chars.hpp> 17 : #include <boost/core/ignore_unused.hpp> 18 : #include <cstdlib> 19 : 20 : namespace boost { 21 : namespace urls { 22 : namespace detail { 23 : 24 : constexpr 25 : char const* const hexdigs[] = { 26 : "0123456789ABCDEF", 27 : "0123456789abcdef" }; 28 : 29 : //------------------------------------------------ 30 : 31 : // re-encode is to percent-encode a 32 : // string that can already contain 33 : // escapes. Characters not in the 34 : // unreserved set are escaped, and 35 : // escapes are passed through unchanged. 36 : // 37 : template<class CharSet> 38 : std::size_t 39 1065 : re_encoded_size_unsafe( 40 : core::string_view s, 41 : CharSet const& unreserved) noexcept 42 : { 43 1065 : std::size_t n = 0; 44 1065 : auto it = s.begin(); 45 1065 : auto const end = s.end(); 46 4702 : while(it != end) 47 : { 48 3637 : if(*it != '%') 49 : { 50 3482 : if( unreserved(*it) ) 51 3275 : n += 1; 52 : else 53 207 : n += 3; 54 3482 : ++it; 55 : } 56 : else 57 : { 58 155 : BOOST_ASSERT(end - it >= 3); 59 155 : BOOST_ASSERT( 60 : grammar::hexdig_value( 61 : it[1]) >= 0); 62 155 : BOOST_ASSERT( 63 : grammar::hexdig_value( 64 : it[2]) >= 0); 65 155 : n += 3; 66 155 : it += 3; 67 : } 68 : } 69 1065 : return n; 70 : } 71 : 72 : // unchecked 73 : // returns decoded size 74 : template<class CharSet> 75 : std::size_t 76 1271 : re_encode_unsafe( 77 : char*& dest_, 78 : char const* const end, 79 : core::string_view s, 80 : CharSet const& unreserved) noexcept 81 : { 82 : static constexpr bool lower_case = false; 83 1271 : char const* const hex = detail::hexdigs[lower_case]; 84 1271 : auto const encode = [end, hex]( 85 : char*& dest, 86 : char c0) noexcept 87 : { 88 213 : auto c = static_cast<unsigned char>(c0); 89 213 : ignore_unused(end); 90 213 : *dest++ = '%'; 91 213 : BOOST_ASSERT(dest != end); 92 213 : *dest++ = hex[c>>4]; 93 213 : BOOST_ASSERT(dest != end); 94 213 : *dest++ = hex[c&0xf]; 95 : }; 96 : ignore_unused(end); 97 : 98 1271 : auto dest = dest_; 99 1271 : auto const dest0 = dest; 100 1271 : auto const last = s.end(); 101 1271 : std::size_t dn = 0; 102 1271 : auto it = s.begin(); 103 5054 : while(it != last) 104 : { 105 3783 : BOOST_ASSERT(dest != end); 106 3783 : if(*it != '%') 107 : { 108 3625 : if(unreserved(*it)) 109 : { 110 3412 : *dest++ = *it; 111 : } 112 : else 113 : { 114 213 : encode(dest, *it); 115 213 : dn += 2; 116 : } 117 3625 : ++it; 118 : } 119 : else 120 : { 121 158 : *dest++ = *it++; 122 158 : BOOST_ASSERT(dest != end); 123 158 : *dest++ = *it++; 124 158 : BOOST_ASSERT(dest != end); 125 158 : *dest++ = *it++; 126 158 : dn += 2; 127 : } 128 : } 129 1271 : dest_ = dest; 130 1271 : return dest - dest0 - dn; 131 : } 132 : 133 : } // detail 134 : } // urls 135 : } // boost 136 : 137 : #endif