[6a3a178] | 1 | // Copyright 2012 The Obvious Corporation.
|
---|
| 2 |
|
---|
| 3 | /*
|
---|
| 4 | * bits: Bitwise buffer utilities. The utilities here treat a buffer
|
---|
| 5 | * as a little-endian bigint, so the lowest-order bit is bit #0 of
|
---|
| 6 | * `buffer[0]`, and the highest-order bit is bit #7 of
|
---|
| 7 | * `buffer[buffer.length - 1]`.
|
---|
| 8 | */
|
---|
| 9 |
|
---|
| 10 | /*
|
---|
| 11 | * Modules used
|
---|
| 12 | */
|
---|
| 13 | "use strict";
|
---|
| 14 | /*
|
---|
| 15 | * Exported bindings
|
---|
| 16 | */
|
---|
| 17 |
|
---|
| 18 | /**
|
---|
| 19 | * Extracts the given number of bits from the buffer at the indicated
|
---|
| 20 | * index, returning a simple number as the result. If bits are requested
|
---|
| 21 | * that aren't covered by the buffer, the `defaultBit` is used as their
|
---|
| 22 | * value.
|
---|
| 23 | *
|
---|
| 24 | * The `bitLength` must be no more than 32. The `defaultBit` if not
|
---|
| 25 | * specified is taken to be `0`.
|
---|
| 26 | */
|
---|
| 27 |
|
---|
| 28 | export function extract(buffer, bitIndex, bitLength, defaultBit) {
|
---|
| 29 | if (bitLength < 0 || bitLength > 32) {
|
---|
| 30 | throw new Error("Bad value for bitLength.");
|
---|
| 31 | }
|
---|
| 32 |
|
---|
| 33 | if (defaultBit === undefined) {
|
---|
| 34 | defaultBit = 0;
|
---|
| 35 | } else if (defaultBit !== 0 && defaultBit !== 1) {
|
---|
| 36 | throw new Error("Bad value for defaultBit.");
|
---|
| 37 | }
|
---|
| 38 |
|
---|
| 39 | var defaultByte = defaultBit * 0xff;
|
---|
| 40 | var result = 0; // All starts are inclusive. The {endByte, endBit} pair is exclusive, but
|
---|
| 41 | // if endBit !== 0, then endByte is inclusive.
|
---|
| 42 |
|
---|
| 43 | var lastBit = bitIndex + bitLength;
|
---|
| 44 | var startByte = Math.floor(bitIndex / 8);
|
---|
| 45 | var startBit = bitIndex % 8;
|
---|
| 46 | var endByte = Math.floor(lastBit / 8);
|
---|
| 47 | var endBit = lastBit % 8;
|
---|
| 48 |
|
---|
| 49 | if (endBit !== 0) {
|
---|
| 50 | // `(1 << endBit) - 1` is the mask of all bits up to but not including
|
---|
| 51 | // the endBit.
|
---|
| 52 | result = get(endByte) & (1 << endBit) - 1;
|
---|
| 53 | }
|
---|
| 54 |
|
---|
| 55 | while (endByte > startByte) {
|
---|
| 56 | endByte--;
|
---|
| 57 | result = result << 8 | get(endByte);
|
---|
| 58 | }
|
---|
| 59 |
|
---|
| 60 | result >>>= startBit;
|
---|
| 61 | return result;
|
---|
| 62 |
|
---|
| 63 | function get(index) {
|
---|
| 64 | var result = buffer[index];
|
---|
| 65 | return result === undefined ? defaultByte : result;
|
---|
| 66 | }
|
---|
| 67 | }
|
---|
| 68 | /**
|
---|
| 69 | * Injects the given bits into the given buffer at the given index. Any
|
---|
| 70 | * bits in the value beyond the length to set are ignored.
|
---|
| 71 | */
|
---|
| 72 |
|
---|
| 73 | export function inject(buffer, bitIndex, bitLength, value) {
|
---|
| 74 | if (bitLength < 0 || bitLength > 32) {
|
---|
| 75 | throw new Error("Bad value for bitLength.");
|
---|
| 76 | }
|
---|
| 77 |
|
---|
| 78 | var lastByte = Math.floor((bitIndex + bitLength - 1) / 8);
|
---|
| 79 |
|
---|
| 80 | if (bitIndex < 0 || lastByte >= buffer.length) {
|
---|
| 81 | throw new Error("Index out of range.");
|
---|
| 82 | } // Just keeping it simple, until / unless profiling shows that this
|
---|
| 83 | // is a problem.
|
---|
| 84 |
|
---|
| 85 |
|
---|
| 86 | var atByte = Math.floor(bitIndex / 8);
|
---|
| 87 | var atBit = bitIndex % 8;
|
---|
| 88 |
|
---|
| 89 | while (bitLength > 0) {
|
---|
| 90 | if (value & 1) {
|
---|
| 91 | buffer[atByte] |= 1 << atBit;
|
---|
| 92 | } else {
|
---|
| 93 | buffer[atByte] &= ~(1 << atBit);
|
---|
| 94 | }
|
---|
| 95 |
|
---|
| 96 | value >>= 1;
|
---|
| 97 | bitLength--;
|
---|
| 98 | atBit = (atBit + 1) % 8;
|
---|
| 99 |
|
---|
| 100 | if (atBit === 0) {
|
---|
| 101 | atByte++;
|
---|
| 102 | }
|
---|
| 103 | }
|
---|
| 104 | }
|
---|
| 105 | /**
|
---|
| 106 | * Gets the sign bit of the given buffer.
|
---|
| 107 | */
|
---|
| 108 |
|
---|
| 109 | export function getSign(buffer) {
|
---|
| 110 | return buffer[buffer.length - 1] >>> 7;
|
---|
| 111 | }
|
---|
| 112 | /**
|
---|
| 113 | * Gets the zero-based bit number of the highest-order bit with the
|
---|
| 114 | * given value in the given buffer.
|
---|
| 115 | *
|
---|
| 116 | * If the buffer consists entirely of the other bit value, then this returns
|
---|
| 117 | * `-1`.
|
---|
| 118 | */
|
---|
| 119 |
|
---|
| 120 | export function highOrder(bit, buffer) {
|
---|
| 121 | var length = buffer.length;
|
---|
| 122 | var fullyWrongByte = (bit ^ 1) * 0xff; // the other-bit extended to a full byte
|
---|
| 123 |
|
---|
| 124 | while (length > 0 && buffer[length - 1] === fullyWrongByte) {
|
---|
| 125 | length--;
|
---|
| 126 | }
|
---|
| 127 |
|
---|
| 128 | if (length === 0) {
|
---|
| 129 | // Degenerate case. The buffer consists entirely of ~bit.
|
---|
| 130 | return -1;
|
---|
| 131 | }
|
---|
| 132 |
|
---|
| 133 | var byteToCheck = buffer[length - 1];
|
---|
| 134 | var result = length * 8 - 1;
|
---|
| 135 |
|
---|
| 136 | for (var i = 7; i > 0; i--) {
|
---|
| 137 | if ((byteToCheck >> i & 1) === bit) {
|
---|
| 138 | break;
|
---|
| 139 | }
|
---|
| 140 |
|
---|
| 141 | result--;
|
---|
| 142 | }
|
---|
| 143 |
|
---|
| 144 | return result;
|
---|
| 145 | } |
---|