Last active
September 1, 2015 17:50
-
-
Save fabiomcosta/1fc1304707f8b1d6323c 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
/*!{id:msgpack.js,ver:1.05,license:"MIT",author:"[email protected]"}*/ | |
// === msgpack === | |
// MessagePack -> http://msgpack.sourceforge.net/ | |
this.msgpack || (function(globalScope) { | |
globalScope.msgpack = { | |
pack: msgpackpack, // msgpack.pack(data:Mix, | |
// toString:Boolean = false):ByteArray/ByteString/false | |
// [1][mix to String] msgpack.pack({}, true) -> "..." | |
// [2][mix to ByteArray] msgpack.pack({}) -> [...]}; | |
}; | |
var _num2bin = {}, // NumberToBinaryString { 0: "\00", ... 255: "\ff" } | |
_error = 0, // msgpack.pack() error code. 1 = CYCLIC_REFERENCE_ERROR | |
_isArray = Array.isArray || (function(mix) { | |
return Object.prototype.toString.call(mix) === "[object Array]"; | |
}), | |
_isUint8Array = function(mix) { | |
return Object.prototype.toString.call(mix) === "[object Uint8Array]"; | |
}, | |
_toString = String.fromCharCode, // CharCode/ByteArray to String | |
_MAX_DEPTH = 512; | |
// msgpack.pack | |
function msgpackpack(data, // @param Mix: | |
toString) { // @param Boolean(= false): | |
// @return ByteArray/BinaryString/false: | |
// false is error return | |
// [1][mix to String] msgpack.pack({}, true) -> "..." | |
// [2][mix to ByteArray] msgpack.pack({}) -> [...] | |
_error = 0; | |
var byteArray = encode([], data, 0); | |
return _error ? false | |
: toString ? byteArrayToByteString(byteArray) | |
: byteArray; | |
} | |
// inner - encoder | |
function encode(rv, // @param ByteArray: result | |
mix, // @param Mix: source data | |
depth) { // @param Number: depth | |
var size, i, iz, c, pos, // for UTF8.encode, Array.encode, Hash.encode | |
high, low, sign, exp, frac; // for IEEE754 | |
if (mix == null) { // null or undefined -> 0xc0 ( null ) | |
rv.push(0xc0); | |
} else if (mix === false) { // false -> 0xc2 ( false ) | |
rv.push(0xc2); | |
} else if (mix === true) { // true -> 0xc3 ( true ) | |
rv.push(0xc3); | |
} else { | |
switch (typeof mix) { | |
case "number": | |
if (mix !== mix) { // isNaN | |
rv.push(0xcb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); // quiet NaN | |
} else if (mix === Infinity) { | |
rv.push(0xcb, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); // positive infinity | |
} else if (Math.floor(mix) === mix) { // int or uint | |
if (mix < 0) { | |
// int | |
if (mix >= -32) { // negative fixnum | |
rv.push(0xe0 + mix + 32); | |
} else if (mix > -0x80) { | |
rv.push(0xd0, mix + 0x100); | |
} else if (mix > -0x8000) { | |
mix += 0x10000; | |
rv.push(0xd1, mix >> 8, mix & 0xff); | |
} else if (mix > -0x80000000) { | |
mix += 0x100000000; | |
rv.push(0xd2, mix >>> 24, (mix >> 16) & 0xff, | |
(mix >> 8) & 0xff, mix & 0xff); | |
} else { | |
high = Math.floor(mix / 0x100000000); | |
low = mix & 0xffffffff; | |
rv.push(0xd3, (high >> 24) & 0xff, (high >> 16) & 0xff, | |
(high >> 8) & 0xff, high & 0xff, | |
(low >> 24) & 0xff, (low >> 16) & 0xff, | |
(low >> 8) & 0xff, low & 0xff); | |
} | |
} else { | |
// uint | |
if (mix < 0x80) { | |
rv.push(mix); // positive fixnum | |
} else if (mix < 0x100) { // uint 8 | |
rv.push(0xcc, mix); | |
} else if (mix < 0x10000) { // uint 16 | |
rv.push(0xcd, mix >> 8, mix & 0xff); | |
} else if (mix < 0x100000000) { // uint 32 | |
rv.push(0xce, mix >>> 24, (mix >> 16) & 0xff, | |
(mix >> 8) & 0xff, mix & 0xff); | |
} else { | |
high = Math.floor(mix / 0x100000000); | |
low = mix & 0xffffffff; | |
rv.push(0xcf, (high >> 24) & 0xff, (high >> 16) & 0xff, | |
(high >> 8) & 0xff, high & 0xff, | |
(low >> 24) & 0xff, (low >> 16) & 0xff, | |
(low >> 8) & 0xff, low & 0xff); | |
} | |
} | |
} else { // double | |
// THX!! @edvakf | |
// http://javascript.g.hatena.ne.jp/edvakf/20101128/1291000731 | |
sign = mix < 0; | |
sign && (mix *= -1); | |
// add offset 1023 to ensure positive | |
// 0.6931471805599453 = Math.LN2; | |
exp = ((Math.log(mix) / 0.6931471805599453) + 1023) | 0; | |
// shift 52 - (exp - 1023) bits to make integer part exactly 53 bits, | |
// then throw away trash less than decimal point | |
frac = mix * Math.pow(2, 52 + 1023 - exp); | |
// S+-Exp(11)--++-----------------Fraction(52bits)-----------------------+ | |
// || || | | |
// v+----------++--------------------------------------------------------+ | |
// 00000000|00000000|00000000|00000000|00000000|00000000|00000000|00000000 | |
// 6 5 55 4 4 3 2 1 8 0 | |
// 3 6 21 8 0 2 4 6 | |
// | |
// +----------high(32bits)-----------+ +----------low(32bits)------------+ | |
// | | | | | |
// +---------------------------------+ +---------------------------------+ | |
// 3 2 21 1 8 0 | |
// 1 4 09 6 | |
low = frac & 0xffffffff; | |
sign && (exp |= 0x800); | |
high = ((frac / 0x100000000) & 0xfffff) | (exp << 20); | |
rv.push(0xcb, (high >> 24) & 0xff, (high >> 16) & 0xff, | |
(high >> 8) & 0xff, high & 0xff, | |
(low >> 24) & 0xff, (low >> 16) & 0xff, | |
(low >> 8) & 0xff, low & 0xff); | |
} | |
break; | |
case "string": | |
// http://d.hatena.ne.jp/uupaa/20101128 | |
iz = mix.length; | |
pos = rv.length; // keep rewrite position | |
rv.push(0); // placeholder | |
// utf8.encode | |
for (i = 0; i < iz; ++i) { | |
c = mix.charCodeAt(i); | |
if (c < 0x80) { // ASCII(0x00 ~ 0x7f) | |
rv.push(c & 0x7f); | |
} else if (c < 0x0800) { | |
rv.push(((c >>> 6) & 0x1f) | 0xc0, (c & 0x3f) | 0x80); | |
} else if (c < 0x10000) { | |
rv.push(((c >>> 12) & 0x0f) | 0xe0, | |
((c >>> 6) & 0x3f) | 0x80, (c & 0x3f) | 0x80); | |
} | |
} | |
size = rv.length - pos - 1; | |
if (size < 32) { | |
rv[pos] = 0xa0 + size; // rewrite | |
} else if (size < 0x100) { // 8 | |
rv.splice(pos, 1, 0xd9, size); | |
} else if (size < 0x10000) { // 16 | |
rv.splice(pos, 1, 0xda, size >> 8, size & 0xff); | |
} else if (size < 0x100000000) { // 32 | |
rv.splice(pos, 1, 0xdb, | |
size >>> 24, (size >> 16) & 0xff, | |
(size >> 8) & 0xff, size & 0xff); | |
} | |
break; | |
default: // array, hash, or Uint8Array | |
if (_isUint8Array(mix)) { | |
size = mix.length; | |
if (size < 0x100) { // 8 | |
rv.push(0xc4, size); | |
} else if (size < 0x10000) { // 16 | |
rv.push(0xc5, size >> 8, size & 0xff); | |
} else if (size < 0x100000000) { // 32 | |
rv.push(0xc6, size >>> 24, (size >> 16) & 0xff, | |
(size >> 8) & 0xff, size & 0xff); | |
} | |
Array.prototype.push.apply(rv, mix); | |
break; | |
} | |
if (++depth >= _MAX_DEPTH) { | |
_error = 1; // CYCLIC_REFERENCE_ERROR | |
return rv = []; // clear | |
} | |
if (_isArray(mix)) { | |
size = mix.length; | |
if (size < 16) { | |
rv.push(0x90 + size); | |
} else if (size < 0x10000) { // 16 | |
rv.push(0xdc, size >> 8, size & 0xff); | |
} else if (size < 0x100000000) { // 32 | |
rv.push(0xdd, size >>> 24, (size >> 16) & 0xff, | |
(size >> 8) & 0xff, size & 0xff); | |
} | |
for (i = 0; i < size; ++i) { | |
encode(rv, mix[i], depth); | |
} | |
} else { // hash | |
// http://d.hatena.ne.jp/uupaa/20101129 | |
pos = rv.length; // keep rewrite position | |
rv.push(0); // placeholder | |
size = 0; | |
for (i in mix) { | |
++size; | |
encode(rv, i, depth); | |
encode(rv, mix[i], depth); | |
} | |
if (size < 16) { | |
rv[pos] = 0x80 + size; // rewrite | |
} else if (size < 0x10000) { // 16 | |
rv.splice(pos, 1, 0xde, size >> 8, size & 0xff); | |
} else if (size < 0x100000000) { // 32 | |
rv.splice(pos, 1, 0xdf, | |
size >>> 24, (size >> 16) & 0xff, | |
(size >> 8) & 0xff, size & 0xff); | |
} | |
} | |
} | |
} | |
return rv; | |
} | |
// inner - byteArray To ByteString | |
function byteArrayToByteString(byteArray) { // @param ByteArray | |
// @return String | |
// http://d.hatena.ne.jp/uupaa/20101128 | |
try { | |
return _toString.apply(this, byteArray); // toString | |
} catch(err) { | |
; // avoid "Maximum call stack size exceeded" | |
} | |
var rv = [], i = 0, iz = byteArray.length, num2bin = _num2bin; | |
for (; i < iz; ++i) { | |
rv[i] = num2bin[byteArray[i]]; | |
} | |
return rv.join(""); | |
} | |
// --- init --- | |
(function() { | |
for (var i = 0; i < 0x100; ++i) { | |
_num2bin[i] = _toString(i); // 0 -> "\00" | |
} | |
})(); | |
})(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment