1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
3  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
4  
//
4  
//
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  
//
7  
//
8  
// Official repository: https://github.com/boostorg/url
8  
// Official repository: https://github.com/boostorg/url
9  
//
9  
//
10  

10  

11  
#ifndef BOOST_URL_DETAIL_ENCODE_HPP
11  
#ifndef BOOST_URL_DETAIL_ENCODE_HPP
12  
#define BOOST_URL_DETAIL_ENCODE_HPP
12  
#define BOOST_URL_DETAIL_ENCODE_HPP
13  

13  

14  
#include <boost/url/encoding_opts.hpp>
14  
#include <boost/url/encoding_opts.hpp>
15  
#include <boost/url/pct_string_view.hpp>
15  
#include <boost/url/pct_string_view.hpp>
16  
#include <boost/url/grammar/hexdig_chars.hpp>
16  
#include <boost/url/grammar/hexdig_chars.hpp>
17  
#include <boost/core/ignore_unused.hpp>
17  
#include <boost/core/ignore_unused.hpp>
18  
#include <cstdlib>
18  
#include <cstdlib>
19  

19  

20  
namespace boost {
20  
namespace boost {
21  
namespace urls {
21  
namespace urls {
22  
namespace detail {
22  
namespace detail {
23  

23  

24  
constexpr
24  
constexpr
25  
char const* const hexdigs[] = {
25  
char const* const hexdigs[] = {
26  
    "0123456789ABCDEF",
26  
    "0123456789ABCDEF",
27  
    "0123456789abcdef" };
27  
    "0123456789abcdef" };
28  

28  

29  
//------------------------------------------------
29  
//------------------------------------------------
30  

30  

31  
// re-encode is to percent-encode a
31  
// re-encode is to percent-encode a
32  
// string that can already contain
32  
// string that can already contain
33  
// escapes. Characters not in the
33  
// escapes. Characters not in the
34  
// unreserved set are escaped, and
34  
// unreserved set are escaped, and
35  
// escapes are passed through unchanged.
35  
// escapes are passed through unchanged.
36  
//
36  
//
37  
template<class CharSet>
37  
template<class CharSet>
38  
std::size_t
38  
std::size_t
39  
re_encoded_size_unsafe(
39  
re_encoded_size_unsafe(
40  
    core::string_view s,
40  
    core::string_view s,
41  
    CharSet const& unreserved) noexcept
41  
    CharSet const& unreserved) noexcept
42  
{
42  
{
43  
    std::size_t n = 0;
43  
    std::size_t n = 0;
44  
    auto it = s.begin();
44  
    auto it = s.begin();
45  
    auto const end = s.end();
45  
    auto const end = s.end();
46  
    while(it != end)
46  
    while(it != end)
47  
    {
47  
    {
48  
        if(*it != '%')
48  
        if(*it != '%')
49  
        {
49  
        {
50  
            if( unreserved(*it) )
50  
            if( unreserved(*it) )
51  
                n += 1;
51  
                n += 1;
52  
            else
52  
            else
53  
                n += 3;
53  
                n += 3;
54  
            ++it;
54  
            ++it;
55  
        }
55  
        }
56  
        else
56  
        else
57  
        {
57  
        {
58  
            BOOST_ASSERT(end - it >= 3);
58  
            BOOST_ASSERT(end - it >= 3);
59  
            BOOST_ASSERT(
59  
            BOOST_ASSERT(
60  
                    grammar::hexdig_value(
60  
                    grammar::hexdig_value(
61  
                            it[1]) >= 0);
61  
                            it[1]) >= 0);
62  
            BOOST_ASSERT(
62  
            BOOST_ASSERT(
63  
                    grammar::hexdig_value(
63  
                    grammar::hexdig_value(
64  
                            it[2]) >= 0);
64  
                            it[2]) >= 0);
65  
            n += 3;
65  
            n += 3;
66  
            it += 3;
66  
            it += 3;
67  
        }
67  
        }
68  
    }
68  
    }
69  
    return n;
69  
    return n;
70  
}
70  
}
71  

71  

72  
// unchecked
72  
// unchecked
73  
// returns decoded size
73  
// returns decoded size
74  
template<class CharSet>
74  
template<class CharSet>
75  
std::size_t
75  
std::size_t
76  
re_encode_unsafe(
76  
re_encode_unsafe(
77  
    char*& dest_,
77  
    char*& dest_,
78  
    char const* const end,
78  
    char const* const end,
79  
    core::string_view s,
79  
    core::string_view s,
80  
    CharSet const& unreserved) noexcept
80  
    CharSet const& unreserved) noexcept
81  
{
81  
{
82  
    static constexpr bool lower_case = false;
82  
    static constexpr bool lower_case = false;
83  
    char const* const hex = detail::hexdigs[lower_case];
83  
    char const* const hex = detail::hexdigs[lower_case];
84  
    auto const encode = [end, hex](
84  
    auto const encode = [end, hex](
85  
            char*& dest,
85  
            char*& dest,
86  
            char c0) noexcept
86  
            char c0) noexcept
87  
    {
87  
    {
88  
        auto c = static_cast<unsigned char>(c0);
88  
        auto c = static_cast<unsigned char>(c0);
89  
        ignore_unused(end);
89  
        ignore_unused(end);
90  
        *dest++ = '%';
90  
        *dest++ = '%';
91  
        BOOST_ASSERT(dest != end);
91  
        BOOST_ASSERT(dest != end);
92  
        *dest++ = hex[c>>4];
92  
        *dest++ = hex[c>>4];
93  
        BOOST_ASSERT(dest != end);
93  
        BOOST_ASSERT(dest != end);
94  
        *dest++ = hex[c&0xf];
94  
        *dest++ = hex[c&0xf];
95  
    };
95  
    };
96  
    ignore_unused(end);
96  
    ignore_unused(end);
97  

97  

98  
    auto dest = dest_;
98  
    auto dest = dest_;
99  
    auto const dest0 = dest;
99  
    auto const dest0 = dest;
100  
    auto const last = s.end();
100  
    auto const last = s.end();
101  
    std::size_t dn = 0;
101  
    std::size_t dn = 0;
102  
    auto it = s.begin();
102  
    auto it = s.begin();
103  
    while(it != last)
103  
    while(it != last)
104  
    {
104  
    {
105  
        BOOST_ASSERT(dest != end);
105  
        BOOST_ASSERT(dest != end);
106  
        if(*it != '%')
106  
        if(*it != '%')
107  
        {
107  
        {
108  
            if(unreserved(*it))
108  
            if(unreserved(*it))
109  
            {
109  
            {
110  
                *dest++ = *it;
110  
                *dest++ = *it;
111  
            }
111  
            }
112  
            else
112  
            else
113  
            {
113  
            {
114  
                encode(dest, *it);
114  
                encode(dest, *it);
115  
                dn += 2;
115  
                dn += 2;
116  
            }
116  
            }
117  
            ++it;
117  
            ++it;
118  
        }
118  
        }
119  
        else
119  
        else
120  
        {
120  
        {
121  
            *dest++ = *it++;
121  
            *dest++ = *it++;
122  
            BOOST_ASSERT(dest != end);
122  
            BOOST_ASSERT(dest != end);
123  
            *dest++ = *it++;
123  
            *dest++ = *it++;
124  
            BOOST_ASSERT(dest != end);
124  
            BOOST_ASSERT(dest != end);
125  
            *dest++ = *it++;
125  
            *dest++ = *it++;
126  
            dn += 2;
126  
            dn += 2;
127  
        }
127  
        }
128  
    }
128  
    }
129  
    dest_ = dest;
129  
    dest_ = dest;
130  
    return dest - dest0 - dn;
130  
    return dest - dest0 - dn;
131  
}
131  
}
132  

132  

133  
} // detail
133  
} // detail
134  
} // urls
134  
} // urls
135  
} // boost
135  
} // boost
136  

136  

137  
#endif
137  
#endif