GCC Code Coverage Report


Directory: libs/url/
File: include/boost/url/impl/encode.hpp
Date: 2025-04-22 15:26:26
Exec Total Coverage
Lines: 99 99 100.0%
Functions: 10 10 100.0%
Branches: 60 70 85.7%

Line Branch Exec Source
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 #ifndef BOOST_URL_IMPL_ENCODE_HPP
11 #define BOOST_URL_IMPL_ENCODE_HPP
12
13 #include "boost/url/grammar/token_rule.hpp"
14 #include <boost/assert.hpp>
15 #include <boost/static_assert.hpp>
16 #include <boost/url/detail/encode.hpp>
17 #include <boost/url/detail/except.hpp>
18 #include <boost/url/encoding_opts.hpp>
19 #include <boost/url/grammar/charset.hpp>
20 #include <boost/url/grammar/hexdig_chars.hpp>
21 #include <boost/url/grammar/string_token.hpp>
22 #include <boost/url/grammar/type_traits.hpp>
23
24 namespace boost {
25 namespace urls {
26
27 //------------------------------------------------
28
29 template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
30 std::size_t
31 899 encoded_size(
32 core::string_view s,
33 CS const& unreserved,
34 encoding_opts opt) noexcept
35 {
36 /* If you get a compile error here, it
37 means that the value you passed does
38 not meet the requirements stated in
39 the documentation.
40 */
41 BOOST_STATIC_ASSERT(
42 grammar::is_charset<CS>::value);
43
44 899 std::size_t n = 0;
45 899 auto it = s.data();
46 899 auto const last = it + s.size();
47
48
5/6
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 833 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
✓ Branch 4 taken 833 times.
✓ Branch 5 taken 22 times.
942 if(! opt.space_as_plus ||
49 43 unreserved(' '))
50 {
51
2/2
✓ Branch 0 taken 3915 times.
✓ Branch 1 taken 833 times.
4809 while(it != last)
52 {
53
2/2
✓ Branch 1 taken 3764 times.
✓ Branch 2 taken 151 times.
3953 if(unreserved(*it))
54 3783 n += 1;
55 else
56 170 n += 3;
57 3953 ++it;
58 }
59 }
60 else
61 {
62
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 22 times.
116 while(it != last)
63 {
64 73 auto c = *it;
65
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 18 times.
73 if(unreserved(c))
66 38 ++n;
67
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
35 else if(c == ' ')
68 17 ++n;
69 else
70 18 n += 3;
71 73 ++it;
72 }
73 }
74 899 return n;
75 }
76
77 //------------------------------------------------
78
79 template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
80 std::size_t
81 600 encode(
82 char* dest,
83 std::size_t size,
84 core::string_view s,
85 CS const& unreserved,
86 encoding_opts opt)
87 {
88 /* If you get a compile error here, it
89 means that the value you passed does
90 not meet the requirements stated in
91 the documentation.
92 */
93 BOOST_STATIC_ASSERT(
94 grammar::is_charset<CS>::value);
95
96 // '%' must be reserved
97
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 543 times.
600 BOOST_ASSERT(! unreserved('%'));
98
99 600 char const* const hex =
100 600 detail::hexdigs[opt.lower_case];
101 710 auto const encode = [hex](
102 char*& dest,
103 unsigned char c) noexcept
104 {
105 110 *dest++ = '%';
106 110 *dest++ = hex[c>>4];
107 110 *dest++ = hex[c&0xf];
108 };
109
110 600 auto it = s.data();
111 600 auto const end = dest + size;
112 600 auto const last = it + s.size();
113 600 auto const dest0 = dest;
114 600 auto const end3 = end - 3;
115
116
2/2
✓ Branch 0 taken 517 times.
✓ Branch 1 taken 26 times.
600 if(! opt.space_as_plus)
117 {
118
2/2
✓ Branch 0 taken 2787 times.
✓ Branch 1 taken 499 times.
3358 while(it != last)
119 {
120
2/2
✓ Branch 1 taken 2668 times.
✓ Branch 2 taken 119 times.
2846 if(unreserved(*it))
121 {
122
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2665 times.
2698 if(dest == end)
123 6 return dest - dest0;
124 2692 *dest++ = *it++;
125 2692 continue;
126 }
127
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 104 times.
148 if(dest > end3)
128 30 return dest - dest0;
129 118 encode(dest, *it++);
130 }
131 512 return dest - dest0;
132 }
133
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
52 else if(! unreserved(' '))
134 {
135 // VFALCO space is usually reserved,
136 // and we depend on this for an
137 // optimization. if this assert
138 // goes off we can split the loop
139 // below into two versions.
140
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
52 BOOST_ASSERT(! unreserved(' '));
141
142
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 12 times.
104 while(it != last)
143 {
144
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 24 times.
80 if(unreserved(*it))
145 {
146
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 13 times.
32 if(dest == end)
147 6 return dest - dest0;
148 26 *dest++ = *it++;
149 26 continue;
150 }
151
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 15 times.
48 if(*it == ' ')
152 {
153
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
18 if(dest == end)
154 4 return dest - dest0;
155 14 *dest++ = '+';
156 14 ++it;
157 14 continue;
158 }
159
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6 times.
30 if(dest > end3)
160 18 return dest - dest0;
161 12 encode(dest, *it++);
162 }
163 }
164 24 return dest - dest0;
165 }
166
167 //------------------------------------------------
168
169 // unsafe encode just
170 // asserts on the output buffer
171 //
172 template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
173 std::size_t
174 175 encode_unsafe(
175 char* dest,
176 std::size_t size,
177 core::string_view s,
178 CS const& unreserved,
179 encoding_opts opt)
180 {
181 BOOST_STATIC_ASSERT(
182 grammar::is_charset<CS>::value);
183
184 // '%' must be reserved
185
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 175 times.
175 BOOST_ASSERT(! unreserved('%'));
186
187 175 auto it = s.data();
188 175 auto const last = it + s.size();
189 175 auto const end = dest + size;
190 ignore_unused(end);
191
192 175 char const* const hex =
193 175 detail::hexdigs[opt.lower_case];
194 267 auto const encode = [end, hex](
195 char*& dest,
196 unsigned char c) noexcept
197 {
198 46 ignore_unused(end);
199 46 *dest++ = '%';
200
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 BOOST_ASSERT(dest != end);
201 46 *dest++ = hex[c>>4];
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 BOOST_ASSERT(dest != end);
203 46 *dest++ = hex[c&0xf];
204 };
205
206 175 auto const dest0 = dest;
207
2/2
✓ Branch 0 taken 166 times.
✓ Branch 1 taken 9 times.
175 if(! opt.space_as_plus)
208 {
209
2/2
✓ Branch 0 taken 439 times.
✓ Branch 1 taken 166 times.
605 while(it != last)
210 {
211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 439 times.
439 BOOST_ASSERT(dest != end);
212
2/2
✓ Branch 1 taken 396 times.
✓ Branch 2 taken 43 times.
439 if(unreserved(*it))
213 396 *dest++ = *it++;
214 else
215 43 encode(dest, *it++);
216 }
217 }
218 else
219 {
220 // VFALCO space is usually reserved,
221 // and we depend on this for an
222 // optimization. if this assert
223 // goes off we can split the loop
224 // below into two versions.
225
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 BOOST_ASSERT(! unreserved(' '));
226
227
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 9 times.
37 while(it != last)
228 {
229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 BOOST_ASSERT(dest != end);
230
2/2
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 8 times.
28 if(unreserved(*it))
231 {
232 20 *dest++ = *it++;
233 }
234
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 else if(*it == ' ')
235 {
236 5 *dest++ = '+';
237 5 ++it;
238 }
239 else
240 {
241 3 encode(dest, *it++);
242 }
243 }
244 }
245 175 return dest - dest0;
246 }
247
248 //------------------------------------------------
249
250 template<
251 BOOST_URL_CONSTRAINT(string_token::StringToken) StringToken,
252 BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
253 BOOST_URL_STRTOK_RETURN
254 24 encode(
255 core::string_view s,
256 CS const& unreserved,
257 encoding_opts opt,
258 StringToken&& token) noexcept
259 {
260 BOOST_STATIC_ASSERT(
261 grammar::is_charset<CS>::value);
262
263 24 auto const n = encoded_size(
264 s, unreserved, opt);
265 24 auto p = token.prepare(n);
266
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 2 times.
24 if(n > 0)
267 22 encode_unsafe(
268 p, n, s, unreserved, opt);
269 24 return token.result();
270 }
271
272 } // urls
273 } // boost
274
275 #endif
276