Skip to content

Instantly share code, notes, and snippets.

@daschl
Last active December 18, 2015 14:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daschl/5796263 to your computer and use it in GitHub Desktop.
Save daschl/5796263 to your computer and use it in GitHub Desktop.
MessagePack Library, Modified for Couchbase View inclusion.
/*!{id:msgpack.js,ver:1.05,license:"MIT",author:"uupaa.js@gmail.com"}*/
/* Modified by @daschl and @avsej to strip out whats not needed */
// === msgpack ===
// MessagePack -> http://msgpack.sourceforge.net/
var msgunpack = (function () {
var _bin2num = {}, // BinaryStringToNumber { "\00": 0, ... "\ff": 255 }
_num2bin = {}, // NumberToBinaryString { 0: "\00", ... 255: "\ff" }
_buf = [], // decode buffer
_idx = 0, // decode buffer[index]
_toString = String.fromCharCode; // CharCode/ByteArray to String
// @param BinaryString/ByteArray:
// @return Mix/undefined:
// undefined is error return
// [1][String to mix] msgpack.unpack("...") -> {}
// [2][ByteArray to mix] msgpack.unpack([...]) -> {}
function unpack(data) {
_buf = typeof data === "string" ? toByteArray(data) : data;
_idx = -1;
return decode(); // mix or undefined
}
// @return Mix:
function decode() {
var size, i, iz, c, num = 0,
sign, exp, frac, ary, hash,
buf = _buf,
type = buf[++_idx];
if (type >= 0xe0) { // Negative FixNum (111x xxxx) (-32 ~ -1)
return type - 0x100;
}
if (type < 0xc0) {
if (type < 0x80) { // Positive FixNum (0xxx xxxx) (0 ~ 127)
return type;
}
if (type < 0x90) { // FixMap (1000 xxxx)
num = type - 0x80;
type = 0x80;
} else if (type < 0xa0) { // FixArray (1001 xxxx)
num = type - 0x90;
type = 0x90;
} else { // if (type < 0xc0) { // FixRaw (101x xxxx)
num = type - 0xa0;
type = 0xa0;
}
}
switch (type) {
case 0xc0:
return null;
case 0xc2:
return false;
case 0xc3:
return true;
case 0xca: // float
num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) +
(buf[++_idx] << 8) + buf[++_idx];
sign = num & 0x80000000; // 1bit
exp = (num >> 23) & 0xff; // 8bits
frac = num & 0x7fffff; // 23bits
if (!num || num === 0x80000000) { // 0.0 or -0.0
return 0;
}
if (exp === 0xff) { // NaN or Infinity
return frac ? NaN : Infinity;
}
return (sign ? -1 : 1) *
(frac | 0x800000) * Math.pow(2, exp - 127 - 23); // 127: bias
case 0xcb: // double
num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) +
(buf[++_idx] << 8) + buf[++_idx];
sign = num & 0x80000000; // 1bit
exp = (num >> 20) & 0x7ff; // 11bits
frac = num & 0xfffff; // 52bits - 32bits (high word)
if (!num || num === 0x80000000) { // 0.0 or -0.0
_idx += 4;
return 0;
}
if (exp === 0x7ff) { // NaN or Infinity
_idx += 4;
return frac ? NaN : Infinity;
}
num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) +
(buf[++_idx] << 8) + buf[++_idx];
return (sign ? -1 : 1) *
((frac | 0x100000) * Math.pow(2, exp - 1023 - 20) // 1023: bias
+ num * Math.pow(2, exp - 1023 - 52));
// 0xcf: uint64, 0xce: uint32, 0xcd: uint16
case 0xcf:
num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) +
(buf[++_idx] << 8) + buf[++_idx];
return num * 0x100000000 +
buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) +
(buf[++_idx] << 8) + buf[++_idx];
case 0xce:
num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16);
case 0xcd:
num += buf[++_idx] << 8;
case 0xcc:
return num + buf[++_idx];
// 0xd3: int64, 0xd2: int32, 0xd1: int16, 0xd0: int8
case 0xd3:
num = buf[++_idx];
if (num & 0x80) { // sign -> avoid overflow
return ((num ^ 0xff) * 0x100000000000000 +
(buf[++_idx] ^ 0xff) * 0x1000000000000 +
(buf[++_idx] ^ 0xff) * 0x10000000000 +
(buf[++_idx] ^ 0xff) * 0x100000000 +
(buf[++_idx] ^ 0xff) * 0x1000000 +
(buf[++_idx] ^ 0xff) * 0x10000 +
(buf[++_idx] ^ 0xff) * 0x100 +
(buf[++_idx] ^ 0xff) + 1) * -1;
}
return num * 0x100000000000000 +
buf[++_idx] * 0x1000000000000 +
buf[++_idx] * 0x10000000000 +
buf[++_idx] * 0x100000000 +
buf[++_idx] * 0x1000000 +
buf[++_idx] * 0x10000 +
buf[++_idx] * 0x100 +
buf[++_idx];
case 0xd2:
num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) +
(buf[++_idx] << 8) + buf[++_idx];
return num < 0x80000000 ? num : num - 0x100000000; // 0x80000000 * 2
case 0xd1:
num = (buf[++_idx] << 8) + buf[++_idx];
return num < 0x8000 ? num : num - 0x10000; // 0x8000 * 2
case 0xd0:
num = buf[++_idx];
return num < 0x80 ? num : num - 0x100; // 0x80 * 2
// 0xdb: raw32, 0xda: raw16, 0xa0: raw ( string )
case 0xdb:
num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16);
case 0xda:
num += (buf[++_idx] << 8) + buf[++_idx];
case 0xa0: // utf8.decode
for (ary = [], i = _idx, iz = i + num; i < iz;) {
c = buf[++i]; // lead byte
ary.push(c < 0x80 ? c : // ASCII(0x00 ~ 0x7f)
c < 0xe0 ? ((c & 0x1f) << 6 | (buf[++i] & 0x3f)) :
((c & 0x0f) << 12 | (buf[++i] & 0x3f) << 6 | (buf[++i] & 0x3f)));
}
_idx = i;
return ary.length < 10240 ? _toString.apply(null, ary) : byteArrayToByteString(ary);
// 0xdf: map32, 0xde: map16, 0x80: map
case 0xdf:
num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16);
case 0xde:
num += (buf[++_idx] << 8) + buf[++_idx];
case 0x80:
hash = {};
while (num--) {
// make key/value pair
size = buf[++_idx] - 0xa0;
for (ary = [], i = _idx, iz = i + size; i < iz;) {
c = buf[++i]; // lead byte
ary.push(c < 0x80 ? c : // ASCII(0x00 ~ 0x7f)
c < 0xe0 ? ((c & 0x1f) << 6 | (buf[++i] & 0x3f)) :
((c & 0x0f) << 12 | (buf[++i] & 0x3f) << 6 | (buf[++i] & 0x3f)));
}
_idx = i;
hash[_toString.apply(null, ary)] = decode();
}
return hash;
// 0xdd: array32, 0xdc: array16, 0x90: array
case 0xdd:
num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16);
case 0xdc:
num += (buf[++_idx] << 8) + buf[++_idx];
case 0x90:
ary = [];
while (num--) {
ary.push(decode());
}
return ary;
}
return;
}
// @param ByteArray
// @return String
// http://d.hatena.ne.jp/uupaa/20101128
function byteArrayToByteString(byteArray) {
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("");
}
// @param BinaryString: "\00\01"
// @return ByteArray: [0x00, 0x01]
function toByteArray(data) {
var rv = [],
bin2num = _bin2num,
remain,
ary = data.split(""),
i = -1,
iz;
iz = ary.length;
remain = iz % 8;
while (remain--) {
++i;
rv[i] = bin2num[ary[i]];
}
remain = iz >> 3;
while (remain--) {
rv.push(bin2num[ary[++i]], bin2num[ary[++i]],
bin2num[ary[++i]], bin2num[ary[++i]],
bin2num[ary[++i]], bin2num[ary[++i]],
bin2num[ary[++i]], bin2num[ary[++i]]);
}
return rv;
}
return unpack;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment