ext-boost/boost/url/detail/encode.hpp
2023-05-22 18:45:02 +10:00

206 lines
4.7 KiB
C++

//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/url
//
#ifndef BOOST_URL_DETAIL_ENCODE_HPP
#define BOOST_URL_DETAIL_ENCODE_HPP
#include <boost/url/encoding_opts.hpp>
#include <boost/url/pct_string_view.hpp>
#include <boost/url/grammar/hexdig_chars.hpp>
#include <boost/core/ignore_unused.hpp>
#include <cstdlib>
namespace boost {
namespace urls {
namespace detail {
constexpr
char const* const hexdigs[] = {
"0123456789ABCDEF",
"0123456789abcdef" };
//------------------------------------------------
// re-encode is to percent-encode a
// string that can already contain
// escapes. Characters not in the
// unreserved set are escaped, and
// escapes are passed through unchanged.
//
template<class CharSet>
std::size_t
re_encoded_size_unsafe(
string_view s,
CharSet const& unreserved,
encoding_opts opt) noexcept
{
std::size_t n = 0;
auto const end = s.end();
auto it = s.begin();
if(opt.space_as_plus)
{
while(it != end)
{
if(*it != '%')
{
if( unreserved(*it)
|| *it == ' ')
n += 1;
else
n += 3;
++it;
}
else
{
BOOST_ASSERT(end - it >= 3);
BOOST_ASSERT(
grammar::hexdig_value(
it[1]) >= 0);
BOOST_ASSERT(
grammar::hexdig_value(
it[2]) >= 0);
n += 3;
it += 3;
}
}
}
else
{
while(it != end)
{
if(*it != '%')
{
if(unreserved(*it))
n += 1;
else
n += 3;
++it;
}
else
{
BOOST_ASSERT(end - it >= 3);
BOOST_ASSERT(
grammar::hexdig_value(
it[1]) >= 0);
BOOST_ASSERT(
grammar::hexdig_value(
it[2]) >= 0);
n += 3;
it += 3;
}
}
}
return n;
}
// unchecked
// returns decoded size
template<class CharSet>
std::size_t
re_encode_unsafe(
char*& dest_,
char const* const end,
string_view s,
CharSet const& unreserved,
encoding_opts opt) noexcept
{
char const* const hex =
detail::hexdigs[opt.lower_case];
auto const encode = [end, hex](
char*& dest,
unsigned char c) noexcept
{
ignore_unused(end);
*dest++ = '%';
BOOST_ASSERT(dest != end);
*dest++ = hex[c>>4];
BOOST_ASSERT(dest != end);
*dest++ = hex[c&0xf];
};
ignore_unused(end);
auto dest = dest_;
auto const dest0 = dest;
auto const last = s.end();
std::size_t dn = 0;
auto it = s.begin();
if(opt.space_as_plus)
{
while(it != last)
{
BOOST_ASSERT(dest != end);
if(*it != '%')
{
if(*it == ' ')
{
*dest++ = '+';
}
else if(unreserved(*it))
{
*dest++ = *it;
}
else
{
encode(dest, *it);
dn += 2;
}
++it;
}
else
{
*dest++ = *it++;
BOOST_ASSERT(dest != end);
*dest++ = *it++;
BOOST_ASSERT(dest != end);
*dest++ = *it++;
dn += 2;
}
}
}
else
{
while(it != last)
{
BOOST_ASSERT(dest != end);
if(*it != '%')
{
if(unreserved(*it))
{
*dest++ = *it;
}
else
{
encode(dest, *it);
dn += 2;
}
++it;
}
else
{
*dest++ = *it++;
BOOST_ASSERT(dest != end);
*dest++ = *it++;
BOOST_ASSERT(dest != end);
*dest++ = *it++;
dn += 2;
}
}
}
dest_ = dest;
return dest - dest0 - dn;
}
} // detail
} // urls
} // boost
#endif