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 : unsigned char c) noexcept 119 : { 120 213 : ignore_unused(end); 121 213 : *dest++ = '%'; 122 213 : BOOST_ASSERT(dest != end); 123 213 : *dest++ = hex[c>>4]; 124 213 : BOOST_ASSERT(dest != end); 125 213 : *dest++ = hex[c&0xf]; 126 : }; 127 : ignore_unused(end); 128 : 129 1271 : auto dest = dest_; 130 1271 : auto const dest0 = dest; 131 1271 : auto const last = s.end(); 132 1271 : std::size_t dn = 0; 133 1271 : auto it = s.begin(); 134 : 135 1271 : if(opt.space_as_plus) 136 : { 137 0 : while(it != last) 138 : { 139 0 : BOOST_ASSERT(dest != end); 140 0 : if(*it != '%') 141 : { 142 0 : if(*it == ' ') 143 : { 144 0 : *dest++ = '+'; 145 : } 146 0 : else if(unreserved(*it)) 147 : { 148 0 : *dest++ = *it; 149 : } 150 : else 151 : { 152 0 : encode(dest, *it); 153 0 : dn += 2; 154 : } 155 0 : ++it; 156 : } 157 : else 158 : { 159 0 : *dest++ = *it++; 160 0 : BOOST_ASSERT(dest != end); 161 0 : *dest++ = *it++; 162 0 : BOOST_ASSERT(dest != end); 163 0 : *dest++ = *it++; 164 0 : dn += 2; 165 : } 166 : } 167 : } 168 : else 169 : { 170 5054 : while(it != last) 171 : { 172 3783 : BOOST_ASSERT(dest != end); 173 3783 : if(*it != '%') 174 : { 175 3625 : if(unreserved(*it)) 176 : { 177 3412 : *dest++ = *it; 178 : } 179 : else 180 : { 181 213 : encode(dest, *it); 182 213 : dn += 2; 183 : } 184 3625 : ++it; 185 : } 186 : else 187 : { 188 158 : *dest++ = *it++; 189 158 : BOOST_ASSERT(dest != end); 190 158 : *dest++ = *it++; 191 158 : BOOST_ASSERT(dest != end); 192 158 : *dest++ = *it++; 193 158 : dn += 2; 194 : } 195 : } 196 : } 197 1271 : dest_ = dest; 198 1271 : return dest - dest0 - dn; 199 : } 200 : 201 : } // detail 202 : } // urls 203 : } // boost 204 : 205 : #endif