Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/boostorg/url
8 : //
9 :
10 :
11 : #include <boost/url/detail/config.hpp>
12 : #include "decode.hpp"
13 : #include <boost/url/grammar/charset.hpp>
14 : #include <boost/url/grammar/hexdig_chars.hpp>
15 : #include <memory>
16 :
17 : namespace boost {
18 : namespace urls {
19 : namespace detail {
20 :
21 : char
22 798 : decode_one(
23 : char const* const it) noexcept
24 : {
25 798 : auto d0 = grammar::hexdig_value(it[0]);
26 798 : auto d1 = grammar::hexdig_value(it[1]);
27 : return static_cast<char>(
28 798 : ((static_cast<
29 798 : unsigned char>(d0) << 4) +
30 798 : (static_cast<
31 798 : unsigned char>(d1))));
32 : }
33 :
34 : std::size_t
35 1977 : decode_bytes_unsafe(
36 : core::string_view s) noexcept
37 : {
38 1977 : auto p = s.begin();
39 1977 : auto const end = s.end();
40 1977 : std::size_t dn = 0;
41 1977 : if(s.size() >= 3)
42 : {
43 826 : auto const safe_end = end - 2;
44 7303 : while(p < safe_end)
45 : {
46 6477 : if(*p != '%')
47 6218 : p += 1;
48 : else
49 259 : p += 3;
50 6477 : ++dn;
51 : }
52 : }
53 1977 : dn += end - p;
54 1977 : return dn;
55 : }
56 :
57 : template <bool SpaceAsPlus>
58 : std::size_t
59 : decode_unsafe_is_plus_impl(char c);
60 :
61 : template <>
62 : std::size_t
63 4247 : decode_unsafe_is_plus_impl<true>(char c)
64 : {
65 4247 : return c == '+';
66 : }
67 :
68 : template <>
69 : std::size_t
70 10696 : decode_unsafe_is_plus_impl<false>(char)
71 : {
72 10696 : return false;
73 : }
74 :
75 :
76 : template <bool SpaceAsPlus>
77 : std::size_t
78 2715 : decode_unsafe_impl(
79 : char* const dest0,
80 : char const* end,
81 : core::string_view s) noexcept
82 : {
83 2715 : auto it = s.data();
84 2715 : auto const last = it + s.size();
85 2715 : auto dest = dest0;
86 :
87 17658 : while(it != last)
88 : {
89 : // LCOV_EXCL_START
90 : if(dest == end)
91 : {
92 : /*
93 : * dest too small: unreachable
94 : * public functions always pass
95 : * a buffer of sufficient size
96 : */
97 : return dest - dest0;
98 : }
99 : // LCOV_EXCL_STOP
100 14943 : if(decode_unsafe_is_plus_impl<SpaceAsPlus>(*it))
101 : {
102 : // plus to space
103 5 : *dest++ = ' ';
104 5 : ++it;
105 5 : continue;
106 : }
107 14938 : if(*it == '%')
108 : {
109 : // escaped
110 690 : ++it;
111 : // LCOV_EXCL_START
112 : if(last - it < 2)
113 : {
114 : // `%` not followed by two hex digits
115 : // invalid input: unreachable
116 : // public functions always pass
117 : // a valid string_view.
118 : // initialize output
119 : std::memset(dest,
120 : 0, end - dest);
121 : return dest - dest0;
122 : }
123 : // LCOV_EXCL_STOP
124 690 : *dest++ = decode_one(it);
125 690 : it += 2;
126 690 : continue;
127 : }
128 : // unescaped
129 14248 : *dest++ = *it++;
130 : }
131 2715 : return dest - dest0;
132 : }
133 :
134 : std::size_t
135 2715 : decode_unsafe(
136 : char* const dest0,
137 : char const* end,
138 : core::string_view s,
139 : encoding_opts opt) noexcept
140 : {
141 2715 : if(opt.space_as_plus)
142 : {
143 709 : return decode_unsafe_impl<true>(
144 709 : dest0, end, s);
145 : }
146 2006 : return decode_unsafe_impl<false>(
147 2006 : dest0, end, s);
148 : }
149 :
150 : } // detail
151 : } // urls
152 : } // boost
153 :
|