1- /*!{id:msgpack.js,ver:1.01 ,license:"MIT",author:"uupaa.js@gmail .com"}*/
1+ /*!{id:msgpack.js,ver:1.02 ,license:"MIT",author:"uupaa.js@gmail .com"}*/
22
33// === msgpack ===
44// MessagePack -> http://msgpack.sourceforge.net/
@@ -24,7 +24,7 @@ var _ie = /MSIE/.test(navigator.userAgent),
2424 _num2b64 = ( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
2525 "abcdefghijklmnopqrstuvwxyz0123456789+/" ) . split ( "" ) ,
2626 _sign = { 8 : 0x80 , 16 : 0x8000 , 32 : 0x80000000 } ,
27- _split8char = / . { 8 } / g;
27+ _8bits = / [ 0 1 ] { 8 } / g;
2828
2929// for WebWorkers Code Block
3030self . importScripts && ( onmessage = function ( event ) {
@@ -42,10 +42,21 @@ function msgpackpack(data, // @param Mix:
4242 // [1][mix to String] msgpack.pack({}, true) -> "..."
4343 // [2][mix to ByteArray] msgpack.pack({}) -> [...]
4444
45- var byteArray = encode ( [ ] , data ) ;
45+ var byteArray = encode ( [ ] , data ) , rv , i , iz , num2bin = _num2bin ;
4646
47- return toString ? String . fromCharCode . apply ( null , byteArray ) // toString
48- : byteArray ;
47+ if ( toString ) {
48+ // http://d.hatena.ne.jp/uupaa/20101128
49+ try {
50+ return String . fromCharCode . apply ( this , byteArray ) ; // toString
51+ } catch ( err ) {
52+ ; // avoid "Maximum call stack size exceeded"
53+ }
54+ for ( rv = [ ] , i = 0 , iz = byteArray . length ; i < iz ; ++ i ) {
55+ rv [ i ] = num2bin [ byteArray [ i ] ] ;
56+ }
57+ return rv . join ( "" ) ;
58+ }
59+ return byteArray ;
4960}
5061
5162// msgpack.unpack
@@ -62,7 +73,7 @@ function msgpackunpack(data) { // @param BinaryString/ByteArray:
6273// inner - encoder
6374function encode ( rv , // @param ByteArray: result
6475 mix ) { // @param Mix: source data
65- var size = 0 , i = 0 , iz , c , ary , hash ,
76+ var size = 0 , i = 0 , iz , c , hash , pos ,
6677 high , low , i64 = 0 , sign , exp , frac ;
6778
6879 if ( mix == null ) { // null or undefined
@@ -77,7 +88,7 @@ function encode(rv, // @param ByteArray: result
7788 rv . push ( 0xcb , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ) ; // quiet NaN
7889 } else if ( mix === Infinity ) {
7990 rv . push ( 0xcb , 0x7f , 0xf0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ) ; // positive infinity
80- } else if ( Math . floor ( mix ) === mix ) {
91+ } else if ( Math . floor ( mix ) === mix ) { // int or uint
8192 if ( mix < 0 ) { // int
8293 if ( mix >= - 32 ) { // negative fixnum
8394 rv . push ( 0xe0 + mix + 32 ) ;
@@ -132,30 +143,52 @@ function encode(rv, // @param ByteArray: result
132143 toString ( 2 ) . slice ( 1 ) ;
133144
134145 // exp is between 1 and 2047. make it 11 bits
135- exp = ( "000000000" + exp . toString ( 2 ) ) . slice ( - 11 ) ;
136-
137- ary = ( + sign + exp + frac ) . match ( _split8char ) ;
146+ // http://d.hatena.ne.jp/uupaa/20101128
147+ if ( ! sign ) {
148+ ary = ( ( exp + 4096 ) . toString ( 2 ) . slice ( 1 ) + frac ) . match ( _8bits ) ;
149+ } else {
150+ ary = ( ( exp + 2048 ) . toString ( 2 ) + frac ) . match ( _8bits ) ;
151+ }
138152 rv . push ( 0xcb , hash [ ary [ 0 ] ] , hash [ ary [ 1 ] ] ,
139153 hash [ ary [ 2 ] ] , hash [ ary [ 3 ] ] ,
140154 hash [ ary [ 4 ] ] , hash [ ary [ 5 ] ] ,
141155 hash [ ary [ 6 ] ] , hash [ ary [ 7 ] ] ) ;
142156 }
143157 break ;
144158 case "string" :
159+ // http://d.hatena.ne.jp/uupaa/20101128
160+ iz = mix . length ;
161+ pos = rv . length ; // keep rewrite position
162+
163+ // set default type [0xa0 + ASCIIString.length]
164+ rv . push ( 0xa0 + iz ) ;
165+
145166 // utf8.encode
146- for ( ary = [ ] , iz = mix . length , i = 0 ; i < iz ; ++ i ) {
167+ for ( i = 0 ; i < iz ; ++ i ) {
147168 c = mix . charCodeAt ( i ) ;
148169 if ( c < 0x80 ) { // ASCII(0x00 ~ 0x7f)
149- ary . push ( c & 0x7f ) ;
170+ rv . push ( c & 0x7f ) ;
150171 } else if ( c < 0x0800 ) {
151- ary . push ( ( ( c >>> 6 ) & 0x1f ) | 0xc0 , ( c & 0x3f ) | 0x80 ) ;
172+ rv . push ( ( ( c >>> 6 ) & 0x1f ) | 0xc0 , ( c & 0x3f ) | 0x80 ) ;
152173 } else if ( c < 0x10000 ) {
153- ary . push ( ( ( c >>> 12 ) & 0x0f ) | 0xe0 ,
174+ rv . push ( ( ( c >>> 12 ) & 0x0f ) | 0xe0 ,
154175 ( ( c >>> 6 ) & 0x3f ) | 0x80 , ( c & 0x3f ) | 0x80 ) ;
155176 }
156177 }
157- setType ( rv , 32 , ary . length , [ 0xa0 , 0xda , 0xdb ] ) ;
158- Array . prototype . push . apply ( rv , ary ) ;
178+ size = rv . length - pos - 1 ; // -1 = default type(0xa0 + length)
179+
180+ // rewrite string type.
181+ if ( iz !== size ) {
182+ // has none ascii string or length >= 32
183+ if ( size < 32 ) {
184+ rv [ pos ] = 0xa0 + size ;
185+ } else if ( size < 0x10000 ) { // 16
186+ rv . splice ( pos , 1 , 0xda , size >> 8 , size & 0xff ) ;
187+ } else if ( size < 0x100000000 ) { // 32
188+ rv . splice ( pos , 1 , 0xdb , size >>> 24 , ( size >> 16 ) & 0xff ,
189+ ( size >> 8 ) & 0xff , size & 0xff ) ;
190+ }
191+ }
159192 break ;
160193 default : // array or hash
161194 if ( Object . prototype . toString . call ( mix ) === "[object Array]" ) { // array
0 commit comments