Skip to content

Instantly share code, notes, and snippets.

@tec27
Created January 30, 2012 07:29
Show Gist options
  • Save tec27/1703053 to your computer and use it in GitHub Desktop.
Save tec27/1703053 to your computer and use it in GitHub Desktop.
Nibbler - multi-byte non-byte-aligned reader for little endian files
// Nibbler - wrapper for Cursorize that allows for reading things that don't fall on even byte boundaries
// (individual bits, reading 5 bits from one byte and 3 bits from the next, etc.)
// Yes, this name is a reference to Futurama. And yes, like the character there, this will likely
// shit up your program with really valuable functionality!
var Nibbler = module.exports = function(curs) {
if(!(this instanceof Nibbler)) return new Nibbler(curs);
this.curs = curs;
this.shifted = 0;
};
var loBitMask = [ 0, 1, 3, 7, 15, 31, 63, 127, 255 ];
Nibbler.prototype._shift = function(cnt) {
if(this.shifted + cnt > 8) throw new RangeError('Not enough bits remaining.');
if(!this.shifted)
this.data = this.curs.read()[0];
var val = (this.data >> this.shifted) & loBitMask[cnt];
this.shifted = (this.shifted + cnt) % 8;
return val;
};
Nibbler.prototype.readBits = function(cnt) {
if(cnt <= 0) throw new RangeError('cnt must be > 0');
var numBytes = cnt >>> 3,
numBits = cnt % 8,
val;
if(this.shifted + cnt <= 8)
return [ this._shift(cnt) ];
if(this.shifted === 0) {
val = this.curs.read(numBytes);
if(numBits > 0) val.push(this._shift(numBits));
return val;
}
val = [];
var loMask = loBitMask[this.shifted],
hiMask = 0xFF ^ loMask,
hi = this.data & hiMask,
lo,
hiShift = 8 - this.shifted,
loShift = this.shifted;
while(numBytes > 0) {
this.data = this.curs.read()[0];
numBytes--;
lo = this.data & loMask;
val.push((hi >>> hiShift) | (lo << loShift));
hi = this.data & hiMask;
}
if(numBits == 0) return val;
if(this.shifted + numBits <= 8) {
val.push(this._shift(numBits));
return val;
}
hi = hi >>> hiShift;
this.data = this.curs.read()[0];
var bitsAfterBoundary = numBits - (8 - this.shifted);
lo = (this.data & loBitMask[bitsAfterBoundary]) << this.shifted;
val.push(hi | lo);
this.shifted = this.shifted + numBits - 8;
return val;
};
Nibbler.prototype.readBytes = function(cnt) {
return this.readBits(cnt << 3);
};
Nibbler.prototype.readCombo = function(nBytes, nBits) {
return this.readBits((nBytes << 3) + nBits);
};
Nibbler.prototype.readToBoundary = function() {
if(this.shifted === 0) return [];
var val = [ (this.data & (0xFF ^ loBitMask[this.shifted])) >>> this.shifted ];
this.shifted = 0;
return val;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment