How to read non-byte-aligned integers with Node.js?

I am trying to read a binary SWF file using Node.JS. As the specification mentions at the bottom of the 17th page, some integers are encoded using variable-length bit fields, and by definition most of them are not byte-aligned.

The problem is that Node.js's Buffer only provides functions for reading byte-aligned integers. So I tried to write a wrapper object that would read bit by bit. However, it seems really hacky. Below is the object prototype I wrote:

/*jslint node:true, bitwise:true */

'use strict';

var util = require('util');
var maxBits = 32;

function BitBuffer() {
    Buffer.apply(this, arguments);

    this.cursor = 0;
    this.bitCursor = 0;
}

util.inherits(BitBuffer, Buffer);
module.exports = BitBuffer;

function padBits(bits, length, bit) {
    var leftPad = '', repeatLength, i;

    bits = bits.toString(2);
    length = length || 8;
    bit = bit || '0';

    if (bits.length >= length) {
        return bits;
    } else {
        repeatLength = length - bits.length;

        for (i = 0; i < repeatLength; i += 1) {
            leftPad += bit;
        }

        return leftPad + bits;
    }
}

BitBuffer.prototype.move = function (bits) {
    var bytes = Math.floor((this.bitCursor + bits) / 8);

    this.bitCursor += bits;

    if (this.bitCursor > 8) {
        this.cursor += bytes;
        this.bitCursor -= bytes * 8;
    }

    if (this.cursor >= this.length) {
        this.rewind();
        return false;
    }

    return true;
};

BitBuffer.prototype.align = function () {
    if (this.bitCursor > 0) {
        this.bitCursor = 0;
        this.cursor += 1;
    }
};

BitBuffer.prototype.rewind = function () {
    this.cursor = this.bitCursor = 0;
};

BitBuffer.prototype.readBits = function (bits) {
    var bytes = Math.ceil((this.bitCursor + bits) / 8), result = 0,
        length, buffer, i;

    if (bits > maxBits) {
        throw new RangeError('Cannot read more than ' + maxBits + ' bits');
    }

    buffer = this.slice(this.cursor, this.cursor + bytes);
    result = padBits(buffer[0]).substr(this.bitCursor);
    length = buffer.length;

    for (i = 1; i < length; i += 1) {
        result += padBits(buffer[i]);
    }

    result = result.substr(0, bits);
    return (this.move(bits)) ? parseInt(result, 2) : false;
};

BitBuffer.prototype.readUB = BitBuffer.prototype.readBits;

BitBuffer.prototype.readSB = function (bits) {
    var readBits = this.readBits(bits),
        stringBits = readBits.toString(2);

    if (readBits === false) {
        return false;
    }

    // add automatically removed zeros
    if (stringBits.length < bits) {
        stringBits = padBits(stringBits, bits);
    }

    // negative, pad to 32 bits then invert bits
    if (stringBits[0] === '1') {
        return -~parseInt(padBits(stringBits, maxBits, '1'), 2) - 1;
    } else {
        return readBits;
    }
};

BitBuffer.prototype.readFB = function (bits) {
    var highBits, lowBits, result;

    if (bits < 17) {
        throw new RangeError('Should be at least 17 bits long');
    }

    highBits = this.readSB(bits - 16);
    lowBits = this.readUB(16);
    lowBits *= Math.pow(10, -lowBits.toString(10).length);

    return (highBits >= 0) ?
            highBits + lowBits : highBits - lowBits;
};

// wrap read functions
(function () {
    var nativeReadFunctions = {
        'readInt8': 8,
        'readInt16LE': 16,
        'readInt16BE': 16,
        'readInt32LE': 32,
        'readInt32BE': 32,
        'readUInt8': 8,
        'readUInt16LE': 16,
        'readUInt16BE': 16,
        'readUInt32LE': 32,
        'readUInt32BE': 32,
        'readDoubleLE': 64,
        'readDoubleBE': 64,
        'readFloatLE': 32,
        'readFloatBE': 32
    }, method;

    function wrapNativeRead(method, length) {
        return function (noAssert) {
            var cursor;

            this.align();
            cursor = this.cursor;
            this.move(length);

            return Buffer.prototype[method].call(
                this,
                this.cursor,
                noAssert
            );
        };
    }

    for (method in nativeReadFunctions) {
        if (nativeReadFunctions.hasOwnProperty(method)) {
            BitBuffer.prototype[method] =
                wrapNativeRead(method, nativeReadFunctions[method]);
        }
    }
}());

Is writing my own object the good way?

Beside your implementation is pretty good, you should understand that in your implementation this.buffer === this and you should change the following lines:

// inside BitBuffer prototype constructor

this.buffer = new Buffer(param1, param2);

// change to

Buffer.call(this, param1, param2); // The right way to call the super constructor

and

// inside BitBuffer.prototype.readBits

buffer = this.buffer.slice(this.cursor, this.cursor + bytes);

// change to

buffer = this.slice(this.cursor, this.cursor + bytes);