/work/workdir/UnpackedTarball/harfbuzz/src/hb-number.cc
Line | Count | Source |
1 | | /* |
2 | | * Copyright © 2019-2026 Ebrahim Byagowi |
3 | | * |
4 | | * This is part of HarfBuzz, a text shaping library. |
5 | | * |
6 | | * Permission is hereby granted, without written agreement and without |
7 | | * license or royalty fees, to use, copy, modify, and distribute this |
8 | | * software and its documentation for any purpose, provided that the |
9 | | * above copyright notice and the following two paragraphs appear in |
10 | | * all copies of this software. |
11 | | * |
12 | | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
13 | | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
14 | | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
15 | | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
16 | | * DAMAGE. |
17 | | * |
18 | | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
19 | | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 | | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
21 | | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
22 | | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
23 | | * |
24 | | */ |
25 | | |
26 | | #ifndef HB_NUMBER_CC |
27 | | #define HB_NUMBER_CC |
28 | | #ifdef HB_NUMBER_CC /* Pacify -Wunused-macros. */ |
29 | | |
30 | | #include "hb.hh" |
31 | | #include "hb-number.hh" |
32 | | #include "hb-number-parser.hh" |
33 | | |
34 | | bool |
35 | | hb_parse_double (const char **pp, const char *end, double *pv, bool whole_buffer) |
36 | 0 | { |
37 | 0 | const char *pend = end; |
38 | 0 | double value = hb_strtod (*pp, &pend); |
39 | 0 | if (unlikely (*pp == pend)) return false; |
40 | 0 | if (unlikely (whole_buffer && end != pend)) return false; |
41 | 0 | *pv = value; |
42 | 0 | *pp = pend; |
43 | 0 | return true; |
44 | 0 | } |
45 | | |
46 | | /* Returns the digit value of c in the given base (2..36), or -1 if c |
47 | | * isn't a digit in that base. */ |
48 | | static int |
49 | | _hb_digit_value (char c, int base) |
50 | 291k | { |
51 | 291k | int d; |
52 | 291k | if ('0' <= c && c <= '9') d = c - '0'; |
53 | 184k | else if ('a' <= c && c <= 'z') d = c - 'a' + 10; |
54 | 177k | else if ('A' <= c && c <= 'Z') d = c - 'A' + 10; |
55 | 161k | else return -1; |
56 | 130k | return d < base ? d : -1; |
57 | 291k | } |
58 | | |
59 | | /* Consumes digits in [p, pe) into *value (magnitude). Sets *overflow |
60 | | * if the value would exceed UINT64_MAX. Sets *any_digits if at least |
61 | | * one digit was consumed. Returns the position past the last digit. */ |
62 | | static const char * |
63 | | _hb_scan_digits (const char *p, const char *pe, int base, |
64 | | uint64_t *value, bool *overflow, bool *any_digits) |
65 | 554k | { |
66 | 554k | const uint64_t cutoff = UINT64_MAX / (unsigned) base; |
67 | 554k | const uint64_t cutlim = UINT64_MAX % (unsigned) base; |
68 | 554k | uint64_t v = 0; |
69 | 554k | bool ov = false, any = false; |
70 | | |
71 | 661k | for (; p < pe; p++) |
72 | 291k | { |
73 | 291k | int d = _hb_digit_value (*p, base); |
74 | 291k | if (d < 0) break; |
75 | 106k | any = true; |
76 | 106k | if (v > cutoff || (v == cutoff && (uint64_t) d > cutlim)) |
77 | 191 | ov = true; |
78 | 106k | else |
79 | 106k | v = v * (unsigned) base + (uint64_t) d; |
80 | 106k | } |
81 | | |
82 | 554k | *value = v; |
83 | 554k | *overflow = ov; |
84 | 554k | *any_digits = any; |
85 | 554k | return p; |
86 | 554k | } |
87 | | |
88 | | template<typename T, typename Postprocess> |
89 | | static bool |
90 | | _parse_number (const char **pp, const char *end, T *pv, |
91 | | bool whole_buffer, int base, Postprocess post) |
92 | 554k | { |
93 | 554k | const char *pend = end; |
94 | 554k | const char *p = *pp; |
95 | 554k | bool neg = false, any = false, overflow = false; |
96 | | |
97 | 577k | while (p < pend && ISSPACE (*p)) p++; |
98 | 554k | if (p < pend && (*p == '+' || *p == '-')) { neg = (*p == '-'); p++; } |
99 | | |
100 | | /* Skip an optional "0x"/"0X" prefix for base 16, but only when a hex |
101 | | * digit follows — "0x" alone parses as the digit 0, matching strtoul. */ |
102 | 554k | if (base == 16 && p + 2 < pend && p[0] == '0' && |
103 | 0 | (p[1] == 'x' || p[1] == 'X') && _hb_digit_value (p[2], 16) >= 0) |
104 | 0 | p += 2; |
105 | | |
106 | 554k | uint64_t v = 0; |
107 | 554k | p = _hb_scan_digits (p, pend, base, &v, &overflow, &any); |
108 | 554k | if (unlikely (!any || overflow)) return false; |
109 | | |
110 | 53.3k | T out; |
111 | 53.3k | if (unlikely (!post (v, neg, &out))) return false; |
112 | 53.0k | if (unlikely (whole_buffer && p != pend)) return false; |
113 | | |
114 | 53.0k | *pv = out; |
115 | 53.0k | *pp = p; |
116 | 53.0k | return true; |
117 | 53.0k | } hb-number.cc:bool _parse_number<int, hb_parse_int(char const**, char const*, int*, bool)::$_0>(char const**, char const*, int*, bool, int, hb_parse_int(char const**, char const*, int*, bool)::$_0) Line | Count | Source | 92 | 554k | { | 93 | 554k | const char *pend = end; | 94 | 554k | const char *p = *pp; | 95 | 554k | bool neg = false, any = false, overflow = false; | 96 | | | 97 | 577k | while (p < pend && ISSPACE (*p)) p++; | 98 | 554k | if (p < pend && (*p == '+' || *p == '-')) { neg = (*p == '-'); p++; } | 99 | | | 100 | | /* Skip an optional "0x"/"0X" prefix for base 16, but only when a hex | 101 | | * digit follows — "0x" alone parses as the digit 0, matching strtoul. */ | 102 | 554k | if (base == 16 && p + 2 < pend && p[0] == '0' && | 103 | 0 | (p[1] == 'x' || p[1] == 'X') && _hb_digit_value (p[2], 16) >= 0) | 104 | 0 | p += 2; | 105 | | | 106 | 554k | uint64_t v = 0; | 107 | 554k | p = _hb_scan_digits (p, pend, base, &v, &overflow, &any); | 108 | 554k | if (unlikely (!any || overflow)) return false; | 109 | | | 110 | 53.3k | T out; | 111 | 53.3k | if (unlikely (!post (v, neg, &out))) return false; | 112 | 53.0k | if (unlikely (whole_buffer && p != pend)) return false; | 113 | | | 114 | 53.0k | *pv = out; | 115 | 53.0k | *pp = p; | 116 | 53.0k | return true; | 117 | 53.0k | } |
Unexecuted instantiation: hb-number.cc:bool _parse_number<unsigned int, hb_parse_uint(char const**, char const*, unsigned int*, bool, int)::$_0>(char const**, char const*, unsigned int*, bool, int, hb_parse_uint(char const**, char const*, unsigned int*, bool, int)::$_0) |
118 | | |
119 | | bool |
120 | | hb_parse_int (const char **pp, const char *end, int *pv, bool whole_buffer) |
121 | 554k | { |
122 | 554k | return _parse_number (pp, end, pv, whole_buffer, 10, |
123 | 554k | [] (uint64_t v, bool neg, int *out) { |
124 | | /* INT_MAX = 2^31-1, INT_MIN magnitude = 2^31 */ |
125 | 53.3k | uint64_t limit = neg ? (uint64_t) INT_MAX + 1 : (uint64_t) INT_MAX; |
126 | 53.3k | if (unlikely (v > limit)) return false; |
127 | 53.0k | *out = (int) (neg ? -(int64_t) v : (int64_t) v); |
128 | 53.0k | return true; |
129 | 53.3k | }); |
130 | 554k | } |
131 | | |
132 | | bool |
133 | | hb_parse_uint (const char **pp, const char *end, unsigned *pv, |
134 | | bool whole_buffer, int base) |
135 | 0 | { |
136 | 0 | return _parse_number (pp, end, pv, whole_buffer, base, |
137 | 0 | [] (uint64_t v, bool neg, unsigned *out) { |
138 | 0 | if (unlikely (v > UINT_MAX)) return false; |
139 | | /* Negate in unsigned so -1 wraps to UINT_MAX, matching strtoul |
140 | | * truncated to unsigned. */ |
141 | 0 | unsigned u = (unsigned) v; |
142 | 0 | *out = neg ? (unsigned) (0u - u) : u; |
143 | 0 | return true; |
144 | 0 | }); |
145 | 0 | } |
146 | | |
147 | | #endif /* HB_NUMBER_CC pacify */ |
148 | | #endif /* HB_NUMBER_CC guard */ |