100.00% Lines (125/125) 100.00% Functions (13/13)
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/ipv6_address.hpp> 12   #include <boost/url/ipv6_address.hpp>
13   #include <boost/url/ipv4_address.hpp> 13   #include <boost/url/ipv4_address.hpp>
14   #include <boost/url/rfc/ipv6_address_rule.hpp> 14   #include <boost/url/rfc/ipv6_address_rule.hpp>
15   #include <boost/url/detail/except.hpp> 15   #include <boost/url/detail/except.hpp>
16   #include <boost/url/grammar/parse.hpp> 16   #include <boost/url/grammar/parse.hpp>
17   #include <cstring> 17   #include <cstring>
18   18  
19   namespace boost { 19   namespace boost {
20   namespace urls { 20   namespace urls {
21   21  
HITCBC 22   4 ipv6_address:: 22   4 ipv6_address::
23   ipv6_address( 23   ipv6_address(
HITCBC 24   4 ipv4_address const& addr) noexcept 24   4 ipv4_address const& addr) noexcept
25   { 25   {
HITCBC 26   4 auto const v = addr.to_bytes(); 26   4 auto const v = addr.to_bytes();
HITCBC 27   4 ipv6_address::bytes_type bytes = { 27   4 ipv6_address::bytes_type bytes = {
28   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
HITCBC 29   4 0xff, 0xff, v[0], v[1], v[2], v[3] } }; 29   4 0xff, 0xff, v[0], v[1], v[2], v[3] } };
HITCBC 30   4 std::memcpy(&addr_, bytes.data(), 16); 30   4 std::memcpy(&addr_, bytes.data(), 16);
HITCBC 31   4 } 31   4 }
32   32  
HITCBC 33   60 ipv6_address:: 33   60 ipv6_address::
34   ipv6_address( 34   ipv6_address(
HITCBC 35   60 core::string_view s) 35   60 core::string_view s)
36   : ipv6_address( 36   : ipv6_address(
HITCBC 37   60 parse_ipv6_address(s 37   60 parse_ipv6_address(s
HITCBC 38   60 ).value(BOOST_URL_POS)) 38   60 ).value(BOOST_URL_POS))
39   { 39   {
HITCBC 40   59 } 40   59 }
41   41  
42   core::string_view 42   core::string_view
HITCBC 43   73 ipv6_address:: 43   73 ipv6_address::
44   to_buffer( 44   to_buffer(
45   char* dest, 45   char* dest,
46   std::size_t dest_size) const 46   std::size_t dest_size) const
47   { 47   {
HITCBC 48   73 if(dest_size < max_str_len) 48   73 if(dest_size < max_str_len)
HITCBC 49   1 detail::throw_length_error(); 49   1 detail::throw_length_error();
HITCBC 50   72 auto n = print_impl(dest); 50   72 auto n = print_impl(dest);
HITCBC 51   72 return core::string_view(dest, n); 51   72 return core::string_view(dest, n);
52   } 52   }
53   53  
54   bool 54   bool
HITCBC 55   4 ipv6_address:: 55   4 ipv6_address::
56   is_loopback() const noexcept 56   is_loopback() const noexcept
57   { 57   {
HITCBC 58   4 return *this == loopback(); 58   4 return *this == loopback();
59   } 59   }
60   60  
61   bool 61   bool
HITCBC 62   3 ipv6_address:: 62   3 ipv6_address::
63   is_unspecified() const noexcept 63   is_unspecified() const noexcept
64   { 64   {
HITCBC 65   3 return *this == ipv6_address(); 65   3 return *this == ipv6_address();
66   } 66   }
67   67  
68   bool 68   bool
HITCBC 69   116 ipv6_address:: 69   116 ipv6_address::
70   is_v4_mapped() const noexcept 70   is_v4_mapped() const noexcept
71   { 71   {
72   return 72   return
HITCBC 73   167 addr_[ 0] == 0 && addr_[ 1] == 0 && 73   167 addr_[ 0] == 0 && addr_[ 1] == 0 &&
HITCBC 74   34 addr_[ 2] == 0 && addr_[ 3] == 0 && 74   34 addr_[ 2] == 0 && addr_[ 3] == 0 &&
HITCBC 75   32 addr_[ 4] == 0 && addr_[ 5] == 0 && 75   32 addr_[ 4] == 0 && addr_[ 5] == 0 &&
HITCBC 76   30 addr_[ 6] == 0 && addr_[ 7] == 0 && 76   30 addr_[ 6] == 0 && addr_[ 7] == 0 &&
HITCBC 77   28 addr_[ 8] == 0 && addr_[ 9] == 0 && 77   28 addr_[ 8] == 0 && addr_[ 9] == 0 &&
HITCBC 78   179 addr_[10] == 0xff && 78   179 addr_[10] == 0xff &&
HITCBC 79   128 addr_[11] == 0xff; 79   128 addr_[11] == 0xff;
80   } 80   }
81   81  
82   ipv6_address 82   ipv6_address
HITCBC 83   6 ipv6_address:: 83   6 ipv6_address::
84   loopback() noexcept 84   loopback() noexcept
85   { 85   {
HITCBC 86   6 ipv6_address a; 86   6 ipv6_address a;
HITCBC 87   6 a.addr_[15] = 1; 87   6 a.addr_[15] = 1;
HITCBC 88   6 return a; 88   6 return a;
89   } 89   }
90   90  
91   void 91   void
HITCBC 92   1 ipv6_address:: 92   1 ipv6_address::
93   write_ostream( 93   write_ostream(
94   std::ostream& os) const 94   std::ostream& os) const
95   { 95   {
96   char buf[ipv6_address::max_str_len]; 96   char buf[ipv6_address::max_str_len];
HITCBC 97   1 auto const s = to_buffer(buf, sizeof(buf)); 97   1 auto const s = to_buffer(buf, sizeof(buf));
HITCBC 98   1 os << s; 98   1 os << s;
HITCBC 99   1 } 99   1 }
100   100  
101   std::size_t 101   std::size_t
HITCBC 102   111 ipv6_address:: 102   111 ipv6_address::
103   print_impl( 103   print_impl(
104   char* dest) const noexcept 104   char* dest) const noexcept
105   { 105   {
106   auto const count_zeroes = 106   auto const count_zeroes =
HITCBC 107   569 []( unsigned char const* first, 107   569 []( unsigned char const* first,
108   unsigned char const* const last) 108   unsigned char const* const last)
109   { 109   {
HITCBC 110   569 std::size_t n = 0; 110   569 std::size_t n = 0;
HITCBC 111   943 while(first != last) 111   943 while(first != last)
112   { 112   {
HITCBC 113   918 if( first[0] != 0 || 113   918 if( first[0] != 0 ||
HITCBC 114   486 first[1] != 0) 114   486 first[1] != 0)
115   break; 115   break;
HITCBC 116   374 n += 2; 116   374 n += 2;
HITCBC 117   374 first += 2; 117   374 first += 2;
118   } 118   }
HITCBC 119   569 return n; 119   569 return n;
120   }; 120   };
121   auto const print_hex = 121   auto const print_hex =
HITCBC 122   520 []( char* dest, 122   520 []( char* dest,
123   unsigned short v) 123   unsigned short v)
124   { 124   {
HITCBC 125   520 char const* const dig = 125   520 char const* const dig =
126   "0123456789abcdef"; 126   "0123456789abcdef";
HITCBC 127   520 if(v >= 0x1000) 127   520 if(v >= 0x1000)
128   { 128   {
HITCBC 129   392 *dest++ = dig[v>>12]; 129   392 *dest++ = dig[v>>12];
HITCBC 130   392 v &= 0x0fff; 130   392 v &= 0x0fff;
HITCBC 131   392 *dest++ = dig[v>>8]; 131   392 *dest++ = dig[v>>8];
HITCBC 132   392 v &= 0x0ff; 132   392 v &= 0x0ff;
HITCBC 133   392 *dest++ = dig[v>>4]; 133   392 *dest++ = dig[v>>4];
HITCBC 134   392 v &= 0x0f; 134   392 v &= 0x0f;
HITCBC 135   392 *dest++ = dig[v]; 135   392 *dest++ = dig[v];
136   } 136   }
HITCBC 137   128 else if(v >= 0x100) 137   128 else if(v >= 0x100)
138   { 138   {
HITCBC 139   29 *dest++ = dig[v>>8]; 139   29 *dest++ = dig[v>>8];
HITCBC 140   29 v &= 0x0ff; 140   29 v &= 0x0ff;
HITCBC 141   29 *dest++ = dig[v>>4]; 141   29 *dest++ = dig[v>>4];
HITCBC 142   29 v &= 0x0f; 142   29 v &= 0x0f;
HITCBC 143   29 *dest++ = dig[v]; 143   29 *dest++ = dig[v];
144   } 144   }
HITCBC 145   99 else if(v >= 0x10) 145   99 else if(v >= 0x10)
146   { 146   {
HITCBC 147   2 *dest++ = dig[v>>4]; 147   2 *dest++ = dig[v>>4];
HITCBC 148   2 v &= 0x0f; 148   2 v &= 0x0f;
HITCBC 149   2 *dest++ = dig[v]; 149   2 *dest++ = dig[v];
150   } 150   }
151   else 151   else
152   { 152   {
HITCBC 153   97 *dest++ = dig[v]; 153   97 *dest++ = dig[v];
154   } 154   }
HITCBC 155   520 return dest; 155   520 return dest;
156   }; 156   };
HITCBC 157   111 auto const dest0 = dest; 157   111 auto const dest0 = dest;
158   // find longest run of zeroes 158   // find longest run of zeroes
HITCBC 159   111 std::size_t best_len = 0; 159   111 std::size_t best_len = 0;
HITCBC 160   111 int best_pos = -1; 160   111 int best_pos = -1;
HITCBC 161   111 auto it = addr_.data(); 161   111 auto it = addr_.data();
162   auto const v4 = 162   auto const v4 =
HITCBC 163   111 is_v4_mapped(); 163   111 is_v4_mapped();
HITCBC 164   111 auto const end = v4 ? 164   111 auto const end = v4 ?
HITCBC 165   18 (it + addr_.size() - 4) 165   18 (it + addr_.size() - 4)
HITCBC 166   204 : it + addr_.size(); 166   204 : it + addr_.size();
HITCBC 167   680 while(it != end) 167   680 while(it != end)
168   { 168   {
HITCBC 169   569 auto n = count_zeroes( 169   569 auto n = count_zeroes(
170   it, end); 170   it, end);
HITCBC 171   569 if(n == 0) 171   569 if(n == 0)
172   { 172   {
HITCBC 173   496 it += 2; 173   496 it += 2;
HITCBC 174   496 continue; 174   496 continue;
175   } 175   }
HITCBC 176   73 if(n > best_len) 176   73 if(n > best_len)
177   { 177   {
HITCBC 178   67 best_pos = static_cast< 178   67 best_pos = static_cast<
HITCBC 179   67 int>(it - addr_.data()); 179   67 int>(it - addr_.data());
HITCBC 180   67 best_len = n; 180   67 best_len = n;
181   } 181   }
HITCBC 182   73 it += n; 182   73 it += n;
183   } 183   }
HITCBC 184   111 it = addr_.data(); 184   111 it = addr_.data();
HITCBC 185   111 if(best_pos != 0) 185   111 if(best_pos != 0)
186   { 186   {
HITCBC 187   87 unsigned short v = 187   87 unsigned short v =
HITCBC 188   87 (it[0] * 256U) + it[1]; 188   87 (it[0] * 256U) + it[1];
HITCBC 189   87 dest = print_hex(dest, v); 189   87 dest = print_hex(dest, v);
HITCBC 190   87 it += 2; 190   87 it += 2;
191   } 191   }
192   else 192   else
193   { 193   {
HITCBC 194   24 *dest++ = ':'; 194   24 *dest++ = ':';
HITCBC 195   24 it += best_len; 195   24 it += best_len;
HITCBC 196   24 if(it == end) 196   24 if(it == end)
HITCBC 197   4 *dest++ = ':'; 197   4 *dest++ = ':';
198   } 198   }
HITCBC 199   581 while(it != end) 199   581 while(it != end)
200   { 200   {
HITCBC 201   470 *dest++ = ':'; 201   470 *dest++ = ':';
HITCBC 202   470 if(it - addr_.data() == 202   470 if(it - addr_.data() ==
HITCBC 203   470 best_pos) 203   470 best_pos)
204   { 204   {
HITCBC 205   37 it += best_len; 205   37 it += best_len;
HITCBC 206   37 if(it == end) 206   37 if(it == end)
HITCBC 207   15 *dest++ = ':'; 207   15 *dest++ = ':';
HITCBC 208   37 continue; 208   37 continue;
209   } 209   }
HITCBC 210   433 unsigned short v = 210   433 unsigned short v =
HITCBC 211   433 (it[0] * 256U) + it[1]; 211   433 (it[0] * 256U) + it[1];
HITCBC 212   433 dest = print_hex(dest, v); 212   433 dest = print_hex(dest, v);
HITCBC 213   433 it += 2; 213   433 it += 2;
214   } 214   }
HITCBC 215   111 if(v4) 215   111 if(v4)
216   { 216   {
217   ipv4_address::bytes_type bytes; 217   ipv4_address::bytes_type bytes;
HITCBC 218   9 bytes[0] = it[0]; 218   9 bytes[0] = it[0];
HITCBC 219   9 bytes[1] = it[1]; 219   9 bytes[1] = it[1];
HITCBC 220   9 bytes[2] = it[2]; 220   9 bytes[2] = it[2];
HITCBC 221   9 bytes[3] = it[3]; 221   9 bytes[3] = it[3];
HITCBC 222   9 ipv4_address a(bytes); 222   9 ipv4_address a(bytes);
HITCBC 223   9 *dest++ = ':'; 223   9 *dest++ = ':';
HITCBC 224   9 dest += a.print_impl(dest); 224   9 dest += a.print_impl(dest);
225   } 225   }
HITCBC 226   111 return dest - dest0; 226   111 return dest - dest0;
227   } 227   }
228   228  
229   void 229   void
HITCBC 230   39 ipv6_address:: 230   39 ipv6_address::
231   to_string_impl( 231   to_string_impl(
232   string_token::arg& t) const 232   string_token::arg& t) const
233   { 233   {
234   char buf[max_str_len]; 234   char buf[max_str_len];
HITCBC 235   39 auto const n = print_impl(buf); 235   39 auto const n = print_impl(buf);
HITCBC 236   39 char* dest = t.prepare(n); 236   39 char* dest = t.prepare(n);
HITCBC 237   39 std::memcpy(dest, buf, n); 237   39 std::memcpy(dest, buf, n);
HITCBC 238   39 } 238   39 }
239   239  
240   //------------------------------------------------ 240   //------------------------------------------------
241   241  
242   auto 242   auto
HITCBC 243   172 parse_ipv6_address( 243   172 parse_ipv6_address(
244   core::string_view s) noexcept -> 244   core::string_view s) noexcept ->
245   system::result<ipv6_address> 245   system::result<ipv6_address>
246   { 246   {
HITCBC 247   172 return grammar::parse( 247   172 return grammar::parse(
HITCBC 248   172 s, ipv6_address_rule); 248   172 s, ipv6_address_rule);
249   } 249   }
250   250  
251   } // urls 251   } // urls
252   } // boost 252   } // boost
253   253