1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2024 Alan de Freitas (alandefreitas@gmail.com)
3  
// Copyright (c) 2024 Alan de Freitas (alandefreitas@gmail.com)
4  
//
4  
//
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  
//
7  
//
8  
// Official repository: https://github.com/boostorg/url
8  
// Official repository: https://github.com/boostorg/url
9  
//
9  
//
10  

10  

11  
#ifndef BOOST_URL_RFC_IMPL_IPV6_ADDRESS_RULE_HPP
11  
#ifndef BOOST_URL_RFC_IMPL_IPV6_ADDRESS_RULE_HPP
12  
#define BOOST_URL_RFC_IMPL_IPV6_ADDRESS_RULE_HPP
12  
#define BOOST_URL_RFC_IMPL_IPV6_ADDRESS_RULE_HPP
13  

13  

14  
#include <boost/url/detail/config.hpp>
14  
#include <boost/url/detail/config.hpp>
15  
#include <boost/url/rfc/ipv4_address_rule.hpp>
15  
#include <boost/url/rfc/ipv4_address_rule.hpp>
16  
#include <boost/url/rfc/detail/h16_rule.hpp>
16  
#include <boost/url/rfc/detail/h16_rule.hpp>
17  
#include <boost/url/grammar/charset.hpp>
17  
#include <boost/url/grammar/charset.hpp>
18  
#include <boost/url/grammar/hexdig_chars.hpp>
18  
#include <boost/url/grammar/hexdig_chars.hpp>
19  
#include <boost/url/grammar/error.hpp>
19  
#include <boost/url/grammar/error.hpp>
20  
#include <boost/url/grammar/parse.hpp>
20  
#include <boost/url/grammar/parse.hpp>
21  
#include <boost/assert.hpp>
21  
#include <boost/assert.hpp>
22  
#include <cstring>
22  
#include <cstring>
23  

23  

24  
namespace boost {
24  
namespace boost {
25  
namespace urls {
25  
namespace urls {
26  

26  

27  
namespace detail {
27  
namespace detail {
28  

28  

29  
// return `true` if the hex
29  
// return `true` if the hex
30  
// word could be 0..255 if
30  
// word could be 0..255 if
31  
// interpreted as decimal
31  
// interpreted as decimal
32  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
32  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
33  
bool
33  
bool
34  
maybe_octet(
34  
maybe_octet(
35  
    unsigned char const* p) noexcept
35  
    unsigned char const* p) noexcept
36  
{
36  
{
37  
    unsigned short word =
37  
    unsigned short word =
38  
        static_cast<unsigned short>(
38  
        static_cast<unsigned short>(
39  
            p[0]) * 256 +
39  
            p[0]) * 256 +
40  
        static_cast<unsigned short>(
40  
        static_cast<unsigned short>(
41  
            p[1]);
41  
            p[1]);
42  
    if(word > 0x255)
42  
    if(word > 0x255)
43  
        return false;
43  
        return false;
44  
    if(((word >>  4) & 0xf) > 9)
44  
    if(((word >>  4) & 0xf) > 9)
45  
        return false;
45  
        return false;
46  
    if((word & 0xf) > 9)
46  
    if((word & 0xf) > 9)
47  
        return false;
47  
        return false;
48  
    return true;
48  
    return true;
49  
}
49  
}
50  

50  

51  
} // detail
51  
} // detail
52  

52  

53  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
53  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
54  
auto
54  
auto
55  
implementation_defined::ipv6_address_rule_t::
55  
implementation_defined::ipv6_address_rule_t::
56  
parse(
56  
parse(
57  
    char const*& it,
57  
    char const*& it,
58  
    char const* const end
58  
    char const* const end
59  
        ) const noexcept ->
59  
        ) const noexcept ->
60  
    system::result<ipv6_address>
60  
    system::result<ipv6_address>
61  
{
61  
{
62  
    int n = 8;      // words needed
62  
    int n = 8;      // words needed
63  
    int b = -1;     // value of n
63  
    int b = -1;     // value of n
64  
                    // when '::' seen
64  
                    // when '::' seen
65  
    bool c = false; // need colon
65  
    bool c = false; // need colon
66  
    auto prev = it;
66  
    auto prev = it;
67  
    ipv6_address::bytes_type bytes;
67  
    ipv6_address::bytes_type bytes;
68  
    system::result<detail::h16_rule_t::value_type> rv;
68  
    system::result<detail::h16_rule_t::value_type> rv;
69  
    for(;;)
69  
    for(;;)
70  
    {
70  
    {
71  
        if(it == end)
71  
        if(it == end)
72  
        {
72  
        {
73  
            if(b != -1)
73  
            if(b != -1)
74  
            {
74  
            {
75  
                // end in "::"
75  
                // end in "::"
76  
                break;
76  
                break;
77  
            }
77  
            }
78  
            BOOST_ASSERT(n > 0);
78  
            BOOST_ASSERT(n > 0);
79  
            // not enough words
79  
            // not enough words
80  
            BOOST_URL_CONSTEXPR_RETURN_EC(
80  
            BOOST_URL_CONSTEXPR_RETURN_EC(
81  
                grammar::error::invalid);
81  
                grammar::error::invalid);
82  
        }
82  
        }
83  
        if(*it == ':')
83  
        if(*it == ':')
84  
        {
84  
        {
85  
            ++it;
85  
            ++it;
86  
            if(it == end)
86  
            if(it == end)
87  
            {
87  
            {
88  
                // expected ':'
88  
                // expected ':'
89  
                BOOST_URL_CONSTEXPR_RETURN_EC(
89  
                BOOST_URL_CONSTEXPR_RETURN_EC(
90  
                    grammar::error::invalid);
90  
                    grammar::error::invalid);
91  
            }
91  
            }
92  
            if(*it == ':')
92  
            if(*it == ':')
93  
            {
93  
            {
94  
                if(b == -1)
94  
                if(b == -1)
95  
                {
95  
                {
96  
                    // first "::"
96  
                    // first "::"
97  
                    ++it;
97  
                    ++it;
98  
                    --n;
98  
                    --n;
99  
                    b = n;
99  
                    b = n;
100  
                    if(n == 0)
100  
                    if(n == 0)
101  
                        break;
101  
                        break;
102  
                    c = false;
102  
                    c = false;
103  
                    continue;
103  
                    continue;
104  
                }
104  
                }
105  
                // extra "::" found
105  
                // extra "::" found
106  
                BOOST_URL_CONSTEXPR_RETURN_EC(
106  
                BOOST_URL_CONSTEXPR_RETURN_EC(
107  
                    grammar::error::invalid);
107  
                    grammar::error::invalid);
108  
            }
108  
            }
109  
            if(c)
109  
            if(c)
110  
            {
110  
            {
111  
                prev = it;
111  
                prev = it;
112  
                rv = grammar::parse(
112  
                rv = grammar::parse(
113  
                    it, end,
113  
                    it, end,
114  
                    detail::h16_rule);
114  
                    detail::h16_rule);
115  
                if(! rv)
115  
                if(! rv)
116  
                    return rv.error();
116  
                    return rv.error();
117  
                bytes[2*(8-n)+0] = rv->hi;
117  
                bytes[2*(8-n)+0] = rv->hi;
118  
                bytes[2*(8-n)+1] = rv->lo;
118  
                bytes[2*(8-n)+1] = rv->lo;
119  
                --n;
119  
                --n;
120  
                if(n == 0)
120  
                if(n == 0)
121  
                    break;
121  
                    break;
122  
                continue;
122  
                continue;
123  
            }
123  
            }
124  
            // expected h16
124  
            // expected h16
125  
            BOOST_URL_CONSTEXPR_RETURN_EC(
125  
            BOOST_URL_CONSTEXPR_RETURN_EC(
126  
                grammar::error::invalid);
126  
                grammar::error::invalid);
127  
        }
127  
        }
128  
        if(*it == '.')
128  
        if(*it == '.')
129  
        {
129  
        {
130  
            if(b == -1 && n > 1)
130  
            if(b == -1 && n > 1)
131  
            {
131  
            {
132  
                // not enough h16
132  
                // not enough h16
133  
                BOOST_URL_CONSTEXPR_RETURN_EC(
133  
                BOOST_URL_CONSTEXPR_RETURN_EC(
134  
                    grammar::error::invalid);
134  
                    grammar::error::invalid);
135  
            }
135  
            }
136  
            if(! detail::maybe_octet(
136  
            if(! detail::maybe_octet(
137  
                &bytes[2*(7-n)]))
137  
                &bytes[2*(7-n)]))
138  
            {
138  
            {
139  
                // invalid octet
139  
                // invalid octet
140  
                BOOST_URL_CONSTEXPR_RETURN_EC(
140  
                BOOST_URL_CONSTEXPR_RETURN_EC(
141  
                    grammar::error::invalid);
141  
                    grammar::error::invalid);
142  
            }
142  
            }
143  
            // rewind the h16 and
143  
            // rewind the h16 and
144  
            // parse it as ipv4
144  
            // parse it as ipv4
145  
            it = prev;
145  
            it = prev;
146  
            auto rv1 = grammar::parse(
146  
            auto rv1 = grammar::parse(
147  
                it, end, ipv4_address_rule);
147  
                it, end, ipv4_address_rule);
148  
            if(! rv1)
148  
            if(! rv1)
149  
                return rv1.error();
149  
                return rv1.error();
150  
            auto v4 = *rv1;
150  
            auto v4 = *rv1;
151  
            auto const b4 =
151  
            auto const b4 =
152  
                v4.to_bytes();
152  
                v4.to_bytes();
153  
            bytes[2*(7-n)+0] = b4[0];
153  
            bytes[2*(7-n)+0] = b4[0];
154  
            bytes[2*(7-n)+1] = b4[1];
154  
            bytes[2*(7-n)+1] = b4[1];
155  
            bytes[2*(7-n)+2] = b4[2];
155  
            bytes[2*(7-n)+2] = b4[2];
156  
            bytes[2*(7-n)+3] = b4[3];
156  
            bytes[2*(7-n)+3] = b4[3];
157  
            --n;
157  
            --n;
158  
            break;
158  
            break;
159  
        }
159  
        }
160  
        auto d =
160  
        auto d =
161  
            grammar::hexdig_value(*it);
161  
            grammar::hexdig_value(*it);
162  
        if( b != -1 &&
162  
        if( b != -1 &&
163  
            d < 0)
163  
            d < 0)
164  
        {
164  
        {
165  
            // ends in "::"
165  
            // ends in "::"
166  
            break;
166  
            break;
167  
        }
167  
        }
168  
        if(! c)
168  
        if(! c)
169  
        {
169  
        {
170  
            prev = it;
170  
            prev = it;
171  
            rv = grammar::parse(
171  
            rv = grammar::parse(
172  
                it, end,
172  
                it, end,
173  
                detail::h16_rule);
173  
                detail::h16_rule);
174  
            if(! rv)
174  
            if(! rv)
175  
                return rv.error();
175  
                return rv.error();
176  
            bytes[2*(8-n)+0] = rv->hi;
176  
            bytes[2*(8-n)+0] = rv->hi;
177  
            bytes[2*(8-n)+1] = rv->lo;
177  
            bytes[2*(8-n)+1] = rv->lo;
178  
            --n;
178  
            --n;
179  
            if(n == 0)
179  
            if(n == 0)
180  
                break;
180  
                break;
181  
            c = true;
181  
            c = true;
182  
            continue;
182  
            continue;
183  
        }
183  
        }
184  
        // ':' divides a word
184  
        // ':' divides a word
185  
        BOOST_URL_CONSTEXPR_RETURN_EC(
185  
        BOOST_URL_CONSTEXPR_RETURN_EC(
186  
            grammar::error::invalid);
186  
            grammar::error::invalid);
187  
    }
187  
    }
188  
    if(b == -1)
188  
    if(b == -1)
189  
        return ipv6_address{bytes};
189  
        return ipv6_address{bytes};
190  
    if(b == n)
190  
    if(b == n)
191  
    {
191  
    {
192  
        // "::" last
192  
        // "::" last
193  
        auto const i =
193  
        auto const i =
194  
            2 * (7 - n);
194  
            2 * (7 - n);
195  
        std::memset(
195  
        std::memset(
196  
            &bytes[i],
196  
            &bytes[i],
197  
            0, 16 - i);
197  
            0, 16 - i);
198  
    }
198  
    }
199  
    else if(b == 7)
199  
    else if(b == 7)
200  
    {
200  
    {
201  
        // "::" first
201  
        // "::" first
202  
        auto const i =
202  
        auto const i =
203  
            2 * (b - n);
203  
            2 * (b - n);
204  
        std::memmove(
204  
        std::memmove(
205  
            &bytes[16 - i],
205  
            &bytes[16 - i],
206  
            &bytes[2],
206  
            &bytes[2],
207  
            i);
207  
            i);
208  
        std::memset(
208  
        std::memset(
209  
            &bytes[0],
209  
            &bytes[0],
210  
            0, 16 - i);
210  
            0, 16 - i);
211  
    }
211  
    }
212  
    else
212  
    else
213  
    {
213  
    {
214  
        // "::" in middle
214  
        // "::" in middle
215  
        auto const i0 =
215  
        auto const i0 =
216  
            2 * (7 - b);
216  
            2 * (7 - b);
217  
        auto const i1 =
217  
        auto const i1 =
218  
            2 * (b - n);
218  
            2 * (b - n);
219  
        std::memmove(
219  
        std::memmove(
220  
            &bytes[16 - i1],
220  
            &bytes[16 - i1],
221  
            &bytes[i0 + 2],
221  
            &bytes[i0 + 2],
222  
            i1);
222  
            i1);
223  
        std::memset(
223  
        std::memset(
224  
            &bytes[i0],
224  
            &bytes[i0],
225  
            0, 16 - (i0 + i1));
225  
            0, 16 - (i0 + i1));
226  
    }
226  
    }
227  
    return ipv6_address{bytes};
227  
    return ipv6_address{bytes};
228  
}
228  
}
229  

229  

230  
} // urls
230  
} // urls
231  
} // boost
231  
} // boost
232  

232  

233  

233  

234  
#endif
234  
#endif