]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | */ | |
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 | ||
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 | */ | |
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 | } |