Subversion Repositories tendra.SVN

Rev

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

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