encode.hpp 4.9 KB

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