100.00% Lines (112/112) 100.00% Functions (10/10)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/boostorg/url 7   // Official repository: https://github.com/boostorg/url
8   // 8   //
9   9  
10   #ifndef BOOST_URL_IMPL_ENCODE_HPP 10   #ifndef BOOST_URL_IMPL_ENCODE_HPP
11   #define BOOST_URL_IMPL_ENCODE_HPP 11   #define BOOST_URL_IMPL_ENCODE_HPP
12   12  
13   #include <boost/url/grammar/token_rule.hpp> 13   #include <boost/url/grammar/token_rule.hpp>
14   #include <boost/assert.hpp> 14   #include <boost/assert.hpp>
15   #include <boost/core/detail/static_assert.hpp> 15   #include <boost/core/detail/static_assert.hpp>
16   #include <boost/url/detail/encode.hpp> 16   #include <boost/url/detail/encode.hpp>
17   #include <boost/url/detail/except.hpp> 17   #include <boost/url/detail/except.hpp>
18   #include <boost/url/encoding_opts.hpp> 18   #include <boost/url/encoding_opts.hpp>
19   #include <boost/url/grammar/charset.hpp> 19   #include <boost/url/grammar/charset.hpp>
20   #include <boost/url/grammar/hexdig_chars.hpp> 20   #include <boost/url/grammar/hexdig_chars.hpp>
21   #include <boost/url/grammar/string_token.hpp> 21   #include <boost/url/grammar/string_token.hpp>
22   #include <boost/url/grammar/type_traits.hpp> 22   #include <boost/url/grammar/type_traits.hpp>
23   23  
24   namespace boost { 24   namespace boost {
25   namespace urls { 25   namespace urls {
26   26  
27   //------------------------------------------------ 27   //------------------------------------------------
28   28  
29   template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS> 29   template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
30   std::size_t 30   std::size_t
HITCBC 31   5523 encoded_size( 31   5531 encoded_size(
32   core::string_view s, 32   core::string_view s,
33   CS const& allowed, 33   CS const& allowed,
34   encoding_opts opt) noexcept 34   encoding_opts opt) noexcept
35   { 35   {
36   /* 36   /*
37   If you get a compilation error here, it 37   If you get a compilation error here, it
38   means that the value you passed does 38   means that the value you passed does
39   not meet the requirements stated in 39   not meet the requirements stated in
40   the documentation. 40   the documentation.
41   */ 41   */
42   BOOST_CORE_STATIC_ASSERT( 42   BOOST_CORE_STATIC_ASSERT(
43   grammar::is_charset<CS>::value); 43   grammar::is_charset<CS>::value);
44   44  
HITCBC 45   5523 std::size_t n = 0; 45   5531 std::size_t n = 0;
HITCBC 46   5523 auto it = s.data(); 46   5531 auto it = s.data();
HITCBC 47   5523 auto const last = it + s.size(); 47   5531 auto const last = it + s.size();
48   48  
HITCBC 49   5523 if (!opt.space_as_plus) 49   5531 if (!opt.space_as_plus)
50   { 50   {
HITCBC 51   25592 while (it != last) 51   25592 while (it != last)
52   { 52   {
HITCBC 53   22571 char const c = *it; 53   22571 char const c = *it;
HITCBC 54   22571 if (allowed(c)) 54   22571 if (allowed(c))
55   { 55   {
HITCBC 56   19533 ++n; 56   19533 ++n;
57   } 57   }
58   else 58   else
59   { 59   {
HITCBC 60   3038 n += 3; 60   3038 n += 3;
61   } 61   }
HITCBC 62   22571 ++it; 62   22571 ++it;
63   } 63   }
64   } 64   }
65   else 65   else
66   { 66   {
67   // '+' is always encoded (thus 67   // '+' is always encoded (thus
68   // spending 3 chars) even if 68   // spending 3 chars) even if
69   // allowed because "%2B" and 69   // allowed because "%2B" and
70   // "+" have different meanings 70   // "+" have different meanings
71   // when space as plus is enabled 71   // when space as plus is enabled
72   using FNT = bool (*)(CS const& allowed, char); 72   using FNT = bool (*)(CS const& allowed, char);
HITCBC 73   2502 FNT takes_one_char = 73   2510 FNT takes_one_char =
HITCBC 74   5004 allowed('+') ? 74   5020 allowed('+') ?
HITCBC 75   2500 (allowed(' ') ? 75   2508 (allowed(' ') ?
HITCBC 76   4 FNT([](CS const& allowed, char c){ return allowed(c) && c != '+'; }) : 76   4 FNT([](CS const& allowed, char c){ return allowed(c) && c != '+'; }) :
HITCBC 77   22612 FNT([](CS const& allowed, char c){ return (allowed(c) || c == ' ') && c != '+'; })) : 77   22628 FNT([](CS const& allowed, char c){ return (allowed(c) || c == ' ') && c != '+'; })) :
HITCBC 78   2 (allowed(' ') ? 78   2 (allowed(' ') ?
HITCBC 79   4 FNT([](CS const& allowed, char c){ return allowed(c); }) : 79   4 FNT([](CS const& allowed, char c){ return allowed(c); }) :
HITCBC 80   4 FNT([](CS const& allowed, char c){ return allowed(c) || c == ' '; })); 80   4 FNT([](CS const& allowed, char c){ return allowed(c) || c == ' '; }));
HITCBC 81   22624 while (it != last) 81   22640 while (it != last)
82   { 82   {
HITCBC 83   20122 char const c = *it; 83   20130 char const c = *it;
HITCBC 84   20122 if (takes_one_char(allowed, c)) 84   20130 if (takes_one_char(allowed, c))
85   { 85   {
HITCBC 86   16975 ++n; 86   16983 ++n;
87   } 87   }
88   else 88   else
89   { 89   {
HITCBC 90   3147 n += 3; 90   3147 n += 3;
91   } 91   }
HITCBC 92   20122 ++it; 92   20130 ++it;
93   } 93   }
94   } 94   }
HITCBC 95   5523 return n; 95   5531 return n;
96   } 96   }
97   97  
98   //------------------------------------------------ 98   //------------------------------------------------
99   99  
100   template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS> 100   template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
101   std::size_t 101   std::size_t
HITCBC 102   21818 encode( 102   21826 encode(
103   char* dest, 103   char* dest,
104   std::size_t size, 104   std::size_t size,
105   core::string_view s, 105   core::string_view s,
106   CS const& allowed, 106   CS const& allowed,
107   encoding_opts opt) 107   encoding_opts opt)
108   { 108   {
109   /* If you get a compilation error here, it 109   /* If you get a compilation error here, it
110   means that the value you passed does 110   means that the value you passed does
111   not meet the requirements stated in 111   not meet the requirements stated in
112   the documentation. 112   the documentation.
113   */ 113   */
114   BOOST_CORE_STATIC_ASSERT( 114   BOOST_CORE_STATIC_ASSERT(
115   grammar::is_charset<CS>::value); 115   grammar::is_charset<CS>::value);
116   116  
117   // '%' must be reserved 117   // '%' must be reserved
HITCBC 118   21818 BOOST_ASSERT(!allowed('%')); 118   21826 BOOST_ASSERT(!allowed('%'));
119   119  
HITCBC 120   21818 char const* const hex = 120   21826 char const* const hex =
HITCBC 121   21818 detail::hexdigs[opt.lower_case]; 121   21826 detail::hexdigs[opt.lower_case];
HITCBC 122   266468 auto const encode = [hex]( 122   266476 auto const encode = [hex](
123   char*& dest, 123   char*& dest,
124   unsigned char c) noexcept 124   unsigned char c) noexcept
125   { 125   {
HITCBC 126   244650 *dest++ = '%'; 126   244650 *dest++ = '%';
HITCBC 127   244650 *dest++ = hex[c>>4]; 127   244650 *dest++ = hex[c>>4];
HITCBC 128   244650 *dest++ = hex[c&0xf]; 128   244650 *dest++ = hex[c&0xf];
129   }; 129   };
130   130  
HITCBC 131   21818 auto it = s.data(); 131   21826 auto it = s.data();
HITCBC 132   21818 auto const end = dest + size; 132   21826 auto const end = dest + size;
HITCBC 133   21818 auto const last = it + s.size(); 133   21826 auto const last = it + s.size();
HITCBC 134   21818 auto const dest0 = dest; 134   21826 auto const dest0 = dest;
135   135  
HITCBC 136   21818 if (!opt.space_as_plus) 136   21826 if (!opt.space_as_plus)
137   { 137   {
HITCBC 138   1303128 while(it != last) 138   1303128 while(it != last)
139   { 139   {
HITCBC 140   1294002 char const c = *it; 140   1294002 char const c = *it;
HITCBC 141   1294002 if (allowed(c)) 141   1294002 if (allowed(c))
142   { 142   {
HITCBC 143   1048403 if(dest == end) 143   1048403 if(dest == end)
HITCBC 144   6102 return dest - dest0; 144   6102 return dest - dest0;
HITCBC 145   1042301 *dest++ = c; 145   1042301 *dest++ = c;
HITCBC 146   1042301 ++it; 146   1042301 ++it;
HITCBC 147   1042301 continue; 147   1042301 continue;
148   } 148   }
HITCBC 149   245599 if (end - dest < 3) 149   245599 if (end - dest < 3)
HITCBC 150   4088 return dest - dest0; 150   4088 return dest - dest0;
HITCBC 151   241511 encode(dest, c); 151   241511 encode(dest, c);
HITCBC 152   241511 ++it; 152   241511 ++it;
153   } 153   }
HITCBC 154   9126 return dest - dest0; 154   9126 return dest - dest0;
155   } 155   }
156   else 156   else
157   { 157   {
HITCBC 158   22594 while (it != last) 158   22610 while (it != last)
159   { 159   {
HITCBC 160   20106 char const c = *it; 160   20114 char const c = *it;
HITCBC 161   20106 if (c == ' ') 161   20114 if (c == ' ')
162   { 162   {
HITCBC 163   262 if(dest == end) 163   262 if(dest == end)
HITCBC 164   2 return dest - dest0; 164   2 return dest - dest0;
HITCBC 165   260 *dest++ = '+'; 165   260 *dest++ = '+';
HITCBC 166   260 ++it; 166   260 ++it;
HITCBC 167   260 continue; 167   260 continue;
168   } 168   }
HITCBC 169   36537 else if ( 169   36553 else if (
HITCBC 170   19844 allowed(c) && 170   19852 allowed(c) &&
171   c != '+') 171   c != '+')
172   { 172   {
HITCBC 173   16696 if(dest == end) 173   16704 if(dest == end)
HITCBC 174   3 return dest - dest0; 174   3 return dest - dest0;
HITCBC 175   16693 *dest++ = c; 175   16701 *dest++ = c;
HITCBC 176   16693 ++it; 176   16701 ++it;
HITCBC 177   16693 continue; 177   16701 continue;
178   } 178   }
HITCBC 179   3148 if(end - dest < 3) 179   3148 if(end - dest < 3)
HITCBC 180   9 return dest - dest0; 180   9 return dest - dest0;
HITCBC 181   3139 encode(dest, c); 181   3139 encode(dest, c);
HITCBC 182   3139 ++it; 182   3139 ++it;
183   } 183   }
184   } 184   }
HITCBC 185   2488 return dest - dest0; 185   2496 return dest - dest0;
186   } 186   }
187   187  
188   //------------------------------------------------ 188   //------------------------------------------------
189   189  
190   // unsafe encode just 190   // unsafe encode just
191   // asserts on the output buffer 191   // asserts on the output buffer
192   // 192   //
193   template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS> 193   template<BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
194   std::size_t 194   std::size_t
HITCBC 195   1569 encode_unsafe( 195   1569 encode_unsafe(
196   char* dest, 196   char* dest,
197   std::size_t size, 197   std::size_t size,
198   core::string_view s, 198   core::string_view s,
199   CS const& allowed, 199   CS const& allowed,
200   encoding_opts opt) 200   encoding_opts opt)
201   { 201   {
202   BOOST_CORE_STATIC_ASSERT( 202   BOOST_CORE_STATIC_ASSERT(
203   grammar::is_charset<CS>::value); 203   grammar::is_charset<CS>::value);
204   204  
205   // '%' must be reserved 205   // '%' must be reserved
HITCBC 206   1569 BOOST_ASSERT(!allowed('%')); 206   1569 BOOST_ASSERT(!allowed('%'));
207   207  
HITCBC 208   1569 auto it = s.data(); 208   1569 auto it = s.data();
HITCBC 209   1569 auto const last = it + s.size(); 209   1569 auto const last = it + s.size();
HITCBC 210   1569 auto const end = dest + size; 210   1569 auto const end = dest + size;
211   ignore_unused(end); 211   ignore_unused(end);
212   212  
HITCBC 213   1569 char const* const hex = 213   1569 char const* const hex =
HITCBC 214   1569 detail::hexdigs[opt.lower_case]; 214   1569 detail::hexdigs[opt.lower_case];
HITCBC 215   2955 auto const encode = [end, hex]( 215   2955 auto const encode = [end, hex](
216   char*& dest, 216   char*& dest,
217   unsigned char c) noexcept 217   unsigned char c) noexcept
218   { 218   {
HITCBC 219   693 ignore_unused(end); 219   693 ignore_unused(end);
HITCBC 220   693 *dest++ = '%'; 220   693 *dest++ = '%';
HITCBC 221   693 BOOST_ASSERT(dest != end); 221   693 BOOST_ASSERT(dest != end);
HITCBC 222   693 *dest++ = hex[c>>4]; 222   693 *dest++ = hex[c>>4];
HITCBC 223   693 BOOST_ASSERT(dest != end); 223   693 BOOST_ASSERT(dest != end);
HITCBC 224   693 *dest++ = hex[c&0xf]; 224   693 *dest++ = hex[c&0xf];
225   }; 225   };
226   226  
HITCBC 227   1569 auto const dest0 = dest; 227   1569 auto const dest0 = dest;
HITCBC 228   1569 if (!opt.space_as_plus) 228   1569 if (!opt.space_as_plus)
229   { 229   {
HITCBC 230   8140 while(it != last) 230   8140 while(it != last)
231   { 231   {
HITCBC 232   6584 BOOST_ASSERT(dest != end); 232   6584 BOOST_ASSERT(dest != end);
HITCBC 233   6584 char const c = *it; 233   6584 char const c = *it;
HITCBC 234   6584 if(allowed(c)) 234   6584 if(allowed(c))
235   { 235   {
HITCBC 236   5899 *dest++ = c; 236   5899 *dest++ = c;
237   } 237   }
238   else 238   else
239   { 239   {
HITCBC 240   685 encode(dest, c); 240   685 encode(dest, c);
241   } 241   }
HITCBC 242   6584 ++it; 242   6584 ++it;
243   } 243   }
244   } 244   }
245   else 245   else
246   { 246   {
HITCBC 247   53 while(it != last) 247   53 while(it != last)
248   { 248   {
HITCBC 249   40 BOOST_ASSERT(dest != end); 249   40 BOOST_ASSERT(dest != end);
HITCBC 250   40 char const c = *it; 250   40 char const c = *it;
HITCBC 251   40 if (c == ' ') 251   40 if (c == ' ')
252   { 252   {
HITCBC 253   9 *dest++ = '+'; 253   9 *dest++ = '+';
254   } 254   }
HITCBC 255   31 else if ( 255   31 else if (
HITCBC 256   31 allowed(c) && 256   31 allowed(c) &&
257   c != '+') 257   c != '+')
258   { 258   {
HITCBC 259   23 *dest++ = c; 259   23 *dest++ = c;
260   } 260   }
261   else 261   else
262   { 262   {
HITCBC 263   8 encode(dest, c); 263   8 encode(dest, c);
264   } 264   }
HITCBC 265   40 ++it; 265   40 ++it;
266   } 266   }
267   } 267   }
HITCBC 268   1569 return dest - dest0; 268   1569 return dest - dest0;
269   } 269   }
270   270  
271   //------------------------------------------------ 271   //------------------------------------------------
272   272  
273   template< 273   template<
274   BOOST_URL_CONSTRAINT(string_token::StringToken) StringToken, 274   BOOST_URL_CONSTRAINT(string_token::StringToken) StringToken,
275   BOOST_URL_CONSTRAINT(grammar::CharSet) CS> 275   BOOST_URL_CONSTRAINT(grammar::CharSet) CS>
276   BOOST_URL_STRTOK_RETURN 276   BOOST_URL_STRTOK_RETURN
HITCBC 277   28 encode( 277   28 encode(
278   core::string_view s, 278   core::string_view s,
279   CS const& allowed, 279   CS const& allowed,
280   encoding_opts opt, 280   encoding_opts opt,
281   StringToken&& token) 281   StringToken&& token)
282   { 282   {
283   BOOST_CORE_STATIC_ASSERT( 283   BOOST_CORE_STATIC_ASSERT(
284   grammar::is_charset<CS>::value); 284   grammar::is_charset<CS>::value);
285   285  
HITCBC 286   28 auto const n = encoded_size( 286   28 auto const n = encoded_size(
287   s, allowed, opt); 287   s, allowed, opt);
HITCBC 288   28 auto p = token.prepare(n); 288   28 auto p = token.prepare(n);
HITCBC 289   28 if(n > 0) 289   28 if(n > 0)
HITCBC 290   26 encode_unsafe( 290   26 encode_unsafe(
291   p, n, s, allowed, opt); 291   p, n, s, allowed, opt);
HITCBC 292   28 return token.result(); 292   28 return token.result();
293   } 293   }
294   294  
295   } // urls 295   } // urls
296   } // boost 296   } // boost
297   297  
298   #endif 298   #endif