encode.hpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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) noexcept
  36. {
  37. std::size_t n = 0;
  38. auto it = s.begin();
  39. auto const end = s.end();
  40. while(it != end)
  41. {
  42. if(*it != '%')
  43. {
  44. if( unreserved(*it) )
  45. n += 1;
  46. else
  47. n += 3;
  48. ++it;
  49. }
  50. else
  51. {
  52. BOOST_ASSERT(end - it >= 3);
  53. BOOST_ASSERT(
  54. grammar::hexdig_value(
  55. it[1]) >= 0);
  56. BOOST_ASSERT(
  57. grammar::hexdig_value(
  58. it[2]) >= 0);
  59. n += 3;
  60. it += 3;
  61. }
  62. }
  63. return n;
  64. }
  65. // unchecked
  66. // returns decoded size
  67. template<class CharSet>
  68. std::size_t
  69. re_encode_unsafe(
  70. char*& dest_,
  71. char const* const end,
  72. core::string_view s,
  73. CharSet const& unreserved) noexcept
  74. {
  75. static constexpr bool lower_case = false;
  76. char const* const hex = detail::hexdigs[lower_case];
  77. auto const encode = [end, hex](
  78. char*& dest,
  79. char c0) noexcept
  80. {
  81. auto c = static_cast<unsigned char>(c0);
  82. ignore_unused(end);
  83. *dest++ = '%';
  84. BOOST_ASSERT(dest != end);
  85. *dest++ = hex[c>>4];
  86. BOOST_ASSERT(dest != end);
  87. *dest++ = hex[c&0xf];
  88. };
  89. ignore_unused(end);
  90. auto dest = dest_;
  91. auto const dest0 = dest;
  92. auto const last = s.end();
  93. std::size_t dn = 0;
  94. auto it = s.begin();
  95. while(it != last)
  96. {
  97. BOOST_ASSERT(dest != end);
  98. if(*it != '%')
  99. {
  100. if(unreserved(*it))
  101. {
  102. *dest++ = *it;
  103. }
  104. else
  105. {
  106. encode(dest, *it);
  107. dn += 2;
  108. }
  109. ++it;
  110. }
  111. else
  112. {
  113. *dest++ = *it++;
  114. BOOST_ASSERT(dest != end);
  115. *dest++ = *it++;
  116. BOOST_ASSERT(dest != end);
  117. *dest++ = *it++;
  118. dn += 2;
  119. }
  120. }
  121. dest_ = dest;
  122. return dest - dest0 - dn;
  123. }
  124. } // detail
  125. } // urls
  126. } // boost
  127. #endif