100.00% Lines (46/46) 100.00% Functions (6/6)
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   10  
11   #include <boost/url/detail/config.hpp> 11   #include <boost/url/detail/config.hpp>
12   #include <boost/url/detail/decode.hpp> 12   #include <boost/url/detail/decode.hpp>
13   #include <boost/url/grammar/charset.hpp> 13   #include <boost/url/grammar/charset.hpp>
14   #include <boost/url/grammar/hexdig_chars.hpp> 14   #include <boost/url/grammar/hexdig_chars.hpp>
15   #include <memory> 15   #include <memory>
16   16  
17   namespace boost { 17   namespace boost {
18   namespace urls { 18   namespace urls {
19   namespace detail { 19   namespace detail {
20   20  
21   char 21   char
HITCBC 22   3196 decode_one( 22   3196 decode_one(
23   char const* const it) noexcept 23   char const* const it) noexcept
24   { 24   {
HITCBC 25   3196 auto d0 = grammar::hexdig_value(it[0]); 25   3196 auto d0 = grammar::hexdig_value(it[0]);
HITCBC 26   3196 auto d1 = grammar::hexdig_value(it[1]); 26   3196 auto d1 = grammar::hexdig_value(it[1]);
27   return static_cast<char>( 27   return static_cast<char>(
HITCBC 28   3196 ((static_cast< 28   3196 ((static_cast<
HITCBC 29   3196 unsigned char>(d0) << 4) + 29   3196 unsigned char>(d0) << 4) +
HITCBC 30   3196 (static_cast< 30   3196 (static_cast<
HITCBC 31   3196 unsigned char>(d1)))); 31   3196 unsigned char>(d1))));
32   } 32   }
33   33  
34   std::size_t 34   std::size_t
HITCBC 35   10111 decode_bytes_unsafe( 35   10123 decode_bytes_unsafe(
36   core::string_view s) noexcept 36   core::string_view s) noexcept
37   { 37   {
HITCBC 38   10111 auto p = s.begin(); 38   10123 auto p = s.begin();
HITCBC 39   10111 auto const end = s.end(); 39   10123 auto const end = s.end();
HITCBC 40   10111 std::size_t dn = 0; 40   10123 std::size_t dn = 0;
HITCBC 41   10111 if(s.size() >= 3) 41   10123 if(s.size() >= 3)
42   { 42   {
HITCBC 43   5248 auto const safe_end = end - 2; 43   5254 auto const safe_end = end - 2;
HITCBC 44   81854 while(p < safe_end) 44   81872 while(p < safe_end)
45   { 45   {
HITCBC 46   76606 if(*p != '%') 46   76618 if(*p != '%')
HITCBC 47   68044 p += 1; 47   68056 p += 1;
48   else 48   else
HITCBC 49   8562 p += 3; 49   8562 p += 3;
HITCBC 50   76606 ++dn; 50   76618 ++dn;
51   } 51   }
52   } 52   }
HITCBC 53   10111 dn += end - p; 53   10123 dn += end - p;
HITCBC 54   10111 return dn; 54   10123 return dn;
55   } 55   }
56   56  
57   template <bool SpaceAsPlus> 57   template <bool SpaceAsPlus>
58   std::size_t 58   std::size_t
59   decode_unsafe_is_plus_impl(char c); 59   decode_unsafe_is_plus_impl(char c);
60   60  
61   template <> 61   template <>
62   std::size_t 62   std::size_t
HITCBC 63   25134 decode_unsafe_is_plus_impl<true>(char c) 63   25134 decode_unsafe_is_plus_impl<true>(char c)
64   { 64   {
HITCBC 65   25134 return c == '+'; 65   25134 return c == '+';
66   } 66   }
67   67  
68   template <> 68   template <>
69   std::size_t 69   std::size_t
HITCBC 70   38041 decode_unsafe_is_plus_impl<false>(char) 70   38041 decode_unsafe_is_plus_impl<false>(char)
71   { 71   {
HITCBC 72   38041 return false; 72   38041 return false;
73   } 73   }
74   74  
75   75  
76   template <bool SpaceAsPlus> 76   template <bool SpaceAsPlus>
77   std::size_t 77   std::size_t
HITCBC 78   19488 decode_unsafe_impl( 78   19488 decode_unsafe_impl(
79   char* const dest0, 79   char* const dest0,
80   char const* end, 80   char const* end,
81   core::string_view s) noexcept 81   core::string_view s) noexcept
82   { 82   {
HITCBC 83   19488 auto it = s.data(); 83   19488 auto it = s.data();
HITCBC 84   19488 auto const last = it + s.size(); 84   19488 auto const last = it + s.size();
HITCBC 85   19488 auto dest = dest0; 85   19488 auto dest = dest0;
86   86  
HITCBC 87   82663 while(it != last) 87   82663 while(it != last)
88   { 88   {
89   // LCOV_EXCL_START 89   // LCOV_EXCL_START
90   if(dest == end) 90   if(dest == end)
91   { 91   {
92   /* 92   /*
93   * dest too small: unreachable 93   * dest too small: unreachable
94   * public functions always pass 94   * public functions always pass
95   * a buffer of sufficient size 95   * a buffer of sufficient size
96   */ 96   */
97   return dest - dest0; 97   return dest - dest0;
98   } 98   }
99   // LCOV_EXCL_STOP 99   // LCOV_EXCL_STOP
HITCBC 100   63175 if(decode_unsafe_is_plus_impl<SpaceAsPlus>(*it)) 100   63175 if(decode_unsafe_is_plus_impl<SpaceAsPlus>(*it))
101   { 101   {
102   // plus to space 102   // plus to space
HITCBC 103   384 *dest++ = ' '; 103   384 *dest++ = ' ';
HITCBC 104   384 ++it; 104   384 ++it;
HITCBC 105   384 continue; 105   384 continue;
106   } 106   }
HITCBC 107   62791 if(*it == '%') 107   62791 if(*it == '%')
108   { 108   {
109   // escaped 109   // escaped
HITCBC 110   2978 ++it; 110   2978 ++it;
111   // LCOV_EXCL_START 111   // LCOV_EXCL_START
112   if(last - it < 2) 112   if(last - it < 2)
113   { 113   {
114   // `%` not followed by two hex digits 114   // `%` not followed by two hex digits
115   // invalid input: unreachable 115   // invalid input: unreachable
116   // public functions always pass 116   // public functions always pass
117   // a valid string_view. 117   // a valid string_view.
118   // initialize output 118   // initialize output
119   std::memset(dest, 119   std::memset(dest,
120   0, end - dest); 120   0, end - dest);
121   return dest - dest0; 121   return dest - dest0;
122   } 122   }
123   // LCOV_EXCL_STOP 123   // LCOV_EXCL_STOP
HITCBC 124   2978 *dest++ = decode_one(it); 124   2978 *dest++ = decode_one(it);
HITCBC 125   2978 it += 2; 125   2978 it += 2;
HITCBC 126   2978 continue; 126   2978 continue;
127   } 127   }
128   // unescaped 128   // unescaped
HITCBC 129   59813 *dest++ = *it++; 129   59813 *dest++ = *it++;
130   } 130   }
HITCBC 131   19487 return dest - dest0; 131   19487 return dest - dest0;
132   } 132   }
133   133  
134   std::size_t 134   std::size_t
HITCBC 135   19488 decode_unsafe( 135   19488 decode_unsafe(
136   char* const dest0, 136   char* const dest0,
137   char const* end, 137   char const* end,
138   core::string_view s, 138   core::string_view s,
139   encoding_opts opt) noexcept 139   encoding_opts opt) noexcept
140   { 140   {
HITCBC 141   19488 if(opt.space_as_plus) 141   19488 if(opt.space_as_plus)
142   { 142   {
HITCBC 143   10722 return decode_unsafe_impl<true>( 143   10722 return decode_unsafe_impl<true>(
HITCBC 144   10722 dest0, end, s); 144   10722 dest0, end, s);
145   } 145   }
HITCBC 146   8766 return decode_unsafe_impl<false>( 146   8766 return decode_unsafe_impl<false>(
HITCBC 147   8766 dest0, end, s); 147   8766 dest0, end, s);
148   } 148   }
149   149  
150   } // detail 150   } // detail
151   } // urls 151   } // urls
152   } // boost 152   } // boost