1 +
//
 
2 +
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
 
3 +
// Copyright (c) 2024 Alan de Freitas (alandefreitas@gmail.com)
 
4 +
//
 
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)
 
7 +
//
 
8 +
// Official repository: https://github.com/boostorg/url
 
9 +
//
 
10 +

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

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

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

 
27 +
namespace detail {
 
28 +

 
29 +
inline BOOST_URL_CXX20_CONSTEXPR
 
30 +
bool
 
31 +
maybe_octet(
 
32 +
    unsigned char const* p) noexcept
 
33 +
{
 
34 +
    unsigned short word =
 
35 +
        static_cast<unsigned short>(
 
36 +
            p[0]) * 256 +
 
37 +
        static_cast<unsigned short>(
 
38 +
            p[1]);
 
39 +
    if(word > 0x255)
 
40 +
        return false;
 
41 +
    if(((word >>  4) & 0xf) > 9)
 
42 +
        return false;
 
43 +
    if((word & 0xf) > 9)
 
44 +
        return false;
 
45 +
    return true;
 
46 +
}
 
47 +

 
48 +
} // detail
 
49 +

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

 
211 +
} // urls
 
212 +
} // boost
 
213 +

 
214 +

 
215 +
#endif