1  
//
1  
//
2  
// Copyright (c) 2022 Alan de Freitas (alandefreitas at gmail dot com)
2  
// Copyright (c) 2022 Alan de Freitas (alandefreitas at gmail dot 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  
#ifndef BOOST_URL_GRAMMAR_IMPL_UNSIGNED_RULE_HPP
10  
#ifndef BOOST_URL_GRAMMAR_IMPL_UNSIGNED_RULE_HPP
11  
#define BOOST_URL_GRAMMAR_IMPL_UNSIGNED_RULE_HPP
11  
#define BOOST_URL_GRAMMAR_IMPL_UNSIGNED_RULE_HPP
12  

12  

13  
#include <boost/url/grammar/error.hpp>
13  
#include <boost/url/grammar/error.hpp>
14  
#include <boost/url/grammar/digit_chars.hpp>
14  
#include <boost/url/grammar/digit_chars.hpp>
15  
#include <algorithm> // VFALCO grr..
15  
#include <algorithm> // VFALCO grr..
16  

16  

17  
namespace boost {
17  
namespace boost {
18  
namespace urls {
18  
namespace urls {
19  
namespace grammar {
19  
namespace grammar {
20  

20  

21  
template<class U>
21  
template<class U>
22  
auto
22  
auto
23  
unsigned_rule<U>::
23  
unsigned_rule<U>::
24  
parse(
24  
parse(
25  
    char const*& it,
25  
    char const*& it,
26  
    char const* end
26  
    char const* end
27  
        ) const noexcept ->
27  
        ) const noexcept ->
28  
    system::result<value_type>
28  
    system::result<value_type>
29  
{
29  
{
30  
    if(it == end)
30  
    if(it == end)
31  
    {
31  
    {
32  
        // end
32  
        // end
33  
        BOOST_URL_RETURN_EC(
33  
        BOOST_URL_RETURN_EC(
34  
            error::mismatch);
34  
            error::mismatch);
35  
    }
35  
    }
36  
    if(*it == '0')
36  
    if(*it == '0')
37  
    {
37  
    {
38  
        ++it;
38  
        ++it;
39  
        if( it == end ||
39  
        if( it == end ||
40  
            ! digit_chars(*it))
40  
            ! digit_chars(*it))
41  
        {
41  
        {
42  
            return U(0);
42  
            return U(0);
43  
        }
43  
        }
44  
        // bad leading zero
44  
        // bad leading zero
45  
        BOOST_URL_RETURN_EC(
45  
        BOOST_URL_RETURN_EC(
46  
            error::invalid);
46  
            error::invalid);
47  
    }
47  
    }
48  
    if(! digit_chars(*it))
48  
    if(! digit_chars(*it))
49  
    {
49  
    {
50  
        // expected digit
50  
        // expected digit
51  
        BOOST_URL_RETURN_EC(
51  
        BOOST_URL_RETURN_EC(
52  
            error::mismatch);
52  
            error::mismatch);
53  
    }
53  
    }
54  
    static constexpr U Digits10 =
54  
    static constexpr U Digits10 =
55  
        std::numeric_limits<
55  
        std::numeric_limits<
56  
            U>::digits10;
56  
            U>::digits10;
57  
    static constexpr U ten = 10;
57  
    static constexpr U ten = 10;
58  
    char const* safe_end;
58  
    char const* safe_end;
59  
    if(static_cast<std::size_t>(
59  
    if(static_cast<std::size_t>(
60  
            end - it) >= Digits10)
60  
            end - it) >= Digits10)
61  
        safe_end = it + Digits10;
61  
        safe_end = it + Digits10;
62  
    else
62  
    else
63  
        safe_end = end;
63  
        safe_end = end;
64  
    U u = *it - '0';
64  
    U u = *it - '0';
65  
    ++it;
65  
    ++it;
66  
    while(it != safe_end &&
66  
    while(it != safe_end &&
67  
        digit_chars(*it))
67  
        digit_chars(*it))
68  
    {
68  
    {
69  
        char const dig = *it - '0';
69  
        char const dig = *it - '0';
70  
        u = u * ten + dig;
70  
        u = u * ten + dig;
71  
        ++it;
71  
        ++it;
72  
    }
72  
    }
73  
    if( it != end &&
73  
    if( it != end &&
74  
        digit_chars(*it))
74  
        digit_chars(*it))
75  
    {
75  
    {
76  
        static constexpr U Max = (
76  
        static constexpr U Max = (
77  
            std::numeric_limits<
77  
            std::numeric_limits<
78  
                U>::max)();
78  
                U>::max)();
79  
        static constexpr
79  
        static constexpr
80  
            auto div = (Max / ten);
80  
            auto div = (Max / ten);
81  
        static constexpr
81  
        static constexpr
82  
            char rem = (Max % ten);
82  
            char rem = (Max % ten);
83  
        char const dig = *it - '0';
83  
        char const dig = *it - '0';
84  
        if( u > div || (
84  
        if( u > div || (
85  
            u == div && dig > rem))
85  
            u == div && dig > rem))
86  
        {
86  
        {
87  
            // integer overflow
87  
            // integer overflow
88  
            BOOST_URL_RETURN_EC(
88  
            BOOST_URL_RETURN_EC(
89  
                error::invalid);
89  
                error::invalid);
90  
        }
90  
        }
91  
        u = u * ten + dig;
91  
        u = u * ten + dig;
92  
        ++it;
92  
        ++it;
93  
        if( it < end &&
93  
        if( it < end &&
94  
            digit_chars(*it))
94  
            digit_chars(*it))
95  
        {
95  
        {
96  
            // integer overflow
96  
            // integer overflow
97  
            BOOST_URL_RETURN_EC(
97  
            BOOST_URL_RETURN_EC(
98  
                error::invalid);
98  
                error::invalid);
99  
        }
99  
        }
100  
    }
100  
    }
101  

101  

102  
    return u;
102  
    return u;
103  
}
103  
}
104  

104  

105  
} // grammar
105  
} // grammar
106  
} // urls
106  
} // urls
107  
} // boost
107  
} // boost
108  

108  

109  
#endif
109  
#endif