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, 42 : encoding_opts opt) noexcept 43 : { 44 1065 : std::size_t n = 0; 45 1065 : auto const end = s.end(); 46 1065 : auto it = s.begin(); 47 1065 : if(opt.space_as_plus) 48 : { 49 0 : while(it != end) 50 : { 51 0 : if(*it != '%') 52 : { 53 0 : if( unreserved(*it) 54 0 : || *it == ' ') 55 0 : n += 1; 56 : else 57 0 : n += 3; 58 0 : ++it; 59 : } 60 : else 61 : { 62 0 : BOOST_ASSERT(end - it >= 3); 63 0 : BOOST_ASSERT( 64 : grammar::hexdig_value( 65 : it[1]) >= 0); 66 0 : BOOST_ASSERT( 67 : grammar::hexdig_value( 68 : it[2]) >= 0); 69 0 : n += 3; 70 0 : it += 3; 71 : } 72 : } 73 : } 74 : else 75 : { 76 4702 : while(it != end) 77 : { 78 3637 : if(*it != '%') 79 : { 80 3482 : if(unreserved(*it)) 81 3275 : n += 1; 82 : else 83 207 : n += 3; 84 3482 : ++it; 85 : } 86 : else 87 : { 88 155 : BOOST_ASSERT(end - it >= 3); 89 155 : BOOST_ASSERT( 90 : grammar::hexdig_value( 91 : it[1]) >= 0); 92 155 : BOOST_ASSERT( 93 : grammar::hexdig_value( 94 : it[2]) >= 0); 95 155 : n += 3; 96 155 : it += 3; 97 : } 98 : } 99 : } 100 1065 : return n; 101 : } 102 : 103 : // unchecked 104 : // returns decoded size 105 : template<class CharSet> 106 : std::size_t 107 1271 : re_encode_unsafe( 108 : char*& dest_, 109 : char const* const end, 110 : core::string_view s, 111 : CharSet const& unreserved, 112 : encoding_opts opt) noexcept 113 : { 114 1271 : char const* const hex = 115 1271 : detail::hexdigs[opt.lower_case]; 116 1271 : auto const encode = [end, hex]( 117 : char*& dest, 118 : char c0) noexcept 119 : { 120 213 : auto c = static_cast<unsigned char>(c0); 121 213 : ignore_unused(end); 122 213 : *dest++ = '%'; 123 213 : BOOST_ASSERT(dest != end); 124 213 : *dest++ = hex[c>>4]; 125 213 : BOOST_ASSERT(dest != end); 126 213 : *dest++ = hex[c&0xf]; 127 : }; 128 : ignore_unused(end); 129 : 130 1271 : auto dest = dest_; 131 1271 : auto const dest0 = dest; 132 1271 : auto const last = s.end(); 133 1271 : std::size_t dn = 0; 134 1271 : auto it = s.begin(); 135 : 136 1271 : if(opt.space_as_plus) 137 : { 138 0 : while(it != last) 139 : { 140 0 : BOOST_ASSERT(dest != end); 141 0 : if(*it != '%') 142 : { 143 0 : if(*it == ' ') 144 : { 145 0 : *dest++ = '+'; 146 : } 147 0 : else if(unreserved(*it)) 148 : { 149 0 : *dest++ = *it; 150 : } 151 : else 152 : { 153 0 : encode(dest, *it); 154 0 : dn += 2; 155 : } 156 0 : ++it; 157 : } 158 : else 159 : { 160 0 : *dest++ = *it++; 161 0 : BOOST_ASSERT(dest != end); 162 0 : *dest++ = *it++; 163 0 : BOOST_ASSERT(dest != end); 164 0 : *dest++ = *it++; 165 0 : dn += 2; 166 : } 167 : } 168 : } 169 : else 170 : { 171 5054 : while(it != last) 172 : { 173 3783 : BOOST_ASSERT(dest != end); 174 3783 : if(*it != '%') 175 : { 176 3625 : if(unreserved(*it)) 177 : { 178 3412 : *dest++ = *it; 179 : } 180 : else 181 : { 182 213 : encode(dest, *it); 183 213 : dn += 2; 184 : } 185 3625 : ++it; 186 : } 187 : else 188 : { 189 158 : *dest++ = *it++; 190 158 : BOOST_ASSERT(dest != end); 191 158 : *dest++ = *it++; 192 158 : BOOST_ASSERT(dest != end); 193 158 : *dest++ = *it++; 194 158 : dn += 2; 195 : } 196 : } 197 : } 198 1271 : dest_ = dest; 199 1271 : return dest - dest0 - dn; 200 : } 201 : 202 : } // detail 203 : } // urls 204 : } // boost 205 : 206 : #endif