encode.hpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. //
  2. // Copyright (c) 2019 Vinnie Falco ([email protected])
  3. // Copyright (c) 2022 Alan de Freitas ([email protected])
  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. #ifndef BOOST_URL_DETAIL_ENCODE_HPP
  11. #define BOOST_URL_DETAIL_ENCODE_HPP
  12. #include <boost/url/encoding_opts.hpp>
  13. #include <boost/url/pct_string_view.hpp>
  14. #include <boost/url/grammar/hexdig_chars.hpp>
  15. #include <boost/core/ignore_unused.hpp>
  16. #include <cstdlib>
  17. namespace boost {
  18. namespace urls {
  19. namespace detail {
  20. constexpr
  21. char const* const hexdigs[] = {
  22. "0123456789ABCDEF",
  23. "0123456789abcdef" };
  24. //------------------------------------------------
  25. // re-encode is to percent-encode a
  26. // string that can already contain
  27. // escapes. Characters not in the
  28. // unreserved set are escaped, and
  29. // escapes are passed through unchanged.
  30. //
  31. template<class CharSet>
  32. std::size_t
  33. re_encoded_size_unsafe(
  34. core::string_view s,
  35. CharSet const& unreserved,
  36. encoding_opts opt) noexcept
  37. {
  38. std::size_t n = 0;
  39. auto const end = s.end();
  40. auto it = s.begin();
  41. if(opt.space_as_plus)
  42. {
  43. while(it != end)
  44. {
  45. if(*it != '%')
  46. {
  47. if( unreserved(*it)
  48. || *it == ' ')
  49. n += 1;
  50. else
  51. n += 3;
  52. ++it;
  53. }
  54. else
  55. {
  56. BOOST_ASSERT(end - it >= 3);
  57. BOOST_ASSERT(
  58. grammar::hexdig_value(
  59. it[1]) >= 0);
  60. BOOST_ASSERT(
  61. grammar::hexdig_value(
  62. it[2]) >= 0);
  63. n += 3;
  64. it += 3;
  65. }
  66. }
  67. }
  68. else
  69. {
  70. while(it != end)
  71. {
  72. if(*it != '%')
  73. {
  74. if(unreserved(*it))
  75. n += 1;
  76. else
  77. n += 3;
  78. ++it;
  79. }
  80. else
  81. {
  82. BOOST_ASSERT(end - it >= 3);
  83. BOOST_ASSERT(
  84. grammar::hexdig_value(
  85. it[1]) >= 0);
  86. BOOST_ASSERT(
  87. grammar::hexdig_value(
  88. it[2]) >= 0);
  89. n += 3;
  90. it += 3;
  91. }
  92. }
  93. }
  94. return n;
  95. }
  96. // unchecked
  97. // returns decoded size
  98. template<class CharSet>
  99. std::size_t
  100. re_encode_unsafe(
  101. char*& dest_,
  102. char const* const end,
  103. core::string_view s,
  104. CharSet const& unreserved,
  105. encoding_opts opt) noexcept
  106. {
  107. char const* const hex =
  108. detail::hexdigs[opt.lower_case];
  109. auto const encode = [end, hex](
  110. char*& dest,
  111. char c0) noexcept
  112. {
  113. auto c = static_cast<unsigned char>(c0);
  114. ignore_unused(end);
  115. *dest++ = '%';
  116. BOOST_ASSERT(dest != end);
  117. *dest++ = hex[c>>4];
  118. BOOST_ASSERT(dest != end);
  119. *dest++ = hex[c&0xf];
  120. };
  121. ignore_unused(end);
  122. auto dest = dest_;
  123. auto const dest0 = dest;
  124. auto const last = s.end();
  125. std::size_t dn = 0;
  126. auto it = s.begin();
  127. if(opt.space_as_plus)
  128. {
  129. while(it != last)
  130. {
  131. BOOST_ASSERT(dest != end);
  132. if(*it != '%')
  133. {
  134. if(*it == ' ')
  135. {
  136. *dest++ = '+';
  137. }
  138. else if(unreserved(*it))
  139. {
  140. *dest++ = *it;
  141. }
  142. else
  143. {
  144. encode(dest, *it);
  145. dn += 2;
  146. }
  147. ++it;
  148. }
  149. else
  150. {
  151. *dest++ = *it++;
  152. BOOST_ASSERT(dest != end);
  153. *dest++ = *it++;
  154. BOOST_ASSERT(dest != end);
  155. *dest++ = *it++;
  156. dn += 2;
  157. }
  158. }
  159. }
  160. else
  161. {
  162. while(it != last)
  163. {
  164. BOOST_ASSERT(dest != end);
  165. if(*it != '%')
  166. {
  167. if(unreserved(*it))
  168. {
  169. *dest++ = *it;
  170. }
  171. else
  172. {
  173. encode(dest, *it);
  174. dn += 2;
  175. }
  176. ++it;
  177. }
  178. else
  179. {
  180. *dest++ = *it++;
  181. BOOST_ASSERT(dest != end);
  182. *dest++ = *it++;
  183. BOOST_ASSERT(dest != end);
  184. *dest++ = *it++;
  185. dn += 2;
  186. }
  187. }
  188. }
  189. dest_ = dest;
  190. return dest - dest0 - dn;
  191. }
  192. } // detail
  193. } // urls
  194. } // boost
  195. #endif