1 : /*-
2 : * Copyright (c) 1990, 1993
3 : * The Regents of the University of California. All rights reserved.
4 : *
5 : * Redistribution and use in source and binary forms, with or without
6 : * modification, are permitted provided that the following conditions
7 : * are met:
8 : * 1. Redistributions of source code must retain the above copyright
9 : * notice, this list of conditions and the following disclaimer.
10 : * 2. Redistributions in binary form must reproduce the above copyright
11 : * notice, this list of conditions and the following disclaimer in the
12 : * documentation and/or other materials provided with the distribution.
13 : * 3. All advertising materials mentioning features or use of this software
14 : * must display the following acknowledgement:
15 : * This product includes software developed by the University of
16 : * California, Berkeley and its contributors.
17 : * 4. Neither the name of the University nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 : #include <zend.h>
35 : #include <limits.h>
36 : #include <ctype.h>
37 : #include <errno.h>
38 : #include <stdlib.h>
39 : #include <stdio.h>
40 : #include <unicode/utypes.h>
41 : #include <unicode/uchar.h>
42 :
43 : /* Disable false positive warning about LONG_MIN, we could use INT_MIN but requires
44 : too much code changes for no gain. */
45 : #ifdef PHP_WIN32
46 : # pragma warning (disable:4146)
47 : #endif
48 :
49 : /* long zend_u_strtol (const UChar *nptr, UChar **endptr, int base) {{{
50 : * Convert a Unicode string to a long integer.
51 : *
52 : * Ignores `locale' stuff.
53 : */
54 : ZEND_API long zend_u_strtol(nptr, endptr, base)
55 : const UChar *nptr;
56 : UChar **endptr;
57 : register int base;
58 1435855 : {
59 1435855 : register const UChar *s = nptr;
60 : register unsigned long acc;
61 : register UChar c;
62 : register unsigned long cutoff;
63 1435855 : register int neg = 0, any, cutlim;
64 :
65 1435855 : if (s == NULL) {
66 0 : errno = ERANGE;
67 0 : if (endptr != NULL) {
68 0 : *endptr = NULL;
69 : }
70 0 : return 0;
71 : }
72 :
73 : /*
74 : * Skip white space and pick up leading +/- sign if any.
75 : * If base is 0, allow 0x for hex and 0 for octal, else
76 : * assume decimal; if base is already 16, allow 0x.
77 : */
78 : do {
79 1436377 : c = *s++;
80 1436377 : } while (u_isspace(c));
81 1435855 : if (c == 0x2D /*'-'*/) {
82 30512 : neg = 1;
83 30512 : c = *s++;
84 1405343 : } else if (c == 0x2B /*'+'*/)
85 50 : c = *s++;
86 1435855 : if ((base == 0 || base == 16) &&
87 : (c == 0x30 /*'0'*/)
88 : && (*s == 0x78 /*'x'*/ || *s == 0x58 /*'X'*/)) {
89 239 : c = s[1];
90 239 : s += 2;
91 239 : base = 16;
92 : }
93 1435855 : if (base == 0)
94 0 : base = (c == 0x30 /*'0'*/) ? 8 : 10;
95 :
96 : /*
97 : * Compute the cutoff value between legal numbers and illegal
98 : * numbers. That is the largest legal value, divided by the
99 : * base. An input number that is greater than this value, if
100 : * followed by a legal input character, is too big. One that
101 : * is equal to this value may be valid or not; the limit
102 : * between valid and invalid numbers is then based on the last
103 : * digit. For instance, if the range for longs is
104 : * [-2147483648..2147483647] and the input base is 10,
105 : * cutoff will be set to 214748364 and cutlim to either
106 : * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
107 : * a value > 214748364, or equal but the next digit is > 7 (or 8),
108 : * the number is too big, and we will return a range error.
109 : *
110 : * Set any if any `digits' consumed; make it negative to indicate
111 : * overflow.
112 : */
113 1435855 : cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
114 1435855 : cutlim = cutoff % (unsigned long)base;
115 1435855 : cutoff /= (unsigned long)base;
116 6313593 : for (acc = 0, any = 0;; c = *s++) {
117 11191224 : if (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/)
118 4877631 : c -= 0x30 /*'0'*/;
119 1531174 : else if (c >= 0x41 /*'A'*/ && c <= 0x5A /*'Z'*/)
120 95212 : c -= 0x41 /*'A'*/ - 10;
121 1340750 : else if (c >= 0x61 /*'a'*/ && c <= 0x7A /*'z'*/)
122 552579 : c -= 0x61 /*'a'*/ - 10;
123 : else
124 : break;
125 5525422 : if (c >= base)
126 647684 : break;
127 :
128 4913665 : if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
129 35927 : any = -1;
130 : else {
131 4841811 : any = 1;
132 4841811 : acc *= base;
133 4841811 : acc += c;
134 : }
135 4877738 : }
136 1435855 : if (any < 0) {
137 2707 : acc = neg ? LONG_MIN : LONG_MAX;
138 2707 : errno = ERANGE;
139 1433148 : } else if (neg)
140 30492 : acc = -acc;
141 1435855 : if (endptr != NULL)
142 1429177 : *endptr = (UChar *)(any ? s - 1 : nptr);
143 1435855 : return (acc);
144 : }
145 : /* }}} */
146 :
147 : /* unsigned long zend_u_strtoul (const UChar *nptr, UChar **endptr, int base) {{{
148 : * Convert a Unicode string to a unsigned long integer.
149 : *
150 : * Ignores `locale' stuff.
151 : */
152 : ZEND_API unsigned long zend_u_strtoul(nptr, endptr, base)
153 : const UChar *nptr;
154 : UChar **endptr;
155 : register int base;
156 42 : {
157 42 : register const UChar *s = nptr;
158 : register unsigned long acc;
159 : register UChar c;
160 : register unsigned long cutoff;
161 42 : register int neg = 0, any, cutlim;
162 :
163 42 : if (s == NULL) {
164 0 : errno = ERANGE;
165 0 : if (endptr != NULL) {
166 0 : *endptr = NULL;
167 : }
168 0 : return 0;
169 : }
170 :
171 : /*
172 : * Skip white space and pick up leading +/- sign if any.
173 : * If base is 0, allow 0x for hex and 0 for octal, else
174 : * assume decimal; if base is already 16, allow 0x.
175 : */
176 : do {
177 42 : c = *s++;
178 42 : } while (u_isspace(c));
179 42 : if (c == 0x2D /*'-'*/) {
180 7 : neg = 1;
181 7 : c = *s++;
182 35 : } else if (c == 0x2B /*'+'*/)
183 2 : c = *s++;
184 42 : if ((base == 0 || base == 16) &&
185 : (c == 0x30 /*'0'*/)
186 : && (*s == 0x78 /*'x'*/ || *s == 0x58 /*'X'*/)) {
187 0 : c = s[1];
188 0 : s += 2;
189 0 : base = 16;
190 : }
191 42 : if (base == 0)
192 0 : base = (c == 0x30 /*'0'*/) ? 8 : 10;
193 :
194 : /*
195 : * Compute the cutoff value between legal numbers and illegal
196 : * numbers. That is the largest legal value, divided by the
197 : * base. An input number that is greater than this value, if
198 : * followed by a legal input character, is too big. One that
199 : * is equal to this value may be valid or not; the limit
200 : * between valid and invalid numbers is then based on the last
201 : * digit. For instance, if the range for longs is
202 : * [-2147483648..2147483647] and the input base is 10,
203 : * cutoff will be set to 214748364 and cutlim to either
204 : * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
205 : * a value > 214748364, or equal but the next digit is > 7 (or 8),
206 : * the number is too big, and we will return a range error.
207 : *
208 : * Set any if any `digits' consumed; make it negative to indicate
209 : * overflow.
210 : */
211 42 : cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
212 42 : cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
213 120 : for (acc = 0, any = 0;; c = *s++) {
214 198 : if (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/)
215 78 : c -= 0x30 /*'0'*/;
216 42 : else if (c >= 0x41 /*'A'*/ && c <= 0x5A /*'Z'*/)
217 0 : c -= 0x41 /*'A'*/ - 10;
218 42 : else if (c >= 0x61 /*'a'*/ && c <= 0x7A /*'z'*/)
219 0 : c -= 0x61 /*'a'*/ - 10;
220 : else
221 : break;
222 78 : if (c >= base)
223 0 : break;
224 :
225 78 : if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
226 0 : any = -1;
227 : else {
228 78 : any = 1;
229 78 : acc *= base;
230 78 : acc += c;
231 : }
232 78 : }
233 42 : if (any < 0) {
234 0 : acc = ULONG_MAX;
235 0 : errno = ERANGE;
236 42 : } else if (neg)
237 7 : acc = -acc;
238 42 : if (endptr != NULL)
239 24 : *endptr = (UChar *)(any ? s - 1 : nptr);
240 42 : return (acc);
241 : }
242 : /* }}} */
243 :
244 : /*
245 : * Local variables:
246 : * tab-width: 4
247 : * c-basic-offset: 4
248 : * indent-tabs-mode: t
249 : * End:
250 : */
|