├── benchmark ├── gensort.msgpack └── benchmark.html ├── README ├── test ├── server.rb ├── test_pack.html ├── test_unpack.html └── test_xhr.html └── lib └── msgpack.js /benchmark/gensort.msgpack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuzic/MessagePack-JS/HEAD/benchmark/gensort.msgpack -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | * MessagePack-JS 2 | JavaScript implimentation for MessagePack serialization format. 3 | 4 | ** usage 5 | 6 | var $true = MessagePack.unpack("\xc3"); 7 | alert($true); // true 8 | 9 | var int8 = MessagePack.unpack("\xd0\xc0")); 10 | alert(int8); // -64 11 | 12 | var fixraw = MessagePack.unpack("\xa1\x61"); 13 | alert(fixraw); // 'a' 14 | 15 | var int32 = MessagePack.unpack("\xd2\xff\xf0\x00\x00"); 16 | alert(int32); // -1048576 17 | 18 | ** environment 19 | tested for IE 8.0.6 , Firefox 3.6.3 , Google Chrome 4.1 20 | 21 | ** see other 22 | http://msgpack.sourceforge.net/ 23 | 24 | ** LISENCE 25 | MIT Lisence 26 | 27 | ** Test 28 | Test code (tests.html) requires JsUnit 29 | Benchmark code needs prototype.js 30 | If you want to test and benchmark msgpack.js, 31 | please deploy as follows: 32 | ./lib/msgpack.js 33 | ./test/test_unpack.html 34 | ./test/test_pack.html 35 | ./test/test_xhr.html 36 | 37 | # see jsunit < http://github.com/pivotal/jsunit > 38 | ./test/jsunit/testRunner.html 39 | ./test/jsunit/app/jsUnitCore.js 40 | ./test/jsunit/testRunner.html 41 | ./test/jsunit/app/jsUnitCore.js 42 | 43 | ./benchmark/benchmark.html 44 | # see prototype.js < http://www.prototypejs.org/ > 45 | ./benchmark/prototype/prototype.js 46 | 47 | Before you test test_xhr.html, you must start server.rb. 48 | > ruby server.rb 49 | server.rb require Ruby MessagePack Library. 50 | Please install Ruby MessagePack Library: 51 | > gem install msgpack 52 | -------------------------------------------------------------------------------- /test/server.rb: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/ruby 2 | require 'webrick' 3 | require 'rubygems' 4 | require 'msgpack' 5 | 6 | def webrick(config = {}) 7 | WEBrick::HTTPServer.new(config).instance_eval do |server| 8 | [:INT, :TERM].each do |signal| 9 | Signal.trap(signal) { shutdown } 10 | end 11 | server.mount_proc("/unpack") do |req, res| 12 | if req.path =~ %r(/unpack/([a-z0-9]+)) then 13 | path = $1 14 | res.content_type = "text/plain; charset=x-user-defined" 15 | case path 16 | when "null" 17 | res.body = nil.to_msgpack 18 | when "true" 19 | res.body = true.to_msgpack 20 | when "false" 21 | res.body = false.to_msgpack 22 | when "fixnum" 23 | res.body = 100.to_msgpack 24 | when "fixraw" 25 | res.body = "0123456789abc".to_msgpack 26 | when "fixarray" 27 | res.body = [0, true, false].to_msgpack 28 | when "fixmap" 29 | res.body = {0 => "0", 1 => "1"}.to_msgpack 30 | when "float" 31 | res.body = (10.5).to_msgpack 32 | when "uint8" 33 | res.body = 200.to_msgpack 34 | when "uint16" 35 | res.body = 40000.to_msgpack 36 | when "uint32" 37 | res.body = (3*(2**30)).to_msgpack 38 | when "uint64" 39 | res.body = (3*(2**62)).to_msgpack 40 | when "int8" 41 | res.body = (-100).to_msgpack 42 | when "int16" 43 | res.body = (-1000).to_msgpack 44 | when "int32" 45 | res.body = (-1000_000).to_msgpack 46 | when "int64" 47 | res.body = (-1000_000_000_000_000).to_msgpack 48 | when "raw16" 49 | res.body = ("a"*1000).to_msgpack 50 | when "raw32" 51 | res.body = ("a"*100_000).to_msgpack 52 | when "array16" 53 | res.body = ([1]*1000).to_msgpack 54 | when "array32" 55 | res.body = ([1]*100_000).to_msgpack 56 | when "map16" 57 | hash = (0..1000).inject({}) do |h, key| 58 | h[key] = key.to_s 59 | h 60 | end 61 | res.body = hash.to_msgpack 62 | when "map32" 63 | hash = (0..1000_000).inject({}) do |h, key| 64 | h[key] = key.to_s 65 | h 66 | end 67 | res.body = hash.to_msgpack 68 | end 69 | end 70 | end 71 | start 72 | end 73 | end 74 | 75 | webrick :DocumentRoot => File.expand_path(File.join(File.dirname(__FILE__), "..")), 76 | :Port => 5001 77 | -------------------------------------------------------------------------------- /benchmark/benchmark.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | MessagePack Benchmark Test 4 | 5 | 6 | 79 | 80 | 81 |
82 | 83 | 84 |
85 |
86 | 87 |
88 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /test/test_pack.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | test pack 4 | 6 | 8 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /test/test_unpack.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | test 4 | 6 | 8 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /test/test_xhr.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | test xml http request 4 | 6 | 8 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 |
184 | 186 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /lib/msgpack.js: -------------------------------------------------------------------------------- 1 | MessagePack = {}; 2 | MessagePack.unpack = function(data){ 3 | var unpacker = new MessagePack.Decoder(data); 4 | return unpacker.unpack(); 5 | }; 6 | 7 | MessagePack.UTF8 = 0; 8 | MessagePack.ASCII8bit = 1; 9 | MessagePack.UTF16 = 2; // not yet implemented 10 | MessagePack.ByteArray = -1; 11 | MessagePack.CharSet = MessagePack.UTF8; 12 | 13 | // data : responseText for FireFox, Chrome, Safari ... 14 | // : responseBody for Internet Explorer 15 | // charSet : specifies how to handle with raw data 16 | // 'utf-8': assume raw data is UTF-8 String 17 | // 'ascii': assume raw data is ASCII-8bit String 18 | // 'utf16': assume raw data is UTF-16 String 19 | // 'byte-array': not convert to string. just return array of numbers 20 | MessagePack.Decoder = function(data, charSet){ 21 | this.index = 0; 22 | if(MessagePack.hasVBS){ 23 | if(typeof(data) == "unknown"){ 24 | // assume data is byte array 25 | this.length = msgpack_getLength(data); 26 | this.byte_array_to_string(data); 27 | }else{ 28 | this.length = msgpack_getLength(data); 29 | this.data = data; 30 | } 31 | }else{ 32 | this.length = data.length; 33 | this.data = data; 34 | } 35 | charSet = charSet || MessagePack.CharSet || 0; 36 | if(charSet == 'utf-8'){ 37 | charSet = MessagePack.UTF8; 38 | } 39 | else if(charSet == 'ascii'){ 40 | charSet = MessagePack.ASCII8bit; 41 | } 42 | else if(charSet == 'utf16'){ 43 | charSet = MessagePack.UTF16; 44 | } 45 | else if(charSet == 'byte-array'){ 46 | charSet = MessagePack.ByteArray; 47 | } 48 | else{ 49 | charSet = MessagePack.UTF8; 50 | } 51 | } 52 | 53 | 54 | if(typeof execScript != 'undefined'){ 55 | execScript( 56 | 'Dim g_msgpack_binary_data\n' + 57 | 'Sub msgpack_set_binary_data(binary)\n' + 58 | ' g_msgpack_binary_data = binary\n' + 59 | 'End Sub\n' + 60 | 'Function msgpack_getByte(pos)\n' + 61 | ' msgpack_getByte = AscB(MidB(g_msgpack_binary_data, pos + 1, 1))\n'+ 62 | 'End Function\n',"VBScript"); 63 | execScript( 64 | 'Function msgpack_substr(pos, len)\n' + 65 | ' Dim array()\n'+ 66 | ' ReDim array(len)\n'+ 67 | ' For i = 1 To len\n'+ 68 | ' array(i-1) = AscB(MidB(g_msgpack_binary_data, pos + i, 1))\n'+ 69 | ' Next\n'+ 70 | ' msgpack_substr = array\n'+ 71 | 'End Function\n' + 72 | 'Function msgpack_getLength(data)\n' + 73 | ' msgpack_getLength = LenB(data)\n' + 74 | 'End Function\n' + 75 | '\n', 'VBScript'); 76 | } 77 | 78 | MessagePack.hasVBS = 'msgpack_getByte' in this; 79 | 80 | with({p: MessagePack.Decoder.prototype}){ 81 | p.unpack = function(){ 82 | var type = this.unpack_uint8(); 83 | if(type < 0x80){ 84 | var positive_fixnum = type; 85 | return positive_fixnum; 86 | }else if((type ^ 0xe0) < 0x20){ 87 | var negative_fixnum = (type ^ 0xe0) - 0x20; 88 | return negative_fixnum; 89 | } 90 | var size; 91 | if((size = type ^ 0xa0) <= 0x1f){ 92 | return this.unpack_raw(size); 93 | }else if((size = type ^ 0x90) <= 0x0f){ 94 | return this.unpack_array(size); 95 | }else if((size = type ^ 0x80) <= 0x0f){ 96 | return this.unpack_map(size); 97 | } 98 | 99 | switch(type){ 100 | case 0xc0: 101 | return null; 102 | case 0xc1: 103 | return undefined; 104 | case 0xc2: 105 | return false; 106 | case 0xc3: 107 | return true; 108 | case 0xca: 109 | return this.unpack_float(); 110 | case 0xcb: 111 | return this.unpack_double(); 112 | case 0xcc: 113 | return this.unpack_uint8(); 114 | case 0xcd: 115 | return this.unpack_uint16(); 116 | case 0xce: 117 | return this.unpack_uint32(); 118 | case 0xcf: 119 | return this.unpack_uint64(); 120 | case 0xd0: 121 | return this.unpack_int8(); 122 | case 0xd1: 123 | return this.unpack_int16(); 124 | case 0xd2: 125 | return this.unpack_int32(); 126 | case 0xd3: 127 | return this.unpack_int64(); 128 | case 0xd4: 129 | return undefined; 130 | case 0xd5: 131 | return undefined; 132 | case 0xd6: 133 | return undefined; 134 | case 0xd7: 135 | return undefined; 136 | case 0xd8: 137 | return undefined; 138 | case 0xd9: 139 | return undefined; 140 | case 0xda: 141 | size = this.unpack_uint16(); 142 | return this.unpack_raw(size); 143 | case 0xdb: 144 | size = this.unpack_uint32; 145 | return this.unpack_raw(size); 146 | case 0xdc: 147 | size = this.unpack_uint16(); 148 | return this.unpack_array(size); 149 | case 0xdd: 150 | size = this.unpack_uint32(); 151 | return this.unpack_array(size); 152 | case 0xde: 153 | size = this.unpack_uint16(); 154 | return this.unpack_map(size); 155 | case 0xdf: 156 | size = this.unpack_uint32(); 157 | return this.unpack_map(size); 158 | } 159 | } 160 | 161 | p.unpack_uint8 = function(){ 162 | var byte = this.getc() & 0xff; 163 | this.index++; 164 | return byte; 165 | }; 166 | 167 | p.unpack_uint16 = function(){ 168 | var bytes = this.read(2); 169 | var uint16 = 170 | ((bytes[0] & 0xff) * 256) + (bytes[1] & 0xff); 171 | this.index += 2; 172 | return uint16; 173 | } 174 | 175 | p.unpack_uint32 = function(){ 176 | var bytes = this.read(4); 177 | var uint32 = 178 | ((bytes[0] * 256 + 179 | bytes[1]) * 256 + 180 | bytes[2]) * 256 + 181 | bytes[3]; 182 | this.index += 4; 183 | return uint32; 184 | } 185 | 186 | p.unpack_uint64 = function(){ 187 | var bytes = this.read(8); 188 | var uint64 = 189 | ((((((bytes[0] * 256 + 190 | bytes[1]) * 256 + 191 | bytes[2]) * 256 + 192 | bytes[3]) * 256 + 193 | bytes[4]) * 256 + 194 | bytes[5]) * 256 + 195 | bytes[6]) * 256 + 196 | bytes[7]; 197 | this.index += 8; 198 | return uint64; 199 | } 200 | 201 | 202 | p.unpack_int8 = function(){ 203 | var uint8 = this.unpack_uint8(); 204 | return (uint8 < 0x80 ) ? uint8 : uint8 - (1 << 8); 205 | }; 206 | 207 | p.unpack_int16 = function(){ 208 | var uint16 = this.unpack_uint16(); 209 | return (uint16 < 0x8000 ) ? uint16 : uint16 - (1 << 16); 210 | } 211 | 212 | p.unpack_int32 = function(){ 213 | var uint32 = this.unpack_uint32(); 214 | return (uint32 < Math.pow(2, 31) ) ? uint32 : 215 | uint32 - Math.pow(2, 32); 216 | } 217 | 218 | p.unpack_int64 = function(){ 219 | var uint64 = this.unpack_uint64(); 220 | return (uint64 < Math.pow(2, 63) ) ? uint64 : 221 | uint64 - Math.pow(2, 64); 222 | } 223 | 224 | p.unpack_raw = function(size){ 225 | if( this.length < this.index + size){ 226 | throw new Error("MessagePackFailure: index is out of range" 227 | + " " + this.index + " " + size + " " + this.length); 228 | } 229 | var bytes = this.read(size); 230 | this.index += size; 231 | if(this.charSet == MessagePack.ASCII8bit){ 232 | // For 8bit encoding 233 | return String.fromCharCode.apply(String, bytes); 234 | }else if(this.charSet == MessagePack.ByteArray){ 235 | // Array of numbers 236 | return bytes; 237 | } 238 | else{ 239 | // assume UTF-8 string 240 | var i = 0, str = "", c, code; 241 | while(i < size){ 242 | c = bytes[i]; 243 | if( c < 128){ 244 | str += String.fromCharCode(c); 245 | i++; 246 | } 247 | else if((c ^ 0xc0) < 32){ 248 | code = ((c ^ 0xc0) << 6) | (bytes[i+1] & 63); 249 | str += String.fromCharCode(code); 250 | i += 2; 251 | } 252 | else { 253 | code = ((c & 15) << 12) | ((bytes[i+1] & 63) << 6) | 254 | (bytes[i+2] & 63); 255 | str += String.fromCharCode(code); 256 | i += 3; 257 | } 258 | } 259 | return str; 260 | } 261 | } 262 | 263 | p.unpack_array = function(size){ 264 | var objects = new Array(size); 265 | for(var i = 0; i < size ; i++){ 266 | objects[i] = this.unpack(); 267 | } 268 | return objects; 269 | } 270 | 271 | p.unpack_map = function(size){ 272 | var map = {}; 273 | for(var i = 0; i < size ; i++){ 274 | var key = this.unpack(); 275 | var value = this.unpack(); 276 | map[key] = value; 277 | } 278 | return map; 279 | } 280 | 281 | p.unpack_float = function(){ 282 | var uint32 = this.unpack_uint32(); 283 | var sign = uint32 >> 31; 284 | var exp = ((uint32 >> 23) & 0xff) - 127; 285 | var fraction = ( uint32 & 0x7fffff ) | 0x800000; 286 | return (sign == 0 ? 1 : -1) * 287 | fraction * Math.pow(2, exp - 23); 288 | } 289 | 290 | p.unpack_double = function(){ 291 | var h32 = this.unpack_uint32(); 292 | var l32 = this.unpack_uint32(); 293 | var sign = h32 >> 31; 294 | var exp = ((h32 >> 20) & 0x7ff) - 1023; 295 | var hfrac = ( h32 & 0xfffff ) | 0x100000; 296 | var frac = hfrac * Math.pow(2, exp - 20) + 297 | l32 * Math.pow(2, exp - 52); 298 | return (sign == 0 ? 1 : -1) * frac; 299 | } 300 | 301 | p.byte_array_to_string = function(data){ 302 | var binary_to_js_array_hex = function(binary){ 303 | var xmldom = new ActiveXObject("Microsoft.XMLDOM"); 304 | var bin = xmldom.createElement("bin"); 305 | bin.nodeTypedValue = data; 306 | bin.dataType = "bin.hex"; 307 | 308 | var text = bin.text; 309 | var size = text.length; 310 | return function (start, length){ 311 | var i = 0, chunk = 4, bytes = [] 312 | chunk2 = chunk*2, hex, int32; 313 | for(; i + 3 < length; i+=4){ 314 | hex = text.substr(2*(i + start), chunk2); 315 | int32 = parseInt(hex, 16); 316 | 317 | bytes[i ] = (int32 > 24) & 0xff; 318 | bytes[i + 1] = (int32 > 16) & 0xff; 319 | bytes[i + 2] = (int32 > 8) & 0xff; 320 | bytes[i + 3] = int32 & 0xff; 321 | } 322 | for(i -= 3; i < length; i++){ 323 | hex = this.data.substr(2*(i+start), 2); 324 | bytes[i] = parseInt(hex, 16); 325 | } 326 | return bytes; 327 | } 328 | } 329 | 330 | var binary_to_js_array_base64 = function(binary){ 331 | var chr2index = {}; 332 | var text; 333 | (function(){ 334 | var xmldom = new ActiveXObject("Microsoft.XMLDOM"); 335 | var bin = xmldom.createElement("bin"); 336 | bin.dataType = "bin.base64"; 337 | bin.nodeTypedValue = binary; 338 | 339 | text = bin.text.replace(/[^A-Za-z0-9\+\/\=]/g, ""); 340 | 341 | var b64map = 342 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 343 | for(var i = 0, length = b64map.length; i < length ; i++){ 344 | chr2index[b64map.charAt(i)] = i; 345 | } 346 | })(); 347 | var chr2, chr3, prev_i = 0; 348 | return function(start, length){ 349 | var bytes, last_pos = Math.floor(3 * prev_i / 4); 350 | switch(last_pos - start){ 351 | case 2: 352 | bytes = [chr2, chr3]; 353 | break; 354 | case 1: 355 | bytes = [chr3]; 356 | break; 357 | default: 358 | bytes = []; 359 | } 360 | var j = bytes.length; 361 | if(length <= j){ 362 | bytes.length = length; 363 | return bytes; 364 | } 365 | var i = prev_i, enc1, enc2, enc3, enc4, 366 | last = 4*Math.ceil((start + length) / 3); 367 | while(i < last){ 368 | enc1 = chr2index[text.charAt(i++)]; 369 | enc2 = chr2index[text.charAt(i++)]; 370 | enc3 = chr2index[text.charAt(i++)]; 371 | enc4 = chr2index[text.charAt(i++)]; 372 | 373 | bytes[j++] = (enc1 << 2) | (enc2 >> 4); 374 | bytes[j++] = ((enc2 & 0x0f) << 4) | (enc3 >> 2); 375 | bytes[j++] = ((enc3 & 0x03) << 6) | enc4; 376 | } 377 | prev_i = i; 378 | chr2 = bytes[j-2]; 379 | chr3 = bytes[j-1]; 380 | bytes.length = length; 381 | return bytes; 382 | } 383 | } 384 | 385 | var binary_to_js_array_vbs = function(data){ 386 | msgpack_set_binary_data(data); 387 | return function(position, length){ 388 | return msgpack_substr(position, length).toArray(); 389 | } 390 | }; 391 | 392 | //var bytes_substr = binary_to_js_array_hex(data); 393 | var bytes_substr = binary_to_js_array_base64(data); 394 | //var bytes_substr = binary_to_js_array_vbs(data); 395 | 396 | this.read = function(length){ 397 | var j = this.index, i = 0; 398 | if( j + length <= this.length){ 399 | return bytes_substr( j, length); 400 | }else{ 401 | throw new Error("MessagePackFailure: index is out of range"); 402 | } 403 | } 404 | 405 | this.getc = function(){ 406 | var j = this.index; 407 | if(j < this.length){ 408 | return bytes_substr( j, 1)[0]; 409 | }else{ 410 | throw new Error("MessagePackFailure: index is out of range"); 411 | } 412 | } 413 | } 414 | 415 | p.read = function(length){ 416 | var j = this.index; 417 | if(j + length <= this.length){ 418 | var bytes = new Array(length); 419 | for(var i = length - 1; i >= 0; --i){ 420 | bytes[i] = this.data.charCodeAt(j+i) & 0xff; 421 | } 422 | return bytes; 423 | }else{ 424 | throw new Error("MessagePackFailure: index is out of range"); 425 | } 426 | } 427 | 428 | p.getc = function(){ 429 | var j = this.index; 430 | if(j < this.length){ 431 | return this.data.charCodeAt(j); 432 | } 433 | else{ 434 | throw new Error("MessagePackFailure: index is out of range"); 435 | } 436 | } 437 | } 438 | 439 | MessagePack.pack = function(data){ 440 | var enc = new MessagePack.Encoder(data); 441 | return enc.pack(data); 442 | } 443 | 444 | // Encoder object has no member and constructor does nothing 445 | // TODO: implement something 446 | MessagePack.Encoder = function(data, charSet){ 447 | } 448 | 449 | with ({p: MessagePack.Encoder.prototype}){ 450 | p.pack = function(value){ 451 | var type = typeof(value); 452 | if(type == "string"){ 453 | return this.pack_string(value); 454 | } 455 | else if(type == "number"){ 456 | if(Math.floor(value) === value){ 457 | return this.pack_integer(value); 458 | } 459 | else{ 460 | return this.pack_double(value); 461 | } 462 | } 463 | else if(type == "boolean"){ 464 | if(value === true){ 465 | return "\xc3"; 466 | } 467 | else if(value === false){ 468 | return "\xc2"; 469 | } 470 | } 471 | else if(type == "object"){ 472 | if(value === null){ 473 | return "\xc0"; 474 | } 475 | var constructor = value.constructor; 476 | if(constructor == Array){ 477 | return this.pack_array(value); 478 | } 479 | else if(constructor == Object){ 480 | return this.pack_object(value); 481 | } 482 | else{ 483 | throw new Error("not yet supported") 484 | } 485 | } 486 | } 487 | 488 | p.pack_string = function(str){ 489 | var length = str.length; 490 | if(length <= 0x1f){ 491 | return this.pack_uint8(0xa0 + length) + str; 492 | } 493 | else if(length <= 0xffff){ 494 | return "\xda" + this.pack_uint16(length) + str; 495 | } 496 | else if(length <= 0xffffffff){ 497 | return "\xdb" + this.pack_uint32(length) + str; 498 | } 499 | else{ 500 | throw new Error("invalid length"); 501 | } 502 | } 503 | 504 | p.pack_array = function(ary){ 505 | var length = ary.length; 506 | var str; 507 | 508 | if(length <= 0x0f){ 509 | str = this.pack_uint8(0x90 + length); 510 | } 511 | else if(length <= 0xffff){ 512 | str = "\xdc" + this.pack_uint16(length); 513 | } 514 | else if(length <= 0xffffffff){ 515 | str = "\xdd" + this.pack_uint32(length); 516 | } 517 | else{ 518 | throw new Error("invalid length"); 519 | } 520 | var elems = []; 521 | for(var i = 0; i < length ; i++){ 522 | elems.push(this.pack(ary[i])); 523 | } 524 | return str + elems.join(""); 525 | } 526 | 527 | p.pack_integer = function(num){ 528 | if( -0x20 <= num && num <= 0x7f){ 529 | return String.fromCharCode(num & 0xff); 530 | } 531 | else if(0x00 <= num && num <= 0xff){ 532 | return "\xcc" + this.pack_uint8(num); 533 | } 534 | else if(-0x80 <= num && num <= 0x7f){ 535 | return "\xd0" + this.pack_int8(num); 536 | } 537 | else if( 0x0000 <= num && num <= 0xffff){ 538 | return "\xcd" + this.pack_uint16(num); 539 | } 540 | else if(-0x8000 <= num && num <= 0x7fff){ 541 | return "\xd1" + this.pack_int16(num); 542 | } 543 | else if( 0x00000000 <= num && num <= 0xffffffff){ 544 | return "\xce" + this.pack_uint32(num); 545 | } 546 | else if(-0x80000000 <= num && num <= 0x7fffffff){ 547 | return "\xd2" + this.pack_int32(num); 548 | } 549 | else if(-0x8000000000000000 <= num && num <= 0x7FFFFFFFFFFFFFFF){ 550 | return "\xd3" + this.pack_int64(num); 551 | } 552 | else if(0x0000000000000000 <= num && num <= 0xFFFFFFFFFFFFFFFF){ 553 | return "\xcf" + this.pack_uint64(num); 554 | } 555 | else{ 556 | throw new Error("invalid integer"); 557 | } 558 | } 559 | 560 | p.pack_double = function(num){ 561 | var sign = 0; 562 | if(num < 0){ 563 | sign = 1; 564 | num = -num; 565 | } 566 | var exp = Math.floor(Math.log(num) / Math.LN2); 567 | var frac0 = num / Math.pow(2, exp) - 1; 568 | var frac1 = Math.floor(frac0 * Math.pow(2, 52)); 569 | var b32 = Math.pow(2, 32); 570 | var h32 = (sign << 31) | ((exp+1023) << 20) | 571 | (frac1 / b32) & 0x0fffff; 572 | var l32 = frac1 % b32; 573 | return "\xcb" + this.pack_int32(h32) + this.pack_int32(l32); 574 | } 575 | 576 | p.pack_object = function(obj){ 577 | var str = ""; 578 | var length = 0; 579 | var ary = []; 580 | for(var prop in obj){ 581 | if(obj.hasOwnProperty(prop)){ 582 | length++; 583 | ary.push(this.pack(prop)); 584 | ary.push(this.pack(obj[prop])); 585 | } 586 | } 587 | if(length <= 0x0f){ 588 | return this.pack_uint8(0x80 + length) + ary.join(""); 589 | } 590 | else if(length <= 0xffff){ 591 | return "\xde" + this.pack_uint16(length) + ary.join(""); 592 | } 593 | else if(length <= 0xffffffff){ 594 | return "\xdf" + this.pack_uint32(length) + ary.join(""); 595 | } 596 | else{ 597 | throw new Error("invalid length"); 598 | } 599 | } 600 | 601 | p.pack_uint8 = function(num){ 602 | return String.fromCharCode(num); 603 | } 604 | 605 | p.pack_uint16 = function(num){ 606 | return String.fromCharCode(num >> 8, num & 0xff); 607 | } 608 | 609 | p.pack_uint32 = function(num){ 610 | var n = num & 0xffffffff; 611 | return String.fromCharCode( 612 | (n & 0xff000000) >>> 24, 613 | (n & 0x00ff0000) >>> 16, 614 | (n & 0x0000ff00) >>> 8, 615 | (n & 0x000000ff)); 616 | } 617 | 618 | p.pack_uint64 = function(num){ 619 | var high = num / Math.pow(2, 32); 620 | var low = num % Math.pow(2, 32); 621 | 622 | return String.fromCharCode( 623 | (high & 0xff000000) >>> 24, 624 | (high & 0x00ff0000) >>> 16, 625 | (high & 0x0000ff00) >>> 8, 626 | (high & 0x000000ff), 627 | (low & 0xff000000) >>> 24, 628 | (low & 0x00ff0000) >>> 16, 629 | (low & 0x0000ff00) >>> 8, 630 | (low & 0x000000ff)); 631 | } 632 | 633 | p.pack_int8 = function(num){ 634 | return String.fromCharCode(num & 0xff); 635 | } 636 | 637 | p.pack_int16 = function(num){ 638 | return String.fromCharCode((num & 0xff00) >> 8, num & 0xff); 639 | } 640 | 641 | p.pack_int32 = function(num){ 642 | return String.fromCharCode((num >>> 24) & 0xff, 643 | (num & 0x00ff0000) >>> 16, 644 | (num & 0x0000ff00) >>> 8, 645 | (num & 0x000000ff)); 646 | } 647 | 648 | p.pack_int64 = function(num){ 649 | var high = Math.floor(num / Math.pow(2, 32)); 650 | var low = num % Math.pow(2, 32); 651 | 652 | return String.fromCharCode( 653 | (high & 0xff000000) >>> 24, 654 | (high & 0x00ff0000) >>> 16, 655 | (high & 0x0000ff00) >>> 8, 656 | (high & 0x000000ff), 657 | (low & 0xff000000) >>> 24, 658 | (low & 0x00ff0000) >>> 16, 659 | (low & 0x0000ff00) >>> 8, 660 | (low & 0x000000ff)); 661 | } 662 | } 663 | --------------------------------------------------------------------------------