[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 | Object.defineProperty(exports, "__esModule", {
|
---|
| 29 | value: true
|
---|
| 30 | });
|
---|
| 31 | exports.extract = extract;
|
---|
| 32 | exports.inject = inject;
|
---|
| 33 | exports.getSign = getSign;
|
---|
| 34 | exports.highOrder = highOrder;
|
---|
| 35 |
|
---|
| 36 | function extract(buffer, bitIndex, bitLength, defaultBit) {
|
---|
| 37 | if (bitLength < 0 || bitLength > 32) {
|
---|
| 38 | throw new Error("Bad value for bitLength.");
|
---|
| 39 | }
|
---|
| 40 |
|
---|
| 41 | if (defaultBit === undefined) {
|
---|
| 42 | defaultBit = 0;
|
---|
| 43 | } else if (defaultBit !== 0 && defaultBit !== 1) {
|
---|
| 44 | throw new Error("Bad value for defaultBit.");
|
---|
| 45 | }
|
---|
| 46 |
|
---|
| 47 | var defaultByte = defaultBit * 0xff;
|
---|
| 48 | var result = 0; // All starts are inclusive. The {endByte, endBit} pair is exclusive, but
|
---|
| 49 | // if endBit !== 0, then endByte is inclusive.
|
---|
| 50 |
|
---|
| 51 | var lastBit = bitIndex + bitLength;
|
---|
| 52 | var startByte = Math.floor(bitIndex / 8);
|
---|
| 53 | var startBit = bitIndex % 8;
|
---|
| 54 | var endByte = Math.floor(lastBit / 8);
|
---|
| 55 | var endBit = lastBit % 8;
|
---|
| 56 |
|
---|
| 57 | if (endBit !== 0) {
|
---|
| 58 | // `(1 << endBit) - 1` is the mask of all bits up to but not including
|
---|
| 59 | // the endBit.
|
---|
| 60 | result = get(endByte) & (1 << endBit) - 1;
|
---|
| 61 | }
|
---|
| 62 |
|
---|
| 63 | while (endByte > startByte) {
|
---|
| 64 | endByte--;
|
---|
| 65 | result = result << 8 | get(endByte);
|
---|
| 66 | }
|
---|
| 67 |
|
---|
| 68 | result >>>= startBit;
|
---|
| 69 | return result;
|
---|
| 70 |
|
---|
| 71 | function get(index) {
|
---|
| 72 | var result = buffer[index];
|
---|
| 73 | return result === undefined ? defaultByte : result;
|
---|
| 74 | }
|
---|
| 75 | }
|
---|
| 76 | /**
|
---|
| 77 | * Injects the given bits into the given buffer at the given index. Any
|
---|
| 78 | * bits in the value beyond the length to set are ignored.
|
---|
| 79 | */
|
---|
| 80 |
|
---|
| 81 |
|
---|
| 82 | function inject(buffer, bitIndex, bitLength, value) {
|
---|
| 83 | if (bitLength < 0 || bitLength > 32) {
|
---|
| 84 | throw new Error("Bad value for bitLength.");
|
---|
| 85 | }
|
---|
| 86 |
|
---|
| 87 | var lastByte = Math.floor((bitIndex + bitLength - 1) / 8);
|
---|
| 88 |
|
---|
| 89 | if (bitIndex < 0 || lastByte >= buffer.length) {
|
---|
| 90 | throw new Error("Index out of range.");
|
---|
| 91 | } // Just keeping it simple, until / unless profiling shows that this
|
---|
| 92 | // is a problem.
|
---|
| 93 |
|
---|
| 94 |
|
---|
| 95 | var atByte = Math.floor(bitIndex / 8);
|
---|
| 96 | var atBit = bitIndex % 8;
|
---|
| 97 |
|
---|
| 98 | while (bitLength > 0) {
|
---|
| 99 | if (value & 1) {
|
---|
| 100 | buffer[atByte] |= 1 << atBit;
|
---|
| 101 | } else {
|
---|
| 102 | buffer[atByte] &= ~(1 << atBit);
|
---|
| 103 | }
|
---|
| 104 |
|
---|
| 105 | value >>= 1;
|
---|
| 106 | bitLength--;
|
---|
| 107 | atBit = (atBit + 1) % 8;
|
---|
| 108 |
|
---|
| 109 | if (atBit === 0) {
|
---|
| 110 | atByte++;
|
---|
| 111 | }
|
---|
| 112 | }
|
---|
| 113 | }
|
---|
| 114 | /**
|
---|
| 115 | * Gets the sign bit of the given buffer.
|
---|
| 116 | */
|
---|
| 117 |
|
---|
| 118 |
|
---|
| 119 | function getSign(buffer) {
|
---|
| 120 | return buffer[buffer.length - 1] >>> 7;
|
---|
| 121 | }
|
---|
| 122 | /**
|
---|
| 123 | * Gets the zero-based bit number of the highest-order bit with the
|
---|
| 124 | * given value in the given buffer.
|
---|
| 125 | *
|
---|
| 126 | * If the buffer consists entirely of the other bit value, then this returns
|
---|
| 127 | * `-1`.
|
---|
| 128 | */
|
---|
| 129 |
|
---|
| 130 |
|
---|
| 131 | function highOrder(bit, buffer) {
|
---|
| 132 | var length = buffer.length;
|
---|
| 133 | var fullyWrongByte = (bit ^ 1) * 0xff; // the other-bit extended to a full byte
|
---|
| 134 |
|
---|
| 135 | while (length > 0 && buffer[length - 1] === fullyWrongByte) {
|
---|
| 136 | length--;
|
---|
| 137 | }
|
---|
| 138 |
|
---|
| 139 | if (length === 0) {
|
---|
| 140 | // Degenerate case. The buffer consists entirely of ~bit.
|
---|
| 141 | return -1;
|
---|
| 142 | }
|
---|
| 143 |
|
---|
| 144 | var byteToCheck = buffer[length - 1];
|
---|
| 145 | var result = length * 8 - 1;
|
---|
| 146 |
|
---|
| 147 | for (var i = 7; i > 0; i--) {
|
---|
| 148 | if ((byteToCheck >> i & 1) === bit) {
|
---|
| 149 | break;
|
---|
| 150 | }
|
---|
| 151 |
|
---|
| 152 | result--;
|
---|
| 153 | }
|
---|
| 154 |
|
---|
| 155 | return result;
|
---|
| 156 | } |
---|