├── 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 |
--------------------------------------------------------------------------------