1 /*
2  *  Bitstream decoder.
3  */
4 
5 #include "duk_internal.h"
6 
7 /* Decode 'bits' bits from the input stream (bits must be 1...24).
8  * When reading past bitstream end, zeroes are shifted in.  The result
9  * is signed to match duk_bd_decode_flagged.
10  */
duk_bd_decode(duk_bitdecoder_ctx * ctx,duk_small_int_t bits)11 DUK_INTERNAL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits) {
12 	duk_small_int_t shift;
13 	duk_uint32_t mask;
14 	duk_uint32_t tmp;
15 
16 	/* Note: cannot read more than 24 bits without possibly shifting top bits out.
17 	 * Fixable, but adds complexity.
18 	 */
19 	DUK_ASSERT(bits >= 1 && bits <= 24);
20 
21 	while (ctx->currbits < bits) {
22 #if 0
23 		DUK_DDD(DUK_DDDPRINT("decode_bits: shift more data (bits=%ld, currbits=%ld)",
24 		                     (long) bits, (long) ctx->currbits));
25 #endif
26 		ctx->currval <<= 8;
27 		if (ctx->offset < ctx->length) {
28 			/* If ctx->offset >= ctx->length, we "shift zeroes in"
29 			 * instead of croaking.
30 			 */
31 			ctx->currval |= ctx->data[ctx->offset++];
32 		}
33 		ctx->currbits += 8;
34 	}
35 #if 0
36 	DUK_DDD(DUK_DDDPRINT("decode_bits: bits=%ld, currbits=%ld, currval=0x%08lx",
37 	                     (long) bits, (long) ctx->currbits, (unsigned long) ctx->currval));
38 #endif
39 
40 	/* Extract 'top' bits of currval; note that the extracted bits do not need
41 	 * to be cleared, we just ignore them on next round.
42 	 */
43 	shift = ctx->currbits - bits;
44 	mask = (1 << bits) - 1;
45 	tmp = (ctx->currval >> shift) & mask;
46 	ctx->currbits = shift;  /* remaining */
47 
48 #if 0
49 	DUK_DDD(DUK_DDDPRINT("decode_bits: %ld bits -> 0x%08lx (%ld), currbits=%ld, currval=0x%08lx",
50 	                     (long) bits, (unsigned long) tmp, (long) tmp, (long) ctx->currbits, (unsigned long) ctx->currval));
51 #endif
52 
53 	return tmp;
54 }
55 
duk_bd_decode_flag(duk_bitdecoder_ctx * ctx)56 DUK_INTERNAL duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx) {
57 	return (duk_small_int_t) duk_bd_decode(ctx, 1);
58 }
59 
60 /* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return
61  * default value.  Return value is signed so that negative marker value can be
62  * used by caller as a "not present" value.
63  */
duk_bd_decode_flagged(duk_bitdecoder_ctx * ctx,duk_small_int_t bits,duk_int32_t def_value)64 DUK_INTERNAL duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) {
65 	if (duk_bd_decode_flag(ctx)) {
66 		return (duk_int32_t) duk_bd_decode(ctx, bits);
67 	} else {
68 		return def_value;
69 	}
70 }
71