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/ipv4_address.hpp>
12  
#include <boost/url/ipv4_address.hpp>
13  
#include <boost/url/detail/except.hpp>
13  
#include <boost/url/detail/except.hpp>
14  
#include <boost/url/grammar/parse.hpp>
14  
#include <boost/url/grammar/parse.hpp>
15  
#include <boost/url/rfc/ipv4_address_rule.hpp>
15  
#include <boost/url/rfc/ipv4_address_rule.hpp>
16  
#include <cstring>
16  
#include <cstring>
17  

17  

18  
namespace boost {
18  
namespace boost {
19  
namespace urls {
19  
namespace urls {
20  

20  

21  
ipv4_address::
21  
ipv4_address::
22  
ipv4_address(
22  
ipv4_address(
23  
    uint_type addr) noexcept
23  
    uint_type addr) noexcept
24  
    : addr_(addr)
24  
    : addr_(addr)
25  
{
25  
{
26  
}
26  
}
27  

27  

28  
ipv4_address::
28  
ipv4_address::
29  
ipv4_address(
29  
ipv4_address(
30  
    bytes_type const& bytes) noexcept
30  
    bytes_type const& bytes) noexcept
31  
{
31  
{
32  
    addr_ =
32  
    addr_ =
33  
(static_cast<unsigned long>(bytes[0]) << 24) |
33  
(static_cast<unsigned long>(bytes[0]) << 24) |
34  
(static_cast<unsigned long>(bytes[1]) << 16) |
34  
(static_cast<unsigned long>(bytes[1]) << 16) |
35  
(static_cast<unsigned long>(bytes[2]) <<  8) |
35  
(static_cast<unsigned long>(bytes[2]) <<  8) |
36  
(static_cast<unsigned long>(bytes[3]));
36  
(static_cast<unsigned long>(bytes[3]));
37  
}
37  
}
38  

38  

39  
ipv4_address::
39  
ipv4_address::
40  
ipv4_address(
40  
ipv4_address(
41  
    core::string_view s)
41  
    core::string_view s)
42  
    : ipv4_address(
42  
    : ipv4_address(
43  
        parse_ipv4_address(s
43  
        parse_ipv4_address(s
44  
            ).value(BOOST_URL_POS))
44  
            ).value(BOOST_URL_POS))
45  
{
45  
{
46  
}
46  
}
47  

47  

48  
auto
48  
auto
49  
ipv4_address::
49  
ipv4_address::
50  
to_bytes() const noexcept ->
50  
to_bytes() const noexcept ->
51  
    bytes_type
51  
    bytes_type
52  
{
52  
{
53  
    bytes_type bytes;
53  
    bytes_type bytes;
54  
    bytes[0] = (addr_ >> 24) & 0xff;
54  
    bytes[0] = (addr_ >> 24) & 0xff;
55  
    bytes[1] = (addr_ >> 16) & 0xff;
55  
    bytes[1] = (addr_ >> 16) & 0xff;
56  
    bytes[2] = (addr_ >>  8) & 0xff;
56  
    bytes[2] = (addr_ >>  8) & 0xff;
57  
    bytes[3] =  addr_        & 0xff;
57  
    bytes[3] =  addr_        & 0xff;
58  
    return bytes;
58  
    return bytes;
59  
}
59  
}
60  

60  

61  
auto
61  
auto
62  
ipv4_address::
62  
ipv4_address::
63  
to_uint() const noexcept ->
63  
to_uint() const noexcept ->
64  
    uint_type
64  
    uint_type
65  
{
65  
{
66  
    return addr_;
66  
    return addr_;
67  
}
67  
}
68  

68  

69  
core::string_view
69  
core::string_view
70  
ipv4_address::
70  
ipv4_address::
71  
to_buffer(
71  
to_buffer(
72  
    char* dest,
72  
    char* dest,
73  
    std::size_t dest_size) const
73  
    std::size_t dest_size) const
74  
{
74  
{
75  
    if(dest_size < max_str_len)
75  
    if(dest_size < max_str_len)
76  
        detail::throw_length_error();
76  
        detail::throw_length_error();
77  
    auto n = print_impl(dest);
77  
    auto n = print_impl(dest);
78  
    return core::string_view(dest, n);
78  
    return core::string_view(dest, n);
79  
}
79  
}
80  

80  

81  
bool
81  
bool
82  
ipv4_address::
82  
ipv4_address::
83  
is_loopback() const noexcept
83  
is_loopback() const noexcept
84  
{
84  
{
85  
    return (to_uint() & 0xFF000000) ==
85  
    return (to_uint() & 0xFF000000) ==
86  
        0x7F000000;
86  
        0x7F000000;
87  
}
87  
}
88  

88  

89  
bool
89  
bool
90  
ipv4_address::
90  
ipv4_address::
91  
is_unspecified() const noexcept
91  
is_unspecified() const noexcept
92  
{
92  
{
93  
    return to_uint() == 0;
93  
    return to_uint() == 0;
94  
}
94  
}
95  

95  

96  
bool
96  
bool
97  
ipv4_address::
97  
ipv4_address::
98  
is_multicast() const noexcept
98  
is_multicast() const noexcept
99  
{
99  
{
100  
    return (to_uint() & 0xF0000000) ==
100  
    return (to_uint() & 0xF0000000) ==
101  
        0xE0000000;
101  
        0xE0000000;
102  
}
102  
}
103  

103  

104  
void
104  
void
105  
ipv4_address::
105  
ipv4_address::
106  
write_ostream(std::ostream& os) const
106  
write_ostream(std::ostream& os) const
107  
{
107  
{
108  
    char buf[ipv4_address::max_str_len];
108  
    char buf[ipv4_address::max_str_len];
109  
    os << to_buffer(buf, sizeof(buf));
109  
    os << to_buffer(buf, sizeof(buf));
110  
}
110  
}
111  

111  

112  
std::size_t
112  
std::size_t
113  
ipv4_address::
113  
ipv4_address::
114  
print_impl(
114  
print_impl(
115  
    char* dest) const noexcept
115  
    char* dest) const noexcept
116  
{
116  
{
117  
    auto const start = dest;
117  
    auto const start = dest;
118  
    auto const write =
118  
    auto const write =
119  
        []( char*& dest,
119  
        []( char*& dest,
120  
            unsigned char v)
120  
            unsigned char v)
121  
        {
121  
        {
122  
            if(v >= 100)
122  
            if(v >= 100)
123  
            {
123  
            {
124  
                *dest++ = '0' +
124  
                *dest++ = '0' +
125  
                    v / 100;
125  
                    v / 100;
126  
                v %= 100;
126  
                v %= 100;
127  
                *dest++ = '0' +
127  
                *dest++ = '0' +
128  
                    v / 10;
128  
                    v / 10;
129  
                v %= 10;
129  
                v %= 10;
130  
            }
130  
            }
131  
            else if(v >= 10)
131  
            else if(v >= 10)
132  
            {
132  
            {
133  
                *dest++ = '0' +
133  
                *dest++ = '0' +
134  
                    v / 10;
134  
                    v / 10;
135  
                v %= 10;
135  
                v %= 10;
136  
            }
136  
            }
137  
            *dest++ = '0' + v;
137  
            *dest++ = '0' + v;
138  
        };
138  
        };
139  
    auto const v = to_uint();
139  
    auto const v = to_uint();
140  
    write(dest, (v >> 24) & 0xff);
140  
    write(dest, (v >> 24) & 0xff);
141  
    *dest++ = '.';
141  
    *dest++ = '.';
142  
    write(dest, (v >> 16) & 0xff);
142  
    write(dest, (v >> 16) & 0xff);
143  
    *dest++ = '.';
143  
    *dest++ = '.';
144  
    write(dest, (v >>  8) & 0xff);
144  
    write(dest, (v >>  8) & 0xff);
145  
    *dest++ = '.';
145  
    *dest++ = '.';
146  
    write(dest, (v      ) & 0xff);
146  
    write(dest, (v      ) & 0xff);
147  
    return dest - start;
147  
    return dest - start;
148  
}
148  
}
149  

149  

150  
void
150  
void
151  
ipv4_address::
151  
ipv4_address::
152  
to_string_impl(
152  
to_string_impl(
153  
    string_token::arg& t) const
153  
    string_token::arg& t) const
154  
{
154  
{
155  
    char buf[max_str_len];
155  
    char buf[max_str_len];
156  
    auto const n = print_impl(buf);
156  
    auto const n = print_impl(buf);
157  
    char* dest = t.prepare(n);
157  
    char* dest = t.prepare(n);
158  
    std::memcpy(dest, buf, n);
158  
    std::memcpy(dest, buf, n);
159  
}
159  
}
160  

160  

161  
//------------------------------------------------
161  
//------------------------------------------------
162  

162  

163  
auto
163  
auto
164  
parse_ipv4_address(
164  
parse_ipv4_address(
165  
    core::string_view s) noexcept ->
165  
    core::string_view s) noexcept ->
166  
        system::result<ipv4_address>
166  
        system::result<ipv4_address>
167  
{
167  
{
168  
    return grammar::parse(
168  
    return grammar::parse(
169  
        s, ipv4_address_rule);
169  
        s, ipv4_address_rule);
170  
}
170  
}
171  

171  

172  
} // urls
172  
} // urls
173  
} // boost
173  
} // boost
174  

174