1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: iscannum.c 9043 2008-08-28 22:48:19Z giles $ */
15
/* Number scanner for Ghostscript interpreter */
21
#include "iscannum.h" /* defines interface */
26
* Warning: this file has a "spaghetti" control structure. But since this
27
* code accounts for over 10% of the execution time of some PostScript
28
* files, this is one of the few places we feel this is justified.
32
* Scan a number. If the number consumes the entire string, return 0;
33
* if not, set *psp to the first character beyond the number and return 1.
36
scan_number(const byte * str, const byte * end, int sign,
37
ref * pref, const byte ** psp, int scanner_options)
40
#define GET_NEXT(cvar, sp, end_action)\
41
if (sp >= end) { end_action; } else cvar = *sp++
44
* Powers of 10 up to 6 can be represented accurately as
45
* a single-precision float.
47
#define NUM_POWERS_10 6
48
static const float powers_10[NUM_POWERS_10 + 1] = {
49
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6
51
static const double neg_powers_10[NUM_POWERS_10 + 1] = {
52
1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6
61
uint max_scan; /* max signed or unsigned int */
62
const byte *const decoder = scan_char_decoder;
63
#define IS_DIGIT(d, c)\
64
((d = decoder[c]) < 10)
65
#define WOULD_OVERFLOW(val, d, maxv)\
66
(val >= maxv / 10 && (val > maxv / 10 || d > (int)(maxv % 10)))
68
GET_NEXT(c, sp, return_error(e_syntaxerror));
69
if (!IS_DIGIT(d, c)) {
71
return_error(e_syntaxerror);
72
/* Might be a number starting with '.'. */
73
GET_NEXT(c, sp, return_error(e_syntaxerror));
75
return_error(e_syntaxerror);
79
/* Accumulate an integer in ival. */
80
/* Do up to 4 digits without a loop, */
81
/* since we know this can't overflow and since */
82
/* most numbers have 4 (integer) digits or fewer. */
84
if (end - sp >= 3) { /* just check once */
85
if (!IS_DIGIT(d, (c = *sp))) {
90
if (!IS_DIGIT(d, (c = sp[1]))) {
96
if (!IS_DIGIT(d, (c = sp[-1])))
100
max_scan = scanner_options & SCAN_PDF_UNSIGNED && sign >= 0 ? ~0 : max_int;
101
for (;; ival = ival * 10 + d) {
102
GET_NEXT(c, sp, goto iret);
105
if (WOULD_OVERFLOW(((unsigned)ival), d, max_scan))
108
ind: /* We saw a non-digit while accumulating an integer in ival. */
111
GET_NEXT(c, sp, c = EOFC);
126
const uint radix = (uint)ival;
127
ulong uval = 0, lmax;
129
if (sign || radix < min_radix || radix > max_radix)
130
return_error(e_syntaxerror);
131
/* Avoid multiplies for power-of-2 radix. */
132
if (!(radix & (radix - 1))) {
137
shift = 1, lmax = max_ulong >> 1;
140
shift = 2, lmax = max_ulong >> 2;
143
shift = 3, lmax = max_ulong >> 3;
146
shift = 4, lmax = max_ulong >> 4;
149
shift = 5, lmax = max_ulong >> 5;
151
default: /* can't happen */
152
return_error(e_rangecheck);
154
for (;; uval = (uval << shift) + d) {
155
GET_NEXT(c, sp, break);
163
return_error(e_limitcheck);
166
int lrem = max_ulong % radix;
168
lmax = max_ulong / radix;
169
for (;; uval = uval * radix + d) {
170
GET_NEXT(c, sp, break);
178
(uval > lmax || d > lrem)
180
return_error(e_limitcheck);
183
make_int(pref, uval);
188
make_int(pref, (sign < 0 ? -ival : ival));
191
/* Accumulate a long in lval. */
193
for (lval = (unsigned)ival;;) {
194
if (WOULD_OVERFLOW(((unsigned long)lval), d, ((unsigned long)max_long))) {
195
/* Make a special check for entering the smallest */
196
/* (most negative) integer. */
197
if (lval == max_long / 10 &&
198
d == (int)(max_long % 10) + 1 && sign < 0
200
GET_NEXT(c, sp, c = EOFC);
201
dval = -(double)min_long;
202
if (c == 'e' || c == 'E') {
205
} else if (c == '.') {
206
GET_NEXT(c, sp, c = EOFC);
209
} else if (!IS_DIGIT(d, c)) {
214
dval = (unsigned long)lval;
217
lval = lval * 10 + d;
218
GET_NEXT(c, sp, goto lret);
224
GET_NEXT(c, sp, c = EOFC);
238
return_error(e_syntaxerror);
241
make_int(pref, (sign < 0 ? -lval : lval));
244
/* Accumulate a double in dval. */
248
dval = dval * 10 + d;
249
GET_NEXT(c, sp, c = EOFC);
255
GET_NEXT(c, sp, c = EOFC);
271
return_error(e_syntaxerror);
274
/* We saw a '.' while accumulating an integer in ival. */
277
while (IS_DIGIT(d, c) || c == '-') {
279
* PostScript gives an error on numbers with a '-' following a '.'
280
* Adobe Acrobat Reader (PDF) apparently doesn't treat this as an
281
* error. Experiments show that the numbers following the '-' are
282
* ignored, so we swallow the fractional part. SCAN_PDF_INV_NUM
283
* enables this compatibility kloodge.
286
if ((SCAN_PDF_INV_NUM & scanner_options) == 0)
289
GET_NEXT(c, sp, c = EOFC);
290
} while (IS_DIGIT(d, c));
293
if (WOULD_OVERFLOW(ival, d, max_int)) {
297
ival = ival * 10 + d;
299
GET_NEXT(c, sp, c = EOFC);
303
/* Take a shortcut for the common case */
304
if (!(c == 'e' || c == 'E' || exp10 < -NUM_POWERS_10)) { /* Check for trailing garbage */
307
make_real(pref, ival * neg_powers_10[-exp10]);
313
/* We saw a '.' while accumulating a long in lval. */
315
while (IS_DIGIT(d, c) || c == '-') {
316
/* Handle bogus '-' following '.' as in i2r above. */
318
if ((scanner_options & SCAN_PDF_INV_NUM) == 0)
321
GET_NEXT(c, sp, c = EOFC);
322
} while (IS_DIGIT(d, c));
325
if (WOULD_OVERFLOW(lval, d, max_long)) {
329
lval = lval * 10 + d;
331
GET_NEXT(c, sp, c = EOFC);
339
/* Now we are accumulating a double in dval. */
341
while (IS_DIGIT(d, c)) {
342
dval = dval * 10 + d;
344
GET_NEXT(c, sp, c = EOFC);
350
/* Now dval contains the value, negated if necessary. */
354
{ /* Check for a following exponent. */
358
GET_NEXT(c, sp, return_error(e_syntaxerror));
363
GET_NEXT(c, sp, return_error(e_syntaxerror));
365
/* Scan the exponent. We limit it arbitrarily to 999. */
367
return_error(e_syntaxerror);
369
for (;; iexp = iexp * 10 + d) {
370
GET_NEXT(c, sp, break);
371
if (!IS_DIGIT(d, c)) {
377
return_error(e_limitcheck);
391
/* Compute dval * 10^exp10. */
393
while (exp10 > NUM_POWERS_10)
394
dval *= powers_10[NUM_POWERS_10],
395
exp10 -= NUM_POWERS_10;
397
dval *= powers_10[exp10];
398
} else if (exp10 < 0) {
399
while (exp10 < -NUM_POWERS_10)
400
dval /= powers_10[NUM_POWERS_10],
401
exp10 += NUM_POWERS_10;
403
dval /= powers_10[-exp10];
406
* Check for an out-of-range result. Currently we don't check for
407
* absurdly large numbers of digits in the accumulation loops,
411
if (dval > MAX_FLOAT)
412
return_error(e_limitcheck);
414
if (dval < -MAX_FLOAT)
415
return_error(e_limitcheck);
418
make_real(pref, dval);