Coverage Report

Created: 2026-11-12 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541/deps/parse_num.c
Line
Count
Source
1
/* Originally released by the musl project (http://www.musl-libc.org/) under the
2
 * MIT license. Taken and adapted from the file src/stdlib/atoi.c 
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining a copy
5
 * of this software and associated documentation files (the "Software"), to deal
6
 * in the Software without restriction, including without limitation the rights
7
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
 * copies of the Software, and to permit persons to whom the Software is
9
 * furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in
12
 * all copies or substantial portions of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
 * THE SOFTWARE.
21
 */
22
23
#include "parse_num.h"
24
25
size_t
26
18.9M
parseUInt64(const char *str, size_t size, uint64_t *result) {
27
18.9M
    size_t i = 0;
28
18.9M
    uint64_t n = 0;
29
30
    /* Hex */
31
18.9M
    if(size > 2 && str[0] == '0' && (str[1] | 32) == 'x') {
32
8.02k
        i = 2;
33
2.01M
        for(; i < size; i++) {
34
2.00M
            uint8_t c = (uint8_t)str[i] | 32;
35
2.00M
            if(c >= '0' && c <= '9')
36
1.98M
                c = (uint8_t)(c - '0');
37
23.8k
            else if(c >= 'a' && c <='f')
38
21.9k
                c = (uint8_t)(c - 'a' + 10);
39
1.93k
            else if(c >= 'A' && c <='F')
40
0
                c = (uint8_t)(c - 'A' + 10);
41
1.93k
            else
42
1.93k
                break;
43
            /* Check for overflow before the shift drops the top bits */
44
2.00M
            if(n > (UINT64_MAX >> 4))
45
58
                return 0;
46
2.00M
            n = (n << 4) | (c & 0xF);
47
2.00M
        }
48
7.97k
        *result = n;
49
7.97k
        return (i > 2) ? i : 0; /* 2 -> No digit was parsed */
50
8.02k
    }
51
52
    /* Decimal */
53
50.0M
    for(; i < size; i++) {
54
31.1M
        if(str[i] < '0' || str[i] > '9')
55
71.4k
            break;
56
31.1M
        uint8_t digit = (uint8_t)(str[i] - '0');
57
        /* Check for overflow before n*10 + digit wraps around. A wrapped
58
         * result is not necessarily smaller than the previous value. Both
59
         * bounds are compile-time constants. */
60
31.1M
        if(n > UINT64_MAX / 10 || (n == UINT64_MAX / 10 && digit > UINT64_MAX % 10))
61
299
            return 0;
62
        /* Fast multiplication: n*10 == (n*8) + (n*2) */
63
31.1M
        n = (n << 3) + (n << 1) + digit;
64
31.1M
    }
65
18.9M
    *result = n;
66
18.9M
    return i;
67
18.9M
}
68
69
size_t
70
20.2M
parseInt64(const char *str, size_t size, int64_t *result) {
71
    /* Negative value? */
72
20.2M
    size_t i = 0;
73
20.2M
    bool neg = false;
74
20.2M
    if(*str == '-' || *str == '+') {
75
1.48M
        neg = (*str == '-');
76
1.48M
        i++;
77
1.48M
    }
78
79
    /* Parse as unsigned */
80
20.2M
    uint64_t n = 0;
81
20.2M
    size_t len = parseUInt64(&str[i], size - i, &n);
82
20.2M
    if(len == 0)
83
937
        return 0;
84
85
    /* Check for overflow, adjust and return */
86
20.2M
    if(!neg) {
87
18.7M
        if(n > 9223372036854775807UL)
88
469
            return 0;
89
18.7M
        *result = (int64_t)n;
90
18.7M
    } else {
91
        /* n is unsigned, so 9223372036854775808UL == 2^63 fits without
92
         * overflow. (int64_t)n would also fit for n in [0, 2^63], but
93
         * the negation -(int64_t)(2^63) is undefined because the result
94
         * (which is +2^63) cannot be represented. Use the unsigned
95
         * representation and reinterpret as int64_t instead. */
96
1.43M
        if(n > 9223372036854775808UL)
97
14
            return 0;
98
1.43M
        *result = (n == 9223372036854775808UL)
99
1.43M
            ? (int64_t)(-9223372036854775807LL - 1)
100
1.43M
            : -(int64_t)n;
101
1.43M
    }
102
20.2M
    return len + i;
103
20.2M
}