Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
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
}