/src/ghostpdl/psi/ibnum.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Level 2 encoded number reading utilities for Ghostscript */ |
18 | | #include "math_.h" |
19 | | #include "memory_.h" |
20 | | #include "ghost.h" |
21 | | #include "opcheck.h" |
22 | | #include "ierrors.h" |
23 | | #include "stream.h" |
24 | | #include "ibnum.h" |
25 | | #include "imemory.h" /* for iutil.h */ |
26 | | #include "iutil.h" |
27 | | |
28 | | /* Define the number of bytes for a given format of encoded number. */ |
29 | | const byte enc_num_bytes[] = { |
30 | | enc_num_bytes_values |
31 | | }; |
32 | | |
33 | | /* ------ Encoded number reading ------ */ |
34 | | |
35 | | /* Set up to read from an encoded number array/string. */ |
36 | | /* Return <0 for error, or a number format. */ |
37 | | int |
38 | | num_array_format(const ref * op) |
39 | 31 | { |
40 | 31 | int format; |
41 | | |
42 | 31 | switch (r_type(op)) { |
43 | 10 | case t_string: |
44 | 10 | { |
45 | | /* Check that this is a legitimate encoded number string. */ |
46 | 10 | const byte *bp = op->value.bytes; |
47 | | |
48 | 10 | if (r_size(op) < 4 || bp[0] != bt_num_array_value) |
49 | 10 | return_error(gs_error_typecheck); |
50 | 0 | format = bp[1]; |
51 | 0 | if (!num_is_valid(format) || |
52 | 0 | sdecodeshort(bp + 2, format) != |
53 | 0 | (r_size(op) - 4) / encoded_number_bytes(format) |
54 | 0 | ) |
55 | 0 | return_error(gs_error_rangecheck); |
56 | 0 | } |
57 | 0 | break; |
58 | 18 | case t_array: |
59 | 18 | case t_mixedarray: |
60 | 18 | case t_shortarray: |
61 | 18 | format = num_array; |
62 | 18 | break; |
63 | 3 | default: |
64 | 3 | return_error(gs_error_typecheck); |
65 | 31 | } |
66 | 18 | check_read(*op); |
67 | 18 | return format; |
68 | 18 | } |
69 | | |
70 | | /* Get the number of elements in an encoded number array/string. */ |
71 | | uint |
72 | | num_array_size(const ref * op, int format) |
73 | 18 | { |
74 | 18 | return (format == num_array ? r_size(op) : |
75 | 18 | (r_size(op) - 4) / encoded_number_bytes(format)); |
76 | 18 | } |
77 | | |
78 | | /* Get an encoded number from an array/string according to the given format. */ |
79 | | /* Put the value in np->value.{intval,realval}. */ |
80 | | /* Return t_int if integer, t_real if real, t_null if end of stream, */ |
81 | | /* or an error if the format is invalid. */ |
82 | | int |
83 | | num_array_get(const gs_memory_t *mem, const ref * op, int format, uint index, ref * np) |
84 | 0 | { |
85 | 0 | if (format == num_array) { |
86 | 0 | int code = array_get(mem, op, (long)index, np); |
87 | |
|
88 | 0 | if (code < 0) |
89 | 0 | return t_null; |
90 | 0 | switch (r_type(np)) { |
91 | 0 | case t_integer: |
92 | 0 | return t_integer; |
93 | 0 | case t_real: |
94 | 0 | return t_real; |
95 | 0 | default: |
96 | 0 | return_error(gs_error_typecheck); |
97 | 0 | } |
98 | 0 | } else { |
99 | 0 | uint nbytes = encoded_number_bytes(format); |
100 | |
|
101 | 0 | if (index >= (r_size(op) - 4) / nbytes) |
102 | 0 | return t_null; |
103 | 0 | return sdecode_number(op->value.bytes + 4 + index * nbytes, |
104 | 0 | format, np); |
105 | 0 | } |
106 | 0 | } |
107 | | |
108 | | /* Internal routine to decode a number in a given format. */ |
109 | | /* Same returns as sget_encoded_number. */ |
110 | | static const double binary_scale[32] = { |
111 | | #define EXPN2(n) (0.5 / (1L << (n-1))) |
112 | | 1.0, EXPN2(1), EXPN2(2), EXPN2(3), |
113 | | EXPN2(4), EXPN2(5), EXPN2(6), EXPN2(7), |
114 | | EXPN2(8), EXPN2(9), EXPN2(10), EXPN2(11), |
115 | | EXPN2(12), EXPN2(13), EXPN2(14), EXPN2(15), |
116 | | EXPN2(16), EXPN2(17), EXPN2(18), EXPN2(19), |
117 | | EXPN2(20), EXPN2(21), EXPN2(22), EXPN2(23), |
118 | | EXPN2(24), EXPN2(25), EXPN2(26), EXPN2(27), |
119 | | EXPN2(28), EXPN2(29), EXPN2(30), EXPN2(31) |
120 | | #undef EXPN2 |
121 | | }; |
122 | | int |
123 | | sdecode_number(const byte * str, int format, ref * np) |
124 | 3.19M | { |
125 | 3.19M | switch (format & 0x170) { |
126 | 980k | case num_int32: |
127 | 2.26M | case num_int32 + 16: |
128 | 2.26M | if ((format & 31) == 0) { |
129 | 201k | np->value.intval = sdecodeint32(str, format); |
130 | 201k | return t_integer; |
131 | 2.06M | } else { |
132 | 2.06M | np->value.realval = |
133 | 2.06M | (double)sdecodeint32(str, format) * |
134 | 2.06M | binary_scale[format & 31]; |
135 | 2.06M | return t_real; |
136 | 2.06M | } |
137 | 132k | case num_int16: |
138 | 132k | if ((format & 15) == 0) { |
139 | 25.7k | np->value.intval = sdecodeshort(str, format); |
140 | 25.7k | return t_integer; |
141 | 107k | } else { |
142 | 107k | np->value.realval = |
143 | 107k | sdecodeshort(str, format) * |
144 | 107k | binary_scale[format & 15]; |
145 | 107k | return t_real; |
146 | 107k | } |
147 | 796k | case num_float: |
148 | 796k | { |
149 | 796k | float fval; |
150 | 796k | int code = sdecode_float(str, format, &fval); |
151 | | |
152 | 796k | if (code < 0) |
153 | 34 | return code; |
154 | 796k | np->value.realval = fval; |
155 | 796k | return t_real; |
156 | 796k | } |
157 | 0 | default: |
158 | 0 | return_error(gs_error_syntaxerror); /* invalid format?? */ |
159 | 3.19M | } |
160 | 3.19M | } |
161 | | |
162 | | /* ------ Decode number ------ */ |
163 | | |
164 | | /* Decode encoded numbers from a string according to format. */ |
165 | | |
166 | | /* Decode a (16-bit, signed or unsigned) short. */ |
167 | | uint |
168 | | sdecodeushort(const byte * p, int format) |
169 | 208k | { |
170 | 208k | int a = p[0], b = p[1]; |
171 | | |
172 | 208k | return (num_is_lsb(format) ? (b << 8) + a : (a << 8) + b); |
173 | 208k | } |
174 | | int |
175 | | sdecodeshort(const byte * p, int format) |
176 | 132k | { |
177 | 132k | int v = (int)sdecodeushort(p, format); |
178 | | |
179 | 132k | return (v & 0x7fff) - (v & 0x8000); |
180 | 132k | } |
181 | | |
182 | | /* Decode a (32-bit, signed) long. */ |
183 | | int |
184 | | sdecodeint32(const byte * p, int format) |
185 | 2.32M | { |
186 | 2.32M | int a = p[0], b = p[1], c = p[2], d = p[3]; |
187 | 2.32M | int v = (num_is_lsb(format) ? |
188 | 1.27M | ((int)d << 24) + ((int)c << 16) + (b << 8) + a : |
189 | 2.32M | ((int)a << 24) + ((int)b << 16) + (c << 8) + d); |
190 | 2.32M | return v; |
191 | 2.32M | } |
192 | | |
193 | | /* Decode a 32-bit number. Return the resukt through a pointer */ |
194 | | /* to work around a gcc 4.2.1 bug on PowerPC, bug 689586 */ |
195 | | static void |
196 | | sdecodebits32(const byte * p, int format, bits32 *v) |
197 | 777k | { |
198 | 777k | int a = p[0], b = p[1], c = p[2], d = p[3]; |
199 | 777k | *v = (num_is_lsb(format) ? |
200 | 61.3k | ((long)d << 24) + ((long)c << 16) + (b << 8) + a : |
201 | 777k | ((long)a << 24) + ((long)b << 16) + (c << 8) + d); |
202 | | |
203 | 777k | } |
204 | | |
205 | | /* Decode a float. We assume that native floats occupy 32 bits. */ |
206 | | /* If the float is an IEEE NaN or Inf, return gs_error_undefinedresult. */ |
207 | | int |
208 | | sdecode_float(const byte * p, int format, float *pfnum) |
209 | 798k | { |
210 | 798k | bits32 lnum; |
211 | | |
212 | 798k | if ((format & ~(num_msb | num_lsb)) == num_float_native) { |
213 | | /* |
214 | | * Just read 4 bytes and interpret them as a float, ignoring |
215 | | * any indication of byte ordering. |
216 | | */ |
217 | 20.4k | memcpy(pfnum, p, 4); |
218 | | #if !ARCH_FLOATS_ARE_IEEE |
219 | | return 0; /* no way to check for anomalies */ |
220 | | #endif |
221 | 20.4k | lnum = *(bits32 *)pfnum; |
222 | 777k | } else { |
223 | 777k | sdecodebits32(p, format, &lnum); |
224 | | |
225 | | #if !ARCH_FLOATS_ARE_IEEE |
226 | | { |
227 | | /* We know IEEE floats take 32 bits. */ |
228 | | /* Convert IEEE float to native float. */ |
229 | | int sign_expt = lnum >> 23; |
230 | | int expt = sign_expt & 0xff; |
231 | | long mant = lnum & 0x7fffff; |
232 | | float fnum; |
233 | | |
234 | | if (expt == 0 && mant == 0) |
235 | | fnum = 0; |
236 | | else if (expt == 0xff) |
237 | | return_error(gs_error_undefinedresult); /* Inf or NaN */ |
238 | | else { |
239 | | mant += 0x800000; |
240 | | fnum = (float)ldexp((float)mant, expt - 127 - 23); |
241 | | } |
242 | | if (sign_expt & 0x100) |
243 | | fnum = -fnum; |
244 | | *pfnum = fnum; |
245 | | return 0; /* checked for Infs and NaNs above */ |
246 | | } |
247 | | #else |
248 | 777k | *pfnum = *(float *)&lnum; |
249 | 777k | #endif |
250 | 777k | } |
251 | | /* |
252 | | * Unfortunately, there is no portable way for testing whether a float |
253 | | * is a NaN or Inf. Do it "by hand" if the input representation is |
254 | | * IEEE (which is the case if control arrives here). |
255 | | */ |
256 | 798k | if (!(~lnum & 0x7f800000)) /* i.e. exponent all 1's */ |
257 | 38 | return_error(gs_error_undefinedresult); /* Inf or NaN */ |
258 | 798k | return 0; |
259 | 798k | } |