fix wcsto[iu]max with high characters
[musl] / src / internal / intparse.c
1 #include <stdint.h>
2 #include <limits.h>
3 #include <stdlib.h>
4 #include <errno.h>
5 #include "intparse.h"
6
7 /* Lookup table for digit values. -1==255>=36 -> invalid */
8 static const unsigned char digits[] = {
9 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
10 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
11 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
12  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
13 -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
14 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
15 -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
16 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
17 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
18 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
19 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
20 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
21 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
22 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
23 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
24 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
25 };
26
27 #define SLIM (UINT_MAX/36-1)
28 #define LLIM (UINTMAX_MAX/36-1)
29
30 int __intparse(struct intparse *v, const void *buf, size_t n)
31 {
32         const unsigned char *s = buf;
33         int d, b = v->base;
34
35         v->cnt += n;
36         for (; n; n--, s++) switch (v->state) {
37         case 0:
38                 v->state++;
39                 if (*s=='+' || *s=='-') {
40                         v->neg = *s=='-';
41                         continue;
42                 }
43         case 1:
44                 v->state++;
45                 if (*s=='0' && (!b || b==16)) continue;
46                 if (!b) v->base = b = 10;
47                 v->state++;
48                 goto firstdigit;
49         case 2:
50                 v->state++;
51                 if ((!b || b==16) && (*s|32) == 'x') {
52                         v->base = b = 16;
53                         continue;
54                 }
55                 if (!b) v->base = b = 8;
56                 goto seconddigit;
57         case 3:
58         firstdigit:
59                 if (digits[*s] >= b) {
60                         v->err = EINVAL;
61                         return 0;
62                 }
63         seconddigit:
64                 v->state++;
65         case 4:
66                 if (b==10) {
67                         for (; n && *s-'0'<10U && v->small<=SLIM; n--, s++)
68                                 v->small = v->small * 10 + (*s-'0');
69                 } else if ((b&-b) == b) {
70                         int bs = "\0\1\2\4\7\3\6\5"[(0x17*b)>>5&7];
71                         for (; n && (d=digits[*s])<b && v->small<=SLIM; n--, s++)
72                                 v->small = (v->small<<bs) + d;
73                 } else {
74                         for (; n && (d=digits[*s])<b && v->small<=SLIM; n--, s++)
75                                 v->small = v->small * b + d;
76                 }
77                 if (!n) return 1;
78                 v->state++;
79                 v->val = v->small;
80         case 5:
81                 for (; n && (d=digits[*s])<b && v->val<=LLIM; n--, s++)
82                         v->val = v->val * b + d;
83                 if (!n) return 1;
84                 if (d >= b) goto finished;
85                 if (v->val < (UINTMAX_MAX-d)/b)
86                         v->val = v->val * b + d;
87                 else
88                         v->err = ERANGE;
89                 v->state++;
90                 n--; s++;
91         case 6:
92                 if (n && digits[*s]<b) {
93                         v->err = ERANGE;
94                         v->val = UINTMAX_MAX;
95
96                         n--; s++;
97                 }
98                 for (; n && digits[*s]<b; n--, s++);
99                 if (!n) return 1;
100         }
101         return 1;
102 finished:
103         v->cnt -= n;
104         return 0;
105 }