2 |
- |
1 |
/* Copyright (C) 1989, 2000 Aladdin Enterprises. All rights reserved.
|
|
|
2 |
|
|
|
3 |
This software is provided AS-IS with no warranty, either express or
|
|
|
4 |
implied.
|
|
|
5 |
|
|
|
6 |
This software is distributed under license and may not be copied,
|
|
|
7 |
modified or distributed except as expressly authorized under the terms
|
|
|
8 |
of the license contained in the file LICENSE in this distribution.
|
|
|
9 |
|
|
|
10 |
For more information about licensing, please refer to
|
|
|
11 |
http://www.ghostscript.com/licensing/. For information on
|
|
|
12 |
commercial licensing, go to http://www.artifex.com/licensing/ or
|
|
|
13 |
contact Artifex Software, Inc., 101 Lucas Valley Road #110,
|
|
|
14 |
San Rafael, CA 94903, U.S.A., +1(415)492-9861.
|
|
|
15 |
*/
|
|
|
16 |
|
|
|
17 |
/* $Id: iscanbin.c,v 1.14 2004/08/04 19:36:13 stefan Exp $ */
|
|
|
18 |
/* Ghostscript binary token scanner and writer */
|
|
|
19 |
#include "math_.h"
|
|
|
20 |
#include "memory_.h"
|
|
|
21 |
#include "ghost.h"
|
|
|
22 |
#include "gsutil.h"
|
|
|
23 |
#include "gxalloc.h" /* for names_array in allocator */
|
|
|
24 |
#include "stream.h"
|
|
|
25 |
#include "strimpl.h" /* for sfilter.h */
|
|
|
26 |
#include "sfilter.h" /* for iscan.h */
|
|
|
27 |
#include "ierrors.h"
|
|
|
28 |
#include "ialloc.h"
|
|
|
29 |
#include "iddict.h"
|
|
|
30 |
#include "dstack.h" /* for immediately evaluated names */
|
|
|
31 |
#include "ostack.h" /* must precede iscan.h */
|
|
|
32 |
#include "iname.h"
|
|
|
33 |
#include "iscan.h" /* for scan_Refill */
|
|
|
34 |
#include "iscanbin.h"
|
|
|
35 |
#include "iutil.h"
|
|
|
36 |
#include "ivmspace.h"
|
|
|
37 |
#include "store.h"
|
|
|
38 |
#include "btoken.h"
|
|
|
39 |
#include "ibnum.h"
|
|
|
40 |
|
|
|
41 |
/* Define the binary token types. */
|
|
|
42 |
typedef enum {
|
|
|
43 |
BT_SEQ = 128, /* binary object sequence: */
|
|
|
44 |
BT_SEQ_IEEE_MSB = 128, /* IEEE floats, big-endian */
|
|
|
45 |
BT_SEQ_IEEE_LSB = 129, /* IEEE float, little-endian */
|
|
|
46 |
BT_SEQ_NATIVE_MSB = 130, /* native floats, big-endian */
|
|
|
47 |
BT_SEQ_NATIVE_LSB = 131, /* native floats, little-endian */
|
|
|
48 |
BT_INT32_MSB = 132,
|
|
|
49 |
BT_INT32_LSB = 133,
|
|
|
50 |
BT_INT16_MSB = 134,
|
|
|
51 |
BT_INT16_LSB = 135,
|
|
|
52 |
BT_INT8 = 136,
|
|
|
53 |
BT_FIXED = 137,
|
|
|
54 |
BT_FLOAT_IEEE_MSB = 138,
|
|
|
55 |
BT_FLOAT_IEEE_LSB = 139,
|
|
|
56 |
BT_FLOAT_NATIVE = 140,
|
|
|
57 |
BT_BOOLEAN = 141,
|
|
|
58 |
BT_STRING_256 = 142,
|
|
|
59 |
BT_STRING_64K_MSB = 143,
|
|
|
60 |
BT_STRING_64K_LSB = 144,
|
|
|
61 |
BT_LITNAME_SYSTEM = 145,
|
|
|
62 |
BT_EXECNAME_SYSTEM = 146,
|
|
|
63 |
BT_LITNAME_USER = 147,
|
|
|
64 |
BT_EXECNAME_USER = 148,
|
|
|
65 |
BT_NUM_ARRAY = 149
|
|
|
66 |
} bin_token_type_t;
|
|
|
67 |
|
|
|
68 |
#define MIN_BIN_TOKEN_TYPE 128
|
|
|
69 |
#define MAX_BIN_TOKEN_TYPE 159
|
|
|
70 |
#define NUM_BIN_TOKEN_TYPES (MAX_BIN_TOKEN_TYPE - MIN_BIN_TOKEN_TYPE + 1)
|
|
|
71 |
|
|
|
72 |
/* Define the number of required initial bytes for binary tokens. */
|
|
|
73 |
private const byte bin_token_bytes[NUM_BIN_TOKEN_TYPES] =
|
|
|
74 |
{
|
|
|
75 |
4, 4, 4, 4, 5, 5, 3, 3, 2, 2, 5, 5, 5,
|
|
|
76 |
2, 2, 3, 3, 2, 2, 2, 2, 4,
|
|
|
77 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* undefined */
|
|
|
78 |
};
|
|
|
79 |
|
|
|
80 |
/* Define the number formats for those binary tokens that need them. */
|
|
|
81 |
private const byte bin_token_num_formats[NUM_BIN_TOKEN_TYPES] =
|
|
|
82 |
{
|
|
|
83 |
num_msb + num_float_IEEE, /* BT_SEQ_IEEE_MSB */
|
|
|
84 |
num_lsb + num_float_IEEE, /* BT_SEQ_IEEE_LSB */
|
|
|
85 |
#if ARCH_FLOATS_ARE_IEEE && BYTE_SWAP_IEEE_NATIVE_REALS
|
|
|
86 |
/* Treat native floats like IEEE floats for byte swapping. */
|
|
|
87 |
num_msb + num_float_IEEE, /* BT_SEQ_NATIVE_MSB */
|
|
|
88 |
num_lsb + num_float_IEEE, /* BT_SEQ_NATIVE_LSB */
|
|
|
89 |
#else
|
|
|
90 |
num_msb + num_float_native, /* BT_SEQ_NATIVE_MSB */
|
|
|
91 |
num_lsb + num_float_native, /* BT_SEQ_NATIVE_LSB */
|
|
|
92 |
#endif
|
|
|
93 |
num_msb + num_int32, /* BT_INT32_MSB */
|
|
|
94 |
num_lsb + num_int32, /* BT_INT32_LSB */
|
|
|
95 |
num_msb + num_int16, /* BT_INT16_MSB */
|
|
|
96 |
num_lsb + num_int16, /* BT_INT16_LSB */
|
|
|
97 |
0, /* BT_INT8, not used */
|
|
|
98 |
0, /* BT_FIXED, not used */
|
|
|
99 |
num_msb + num_float_IEEE, /* BT_FLOAT_IEEE_MSB */
|
|
|
100 |
num_lsb + num_float_IEEE, /* BT_FLOAT_IEEE_LSB */
|
|
|
101 |
num_float_native, /* BT_FLOAT_NATIVE */
|
|
|
102 |
0, /* BT_BOOLEAN, not used */
|
|
|
103 |
0, /* BT_STRING_256, not used */
|
|
|
104 |
num_msb, /* BT_STRING_64K_MSB */
|
|
|
105 |
num_lsb /* BT_STRING_64K_LSB */
|
|
|
106 |
/* rest not used */
|
|
|
107 |
};
|
|
|
108 |
|
|
|
109 |
/* Binary object sequence element types */
|
|
|
110 |
typedef enum {
|
|
|
111 |
BS_TYPE_NULL = 0,
|
|
|
112 |
BS_TYPE_INTEGER = 1,
|
|
|
113 |
BS_TYPE_REAL = 2,
|
|
|
114 |
BS_TYPE_NAME = 3,
|
|
|
115 |
BS_TYPE_BOOLEAN = 4,
|
|
|
116 |
BS_TYPE_STRING = 5,
|
|
|
117 |
BS_TYPE_EVAL_NAME = 6,
|
|
|
118 |
BS_TYPE_ARRAY = 9,
|
|
|
119 |
BS_TYPE_MARK = 10,
|
|
|
120 |
/*
|
|
|
121 |
* We extend the PostScript language definition by allowing
|
|
|
122 |
* dictionaries in binary object sequences. The data for
|
|
|
123 |
* a dictionary is like that for an array, with the following
|
|
|
124 |
* changes:
|
|
|
125 |
* - If the size is an even number, the value is the index of
|
|
|
126 |
* the first of a series of alternating keys and values.
|
|
|
127 |
* - If the size is 1, the value is the index of another
|
|
|
128 |
* object (which must also be a dictionary, and must not have
|
|
|
129 |
* size = 1); this object represents the same object as that one.
|
|
|
130 |
*/
|
|
|
131 |
BS_TYPE_DICTIONARY = 15
|
|
|
132 |
} bin_seq_type_t;
|
|
|
133 |
|
|
|
134 |
#define BS_EXECUTABLE 128
|
|
|
135 |
#define SIZEOF_BIN_SEQ_OBJ ((uint)8)
|
|
|
136 |
|
|
|
137 |
/* Forward references */
|
|
|
138 |
private int scan_bin_get_name(const gs_memory_t *mem, const ref *, int, ref *);
|
|
|
139 |
private int scan_bin_num_array_continue(i_ctx_t *, stream *, ref *, scanner_state *);
|
|
|
140 |
private int scan_bin_string_continue(i_ctx_t *, stream *, ref *, scanner_state *);
|
|
|
141 |
private int scan_bos_continue(i_ctx_t *, stream *, ref *, scanner_state *);
|
|
|
142 |
private byte *scan_bos_resize(i_ctx_t *, scanner_state *, uint, uint);
|
|
|
143 |
private int scan_bos_string_continue(i_ctx_t *, stream *, ref *, scanner_state *);
|
|
|
144 |
|
|
|
145 |
/* Scan a binary token. Called from the main scanner */
|
|
|
146 |
/* when it encounters an ASCII code 128-159, */
|
|
|
147 |
/* if binary tokens are being recognized (object format != 0). */
|
|
|
148 |
int
|
|
|
149 |
scan_binary_token(i_ctx_t *i_ctx_p, stream *s, ref *pref,
|
|
|
150 |
scanner_state *pstate)
|
|
|
151 |
{
|
|
|
152 |
scan_binary_state *const pbs = &pstate->s_ss.binary;
|
|
|
153 |
|
|
|
154 |
s_declare_inline(s, p, rlimit);
|
|
|
155 |
int num_format, code;
|
|
|
156 |
uint arg;
|
|
|
157 |
uint wanted;
|
|
|
158 |
uint rcnt;
|
|
|
159 |
|
|
|
160 |
s_begin_inline(s, p, rlimit);
|
|
|
161 |
wanted = bin_token_bytes[*p - MIN_BIN_TOKEN_TYPE] - 1;
|
|
|
162 |
rcnt = rlimit - p;
|
|
|
163 |
if (rcnt < wanted) {
|
|
|
164 |
s_end_inline(s, p - 1, rlimit);
|
|
|
165 |
pstate->s_scan_type = scanning_none;
|
|
|
166 |
return scan_Refill;
|
|
|
167 |
}
|
|
|
168 |
num_format = bin_token_num_formats[*p - MIN_BIN_TOKEN_TYPE];
|
|
|
169 |
switch (*p) {
|
|
|
170 |
case BT_SEQ_IEEE_MSB:
|
|
|
171 |
case BT_SEQ_IEEE_LSB:
|
|
|
172 |
case BT_SEQ_NATIVE_MSB:
|
|
|
173 |
case BT_SEQ_NATIVE_LSB:{
|
|
|
174 |
uint top_size = p[1];
|
|
|
175 |
uint hsize, size;
|
|
|
176 |
|
|
|
177 |
pbs->num_format = num_format;
|
|
|
178 |
if (top_size == 0) {
|
|
|
179 |
/* Extended header (2-byte array size, 4-byte length) */
|
|
|
180 |
ulong lsize;
|
|
|
181 |
|
|
|
182 |
if (rcnt < 7) {
|
|
|
183 |
s_end_inline(s, p - 1, rlimit);
|
|
|
184 |
pstate->s_scan_type = scanning_none;
|
|
|
185 |
return scan_Refill;
|
|
|
186 |
}
|
|
|
187 |
if (p[1] != 0) /* reserved, must be 0 */
|
|
|
188 |
return_error(e_syntaxerror);
|
|
|
189 |
top_size = sdecodeushort(p + 2, num_format);
|
|
|
190 |
lsize = sdecodelong(p + 4, num_format);
|
|
|
191 |
if ((size = lsize) != lsize)
|
|
|
192 |
return_error(e_limitcheck);
|
|
|
193 |
hsize = 8;
|
|
|
194 |
} else {
|
|
|
195 |
/* Normal header (1-byte array size, 2-byte length). */
|
|
|
196 |
/* We already checked rcnt >= 3. */
|
|
|
197 |
size = sdecodeushort(p + 2, num_format);
|
|
|
198 |
hsize = 4;
|
|
|
199 |
}
|
|
|
200 |
if (size < hsize)
|
|
|
201 |
return_error(e_syntaxerror);
|
|
|
202 |
/* Preallocate an array large enough for the worst case, */
|
|
|
203 |
/* namely, all objects and no strings. */
|
|
|
204 |
code = ialloc_ref_array(&pbs->bin_array,
|
|
|
205 |
a_all + a_executable, size / sizeof(ref),
|
|
|
206 |
"binary object sequence(objects)");
|
|
|
207 |
if (code < 0)
|
|
|
208 |
return code;
|
|
|
209 |
p += hsize - 1;
|
|
|
210 |
size -= hsize;
|
|
|
211 |
s_end_inline(s, p, rlimit);
|
|
|
212 |
pbs->max_array_index = pbs->top_size = top_size;
|
|
|
213 |
pbs->min_string_index = pbs->size = size;
|
|
|
214 |
pbs->index = 0;
|
|
|
215 |
pstate->s_da.is_dynamic = false;
|
|
|
216 |
pstate->s_da.base = pstate->s_da.next =
|
|
|
217 |
pstate->s_da.limit = pstate->s_da.buf;
|
|
|
218 |
code = scan_bos_continue(i_ctx_p, s, pref, pstate);
|
|
|
219 |
if (code == scan_Refill || code < 0) {
|
|
|
220 |
/* Clean up array for GC. */
|
|
|
221 |
uint index = pbs->index;
|
|
|
222 |
|
|
|
223 |
refset_null(pbs->bin_array.value.refs + index,
|
|
|
224 |
r_size(&pbs->bin_array) - index);
|
|
|
225 |
}
|
|
|
226 |
return code;
|
|
|
227 |
}
|
|
|
228 |
case BT_INT8:
|
|
|
229 |
make_int(pref, (p[1] ^ 128) - 128);
|
|
|
230 |
s_end_inline(s, p + 1, rlimit);
|
|
|
231 |
return 0;
|
|
|
232 |
case BT_FIXED:
|
|
|
233 |
num_format = p[1];
|
|
|
234 |
if (!num_is_valid(num_format))
|
|
|
235 |
return_error(e_syntaxerror);
|
|
|
236 |
wanted = 1 + encoded_number_bytes(num_format);
|
|
|
237 |
if (rcnt < wanted) {
|
|
|
238 |
s_end_inline(s, p - 1, rlimit);
|
|
|
239 |
pstate->s_scan_type = scanning_none;
|
|
|
240 |
return scan_Refill;
|
|
|
241 |
}
|
|
|
242 |
code = sdecode_number(p + 2, num_format, pref);
|
|
|
243 |
goto rnum;
|
|
|
244 |
case BT_INT32_MSB:
|
|
|
245 |
case BT_INT32_LSB:
|
|
|
246 |
case BT_INT16_MSB:
|
|
|
247 |
case BT_INT16_LSB:
|
|
|
248 |
case BT_FLOAT_IEEE_MSB:
|
|
|
249 |
case BT_FLOAT_IEEE_LSB:
|
|
|
250 |
case BT_FLOAT_NATIVE:
|
|
|
251 |
code = sdecode_number(p + 1, num_format, pref);
|
|
|
252 |
rnum:
|
|
|
253 |
switch (code) {
|
|
|
254 |
case t_integer:
|
|
|
255 |
case t_real:
|
|
|
256 |
r_set_type(pref, code);
|
|
|
257 |
break;
|
|
|
258 |
case t_null:
|
|
|
259 |
return_error(e_syntaxerror);
|
|
|
260 |
default:
|
|
|
261 |
return code;
|
|
|
262 |
}
|
|
|
263 |
s_end_inline(s, p + wanted, rlimit);
|
|
|
264 |
return 0;
|
|
|
265 |
case BT_BOOLEAN:
|
|
|
266 |
arg = p[1];
|
|
|
267 |
if (arg & ~1)
|
|
|
268 |
return_error(e_syntaxerror);
|
|
|
269 |
make_bool(pref, arg);
|
|
|
270 |
s_end_inline(s, p + 1, rlimit);
|
|
|
271 |
return 0;
|
|
|
272 |
case BT_STRING_256:
|
|
|
273 |
arg = *++p;
|
|
|
274 |
goto str;
|
|
|
275 |
case BT_STRING_64K_MSB:
|
|
|
276 |
case BT_STRING_64K_LSB:
|
|
|
277 |
arg = sdecodeushort(p + 1, num_format);
|
|
|
278 |
p += 2;
|
|
|
279 |
str:
|
|
|
280 |
if (s->foreign && rlimit - p >= arg) {
|
|
|
281 |
/*
|
|
|
282 |
* Reference the string directly in the buffer. It is
|
|
|
283 |
* marked writable for consistency with the non-direct
|
|
|
284 |
* case, but since the "buffer" may be data compiled into
|
|
|
285 |
* the executable, it is probably actually read-only.
|
|
|
286 |
*/
|
|
|
287 |
s_end_inline(s, p, rlimit);
|
|
|
288 |
make_const_string(pref, a_all | avm_foreign, arg, sbufptr(s));
|
|
|
289 |
sbufskip(s, arg);
|
|
|
290 |
return 0;
|
|
|
291 |
} else {
|
|
|
292 |
byte *str = ialloc_string(arg, "string token");
|
|
|
293 |
|
|
|
294 |
if (str == 0)
|
|
|
295 |
return_error(e_VMerror);
|
|
|
296 |
s_end_inline(s, p, rlimit);
|
|
|
297 |
pstate->s_da.base = pstate->s_da.next = str;
|
|
|
298 |
pstate->s_da.limit = str + arg;
|
|
|
299 |
code = scan_bin_string_continue(i_ctx_p, s, pref, pstate);
|
|
|
300 |
if (code == scan_Refill || code < 0) {
|
|
|
301 |
pstate->s_da.is_dynamic = true;
|
|
|
302 |
make_null(&pbs->bin_array); /* clean up for GC */
|
|
|
303 |
pbs->cont = scan_bin_string_continue;
|
|
|
304 |
}
|
|
|
305 |
return code;
|
|
|
306 |
}
|
|
|
307 |
case BT_LITNAME_SYSTEM:
|
|
|
308 |
code = scan_bin_get_name(imemory, system_names_p, p[1], pref);
|
|
|
309 |
goto lname;
|
|
|
310 |
case BT_EXECNAME_SYSTEM:
|
|
|
311 |
code = scan_bin_get_name(imemory, system_names_p, p[1], pref);
|
|
|
312 |
goto xname;
|
|
|
313 |
case BT_LITNAME_USER:
|
|
|
314 |
code = scan_bin_get_name(imemory, user_names_p, p[1], pref);
|
|
|
315 |
lname:
|
|
|
316 |
if (code < 0)
|
|
|
317 |
return code;
|
|
|
318 |
if (!r_has_type(pref, t_name))
|
|
|
319 |
return_error(e_undefined);
|
|
|
320 |
s_end_inline(s, p + 1, rlimit);
|
|
|
321 |
return 0;
|
|
|
322 |
case BT_EXECNAME_USER:
|
|
|
323 |
code = scan_bin_get_name(imemory, user_names_p, p[1], pref);
|
|
|
324 |
xname:
|
|
|
325 |
if (code < 0)
|
|
|
326 |
return code;
|
|
|
327 |
if (!r_has_type(pref, t_name))
|
|
|
328 |
return_error(e_undefined);
|
|
|
329 |
r_set_attrs(pref, a_executable);
|
|
|
330 |
s_end_inline(s, p + 1, rlimit);
|
|
|
331 |
return 0;
|
|
|
332 |
case BT_NUM_ARRAY:
|
|
|
333 |
num_format = p[1];
|
|
|
334 |
if (!num_is_valid(num_format))
|
|
|
335 |
return_error(e_syntaxerror);
|
|
|
336 |
arg = sdecodeushort(p + 2, num_format);
|
|
|
337 |
code = ialloc_ref_array(&pbs->bin_array, a_all, arg,
|
|
|
338 |
"number array token");
|
|
|
339 |
if (code < 0)
|
|
|
340 |
return code;
|
|
|
341 |
pbs->num_format = num_format;
|
|
|
342 |
pbs->index = 0;
|
|
|
343 |
p += 3;
|
|
|
344 |
s_end_inline(s, p, rlimit);
|
|
|
345 |
code = scan_bin_num_array_continue(i_ctx_p, s, pref, pstate);
|
|
|
346 |
if (code == scan_Refill || code < 0) {
|
|
|
347 |
/* Make sure the array is clean for the GC. */
|
|
|
348 |
refset_null(pbs->bin_array.value.refs + pbs->index,
|
|
|
349 |
arg - pbs->index);
|
|
|
350 |
pbs->cont = scan_bin_num_array_continue;
|
|
|
351 |
}
|
|
|
352 |
return code;
|
|
|
353 |
}
|
|
|
354 |
return_error(e_syntaxerror);
|
|
|
355 |
}
|
|
|
356 |
|
|
|
357 |
/* Get a system or user name. */
|
|
|
358 |
private int
|
|
|
359 |
scan_bin_get_name(const gs_memory_t *mem, const ref *pnames /*t_array*/, int index, ref *pref)
|
|
|
360 |
{
|
|
|
361 |
if (pnames == 0)
|
|
|
362 |
return_error(e_rangecheck);
|
|
|
363 |
return array_get(mem, pnames, (long)index, pref);
|
|
|
364 |
}
|
|
|
365 |
|
|
|
366 |
/* Continue collecting a binary string. */
|
|
|
367 |
private int
|
|
|
368 |
scan_bin_string_continue(i_ctx_t *i_ctx_p, stream * s, ref * pref,
|
|
|
369 |
scanner_state * pstate)
|
|
|
370 |
{
|
|
|
371 |
byte *q = pstate->s_da.next;
|
|
|
372 |
uint wanted = pstate->s_da.limit - q;
|
|
|
373 |
uint rcnt;
|
|
|
374 |
|
|
|
375 |
/* We don't check the return status from 'sgets' here.
|
|
|
376 |
If there is an error in sgets, the condition rcnt==wanted
|
|
|
377 |
would be false and this function will return scan_Refill.
|
|
|
378 |
*/
|
|
|
379 |
sgets(s, q, wanted, &rcnt);
|
|
|
380 |
if (rcnt == wanted) {
|
|
|
381 |
/* Finished collecting the string. */
|
|
|
382 |
make_string(pref, a_all | icurrent_space,
|
|
|
383 |
pstate->s_da.limit - pstate->s_da.base,
|
|
|
384 |
pstate->s_da.base);
|
|
|
385 |
return 0;
|
|
|
386 |
}
|
|
|
387 |
pstate->s_da.next = q + rcnt;
|
|
|
388 |
pstate->s_scan_type = scanning_binary;
|
|
|
389 |
return scan_Refill;
|
|
|
390 |
}
|
|
|
391 |
|
|
|
392 |
/* Continue scanning a binary number array. */
|
|
|
393 |
private int
|
|
|
394 |
scan_bin_num_array_continue(i_ctx_t *i_ctx_p, stream * s, ref * pref,
|
|
|
395 |
scanner_state * pstate)
|
|
|
396 |
{
|
|
|
397 |
scan_binary_state *const pbs = &pstate->s_ss.binary;
|
|
|
398 |
uint index = pbs->index;
|
|
|
399 |
ref *np = pbs->bin_array.value.refs + index;
|
|
|
400 |
uint wanted = encoded_number_bytes(pbs->num_format);
|
|
|
401 |
|
|
|
402 |
for (; index < r_size(&pbs->bin_array); index++, np++) {
|
|
|
403 |
int code;
|
|
|
404 |
|
|
|
405 |
if (sbufavailable(s) < wanted) {
|
|
|
406 |
pbs->index = index;
|
|
|
407 |
pstate->s_scan_type = scanning_binary;
|
|
|
408 |
return scan_Refill;
|
|
|
409 |
}
|
|
|
410 |
code = sdecode_number(sbufptr(s), pbs->num_format, np);
|
|
|
411 |
switch (code) {
|
|
|
412 |
case t_integer:
|
|
|
413 |
case t_real:
|
|
|
414 |
r_set_type(np, code);
|
|
|
415 |
sbufskip(s, wanted);
|
|
|
416 |
break;
|
|
|
417 |
case t_null:
|
|
|
418 |
return_error(e_syntaxerror);
|
|
|
419 |
default:
|
|
|
420 |
return code;
|
|
|
421 |
}
|
|
|
422 |
}
|
|
|
423 |
*pref = pbs->bin_array;
|
|
|
424 |
return 0;
|
|
|
425 |
}
|
|
|
426 |
|
|
|
427 |
/*
|
|
|
428 |
* Continue scanning a binary object sequence. We preallocated space for
|
|
|
429 |
* the largest possible number of objects, but not for strings, since
|
|
|
430 |
* the latter would probably be a gross over-estimate. Instead,
|
|
|
431 |
* we wait until we see the first string or name, and allocate string space
|
|
|
432 |
* based on the hope that its string index is the smallest one we will see.
|
|
|
433 |
* If this turns out to be wrong, we may have to reallocate, and adjust
|
|
|
434 |
* all the pointers.
|
|
|
435 |
*/
|
|
|
436 |
private int
|
|
|
437 |
scan_bos_continue(i_ctx_t *i_ctx_p, register stream * s, ref * pref,
|
|
|
438 |
scanner_state * pstate)
|
|
|
439 |
{
|
|
|
440 |
scan_binary_state *const pbs = &pstate->s_ss.binary;
|
|
|
441 |
s_declare_inline(s, p, rlimit);
|
|
|
442 |
uint max_array_index = pbs->max_array_index;
|
|
|
443 |
uint min_string_index = pbs->min_string_index;
|
|
|
444 |
int num_format = pbs->num_format;
|
|
|
445 |
uint index = pbs->index;
|
|
|
446 |
uint size = pbs->size;
|
|
|
447 |
ref *abase = pbs->bin_array.value.refs;
|
|
|
448 |
int code;
|
|
|
449 |
|
|
|
450 |
pbs->cont = scan_bos_continue; /* in case of premature return */
|
|
|
451 |
s_begin_inline(s, p, rlimit);
|
|
|
452 |
for (; index < max_array_index; p += SIZEOF_BIN_SEQ_OBJ, index++) {
|
|
|
453 |
ref *op = abase + index;
|
|
|
454 |
uint osize;
|
|
|
455 |
long value;
|
|
|
456 |
uint atype, attrs;
|
|
|
457 |
|
|
|
458 |
s_end_inline(s, p, rlimit); /* in case of error */
|
|
|
459 |
if (rlimit - p < SIZEOF_BIN_SEQ_OBJ) {
|
|
|
460 |
pbs->index = index;
|
|
|
461 |
pbs->max_array_index = max_array_index;
|
|
|
462 |
pbs->min_string_index = min_string_index;
|
|
|
463 |
pstate->s_scan_type = scanning_binary;
|
|
|
464 |
return scan_Refill;
|
|
|
465 |
}
|
|
|
466 |
if (p[2] != 0) /* reserved, must be 0 */
|
|
|
467 |
return_error(e_syntaxerror);
|
|
|
468 |
attrs = (p[1] & 128 ? a_executable : 0);
|
|
|
469 |
switch (p[1] & 0x7f) {
|
|
|
470 |
case BS_TYPE_NULL:
|
|
|
471 |
make_null(op);
|
|
|
472 |
break;
|
|
|
473 |
case BS_TYPE_INTEGER:
|
|
|
474 |
make_int(op, sdecodelong(p + 5, num_format));
|
|
|
475 |
break;
|
|
|
476 |
case BS_TYPE_REAL:{
|
|
|
477 |
float vreal;
|
|
|
478 |
|
|
|
479 |
osize = sdecodeushort(p + 3, num_format);
|
|
|
480 |
if (osize != 0) { /* fixed-point number */
|
|
|
481 |
value = sdecodelong(p + 5, num_format);
|
|
|
482 |
/* ldexp requires a signed 2nd argument.... */
|
|
|
483 |
vreal = (float)ldexp((double)value, -(int)osize);
|
|
|
484 |
} else {
|
|
|
485 |
vreal = sdecodefloat(p + 5, num_format);
|
|
|
486 |
}
|
|
|
487 |
make_real(op, vreal);
|
|
|
488 |
break;
|
|
|
489 |
}
|
|
|
490 |
case BS_TYPE_BOOLEAN:
|
|
|
491 |
make_bool(op, sdecodelong(p + 5, num_format) != 0);
|
|
|
492 |
break;
|
|
|
493 |
case BS_TYPE_STRING:
|
|
|
494 |
osize = sdecodeushort(p + 3, num_format);
|
|
|
495 |
attrs |= a_all;
|
|
|
496 |
str:
|
|
|
497 |
if (osize == 0) {
|
|
|
498 |
/* For zero-length strings, the offset */
|
|
|
499 |
/* doesn't matter, and may be zero. */
|
|
|
500 |
make_empty_string(op, attrs);
|
|
|
501 |
break;
|
|
|
502 |
}
|
|
|
503 |
value = sdecodelong(p + 5, num_format);
|
|
|
504 |
if (value < max_array_index * SIZEOF_BIN_SEQ_OBJ ||
|
|
|
505 |
value + osize > size
|
|
|
506 |
)
|
|
|
507 |
return_error(e_syntaxerror);
|
|
|
508 |
if (value < min_string_index) {
|
|
|
509 |
/* We have to (re)allocate the strings. */
|
|
|
510 |
uint str_size = size - value;
|
|
|
511 |
byte *sbase;
|
|
|
512 |
|
|
|
513 |
if (pstate->s_da.is_dynamic)
|
|
|
514 |
sbase = scan_bos_resize(i_ctx_p, pstate, str_size,
|
|
|
515 |
index);
|
|
|
516 |
else
|
|
|
517 |
sbase = ialloc_string(str_size,
|
|
|
518 |
"bos strings");
|
|
|
519 |
if (sbase == 0)
|
|
|
520 |
return_error(e_VMerror);
|
|
|
521 |
pstate->s_da.is_dynamic = true;
|
|
|
522 |
pstate->s_da.base = pstate->s_da.next = sbase;
|
|
|
523 |
pstate->s_da.limit = sbase + str_size;
|
|
|
524 |
min_string_index = value;
|
|
|
525 |
}
|
|
|
526 |
make_string(op, attrs | icurrent_space, osize,
|
|
|
527 |
pstate->s_da.base +
|
|
|
528 |
(value - min_string_index));
|
|
|
529 |
break;
|
|
|
530 |
case BS_TYPE_EVAL_NAME:
|
|
|
531 |
attrs |= a_readonly; /* mark as executable for later */
|
|
|
532 |
/* falls through */
|
|
|
533 |
case BS_TYPE_NAME:
|
|
|
534 |
osize = sdecodeushort(p + 3, num_format);
|
|
|
535 |
value = sdecodelong(p + 5, num_format);
|
|
|
536 |
switch (osize) {
|
|
|
537 |
case 0:
|
|
|
538 |
code = array_get(imemory, user_names_p, value, op);
|
|
|
539 |
goto usn;
|
|
|
540 |
case 0xffff:
|
|
|
541 |
code = array_get(imemory, system_names_p, value, op);
|
|
|
542 |
usn:
|
|
|
543 |
if (code < 0)
|
|
|
544 |
return code;
|
|
|
545 |
if (!r_has_type(op, t_name))
|
|
|
546 |
return_error(e_undefined);
|
|
|
547 |
r_set_attrs(op, attrs);
|
|
|
548 |
break;
|
|
|
549 |
default:
|
|
|
550 |
goto str;
|
|
|
551 |
}
|
|
|
552 |
break;
|
|
|
553 |
case BS_TYPE_ARRAY:
|
|
|
554 |
osize = sdecodeushort(p + 3, num_format);
|
|
|
555 |
atype = t_array;
|
|
|
556 |
arr:
|
|
|
557 |
value = sdecodelong(p + 5, num_format);
|
|
|
558 |
if (value + osize > min_string_index ||
|
|
|
559 |
value & (SIZEOF_BIN_SEQ_OBJ - 1)
|
|
|
560 |
)
|
|
|
561 |
return_error(e_syntaxerror);
|
|
|
562 |
{
|
|
|
563 |
uint aindex = value / SIZEOF_BIN_SEQ_OBJ;
|
|
|
564 |
|
|
|
565 |
max_array_index =
|
|
|
566 |
max(max_array_index, aindex + osize);
|
|
|
567 |
make_tasv_new(op, atype,
|
|
|
568 |
attrs | a_all | icurrent_space,
|
|
|
569 |
osize, refs, abase + aindex);
|
|
|
570 |
}
|
|
|
571 |
break;
|
|
|
572 |
case BS_TYPE_DICTIONARY: /* EXTENSION */
|
|
|
573 |
osize = sdecodeushort(p + 3, num_format);
|
|
|
574 |
if ((osize & 1) != 0 && osize != 1)
|
|
|
575 |
return_error(e_syntaxerror);
|
|
|
576 |
atype = t_mixedarray; /* mark as dictionary */
|
|
|
577 |
goto arr;
|
|
|
578 |
case BS_TYPE_MARK:
|
|
|
579 |
make_mark(op);
|
|
|
580 |
break;
|
|
|
581 |
default:
|
|
|
582 |
return_error(e_syntaxerror);
|
|
|
583 |
}
|
|
|
584 |
}
|
|
|
585 |
s_end_inline(s, p, rlimit);
|
|
|
586 |
/* Shorten the objects to remove the space that turned out */
|
|
|
587 |
/* to be used for strings. */
|
|
|
588 |
pbs->index = max_array_index;
|
|
|
589 |
iresize_ref_array(&pbs->bin_array, max_array_index,
|
|
|
590 |
"binary object sequence(objects)");
|
|
|
591 |
code = scan_bos_string_continue(i_ctx_p, s, pref, pstate);
|
|
|
592 |
if (code == scan_Refill)
|
|
|
593 |
pbs->cont = scan_bos_string_continue;
|
|
|
594 |
return code;
|
|
|
595 |
}
|
|
|
596 |
|
|
|
597 |
/* Reallocate the strings for a binary object sequence, */
|
|
|
598 |
/* adjusting all the pointers to them from objects. */
|
|
|
599 |
private byte *
|
|
|
600 |
scan_bos_resize(i_ctx_t *i_ctx_p, scanner_state * pstate, uint new_size,
|
|
|
601 |
uint index)
|
|
|
602 |
{
|
|
|
603 |
scan_binary_state *const pbs = &pstate->s_ss.binary;
|
|
|
604 |
uint old_size = da_size(&pstate->s_da);
|
|
|
605 |
byte *old_base = pstate->s_da.base;
|
|
|
606 |
byte *new_base = iresize_string(old_base, old_size, new_size,
|
|
|
607 |
"scan_bos_resize");
|
|
|
608 |
byte *relocated_base = new_base + (new_size - old_size);
|
|
|
609 |
uint i;
|
|
|
610 |
ref *aptr = pbs->bin_array.value.refs;
|
|
|
611 |
|
|
|
612 |
if (new_base == 0)
|
|
|
613 |
return 0;
|
|
|
614 |
/* Since the allocator normally extends strings downward, */
|
|
|
615 |
/* it's quite possible that new and old addresses are the same. */
|
|
|
616 |
if (relocated_base != old_base)
|
|
|
617 |
for (i = index; i != 0; i--, aptr++)
|
|
|
618 |
if (r_has_type(aptr, t_string) && r_size(aptr) != 0)
|
|
|
619 |
aptr->value.bytes =
|
|
|
620 |
aptr->value.bytes - old_base + relocated_base;
|
|
|
621 |
return new_base;
|
|
|
622 |
}
|
|
|
623 |
|
|
|
624 |
/* Continue reading the strings for a binary object sequence. */
|
|
|
625 |
private int
|
|
|
626 |
scan_bos_string_continue(i_ctx_t *i_ctx_p, register stream * s, ref * pref,
|
|
|
627 |
scanner_state * pstate)
|
|
|
628 |
{
|
|
|
629 |
scan_binary_state *const pbs = &pstate->s_ss.binary;
|
|
|
630 |
ref rstr;
|
|
|
631 |
ref *op;
|
|
|
632 |
int code = scan_bin_string_continue(i_ctx_p, s, &rstr, pstate);
|
|
|
633 |
uint space = ialloc_space(idmemory);
|
|
|
634 |
bool rescan = false;
|
|
|
635 |
uint i;
|
|
|
636 |
|
|
|
637 |
if (code != 0)
|
|
|
638 |
return code;
|
|
|
639 |
|
|
|
640 |
/* Fix up names. We must do this before creating dictionaries. */
|
|
|
641 |
|
|
|
642 |
for (op = pbs->bin_array.value.refs, i = r_size(&pbs->bin_array);
|
|
|
643 |
i != 0; i--, op++
|
|
|
644 |
)
|
|
|
645 |
switch (r_type(op)) {
|
|
|
646 |
case t_string:
|
|
|
647 |
if (r_has_attr(op, a_write)) /* a real string */
|
|
|
648 |
break;
|
|
|
649 |
/* This is actually a name; look it up now. */
|
|
|
650 |
{
|
|
|
651 |
uint attrs =
|
|
|
652 |
(r_has_attr(op, a_executable) ? a_executable : 0);
|
|
|
653 |
|
|
|
654 |
code = name_ref(imemory, op->value.bytes, r_size(op), op, 1);
|
|
|
655 |
if (code < 0)
|
|
|
656 |
return code;
|
|
|
657 |
r_set_attrs(op, attrs);
|
|
|
658 |
}
|
|
|
659 |
/* falls through */
|
|
|
660 |
case t_name:
|
|
|
661 |
if (r_has_attr(op, a_read)) { /* BS_TYPE_EVAL_NAME */
|
|
|
662 |
ref *defp = dict_find_name(op);
|
|
|
663 |
|
|
|
664 |
if (defp == 0)
|
|
|
665 |
return_error(e_undefined);
|
|
|
666 |
store_check_space(space, defp);
|
|
|
667 |
ref_assign(op, defp);
|
|
|
668 |
}
|
|
|
669 |
break;
|
|
|
670 |
case t_mixedarray: /* actually a dictionary */
|
|
|
671 |
rescan = true;
|
|
|
672 |
}
|
|
|
673 |
|
|
|
674 |
/* Create dictionaries, if any. */
|
|
|
675 |
|
|
|
676 |
if (rescan) {
|
|
|
677 |
rescan = false;
|
|
|
678 |
for (op = pbs->bin_array.value.refs, i = r_size(&pbs->bin_array);
|
|
|
679 |
i != 0; i--, op++
|
|
|
680 |
)
|
|
|
681 |
switch (r_type(op)) {
|
|
|
682 |
case t_mixedarray: /* actually a dictionary */
|
|
|
683 |
{
|
|
|
684 |
uint count = r_size(op);
|
|
|
685 |
ref rdict;
|
|
|
686 |
|
|
|
687 |
if (count == 1) {
|
|
|
688 |
/* Indirect reference. */
|
|
|
689 |
if (op->value.refs < op)
|
|
|
690 |
ref_assign(&rdict, op->value.refs);
|
|
|
691 |
else {
|
|
|
692 |
rescan = true;
|
|
|
693 |
continue;
|
|
|
694 |
}
|
|
|
695 |
} else {
|
|
|
696 |
code = dict_create(count >> 1, &rdict);
|
|
|
697 |
if (code < 0)
|
|
|
698 |
return code;
|
|
|
699 |
while (count) {
|
|
|
700 |
count -= 2;
|
|
|
701 |
code = idict_put(&rdict,
|
|
|
702 |
&op->value.refs[count],
|
|
|
703 |
&op->value.refs[count + 1]);
|
|
|
704 |
if (code < 0)
|
|
|
705 |
return code;
|
|
|
706 |
}
|
|
|
707 |
}
|
|
|
708 |
r_set_attrs(&rdict, a_all);
|
|
|
709 |
r_copy_attrs(&rdict, a_executable, op);
|
|
|
710 |
ref_assign(op, &rdict);
|
|
|
711 |
}
|
|
|
712 |
break;
|
|
|
713 |
}
|
|
|
714 |
}
|
|
|
715 |
|
|
|
716 |
/* If there were any forward indirect references, fix them up now. */
|
|
|
717 |
|
|
|
718 |
if (rescan)
|
|
|
719 |
for (op = pbs->bin_array.value.refs, i = r_size(&pbs->bin_array);
|
|
|
720 |
i != 0; i--, op++
|
|
|
721 |
)
|
|
|
722 |
if (r_has_type(op, t_mixedarray)) {
|
|
|
723 |
const ref *piref = op->value.const_refs;
|
|
|
724 |
ref rdict;
|
|
|
725 |
|
|
|
726 |
if (r_has_type(piref, t_mixedarray)) /* ref to indirect */
|
|
|
727 |
return_error(e_syntaxerror);
|
|
|
728 |
ref_assign(&rdict, piref);
|
|
|
729 |
r_copy_attrs(&rdict, a_executable, op);
|
|
|
730 |
ref_assign(op, &rdict);
|
|
|
731 |
}
|
|
|
732 |
|
|
|
733 |
ref_assign(pref, &pbs->bin_array);
|
|
|
734 |
r_set_size(pref, pbs->top_size);
|
|
|
735 |
return scan_BOS;
|
|
|
736 |
}
|
|
|
737 |
|
|
|
738 |
/* ---------------- Writing ---------------- */
|
|
|
739 |
|
|
|
740 |
int
|
|
|
741 |
encode_binary_token(i_ctx_t *i_ctx_p, const ref *obj, long *ref_offset,
|
|
|
742 |
long *char_offset, byte *str)
|
|
|
743 |
{
|
|
|
744 |
bin_seq_type_t type;
|
|
|
745 |
uint size = 0;
|
|
|
746 |
int format = (int)ref_binary_object_format.value.intval;
|
|
|
747 |
long value;
|
|
|
748 |
ref nstr;
|
|
|
749 |
|
|
|
750 |
switch (r_type(obj)) {
|
|
|
751 |
case t_null:
|
|
|
752 |
type = BS_TYPE_NULL;
|
|
|
753 |
goto tx;
|
|
|
754 |
case t_mark:
|
|
|
755 |
type = BS_TYPE_MARK;
|
|
|
756 |
goto tx;
|
|
|
757 |
case t_integer:
|
|
|
758 |
type = BS_TYPE_INTEGER;
|
|
|
759 |
value = obj->value.intval;
|
|
|
760 |
break;
|
|
|
761 |
case t_real:
|
|
|
762 |
type = BS_TYPE_REAL;
|
|
|
763 |
if (sizeof(obj->value.realval) != sizeof(int)) {
|
|
|
764 |
/* The PLRM allocates exactly 4 bytes for reals. */
|
|
|
765 |
return_error(e_rangecheck);
|
|
|
766 |
}
|
|
|
767 |
value = *(const int *)&obj->value.realval;
|
|
|
768 |
#if !(ARCH_FLOATS_ARE_IEEE && BYTE_SWAP_IEEE_NATIVE_REALS)
|
|
|
769 |
if (format >= 3) {
|
|
|
770 |
/* Never byte-swap native reals -- use native byte order. */
|
|
|
771 |
format = 4 - ARCH_IS_BIG_ENDIAN;
|
|
|
772 |
}
|
|
|
773 |
#endif
|
|
|
774 |
break;
|
|
|
775 |
case t_boolean:
|
|
|
776 |
type = BS_TYPE_BOOLEAN;
|
|
|
777 |
value = obj->value.boolval;
|
|
|
778 |
break;
|
|
|
779 |
case t_array:
|
|
|
780 |
type = BS_TYPE_ARRAY;
|
|
|
781 |
size = r_size(obj);
|
|
|
782 |
goto aod;
|
|
|
783 |
case t_dictionary: /* EXTENSION */
|
|
|
784 |
type = BS_TYPE_DICTIONARY;
|
|
|
785 |
size = dict_length(obj) << 1;
|
|
|
786 |
aod:value = *ref_offset;
|
|
|
787 |
*ref_offset += size * (ulong) SIZEOF_BIN_SEQ_OBJ;
|
|
|
788 |
break;
|
|
|
789 |
case t_string:
|
|
|
790 |
type = BS_TYPE_STRING;
|
|
|
791 |
nos:
|
|
|
792 |
size = r_size(obj);
|
|
|
793 |
value = *char_offset;
|
|
|
794 |
*char_offset += size;
|
|
|
795 |
break;
|
|
|
796 |
case t_name:
|
|
|
797 |
type = BS_TYPE_NAME;
|
|
|
798 |
name_string_ref(imemory, obj, &nstr);
|
|
|
799 |
r_copy_attrs(&nstr, a_executable, obj);
|
|
|
800 |
obj = &nstr;
|
|
|
801 |
goto nos;
|
|
|
802 |
default:
|
|
|
803 |
return_error(e_rangecheck);
|
|
|
804 |
}
|
|
|
805 |
{
|
|
|
806 |
byte s0 = (byte) size, s1 = (byte) (size >> 8);
|
|
|
807 |
byte v0 = (byte) value, v1 = (byte) (value >> 8),
|
|
|
808 |
v2 = (byte) (value >> 16), v3 = (byte) (value >> 24);
|
|
|
809 |
|
|
|
810 |
if (format & 1) {
|
|
|
811 |
/* Store big-endian */
|
|
|
812 |
str[2] = s1, str[3] = s0;
|
|
|
813 |
str[4] = v3, str[5] = v2, str[6] = v1, str[7] = v0;
|
|
|
814 |
} else {
|
|
|
815 |
/* Store little-endian */
|
|
|
816 |
str[2] = s0, str[3] = s1;
|
|
|
817 |
str[4] = v0, str[5] = v1, str[6] = v2, str[7] = v3;
|
|
|
818 |
}
|
|
|
819 |
}
|
|
|
820 |
tx:
|
|
|
821 |
if (r_has_attr(obj, a_executable))
|
|
|
822 |
type += BS_EXECUTABLE;
|
|
|
823 |
str[0] = (byte) type;
|
|
|
824 |
return 0;
|
|
|
825 |
}
|