Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
2
    		 Crown Copyright (c) 1997
3
 
4
    This TenDRA(r) Computer Program is subject to Copyright
5
    owned by the United Kingdom Secretary of State for Defence
6
    acting through the Defence Evaluation and Research Agency
7
    (DERA).  It is made available to Recipients with a
8
    royalty-free licence for its use, reproduction, transfer
9
    to other parties and amendment for any purpose not excluding
10
    product development provided that any such use et cetera
11
    shall be deemed to be acceptance of the following conditions:-
12
 
13
        (1) Its Recipients shall ensure that this Notice is
14
        reproduced upon any copies or amended versions of it;
15
 
16
        (2) Any amended version of it shall be clearly marked to
17
        show both the nature of and the organisation responsible
18
        for the relevant amendment or amendments;
19
 
20
        (3) Its onward transfer from a recipient to another
21
        party shall be deemed to be that party's acceptance of
22
        these conditions;
23
 
24
        (4) DERA gives no warranty or assurance as to its
25
        quality or suitability for any purpose and DERA accepts
26
        no liability whatsoever in relation to any use to which
27
        it may be put.
28
*/
29
 
30
 
31
#include "config.h"
32
#include <limits.h>
33
#include "c_types.h"
34
#include "error.h"
35
#include "char.h"
36
#include "encode.h"
37
#include "literal.h"
38
#include "ustring.h"
39
#include "xalloc.h"
40
 
41
 
42
/*
43
    DUMP A BITSTREAM TO A FILE
44
 
45
    This routine dumps the contents of the bitstream bs to its associated
46
    file.  The contents will be lost if this is the null file.  Any odd
47
    bits will remain in the bitstream.
48
*/
49
 
50
static void dump_bitstream
51
    PROTO_N ( ( bs ) )
52
    PROTO_T ( BITSTREAM *bs )
53
{
54
    size_t n = ( size_t ) bs->bytes ;
55
    if ( n ) {
56
	string t = bs->text ;
57
	FILE *f = bs->file ;
58
	if ( f ) {
59
	    IGNORE fwrite ( ( gen_ptr ) t, sizeof ( character ), n, f ) ;
60
	}
61
	t [0] = t [n] ;
62
    }
63
    bs->bytes = 0 ;
64
    return ;
65
}
66
 
67
 
68
/*
69
    LIST OF FREE BITSTREAMS
70
 
71
    This variable gives the list of bitstreams from which new bitstreams
72
    are allocated.
73
*/
74
 
75
static BITSTREAM *free_bitstreams = NULL ;
76
 
77
 
78
/*
79
    CREATE A NEW BITSTREAM
80
 
81
    This routine creates a new bitstream with associated file f and
82
    linkage lnk.
83
*/
84
 
85
BITSTREAM *start_bitstream
86
    PROTO_N ( ( f, lnk ) )
87
    PROTO_T ( FILE *f X gen_ptr lnk )
88
{
89
    BITSTREAM *bs = free_bitstreams ;
90
    if ( bs ) {
91
	free_bitstreams = bs->prev ;
92
    } else {
93
	bs = xmalloc_one ( BITSTREAM ) ;
94
	bs->text = xustr ( ( gen_size ) CHUNK_SIZE ) ;
95
    }
96
    bs->bytes = 0 ;
97
    bs->bits = 0 ;
98
    bs->size = 0 ;
99
    bs->file = f ;
100
    bs->link = lnk ;
101
    bs->prev = NULL ;
102
    return ( bs ) ;
103
}
104
 
105
 
106
/*
107
    END A BITSTREAM
108
 
109
    This routine frees the bitstream bs including clearing the buffer
110
    for any file bitstream if w is true.
111
*/
112
 
113
void end_bitstream
114
    PROTO_N ( ( bs, w ) )
115
    PROTO_T ( BITSTREAM *bs X int w )
116
{
117
    BITSTREAM *ps = bs ;
118
    if ( w && ps->file ) {
119
	/* Align bitstream and dump */
120
	ps = enc_boundary ( ps ) ;
121
	dump_bitstream ( ps ) ;
122
    }
123
    while ( ps->prev ) ps = ps->prev ;
124
    ps->prev = free_bitstreams ;
125
    free_bitstreams = bs ;
126
    return ;
127
}
128
 
129
 
130
/*
131
    EXTEND A BITSTREAM
132
 
133
    This routine extends the bitstream bs by dumping its contents to a
134
    file or linking it to a fresh chunk.
135
*/
136
 
137
static BITSTREAM *extend_bitstream
138
    PROTO_N ( ( bs ) )
139
    PROTO_T ( BITSTREAM *bs )
140
{
141
    bs->bytes = CHUNK_SIZE ;
142
    bs->bits = 0 ;
143
    if ( bs->file ) {
144
	dump_bitstream ( bs ) ;
145
    } else {
146
	BITSTREAM *ps = start_bitstream ( NIL ( FILE ), bs->link ) ;
147
	ps->prev = bs ;
148
	bs = ps ;
149
    }
150
    return ( bs ) ;
151
}
152
 
153
 
154
/*
155
    ADD A NUMBER OF BITS TO A BITSTREAM
156
 
157
    This routine adds the n bits given by d to the bitstream bs.  n will
158
    always be at most 16.
159
*/
160
 
161
BITSTREAM *enc_bits
162
    PROTO_N ( ( bs, n, d ) )
163
    PROTO_T ( BITSTREAM *bs X unsigned n X unsigned d )
164
{
165
    if ( n ) {
166
	unsigned long b = ( unsigned long ) d ;
167
	string text = bs->text ;
168
	unsigned bytes = bs->bytes ;
169
	unsigned bits = bs->bits ;
170
	if ( bits ) {
171
	    /* Add existing bits */
172
	    unsigned r = ( BYTE_SIZE - bits ) ;
173
	    unsigned long c = ( unsigned long ) text [ bytes ] ;
174
	    b |= ( ( c >> r ) << n ) ;
175
	    n += bits ;
176
	}
177
	bits = ( n % BYTE_SIZE ) ;
178
	if ( bits ) {
179
	    /* Zero pad to a whole number of bytes */
180
	    unsigned r = ( BYTE_SIZE - bits ) ;
181
	    b <<= r ;
182
	    n += r ;
183
	}
184
	do {
185
	    /* Output each byte */
186
	    if ( bytes >= CHUNK_SIZE ) {
187
		/* Start new chunk if necessary */
188
		bs = extend_bitstream ( bs ) ;
189
		text = bs->text ;
190
		bytes = 0 ;
191
	    }
192
	    n -= BYTE_SIZE ;
193
	    text [ bytes ] = ( character ) ( ( b >> n ) & BYTE_MASK ) ;
194
	    bytes++ ;
195
	} while ( n ) ;
196
	if ( bits ) bytes-- ;
197
	bs->bytes = bytes ;
198
	bs->bits = bits ;
199
    }
200
    return ( bs ) ;
201
}
202
 
203
 
204
/*
205
    ADD A LARGER NUMBER OF BITS TO A BITSTREAM
206
 
207
    This routine is identical to enc_bits except that it works for up to
208
    32 bits.
209
*/
210
 
211
BITSTREAM *enc_long_bits
212
    PROTO_N ( ( bs, n, d ) )
213
    PROTO_T ( BITSTREAM *bs X unsigned n X unsigned long d )
214
{
215
    if ( n > 16 ) {
216
	bs = enc_bits ( bs, n - 16, ( unsigned ) ( d >> 16 ) ) ;
217
	n = 16 ;
218
    }
219
    bs = enc_bits ( bs, n, ( unsigned ) d ) ;
220
    return ( bs ) ;
221
}
222
 
223
 
224
/*
225
    ADD A NUMBER OF BYTES TO A BITSTREAM
226
 
227
    This routine adds the n bytes given by s to the bitstream bs.
228
*/
229
 
230
BITSTREAM *enc_bytes
231
    PROTO_N ( ( bs, n, s ) )
232
    PROTO_T ( BITSTREAM *bs X unsigned long n X string s )
233
{
234
    if ( bs->bits ) {
235
	/* Unaligned bitstream */
236
	unsigned long i ;
237
	for ( i = 0 ; i < n ; i++ ) {
238
	    unsigned c = ( unsigned ) s [i] ;
239
	    bs = enc_bits ( bs, ( unsigned ) BYTE_SIZE, c ) ;
240
	}
241
    } else {
242
	/* Aligned bitstream */
243
	unsigned long i ;
244
	string text = bs->text ;
245
	unsigned bytes = bs->bytes ;
246
	for ( i = 0 ; i < n ; i++ ) {
247
	    if ( bytes >= CHUNK_SIZE ) {
248
		/* Start new chunk if necessary */
249
		bs = extend_bitstream ( bs ) ;
250
		text = bs->text ;
251
		bytes = 0 ;
252
	    }
253
	    text [ bytes ] = s [i] ;
254
	    bytes++ ;
255
	}
256
	bs->bytes = bytes ;
257
    }
258
    return ( bs ) ;
259
}
260
 
261
 
262
/*
263
    ADD A NUMBER OF ASCII CHARACTERS TO A BITSTREAM
264
 
265
    This routine adds the n ASCII characters given by s to the bitstream bs.
266
*/
267
 
268
BITSTREAM *enc_ascii
269
    PROTO_N ( ( bs, n, s ) )
270
    PROTO_T ( BITSTREAM *bs X unsigned long n X string s )
271
{
272
    if ( is_ascii ) {
273
	bs = enc_bytes ( bs, n, s ) ;
274
    } else {
275
	if ( bs->bits ) {
276
	    /* Unaligned bitstream */
277
	    unsigned long i ;
278
	    for ( i = 0 ; i < n ; i++ ) {
279
		int ch = CHAR_SIMPLE ;
280
		unsigned long c = ( unsigned long ) s [i] ;
281
		c = to_ascii ( c, &ch ) ;
282
		bs = enc_bits ( bs, ( unsigned ) BYTE_SIZE, ( unsigned ) c ) ;
283
	    }
284
	} else {
285
	    /* Aligned bitstream */
286
	    unsigned long i ;
287
	    string text = bs->text ;
288
	    unsigned bytes = bs->bytes ;
289
	    for ( i = 0 ; i < n ; i++ ) {
290
		int ch = CHAR_SIMPLE ;
291
		unsigned long c = ( unsigned long ) s [i] ;
292
		if ( bytes >= CHUNK_SIZE ) {
293
		    /* Start new chunk if necessary */
294
		    bs = extend_bitstream ( bs ) ;
295
		    text = bs->text ;
296
		    bytes = 0 ;
297
		}
298
		c = to_ascii ( c, &ch ) ;
299
		text [ bytes ] = ( unsigned char ) c ;
300
		bytes++ ;
301
	    }
302
	    bs->bytes = bytes ;
303
	}
304
    }
305
    return ( bs ) ;
306
}
307
 
308
 
309
/*
310
    COPY A BITSTREAM
311
 
312
    This routine copies a component of the bitstream bs to the end of
313
    the bitstream fs.
314
*/
315
 
316
static BITSTREAM *copy_bitstream
317
    PROTO_N ( ( fs, bs ) )
318
    PROTO_T ( BITSTREAM *fs X BITSTREAM *bs )
319
{
320
    string text = bs->text ;
321
    unsigned bits = bs->bits ;
322
    unsigned bytes = bs->bytes ;
323
    if ( bytes ) {
324
	/* Copy any bytes */
325
	fs = enc_bytes ( fs, ( unsigned long ) bytes, text ) ;
326
    }
327
    if ( bits ) {
328
	/* Copy any spare bits */
329
	unsigned c = ( unsigned ) text [ bytes ] ;
330
	c >>= ( BYTE_SIZE - bits ) ;
331
	fs = enc_bits ( fs, bits, c ) ;
332
    }
333
    return ( fs ) ;
334
}
335
 
336
 
337
/*
338
    JOIN TWO BITSTREAMS
339
 
340
    This routine adds the bitstream bs to the end of the bitstream fs.
341
    bs will not have an associated file.
342
*/
343
 
344
BITSTREAM *join_bitstreams
345
    PROTO_N ( ( fs, bs ) )
346
    PROTO_T ( BITSTREAM *fs X BITSTREAM *bs )
347
{
348
    FILE *f ;
349
    BITSTREAM *ps ;
350
    if ( bs == NULL ) return ( fs ) ;
351
    if ( fs == NULL ) return ( bs ) ;
352
    if ( fs->link == NULL ) fs->link = bs->link ;
353
 
354
    /* Copy bitstream to file */
355
    ps = bs->prev ;
356
    f = fs->file ;
357
    if ( f ) {
358
	if ( ps ) fs = join_bitstreams ( fs, ps ) ;
359
	if ( fs->bits == 0 && bs->bytes ) {
360
	    /* Dump any bytes to file */
361
	    bs->file = f ;
362
	    if ( fs->bytes ) dump_bitstream ( fs ) ;
363
	    dump_bitstream ( bs ) ;
364
	    bs->file = NULL ;
365
	}
366
	fs = copy_bitstream ( fs, bs ) ;
367
	if ( ps == NULL ) end_bitstream ( bs, 0 ) ;
368
	return ( fs ) ;
369
    }
370
 
371
    /* Copy small bitstreams */
372
    if ( ps == NULL && bs->bytes < CHUNK_COPY ) {
373
	fs = copy_bitstream ( fs, bs ) ;
374
	end_bitstream ( bs, 0 ) ;
375
	return ( fs ) ;
376
    }
377
 
378
    /* Link larger bitstreams */
379
    ps = bs ;
380
    while ( ps->prev ) ps = ps->prev ;
381
    ps->prev = fs ;
382
    return ( bs ) ;
383
}
384
 
385
 
386
/*
387
    FIND THE LENGTH OF A BITSTREAM
388
 
389
    This routine returns the length of the bitstream bs in bits.
390
*/
391
 
392
unsigned length_bitstream
393
    PROTO_N ( ( bs ) )
394
    PROTO_T ( BITSTREAM *bs )
395
{
396
    unsigned n = 0 ;
397
    while ( bs ) {
398
	n += ( BYTE_SIZE * bs->bytes + bs->bits ) ;
399
	bs = bs->prev ;
400
    }
401
    return ( n ) ;
402
}
403
 
404
 
405
/*
406
    ALIGN A BITSTREAM TO A BYTE BOUNDARY
407
 
408
    This routine aligns the bitstream bs so that it consists of a whole
409
    number of bytes.
410
*/
411
 
412
BITSTREAM *enc_boundary
413
    PROTO_N ( ( bs ) )
414
    PROTO_T ( BITSTREAM *bs )
415
{
416
    unsigned n = length_bitstream ( bs ) ;
417
    unsigned r = ( n % BYTE_SIZE ) ;
418
    if ( r ) {
419
	/* Add extra bits if necessary */
420
	bs = enc_bits ( bs, BYTE_SIZE - r, ( unsigned ) 0 ) ;
421
    }
422
    return ( bs ) ;
423
}
424
 
425
 
426
/*
427
    ADD AN EXTENDED BIT PATTERN TO A BITSTREAM
428
 
429
    This routine adds the bit pattern d to the bitstream bs using the
430
    extended encoding as n-bit packets.  Note that d cannot be zero.
431
*/
432
 
433
BITSTREAM *enc_extn
434
    PROTO_N ( ( bs, n, d ) )
435
    PROTO_T ( BITSTREAM *bs X unsigned n X unsigned d )
436
{
437
    unsigned e = ( ( unsigned ) 1 << n ) - 1 ;
438
    while ( d > e ) {
439
	/* Encode zero for each multiple of e */
440
	bs = enc_bits ( bs, n, ( unsigned ) 0 ) ;
441
	d -= e ;
442
    }
443
    /* Encode the remainder */
444
    bs = enc_bits ( bs, n, d ) ;
445
    return ( bs ) ;
446
}
447
 
448
 
449
/*
450
    ADD A SERIES OF OCTAL DIGITS TO A BITSTREAM
451
 
452
    This is an auxiliary routine used by enc_int.  It is identical
453
    except that the last digit is not marked.
454
*/
455
 
456
BITSTREAM *enc_int_aux
457
    PROTO_N ( ( bs, n ) )
458
    PROTO_T ( BITSTREAM *bs X unsigned long n )
459
{
460
    unsigned m ;
461
    if ( n >= 8 ) bs = enc_int_aux ( bs, n >> 3 ) ;
462
    m = ( unsigned ) ( n & 0x7 ) ;
463
    bs = enc_bits ( bs, ( unsigned ) 4, m ) ;
464
    return ( bs ) ;
465
}
466
 
467
 
468
/*
469
    ADD AN INTEGER TO A BITSTREAM
470
 
471
    This routine adds the integer n as a series of octal digits to the
472
    bitstream bs.  The last digit is marked by means of a set bit.
473
*/
474
 
475
BITSTREAM *enc_int
476
    PROTO_N ( ( bs, n ) )
477
    PROTO_T ( BITSTREAM *bs X unsigned long n )
478
{
479
    unsigned m ;
480
    if ( n >= 8 ) bs = enc_int_aux ( bs, n >> 3 ) ;
481
    m = ( unsigned ) ( ( n & 0x7 ) | 0x8 ) ;
482
    bs = enc_bits ( bs, ( unsigned ) 4, m ) ;
483
    return ( bs ) ;
484
}
485
 
486
 
487
/*
488
    ADD AN IDENTIFIER TO A BITSTREAM
489
 
490
    This routine adds the identifier string starting with s of length n
491
    to the bitstream bs.  This is encoded as two integers, giving the
492
    bits per character and the number of characters, followed by an
493
    alignment, followed by the characters comprising the identifier.
494
*/
495
 
496
BITSTREAM *enc_ident
497
    PROTO_N ( ( bs, s, n ) )
498
    PROTO_T ( BITSTREAM *bs X string s X unsigned long n )
499
{
500
    bs = enc_int ( bs, ( unsigned long ) BYTE_SIZE ) ;
501
    bs = enc_int ( bs, n ) ;
502
    bs = enc_boundary ( bs ) ;
503
    bs = enc_ascii ( bs, n, s ) ;
504
    return ( bs ) ;
505
}
506
 
507
 
508
/*
509
    ADD A STRING TO A BITSTREAM
510
 
511
    This routine adds the string s of length n to the bitstream bs.
512
*/
513
 
514
BITSTREAM *enc_tdfstring
515
    PROTO_N ( ( bs, n, s ) )
516
    PROTO_T ( BITSTREAM *bs X unsigned long n X string s )
517
{
518
    bs = enc_int ( bs, ( unsigned long ) BYTE_SIZE ) ;
519
    bs = enc_int ( bs, n ) ;
520
    bs = enc_ascii ( bs, n, s ) ;
521
    return ( bs ) ;
522
}
523
 
524
 
525
/*
526
    ADD A STRING TO A BITSTREAM
527
 
528
    This routine is identical to enc_tdfstring except that strlen is
529
    used to calculate the length of the string.
530
*/
531
 
532
BITSTREAM *enc_ustring
533
    PROTO_N ( ( bs, s ) )
534
    PROTO_T ( BITSTREAM *bs X string s )
535
{
536
    unsigned long n = ( unsigned long ) ustrlen ( s ) ;
537
    bs = enc_int ( bs, ( unsigned long ) BYTE_SIZE ) ;
538
    bs = enc_int ( bs, n ) ;
539
    bs = enc_ascii ( bs, n, s ) ;
540
    return ( bs ) ;
541
}
542
 
543
 
544
/*
545
    ADD A TDF BITSTREAM TO A BITSTREAM
546
 
547
    This routine adds the bitstream ps, preceded by its length, to the
548
    bitstream bs.
549
*/
550
 
551
BITSTREAM *enc_bitstream
552
    PROTO_N ( ( bs, ps ) )
553
    PROTO_T ( BITSTREAM *bs X BITSTREAM *ps )
554
{
555
    unsigned n = length_bitstream ( ps ) ;
556
    bs = enc_int ( bs, ( unsigned long ) n ) ;
557
    bs = join_bitstreams ( bs, ps ) ;
558
    return ( bs ) ;
559
}