Last active
February 4, 2016 17:20
-
-
Save copy/0f4669bc5636d698faa0 to your computer and use it in GitHub Desktop.
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
"use strict"; | |
// Format | |
// | |
// 000 1 bit integer | |
// 001 4 bit integer | |
// 002 8 bit integer | |
// 003 16 bit integer | |
// 004 32 bit integer | |
// 005 32 bit float | |
// 006 start of array | |
// 007 end of array | |
var TYPE_FLOAT = 5; | |
var TYPE_ARRAY_START = 6; | |
var TYPE_ARRAY_END = 7; | |
var USE_NODE_BUFFER = typeof Buffer !== "undefined" && !!Buffer.prototype.readInt32LE; | |
var NODE_BUFFER_NO_ASSERT = false; | |
var byson = {}; | |
typeof module === "undefined" || (module.exports = byson); | |
byson._float32 = new Float32Array(1); | |
byson._int32 = new Int32Array(byson._float32.buffer); | |
/** @constructor */ | |
byson.ParseError = function(message) | |
{ | |
this.name = "ParseError"; | |
this.message = message; | |
}; | |
byson.ParseError.prototype = Error.prototype; | |
byson.encode = function(data) | |
{ | |
//console.log("encode", data); | |
var state = { | |
data: [], | |
bit: 0, | |
}; | |
byson._encode(state, data); | |
if(USE_NODE_BUFFER) | |
{ | |
var b = new Buffer(state.data.length << 2); | |
for(var i = 0; i < state.data.length; i++) | |
{ | |
b.writeInt32LE(state.data[i], i << 2, NODE_BUFFER_NO_ASSERT); | |
} | |
return b; | |
} | |
else | |
{ | |
return new Int32Array(state.data).buffer; | |
} | |
}; | |
byson._encode = function(state, data) | |
{ | |
if(typeof data === "object") { | |
byson._encodeArray(state, data); | |
} | |
else if(typeof data === "number") { | |
byson._encodeNumber(state, data); | |
} | |
else { | |
byson._encodeBoolean(state, data); | |
} | |
}; | |
byson._encodeNumber = function(state, data) | |
{ | |
if((data | 0) === data) { | |
byson._encodeInt(state, data); | |
} | |
else { | |
byson._encodeFloat(state, data); | |
} | |
}; | |
byson._encodeBoolean = function(state, bool) | |
{ | |
byson._write(state, 4, bool << 3); | |
}; | |
byson._encodeFloat = function(state, number) | |
{ | |
byson._float32[0] = number; | |
byson._write(state, 3, TYPE_FLOAT); | |
byson._write(state, 32, byson._int32[0]); | |
}; | |
byson._encodeInt = function(state, number) | |
{ | |
if(number < 0) | |
{ | |
if(-8 <= number) { | |
byson._write(state, 3+4, 1 | (number & 0xF) << 3); | |
} | |
else if(-0x80 <= number) { | |
byson._write(state, 3+8, 2 | (number & 0xFF) << 3); | |
} | |
else if(-0x8000 <= number) { | |
byson._write(state, 3+16, 3 | (number & 0xFFFF) << 3); | |
} | |
else { | |
byson._write(state, 3, 4); | |
byson._write(state, 32, number); | |
} | |
} | |
else | |
{ | |
if(number < 2) { | |
byson._write(state, 3+1, number << 3); | |
} | |
else if(number < 8) { | |
byson._write(state, 3+4, 1 | number << 3); | |
} | |
else if(number < 0x80) { | |
byson._write(state, 3+8, 2 | number << 3); | |
} | |
else if(number < 0x8000) { | |
byson._write(state, 3+16, 3 | number << 3); | |
} | |
else { | |
byson._write(state, 3, 4); | |
byson._write(state, 32, number); | |
} | |
} | |
}; | |
byson._encodeArray = function(state, array) | |
{ | |
//console.assert(typeof array === "object" && | |
// typeof array.length === "number", "Got invalid object: " + array); | |
// array | |
byson._write(state, 3, TYPE_ARRAY_START); | |
//console.log("array ["); | |
for(var i = 0; i < array.length; i++) { | |
byson._encode(state, array[i]); | |
} | |
byson._write(state, 3, TYPE_ARRAY_END); | |
//console.log("]"); | |
}; | |
byson._write = function(state, len, value) { | |
var bit = state.bit; | |
//console.assert(len <= 32); | |
//console.assert(bit <= 32); | |
//console.log("write bit=" + bit + " len=" + len + " value=" + value); | |
if(bit === 0) { | |
state.data.push(value); | |
} | |
else { | |
var lastIndex = state.data.length - 1; | |
state.data[lastIndex] |= value << bit; | |
//console.log(state.data[lastIndex].toString(16)); | |
if((bit + len) > 32) { | |
state.data.push(value >>> -bit); | |
//console.log(state.data[lastIndex+1].toString(16)); | |
} | |
} | |
state.bit = bit + len & 31; | |
}; | |
byson.decode = function(data) | |
{ | |
//console.assert(data instanceof ArrayBuffer); | |
//console.assert((data.byteLength & 3) === 0); // may be changed later | |
//console.log(data, typeof data, data.constructor); | |
var state = { | |
data: USE_NODE_BUFFER ? data : new Int32Array(data), | |
byteLength: USE_NODE_BUFFER ? data.length : data.byteLength, | |
bit: 0, | |
}; | |
var decoded = byson._decode(state); | |
if(decoded === undefined) { | |
throw new byson.ParseError(); | |
} | |
//console.log("decode", decoded); | |
return decoded; | |
}; | |
/** @this {byson} */ | |
byson._decode = function(state) | |
{ | |
var id = this._read(state, 3); | |
//console.log("id:", id); | |
if(id === TYPE_FLOAT) { | |
return this._decodeFloat(state); | |
} | |
else if(id === TYPE_ARRAY_START) { | |
return this._decodeArray(state); | |
} | |
else if(id === TYPE_ARRAY_END) { | |
// end of array | |
return undefined; | |
} | |
else { | |
return this._decodeInt(id, state); | |
} | |
}; | |
byson._decodeFloat = function(state) | |
{ | |
var data = this._read(state, 32); | |
byson._int32[0] = data; | |
//console.log("float", byson._float32[0]); | |
return byson._float32[0]; | |
}; | |
byson._decodeArray = function(state) | |
{ | |
var result = []; | |
var lastBit = state.byteLength << 5; | |
//console.log("array ["); | |
while(true) { | |
var p = this._decode(state); | |
if(p === undefined) { | |
break; | |
} | |
if(state.bit >= lastBit) { | |
throw new byson.ParseError(); | |
} | |
result.push(p); | |
} | |
//console.log("]", result); | |
return result; | |
}; | |
byson._decodeInt = function(id, state) | |
{ | |
//console.assert(id !== undefined); | |
var result; | |
if(id === 0) { | |
result = this._read(state, 1); | |
} | |
else { | |
var len = 2 << id; | |
result = this._read(state, len) << -len >> -len; | |
} | |
//console.log("int type=" + type, result); | |
return result; | |
}; | |
byson._read = function(state, len) | |
{ | |
var offset = state.bit; | |
var bit = offset & 31; | |
var index = offset >>> 5; | |
var result; | |
if(bit === 0) | |
{ | |
result = byson._readInt32s(state.data, index); | |
} | |
else | |
{ | |
result = byson._readInt32s(state.data, index) >>> bit; | |
if((bit + len) > 32) { | |
result |= byson._readInt32s(state.data, index + 1) << -bit; | |
} | |
} | |
if(len !== 32) { | |
result &= (1 << len) - 1; | |
} | |
state.bit += len; | |
return result; | |
}; | |
if(USE_NODE_BUFFER) | |
{ | |
byson._readInt32s = function(data, offset) | |
{ | |
return data.readInt32LE(offset << 2, NODE_BUFFER_NO_ASSERT); | |
}; | |
} | |
else | |
{ | |
byson._readInt32s = function(data, offset) | |
{ | |
return data[offset]; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment