ipv6_address.ipp 5.0 KB

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