Created
August 14, 2012 07:40
-
-
Save Jxck/3347255 to your computer and use it in GitHub Desktop.
binary parse for spdy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var log = console.log.bind(console); | |
function choiceReadLength(length) { | |
if (length <= 8) return 8; | |
if (length <= 16) return 16; | |
if (length <= 32) return 32; | |
throw new Error('too large length'); | |
} | |
function choiceReadMethod(readLength) { | |
var flg = ~[8, 16, 32].indexOf(readLength) | |
if(!flg) { | |
throw new Error('length should be 8 or 16 or 32'); | |
} | |
if (readLength != 8) readLength += 'BE'; | |
return 'readUInt' + readLength; | |
} | |
function generateBinStr(length) { | |
if(length < 0) { | |
throw new Error('length should be grater than 0'); | |
} | |
return (new Array(length + 1)) | |
.slice() | |
.join('1'); | |
} | |
function binStr2hexStr(bin) { | |
return eval('0x' + parseInt(bin, 2).toString(16)); | |
} | |
function parse(buf, pos) { | |
var ans = {}; | |
for (var i in pos) { | |
var p = pos[i]; | |
var start = p[0]; | |
var length = p[1]; | |
var offset = Math.floor(start / 8); | |
var readLength = choiceReadLength(length); | |
var method = choiceReadMethod(readLength); | |
var mask = start - offset * 8; | |
var shift = readLength - mask - length; | |
//log(i, p, offset, readLength, mask, shift); | |
var temp = buf[method](offset); | |
var maskLength = readLength; | |
if (mask) { | |
maskLength -= mask; | |
} | |
var bin = generateBinStr(maskLength); | |
var hex = binStr2hexStr(bin); | |
temp = temp & hex; | |
if (shift) { | |
temp = temp >>> shift; | |
} | |
ans[i] = temp; | |
} | |
return ans; | |
} | |
function padding(buf, length) { | |
var str = buf.toString(2); | |
while (str.length < 8) { | |
str = '0' + str; | |
} | |
return str; | |
} | |
function showbuffer(buffers) { | |
for (i = 0; i < buffers.length; i++) { | |
log(padding(buffers[i], 8) | |
, buffers.readUInt8(i)); | |
} | |
} | |
exports.choiceReadLength = choiceReadLength; | |
exports.choiceReadMethod = choiceReadMethod; | |
exports.generateBinStr = generateBinStr; | |
exports.binStr2hexStr = binStr2hexStr; | |
exports.parse = parse; | |
exports.showbuffer = showbuffer; | |
exports.padding = padding; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var log = console.log.bind(console); | |
var binparser = require('./binparser') | |
, assert = require('assert') | |
; | |
var parse = binparser.parse | |
, showbuf = binparser.showbuffer | |
, hex = binparser.binStr2hexStr | |
; | |
function case1() { | |
log('case1'); | |
/* protocol | |
01234567 01234567 01234567 01234567 | |
abcd---- e------- f--g---- -------- | |
h------- -i------ ----j--- -------- | |
k------- -------- -------- -------- | |
*/ | |
/* ex | |
11100111 00000011 10100001 10000111 | |
00000001 00001000 00000000 11110100 | |
00000000 00000000 00000000 00010101 | |
a = 1, b = 1, c = 1, d = 7, e = 3 | |
f = 5, g = 391, h = 2, i = 128 | |
j = 244, k = 21 | |
*/ | |
var pos = { | |
a: [0, 1] | |
, b: [1, 1] | |
, c: [2, 1] | |
, d: [3, 5] | |
, e: [8, 8] | |
, f: [16, 3] | |
, g: [19, 13] | |
, h: [32, 9] | |
, i: [41, 11] | |
, j: [52, 12] | |
, k: [64, 32] | |
}; | |
var buf = new Buffer(12); | |
buf.writeUInt8(hex('11100111'), 0); | |
buf.writeUInt8(hex('00000011'), 1); | |
buf.writeUInt8(hex('10100001'), 2); | |
buf.writeUInt8(hex('10000111'), 3); | |
buf.writeUInt8(hex('00000001'), 4); | |
buf.writeUInt8(hex('00001000'), 5); | |
buf.writeUInt8(hex('00000000'), 6); | |
buf.writeUInt8(hex('11110100'), 7); | |
buf.writeUInt8(hex('00000000'), 8); | |
buf.writeUInt8(hex('00000000'), 9); | |
buf.writeUInt8(hex('00000000'), 10); | |
buf.writeUInt8(hex('00010101'), 11); | |
var actual = parse(buf, pos); | |
// a: [0, 1] | |
// offset 0/8 => 0 | |
// length 1 => readInt8 | |
// 0-0 = 0 => 0xff | |
// 8-0-1 = 7 => >>> 7 | |
var a = (buf.readUInt8(0) & 0xff) >>> 7; | |
assert.equal(actual['a'], a); | |
// b: [1, 1] | |
// offset 1/8 => 0 | |
// length 1 => readInt8 | |
// 1-0*8 = 1 => '01111111' 0x7f | |
// 8-1-1 = 6 => >>> 6 | |
var b = (buf.readUInt8(0) & 0x7f) >>> 6; | |
assert.equal(actual['b'], b); | |
// c: [2, 1] | |
// offset 2/8 => 0 | |
// length 1 => readInt8 | |
// 2-0*8 = 2 => '00111111' 0x3f | |
// 8-2-1 = 5 => >>> 5 | |
var c = (buf.readUInt8(0) & 0x3f) >>> 5; | |
assert.equal(actual['c'], c); | |
// d: [3, 5] | |
// offset 3/8 => 0 | |
// length 1 => readInt8 | |
// 3-0*8 = 3 => '00011111' 0x1f | |
// 8-3-5 = 0 => none | |
var d = (buf.readUInt8(0) & 0x1f); | |
assert.equal(actual['d'], d); | |
// e: [8, 8] | |
// offset 8/8 => 1 | |
// length 8 => readInt8 | |
// 8-1*8 = 0 => none | |
// 8-0-8 = 0 => none | |
var e = buf.readUInt8(1); | |
assert.equal(actual['e'], e); | |
// f: [16, 3] | |
// offset 16/8 => 2 | |
// length 3 => readInt8 | |
// 16-2*8 = 0 => 0xff | |
// 8-0-3 = 5 => >>> 5 | |
var f = (buf.readInt8(2) & 0xff) >>> 5; | |
assert.equal(actual['f'], f); | |
// g: [19, 13] | |
// offset 19/8 => 2 | |
// length 13 => readInt16BE | |
// 19-2*8 = 3 => '0001111111111111' 0x1fff | |
// 16-3-13 = 0 => none | |
var g = (buf.readInt16BE(2) & 0x1fff); | |
assert.equal(actual['g'], g); | |
// h: [32, 9] | |
// offset 32/8 => 4 | |
// length 9 => readInt16BE | |
// 32-4*8 = 0 => 0xffff | |
// 16-0-9 = 7 => >>> 7 | |
var h = (buf.readInt16BE(4) & 0xffff) >>> 7; | |
assert.equal(actual['h'], h); | |
// i: [41, 11] | |
// pos 41 は 41/8 = 5 なので、offset 5 を読む | |
// length 11 を読むので readInt16BE で足りる | |
// offset 5 は 5*8=40 から始まるので | |
// 41 から読んだら前の 41-40=1 ついらない | |
// 16-1=15 '111111111111111' => 0x7fff | |
// 11 しか読まないので 上の残り 後の 15-11=4 つがいらない | |
// >>> 5 | |
var i = (buf.readInt16BE(5) & 0x7fff) >>> 4; | |
assert.equal(actual['i'], i); | |
// j: [52, 12] | |
// pos 52 は 52/8 = 6 なので、offset 6 を読む | |
// length 12 を読むので readInt16BE で足りる | |
// offset 6 は 6*8=48 から始まるので | |
// 52 から読んだら前の 52-48=4 ついらない | |
// 16-4=12 '111111111111' => 0xfff | |
// 12 しか読まないので 上の残り 後の 16-4-12=0 つがいらない | |
// >>> 0 | |
var j = buf.readUInt16BE(6) & 0xfff; | |
assert.equal(actual['j'], j); | |
// k: [64, 32] | |
// offset 64/8 => 8 | |
// length 32 => readInt32BE | |
// 64-8*8 = 0 => 0xffff | |
// 32-32-0 = 0 => none | |
var k = buf.readInt32BE(8) & 0xffff; | |
assert.equal(actual['k'], k); | |
} | |
function case2() { | |
log('case2'); | |
/* protocol | |
01234567 01234567 01234567 01234567 | |
ab------ -------- c------- -------- | |
d------- e------- -------- -------- | |
f------- -------- -------- -------- | |
*/ | |
/* ex | |
10000000 00000011 00000000 00000001 | |
00000001 00000000 00000000 11110100 | |
00000000 00000000 00000000 00000000 | |
a = 1, b = 3, c = 1, d = 1, e = 244 | |
f = 0 | |
*/ | |
var pos = { | |
a: [0, 1] | |
, b: [1, 15] | |
, c: [16, 16] | |
, d: [32, 8] | |
, e: [40, 24] | |
, f: [64, 32] | |
}; | |
var buf = new Buffer(12); | |
buf.writeUInt8(0x80, 0); | |
buf.writeUInt8(0x3, 1); | |
buf.writeUInt8(0, 2); | |
buf.writeUInt8(0x1, 3); | |
buf.writeUInt8(0x1, 4); | |
buf.writeUInt8(0, 5); | |
buf.writeUInt8(0, 6); | |
buf.writeUInt8(0xf4, 7); | |
buf.writeUInt8(0, 8); | |
buf.writeUInt8(0, 9); | |
buf.writeUInt8(0, 10); | |
buf.writeUInt8(0, 11); | |
var actual = parse(buf, pos); | |
assert.equal(actual['a'], 1); | |
assert.equal(actual['b'], 3); | |
assert.equal(actual['c'], 1); | |
assert.equal(actual['d'], 1); | |
assert.equal(actual['e'], 244); | |
assert.equal(actual['f'], 0); | |
} | |
function utiltest() { | |
log('choiceReadLength'); | |
var rl = binparser.choiceReadLength; | |
assert.equal(rl(0), 8); | |
assert.equal(rl(1), 8); | |
assert.equal(rl(8), 8); | |
assert.equal(rl(16), 16); | |
assert.equal(rl(17), 32); | |
assert.equal(rl(32), 32); | |
assert.throws( | |
function() { rl(33); }, | |
/too large length/ | |
); | |
log('choiceReadMethod'); | |
var rm = binparser.choiceReadMethod; | |
assert.equal(rm(8), 'readUInt8'); | |
assert.equal(rm(16), 'readUInt16BE'); | |
assert.equal(rm(32), 'readUInt32BE'); | |
assert.throws( | |
function() { rm(33); }, | |
/length should be 8 or 16 or 32/ | |
); | |
log('generateBinStr'); | |
var gbs = binparser.generateBinStr; | |
assert.equal(gbs(0), ''); | |
assert.equal(gbs(1), '1'); | |
assert.equal(gbs(10), '1111111111'); | |
assert.throws( | |
function() { gbs(-1); }, | |
/length should be grater than 0/ | |
); | |
log('binStr2bexStr'); | |
var b2h = binparser.binStr2hexStr; | |
assert.equal(b2h('0'), 0x0); | |
assert.equal(b2h('1'), 0x1); | |
assert.equal(b2h('101'), 0x5); | |
assert.equal(b2h('001'), 0x1); | |
assert.equal(b2h('110010001'), 0x191); | |
} | |
(function() { | |
case1(); | |
case2(); | |
utiltest(); | |
log('done'); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment