1 /* Copyright (C) 1994, 1995, 1997, 1998, 1999 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: iscannum.c,v 1.3.2.1.2.1 2003/01/17 00:49:04 giles Exp $ */
20 /* Number scanner for Ghostscript interpreter */
21 #include "math_.h"
22 #include "ghost.h"
23 #include "errors.h"
24 #include "scommon.h"
25 #include "iscannum.h"		/* defines interface */
26 #include "scanchar.h"
27 #include "store.h"
28 
29 /*
30  * Warning: this file has a "spaghetti" control structure.  But since this
31  * code accounts for over 10% of the execution time of some PostScript
32  * files, this is one of the few places we feel this is justified.
33  */
34 
35 /*
36  * Scan a number.  If the number consumes the entire string, return 0;
37  * if not, set *psp to the first character beyond the number and return 1.
38  */
39 int
scan_number(const byte * str,const byte * end,int sign,ref * pref,const byte ** psp)40 scan_number(const byte * str, const byte * end, int sign,
41 	    ref * pref, const byte ** psp)
42 {
43     const byte *sp = str;
44 #define GET_NEXT(cvar, sp, end_action)\
45   if (sp >= end) { end_action; } else cvar = *sp++
46 
47     /*
48      * Powers of 10 up to 6 can be represented accurately as
49      * a single-precision float.
50      */
51 #define NUM_POWERS_10 6
52     static const float powers_10[NUM_POWERS_10 + 1] = {
53 	1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6
54     };
55     static const double neg_powers_10[NUM_POWERS_10 + 1] = {
56 	1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6
57     };
58 
59     int ival;
60     double dval;
61     int exp10;
62     int code = 0;
63     int c, d;
64     const byte *const decoder = scan_char_decoder;
65 #define IS_DIGIT(d, c)\
66   ((d = decoder[c]) < 10)
67 #define WOULD_OVERFLOW(val, d, maxv)\
68   (val >= maxv / 10 && (val > maxv / 10 || d > (int)(maxv % 10)))
69 
70     GET_NEXT(c, sp, return_error(e_syntaxerror));
71     if (!IS_DIGIT(d, c)) {
72 	if (c != '.')
73 	    return_error(e_syntaxerror);
74 	/* Might be a number starting with '.'. */
75 	GET_NEXT(c, sp, return_error(e_syntaxerror));
76 	if (!IS_DIGIT(d, c))
77 	    return_error(e_syntaxerror);
78 	ival = 0;
79 	goto i2r;
80     }
81     /* Accumulate an integer in ival. */
82     /* Do up to 4 digits without a loop, */
83     /* since we know this can't overflow and since */
84     /* most numbers have 4 (integer) digits or fewer. */
85     ival = d;
86     if (end - sp >= 3) {	/* just check once */
87 	if (!IS_DIGIT(d, (c = *sp))) {
88 	    sp++;
89 	    goto ind;
90 	}
91 	ival = ival * 10 + d;
92 	if (!IS_DIGIT(d, (c = sp[1]))) {
93 	    sp += 2;
94 	    goto ind;
95 	}
96 	ival = ival * 10 + d;
97 	sp += 3;
98 	if (!IS_DIGIT(d, (c = sp[-1])))
99 	    goto ind;
100 	ival = ival * 10 + d;
101     }
102     for (;; ival = ival * 10 + d) {
103 	GET_NEXT(c, sp, goto iret);
104 	if (!IS_DIGIT(d, c))
105 	    break;
106 	if (WOULD_OVERFLOW((unsigned)ival, d, max_int)) {
107 	    /* goto i2l; */
108 	    if (ival == max_int / 10 && d == (max_int % 10) + 1 && sign < 0) {
109 		GET_NEXT(c, sp, c= EOFC);
110 		dval = -(double)min_int;
111 		if (c == 'e' || c == 'E') {
112 		    exp10 = 0;
113 		    goto fs;
114 		} else if (c == '.') {
115 		    GET_NEXT(c, sp, c = EOFC);
116 		    exp10 = 0;
117 		    goto fd;
118 		} else if (!IS_DIGIT(d, c)) {
119 		    ival = min_int;
120 		    break;
121 		}
122 	    } else
123 		dval = ival;
124 	    goto l2d;
125 	}
126     }
127   ind:				/* We saw a non-digit while accumulating an integer in ival. */
128     switch (c) {
129 	case '.':
130 	    GET_NEXT(c, sp, c = EOFC);
131 	    goto i2r;
132 	default:
133 	    *psp = sp;
134 	    code = 1;
135 	    break;
136 	case EOFC:
137 	    break;
138 	case 'e':
139 	case 'E':
140 	    if (sign < 0)
141 		ival = -ival;
142 	    dval = ival;
143 	    exp10 = 0;
144 	    goto fe;
145 	case '#':
146 	    {
147 		const int radix = ival;
148 		uint uval = 0, imax;
149 
150 		if (sign || radix < min_radix || radix > max_radix)
151 		    return_error(e_syntaxerror);
152 		/* Avoid multiplies for power-of-2 radix. */
153 		if (!(radix & (radix - 1))) {
154 		    int shift;
155 
156 		    switch (radix) {
157 			case 2:
158 			    shift = 1, imax = max_uint >> 1;
159 			    break;
160 			case 4:
161 			    shift = 2, imax = max_uint >> 2;
162 			    break;
163 			case 8:
164 			    shift = 3, imax = max_uint >> 3;
165 			    break;
166 			case 16:
167 			    shift = 4, imax = max_uint >> 4;
168 			    break;
169 			case 32:
170 			    shift = 5, imax = max_uint >> 5;
171 			    break;
172 			default:	/* can't happen */
173 			    return_error(e_rangecheck);
174 		    }
175 		    for (;; uval = (uval << shift) + d) {
176 			GET_NEXT(c, sp, break);
177 			d = decoder[c];
178 			if (d >= radix) {
179 			    *psp = sp;
180 			    code = 1;
181 			    break;
182 			}
183 			if (uval > imax)
184 			    return_error(e_limitcheck);
185 		    }
186 		} else {
187 		    int irem = max_uint % radix;
188 
189 		    imax = max_uint / radix;
190 		    for (;; uval = uval * radix + d) {
191 			GET_NEXT(c, sp, break);
192 			d = decoder[c];
193 			if (d >= radix) {
194 			    *psp = sp;
195 			    code = 1;
196 			    break;
197 			}
198 			if (uval >= imax &&
199 			    (uval > imax || d > irem)
200 			    )
201 			    return_error(e_limitcheck);
202 		    }
203 		}
204 		make_int(pref, uval);
205 		return code;
206 	    }
207     }
208 iret:
209     make_int(pref, (sign < 0 ? -ival : ival));
210     return code;
211 
212     /* Accumulate a double in dval. */
213 l2d:
214     exp10 = 0;
215     for (;;) {
216 	dval = dval * 10 + d;
217 	GET_NEXT(c, sp, c = EOFC);
218 	if (!IS_DIGIT(d, c))
219 	    break;
220     }
221     switch (c) {
222 	case '.':
223 	    GET_NEXT(c, sp, c = EOFC);
224 	    exp10 = 0;
225 	    goto fd;
226 	default:
227 	    *psp = sp;
228 	    code = 1;
229 	    /* falls through */
230 	case EOFC:
231 	    if (sign < 0)
232 		dval = -dval;
233 	    goto rret;
234 	case 'e':
235 	case 'E':
236 	    exp10 = 0;
237 	    goto fs;
238 	case '#':
239 	    return_error(e_syntaxerror);
240     }
241 
242     /* We saw a '.' while accumulating an integer in ival. */
243 i2r:
244     exp10 = 0;
245     while (IS_DIGIT(d, c)) {
246 	if (WOULD_OVERFLOW(ival, d, max_int)) {
247 	    dval = ival;
248 	    goto fd;
249 	}
250 	ival = ival * 10 + d;
251 	exp10--;
252 	GET_NEXT(c, sp, c = EOFC);
253     }
254     if (sign < 0)
255 	ival = -ival;
256     /* Take a shortcut for the common case */
257     if (!(c == 'e' || c == 'E' || exp10 < -NUM_POWERS_10)) {	/* Check for trailing garbage */
258 	if (c != EOFC)
259 	    *psp = sp, code = 1;
260 	make_real(pref, ival * neg_powers_10[-exp10]);
261 	return code;
262     }
263     dval = ival;
264     goto fe;
265 
266     /* Now we are accumulating a double in dval. */
267 fd:
268     while (IS_DIGIT(d, c)) {
269 	dval = dval * 10 + d;
270 	exp10--;
271 	GET_NEXT(c, sp, c = EOFC);
272     }
273 fs:
274     if (sign < 0)
275 	dval = -dval;
276 fe:
277     /* Now dval contains the value, negated if necessary. */
278     switch (c) {
279 	case 'e':
280 	case 'E':
281 	    {			/* Check for a following exponent. */
282 		int esign = 0;
283 		int iexp;
284 
285 		GET_NEXT(c, sp, return_error(e_syntaxerror));
286 		switch (c) {
287 		    case '-':
288 			esign = 1;
289 		    case '+':
290 			GET_NEXT(c, sp, return_error(e_syntaxerror));
291 		}
292 		/* Scan the exponent.  We limit it arbitrarily to 999. */
293 		if (!IS_DIGIT(d, c))
294 		    return_error(e_syntaxerror);
295 		iexp = d;
296 		for (;; iexp = iexp * 10 + d) {
297 		    GET_NEXT(c, sp, break);
298 		    if (!IS_DIGIT(d, c)) {
299 			*psp = sp;
300 			code = 1;
301 			break;
302 		    }
303 		    if (iexp > 99)
304 			return_error(e_limitcheck);
305 		}
306 		if (esign)
307 		    exp10 -= iexp;
308 		else
309 		    exp10 += iexp;
310 		break;
311 	    }
312 	default:
313 	    *psp = sp;
314 	    code = 1;
315 	case EOFC:
316 	    ;
317     }
318     /* Compute dval * 10^exp10. */
319     if (exp10 > 0) {
320 	while (exp10 > NUM_POWERS_10)
321 	    dval *= powers_10[NUM_POWERS_10],
322 		exp10 -= NUM_POWERS_10;
323 	if (exp10 > 0)
324 	    dval *= powers_10[exp10];
325     } else if (exp10 < 0) {
326 	while (exp10 < -NUM_POWERS_10)
327 	    dval /= powers_10[NUM_POWERS_10],
328 		exp10 += NUM_POWERS_10;
329 	if (exp10 < 0)
330 	    dval /= powers_10[-exp10];
331     }
332     /*
333      * Check for an out-of-range result.  Currently we don't check for
334      * absurdly large numbers of digits in the accumulation loops,
335      * but we should.
336      */
337     if (dval >= 0) {
338 	if (dval > MAX_FLOAT)
339 	    return_error(e_limitcheck);
340     } else {
341 	if (dval < -MAX_FLOAT)
342 	    return_error(e_limitcheck);
343     }
344 rret:
345     make_real(pref, dval);
346     return code;
347 }
348