From caea0e4130c353168ae458f52405170816b5f5a9 Mon Sep 17 00:00:00 2001 From: Takatoshi Kondo Date: Wed, 27 Aug 2014 16:55:56 +0900 Subject: [PATCH] Added bin format familiy support. https://github.com/msgpack/msgpack/blob/master/spec.md#bin-format-family --- msgpack.codec.js | 36 +++++++++++++++++++--- msgpack.js | 36 +++++++++++++++++++--- test/codec.htm | 79 +++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 132 insertions(+), 19 deletions(-) diff --git a/msgpack.codec.js b/msgpack.codec.js index cd8ab882..52a909e0 100644 --- a/msgpack.codec.js +++ b/msgpack.codec.js @@ -23,6 +23,9 @@ var _bin2num = {}, // BinaryStringToNumber { "\00": 0, ... "\ff": 255 } _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; @@ -176,6 +179,8 @@ function encode(rv, // @param ByteArray: result 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 @@ -184,7 +189,21 @@ function encode(rv, // @param ByteArray: result (size >> 8) & 0xff, size & 0xff); } break; - default: // array or hash + 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 @@ -324,9 +343,10 @@ function decode() { // @return Mix: 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]; + // 0xdb: str32, 0xda: str16, 0xd9: str8, 0xa0: fixstr + case 0xdb: num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16); + case 0xda: num += buf[++_idx] << 8; + case 0xd9: num += buf[++_idx]; case 0xa0: // utf8.decode for (ary = [], i = _idx, iz = i + num; i < iz; ) { c = buf[++i]; // lead byte @@ -338,6 +358,14 @@ function decode() { // @return Mix: _idx = i; return ary.length < 10240 ? _toString.apply(null, ary) : byteArrayToByteString(ary); + // 0xc6: bin32, 0xc5: bin16, 0xc4: bin8 + case 0xc6: num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16); + case 0xc5: num += buf[++_idx] << 8; + case 0xc4: num += buf[++_idx]; + var end = ++_idx + num + var ret = buf.slice(_idx, end); + _idx += num; + return ret; // 0xdf: map32, 0xde: map16, 0x80: map case 0xdf: num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16); case 0xde: num += (buf[++_idx] << 8) + buf[++_idx]; diff --git a/msgpack.js b/msgpack.js index 46ed0cb2..08f5de6b 100644 --- a/msgpack.js +++ b/msgpack.js @@ -29,6 +29,9 @@ var _ie = /MSIE/.test(navigator.userAgent), _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; @@ -191,6 +194,8 @@ function encode(rv, // @param ByteArray: result 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 @@ -199,7 +204,21 @@ function encode(rv, // @param ByteArray: result (size >> 8) & 0xff, size & 0xff); } break; - default: // array or hash + 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 @@ -339,9 +358,10 @@ function decode() { // @return Mix: 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]; + // 0xdb: str32, 0xda: str16, 0xd9: str8, 0xa0: fixstr + case 0xdb: num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16); + case 0xda: num += buf[++_idx] << 8; + case 0xd9: num += buf[++_idx]; case 0xa0: // utf8.decode for (ary = [], i = _idx, iz = i + num; i < iz; ) { c = buf[++i]; // lead byte @@ -353,6 +373,14 @@ function decode() { // @return Mix: _idx = i; return ary.length < 10240 ? _toString.apply(null, ary) : byteArrayToByteString(ary); + // 0xc6: bin32, 0xc5: bin16, 0xc4: bin8 + case 0xc6: num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16); + case 0xc5: num += buf[++_idx] << 8; + case 0xc4: num += buf[++_idx]; + var end = ++_idx + num + var ret = buf.slice(_idx, end); + _idx += num; + return ret; // 0xdf: map32, 0xde: map16, 0x80: map case 0xdf: num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16); case 0xde: num += (buf[++_idx] << 8) + buf[++_idx]; diff --git a/test/codec.htm b/test/codec.htm index eb2dbdc5..d424d986 100644 --- a/test/codec.htm +++ b/test/codec.htm @@ -486,31 +486,52 @@ return [rv, "==", -3.14159565358979, hex(pack)]; }, - "Raw (as String)": "", - "String('') -> [0xa0] (FixRaw)": function() { + "Str (as String)": "", + "String('') -> [0xa0] (FixStr)": function() { var pack = msgpack.pack(""); var rv = msgpack.unpack(pack); return [rv, "==", "", hex(pack)]; }, - "String('abc') -> [0xa3, 0x61, 0x62, 0x63] (FixRaw)": function() { + "String('abc') -> [0xa3, 0x61, 0x62, 0x63] (FixStr)": function() { var pack = msgpack.pack("abc"); var rv = msgpack.unpack(pack); return [rv, "==", "abc", hex(pack)]; }, - "String('あいう') -> [0xa9, 0xe3, 0x81, 0x82, 0xe3, 0x81, 0x84, 0xe3, 0x81, 0x86] (FixRaw)": function() { + "String('あいう') -> [0xa9, 0xe3, 0x81, 0x82, 0xe3, 0x81, 0x84, 0xe3, 0x81, 0x86] (FixStr)": function() { var pack = msgpack.pack("あいう"); var rv = msgpack.unpack(pack); return [rv, "==", "あいう", hex(pack)]; }, - "String('カルビx3, ハラミx2, ブタバラ, T-BORNx500g, ライス大盛りで') -> [] (Raw16)": function() { + "String('カルビx3, ハラミx2, ブタバラ, T-BORNx500g, ライス大盛りで') -> [] (Str8)": function() { var pack = msgpack.pack("カルビx3, ハラミx2, ブタバラ, T-BORNx500g, ライス大盛りで"); var rv = msgpack.unpack(pack); return [rv, "==", "カルビx3, ハラミx2, ブタバラ, T-BORNx500g, ライス大盛りで", hex(pack)]; }, + "String('カルビx3, ハラミx2, ブタバラ, T-BORNx500g, ライス大盛りで、あとナポリタンと天丼、スープカレーに餃子とチャーハン、それからそれからビーフストロガノフとアクアパッツァ、すき焼きにざるそば') -> [] (Str16)": function() { + var pack = msgpack.pack("カルビx3, ハラミx2, ブタバラ, T-BORNx500g, ライス大盛りで、あとナポリタンと天丼、スープカレーに餃子とチャーハン、それからそれからビーフストロガノフとアクアパッツァ、すき焼きにざるそば"); + var rv = msgpack.unpack(pack); + + return [rv, "==", "カルビx3, ハラミx2, ブタバラ, T-BORNx500g, ライス大盛りで、あとナポリタンと天丼、スープカレーに餃子とチャーハン、それからそれからビーフストロガノフとアクアパッツァ、すき焼きにざるそば", hex(pack)]; + }, + "Bin (as Uint8Array)": "", + "Uint8Array(1,2,3) -> [1,2,3] (Bin8)": function() { + var pack = msgpack.pack(new Uint8Array([1,2,3])); + var rv = msgpack.unpack(pack); + + return [rv, "==", [1,2,3], hex(pack)]; + }, + "Uint8Array(0..255) -> [0..255] (Bin16)": function() { + var expected = new Array(256); + for (var i = 0; i < 256; ++i) expected[i] = i; + var pack = msgpack.pack(new Uint8Array(expected)); + var rv = msgpack.unpack(pack); + + return [rv, "==", expected, hex(pack)]; + }, "Map (as Hash)": "", "Hash({}) -> [0x80] (FixMap)": function() { var pack = msgpack.pack({}); @@ -769,21 +790,28 @@ return [rv, "==", -1.0, hex(result)]; }, - '[a1 61] "a" FixRaw': function() { + '[a1 61] "a" FixStr': function() { var data = unescape('%a1%61'); var result = [0xa1, 0x61]; var rv = msgpack.unpack(data); return [rv, "==", "a", hex(result)]; }, - '[da 00 01 61] "a" raw 16': function() { + '[d9 01 61] "a" str 8': function() { + var data = unescape('%d9%01%61'); + var result = [0xda, 0x01, 0x61]; + var rv = msgpack.unpack(data); + + return [rv, "==", "a", hex(result)]; + }, + '[da 00 01 61] "a" str 16': function() { var data = unescape('%da%00%01%61'); var result = [0xda, 0x00, 0x01, 0x61]; var rv = msgpack.unpack(data); return [rv, "==", "a", hex(result)]; }, - '[db 00 00 00 01 61] "a" raw 32': function() { + '[db 00 00 00 01 61] "a" str 32': function() { var data = unescape('%db%00%00%00%01%61'); var result = [0xdb, 0x00, 0x00, 0x00, 0x01, 0x61]; var rv = msgpack.unpack(data); @@ -791,21 +819,28 @@ return [rv, "==", "a", hex(result)]; }, - '[a0] "" FixRaw': function() { + '[a0] "" FixStr': function() { var data = unescape('%a0'); var result = [0xa0]; var rv = msgpack.unpack(data); return [rv, "==", "", hex(result)]; }, - '[da 00 00] "" raw 16': function() { + '[d9 00] "" str 8': function() { + var data = unescape('%d9%00'); + var result = [0xd9, 0x00]; + var rv = msgpack.unpack(data); + + return [rv, "==", "", hex(result)]; + }, + '[da 00 00] "" str 16': function() { var data = unescape('%da%00%00'); var result = [0xda, 0x00, 0x00]; var rv = msgpack.unpack(data); return [rv, "==", "", hex(result)]; }, - '[db 00 00 00 00] "" raw 32': function() { + '[db 00 00 00 00] "" str 32': function() { var data = unescape('%db%00%00%00%00'); var result = [0xdb, 0x00, 0x00, 0x00, 0x00]; var rv = msgpack.unpack(data); @@ -813,6 +848,28 @@ return [rv, "==", "", hex(result)]; }, + '[c4 00] "" bin 8': function() { + var data = unescape('%c4%00'); + var result = [0xc4, 0x00]; + var rv = msgpack.unpack(data); + + return [rv, "==", [], hex(result)]; + }, + '[c5 00 00] "" bin 16': function() { + var data = unescape('%c5%00%00'); + var result = [0xc5, 0x00, 0x00]; + var rv = msgpack.unpack(data); + + return [rv, "==", [], hex(result)]; + }, + '[c6 00 00 00 00] "" bin 32': function() { + var data = unescape('%c6%00%00%00%00'); + var result = [0xc6, 0x00, 0x00, 0x00, 0x00]; + var rv = msgpack.unpack(data); + + return [rv, "==", [], hex(result)]; + }, + '[91 00] [0] FixArray': function() { var data = unescape('%91%00'); var result = [0x91, 0x00];