UNPKG

bit-buffer

Version:

Bit-level reads and writes for ArrayBuffers

629 lines (482 loc) 14.9 kB
var assert = require('assert'), BitView = require('./bit-buffer').BitView, BitStream = require('./bit-buffer').BitStream; suite('BitBuffer', function () { var array, bv, bsw, bsr; setup(function () { array = new ArrayBuffer(64); bv = new BitView(array); bsw = new BitStream(bv); // Test initializing straight from the array. bsr = new BitStream(array); }); test('Min / max signed 5 bits', function () { var signed_max = (1 << 4) - 1; bsw.writeBits(signed_max, 5); bsw.writeBits(-signed_max - 1, 5); assert(bsr.readBits(5, true) === signed_max); assert(bsr.readBits(5, true) === -signed_max - 1); }); test('Min / max unsigned 5 bits', function () { var unsigned_max = (1 << 5) - 1; bsw.writeBits(unsigned_max, 5); bsw.writeBits(-unsigned_max, 5); assert.equal(bsr.readBits(5), unsigned_max); assert.equal(bsr.readBits(5), 1); }); test('Min / max int8', function () { var signed_max = 0x7F; bsw.writeInt8(signed_max); bsw.writeInt8(-signed_max - 1); assert.equal(bsr.readInt8(), signed_max); assert.equal(bsr.readInt8(), -signed_max - 1); }); test('Min / max uint8', function () { var unsigned_max = 0xFF; bsw.writeUint8(unsigned_max); bsw.writeUint8(-unsigned_max); assert.equal(bsr.readUint8(), unsigned_max); assert.equal(bsr.readUint8(), 1); }); test('Min / max int16', function () { var signed_max = 0x7FFF; bsw.writeInt16(signed_max); bsw.writeInt16(-signed_max - 1); assert.equal(bsr.readInt16(), signed_max); assert.equal(bsr.readInt16(), -signed_max - 1); }); test('Min / max uint16', function () { var unsigned_max = 0xFFFF; bsw.writeUint16(unsigned_max); bsw.writeUint16(-unsigned_max); assert.equal(bsr.readUint16(), unsigned_max); assert.equal(bsr.readUint16(), 1); }); test('Min / max int32', function () { var signed_max = 0x7FFFFFFF; bsw.writeInt32(signed_max); bsw.writeInt32(-signed_max - 1); assert.equal(bsr.readInt32(), signed_max); assert.equal(bsr.readInt32(), -signed_max - 1); }); test('Min / max uint32', function () { var unsigned_max = 0xFFFFFFFF; bsw.writeUint32(unsigned_max); bsw.writeUint32(-unsigned_max); assert.equal(bsr.readUint32(), unsigned_max); assert.equal(bsr.readUint32(), 1); }); test('Unaligned reads', function () { bsw.writeBits(13, 5); bsw.writeUint8(0xFF); bsw.writeBits(14, 5); assert.equal(bsr.readBits(5), 13); assert.equal(bsr.readUint8(), 0xFF); assert.equal(bsr.readBits(5), 14); }); test('Min / max float32 (normal values)', function () { var scratch = new DataView(new ArrayBuffer(8)); scratch.setUint32(0, 0x00800000); scratch.setUint32(4, 0x7f7fffff); var min = scratch.getFloat32(0); var max = scratch.getFloat32(4); bsw.writeFloat32(min); bsw.writeFloat32(max); assert.equal(bsr.readFloat32(), min); assert.equal(bsr.readFloat32(), max); }); test('Min / max float64 (normal values)', function () { var scratch = new DataView(new ArrayBuffer(16)); scratch.setUint32(0, 0x00100000); scratch.setUint32(4, 0x00000000); scratch.setUint32(8, 0x7fefffff); scratch.setUint32(12, 0xffffffff); var min = scratch.getFloat64(0); var max = scratch.getFloat64(8); bsw.writeFloat64(min); bsw.writeFloat64(max); assert.equal(bsr.readFloat64(), min); assert.equal(bsr.readFloat64(), max); }); test('Overwrite previous value with 0', function () { bv.setUint8(0, 13); bv.setUint8(0, 0); assert.equal(bv.getUint8(0), 0); }); test('Read / write ASCII string, fixed length', function () { var str = 'foobar'; var len = 16; bsw.writeASCIIString(str, len); assert.equal(bsw.byteIndex, len); assert.equal(bsr.readASCIIString(len), str); assert.equal(bsr.byteIndex, len); }); test('Read / write ASCII string, unknown length', function () { var str = 'foobar'; bsw.writeASCIIString(str); assert.equal(bsw.byteIndex, str.length + 1); // +1 for 0x00 assert.equal(bsr.readASCIIString(), str); assert.equal(bsr.byteIndex, str.length + 1); }); test('Read ASCII string, 0 length', function () { var str = 'foobar'; bsw.writeASCIIString(str); assert.equal(bsw.byteIndex, str.length + 1); // +1 for 0x00 assert.equal(bsr.readASCIIString(0), ''); assert.equal(bsr.byteIndex, 0); }); test('Read overflow', function () { var exception = false; try { bsr.readASCIIString(128); } catch (e) { exception = true; } assert(exception); }); test('Write overflow', function () { var exception = false; try { bsw.writeASCIIString('foobar', 128); } catch (e) { exception = true; } assert(exception); }); test('Get boolean', function () { bv.setUint8(0, 1); assert(bv.getBoolean(0)); bv.setUint8(0, 0); assert(!bv.getBoolean(0)); }); test('Set boolean', function () { bv.setBoolean(0, true); assert(bv.getBoolean(0)); bv.setBoolean(0, false); assert(!bv.getBoolean(0)); }); test('Read boolean', function () { bv.setBits(0, 1, 1); bv.setBits(1, 0, 1); assert(bsr.readBoolean()); assert(!bsr.readBoolean()); }); test('Write boolean', function () { bsr.writeBoolean(true); assert.equal(bv.getBits(0, 1, false), 1); bsr.writeBoolean(false); assert.equal(bv.getBits(1, 1, false), 0); }); test('Read / write UTF8 string, only ASCII characters', function () { var str = 'foobar'; bsw.writeUTF8String(str); assert(bsw.byteIndex === str.length + 1); // +1 for 0x00 assert.equal(bsr.readUTF8String(), str); assert.equal(bsr.byteIndex, str.length + 1); }); test('Read / write UTF8 string, non ASCII characters', function () { var str = '日本語'; var bytes = [ 0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC, 0xE8, 0xAA, 0x9E ]; bsw.writeUTF8String(str); for (var i = 0; i < bytes.length; i++) { assert.equal(bytes[i], bv.getBits(i * 8, 8)); } assert.equal(bsw.byteIndex, bytes.length + 1); // +1 for 0x00 assert.equal(str, bsr.readUTF8String()); assert.equal(bsr.byteIndex, bytes.length + 1); }); test('readBitStream', function () { bsw.writeBits(0xF0, 8); //0b11110000 bsw.writeBits(0xF1, 8); //0b11110001 bsr.readBits(3); //offset var slice = bsr.readBitStream(8); assert.equal(slice.readBits(6), 0x3E); //0b111110 assert.equal(9, slice._index); assert.equal(6, slice.index); assert.equal(8, slice.length); assert.equal(2, slice.bitsLeft); assert.equal(bsr._index, 11); assert.equal((64 * 8) - 11, bsr.bitsLeft); }); test('readBitStream overflow', function () { bsw.writeBits(0xF0, 8); //0b11110000 bsw.writeBits(0xF1, 8); //0b11110001 bsr.readBits(3); //offset var slice = bsr.readBitStream(4); var exception = false; try { slice.readUint8(); } catch (e) { exception = true; } assert(exception); }); test('writeBitStream', function () { var buf = new ArrayBuffer(64); var sourceStream = new BitStream(buf); sourceStream.writeBits(0xF0, 8); //0b11110000 sourceStream.writeBits(0xF1, 8); //0b11110001 sourceStream.index = 0; sourceStream.readBits(3); //offset bsr.writeBitStream(sourceStream, 8); assert.equal(8, bsr.index); bsr.index = 0; assert.equal(bsr.readBits(6), 0x3E); //0b00111110 assert.equal(11, sourceStream.index); var bin = new Uint8Array(buf); assert.equal(bin[0], 0xF0); assert.equal(bin[1], 0xF1); }); test('writeBitStream Buffer', function () { var buf = Buffer.alloc(64); var sourceStream = new BitStream(buf); sourceStream.writeBits(0xF0, 8); //0b11110000 sourceStream.writeBits(0xF1, 8); //0b11110001 sourceStream.index = 0; sourceStream.readBits(3); //offset bsr.writeBitStream(sourceStream, 8); assert.equal(8, bsr.index); bsr.index = 0; assert.equal(bsr.readBits(6), 0x3E); //0b00111110 assert.equal(11, sourceStream.index); var bin = new Uint8Array(buf.buffer); assert.equal(bin[0], 0xF0); assert.equal(bin[1], 0xF1); }); test('writeBitStream long', function () { var sourceStream = new BitStream(new ArrayBuffer(64)); sourceStream.writeBits(0xF0, 8); sourceStream.writeBits(0xF1, 8); sourceStream.writeBits(0xF1, 8); sourceStream.writeBits(0xF1, 8); sourceStream.writeBits(0xF1, 8); sourceStream.index = 0; sourceStream.readBits(3); //offset bsr.index = 3; bsr.writeBitStream(sourceStream, 35); assert.equal(38, bsr.index); bsr.index = 3; assert.equal(bsr.readBits(35), 1044266558); assert.equal(38, sourceStream.index); }); test('readArrayBuffer', function () { bsw.writeBits(0xF0, 8); //0b11110000 bsw.writeBits(0xF1, 8); //0b11110001 bsw.writeBits(0xF0, 8); //0b11110000 bsr.readBits(3); //offset var buffer = bsr.readArrayBuffer(2); assert.equal(0x3E, buffer[0]); //0b00111110 assert.equal(0x1E, buffer[1]); //0b00011110 assert.equal(3 + (2 * 8), bsr._index); }); test('writeArrayBuffer', function () { var source = new Uint8Array(4); source[0] = 0xF0; source[1] = 0xF1; source[2] = 0xF1; bsr.readBits(3); //offset bsr.writeArrayBuffer(source.buffer, 2); assert.equal(19, bsr.index); bsr.index = 0; assert.equal(bsr.readBits(8), 128); }); test('Get buffer from view', function () { bv.setBits(0, 0xFFFFFFFF, 32); var buffer = bv.buffer; assert.equal(64, buffer.length); assert.equal(0xFFFF, buffer.readUInt16LE(0)); }); test('Get buffer from stream', function () { bsw.writeBits(0xFFFFFFFF, 32); var buffer = bsr.buffer; assert.equal(64, buffer.length); assert.equal(0xFFFF, buffer.readUInt16LE(0)); }); }); suite('Reading big/little endian', function () { var array, u8, bv, bsw, bsr; setup(function () { array = new ArrayBuffer(64); u8 = new Uint8Array(array); u8[0] = 0x01; u8[1] = 0x02; // Test initializing straight from the array. bsr = new BitStream(array); }); test('4b, little-endian', function () { assert.equal(bsr.index, 0, 'BitStream didn\'t init at offset 0'); var result = []; result.push(bsr.readBits(4)); result.push(bsr.readBits(4)); result.push(bsr.readBits(4)); result.push(bsr.readBits(4)); // 0000 0001 0000 0010 [01 02] // [#2] [#1] [#4] [#3] assert.deepEqual(result, [1, 0, 2, 0]); }); test('8b, little-endian', function () { assert.equal(bsr.index, 0, 'BitStream didn\'t init at offset 0'); var result = []; result.push(bsr.readBits(8)); result.push(bsr.readBits(8)); // 0000 0001 0000 0010 [01 02] // [ #1] [ #2] assert.deepEqual(result, [1, 2]); }); test('10b, little-endian', function () { assert.equal(bsr.index, 0, 'BitStream didn\'t init at offset 0'); var result = []; result.push(bsr.readBits(10)); // 0000 0001 0000 0010 [01 02] // ... #1] [ #2][#1... assert.deepEqual(result, [513]); }); test('16b, little-endian', function () { assert.equal(bsr.index, 0, 'BitStream didn\'t init at offset 0'); var result = []; result.push(bsr.readBits(16)); // 0000 0001 0000 0010 [01 02] // [ #1] assert.deepEqual(result, [0x201]); }); test('24b, little-endian', function () { u8[2] = 0x03; assert.equal(bsr.index, 0, 'BitStream didn\'t init at offset 0'); var result = []; result.push(bsr.readBits(24)); // 0000 0001 0000 0010 0000 0011 [01 02 03] // [ #1] assert.deepEqual(result, [0x30201]); }); test('4b, big-endian', function () { bsr.bigEndian = true; assert.equal(bsr.index, 0, 'BitStream didn\'t init at offset 0'); var result = []; result.push(bsr.readBits(4)); result.push(bsr.readBits(4)); result.push(bsr.readBits(4)); result.push(bsr.readBits(4)); // 0000 0001 0000 0010 [01 02] // [#1] [#2] [#3] [#4] assert.deepEqual(result, [0, 1, 0, 2]); }); test('8b, big-endian', function () { bsr.bigEndian = true; assert.equal(bsr.index, 0, 'BitStream didn\'t init at offset 0'); var result = []; result.push(bsr.readBits(8)); result.push(bsr.readBits(8)); // 0000 0001 0000 0010 [01 02] // [ #1] [ #2] assert.deepEqual(result, [1, 2]); }); test('10b, big-endian', function () { bsr.bigEndian = true; assert.equal(bsr.index, 0, 'BitStream didn\'t init at offset 0'); var result = []; result.push(bsr.readBits(10)); result.push(bsr.readBits(6)); // 0000 0001 0000 0010 [01 02] // [ #1][ #2] assert.deepEqual(result, [4, 2]); }); test('16b, big-endian', function () { bsr.bigEndian = true; assert.equal(bsr.index, 0, 'BitStream didn\'t init at offset 0'); var result = []; result.push(bsr.readBits(16)); // 0000 0001 0000 0010 [01 02] // [ #1] assert.deepEqual(result, [0x102]); }); test('24b, big-endian', function () { u8[2] = 0x03; bsr.bigEndian = true; assert.equal(bsr.index, 0, 'BitStream didn\'t init at offset 0'); var result = []; result.push(bsr.readBits(24)); // 0000 0001 0000 0010 0000 0011 [01 02 03] // [ #1] assert.deepEqual(result, [0x10203]); }); }); suite('Writing big/little endian', function () { var array, u8, bv, bsw, bsr; setup(function () { array = new ArrayBuffer(2); u8 = new Uint8Array(array); bv = new BitView(array); bsw = new BitStream(bv); }); test('4b, little-endian', function () { // 0000 0001 0000 0010 [01 02] // [#2] [#1] [#4] [#3] bsw.writeBits(1, 4); bsw.writeBits(0, 4); bsw.writeBits(2, 4); bsw.writeBits(0, 4); assert.deepEqual(u8, new Uint8Array([0x01, 0x02])); }); test('8b, little-endian', function () { // 0000 0001 0000 0010 [01 02] // [ #1] [ #2] bsw.writeBits(1, 8); bsw.writeBits(2, 8); assert.deepEqual(u8, new Uint8Array([0x01, 0x02])); }); test('10b, little-endian', function () { // 0000 0001 0000 0010 [01 02] // ... #1] [ #2][#1... bsw.writeBits(513, 10); assert.deepEqual(u8, new Uint8Array([0x01, 0x02])); }); test('16b, little-endian', function () { // 0000 0001 0000 0010 [01 02] // [ #1] bsw.writeBits(0x201, 16); assert.deepEqual(u8, new Uint8Array([0x01, 0x02])); }); test('4b, big-endian', function () { bsw.bigEndian = true; // 0000 0001 0000 0010 [01 02] // [#1] [#2] [#3] [#4] bsw.writeBits(0, 4); bsw.writeBits(1, 4); bsw.writeBits(0, 4); bsw.writeBits(2, 4); assert.deepEqual(u8, new Uint8Array([0x01, 0x02])); }); test('8b, big-endian', function () { bsw.bigEndian = true; // 0000 0001 0000 0010 [01 02] // [ #1] [ #2] bsw.writeBits(1, 8); bsw.writeBits(2, 8); assert.deepEqual(u8, new Uint8Array([0x01, 0x02])); }); test('10b, big-endian', function () { bsw.bigEndian = true; // 0000 0001 0000 0010 [01 02] // [ #1][ #2] bsw.writeBits(4, 10); bsw.writeBits(2, 6); assert.deepEqual(u8, new Uint8Array([0x01, 0x02])); }); test('16b, big-endian', function () { bsw.bigEndian = true; // 0000 0001 0000 0010 [01 02] // [ #1] bsw.writeBits(0x102, 16); assert.deepEqual(u8, new Uint8Array([0x01, 0x02])); }); });