├── .vscode └── launch.json ├── README.md ├── netutils.js ├── proto └── base.sproto ├── protocol.spb ├── sproto.js └── test.js /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "启动程序", 11 | "program": "${workspaceFolder}/test_c2s_all.js" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | sprotojs 2 | ======= 3 | use sproto in javascript, you can find example in test.js, protocol.spb is generate by proto/*.sproto 4 | 5 | 6 | Support Types 7 | ======= 8 | 9 | * **string** : string 10 | * **binary** : binary string (it's a sub type of string) 11 | * **integer** : integer, the max length of an integer is signed 52bit [the IEEE 754 standard]. It can be a fixed-point number with specified precision. 12 | * **double** : double precision floating-point number, satisfy [the IEEE 754 standard](https://en.wikipedia.org/wiki/Double-precision_floating-point_format). 13 | * **boolean** : true or false 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /netutils.js: -------------------------------------------------------------------------------- 1 | var netutils = (function() { 2 | var t = {}; 3 | 4 | t.array2arraybuffer = function(array) { 5 | var b = new ArrayBuffer(array.length); 6 | var v = new DataView(b, 0); 7 | for (var i = 0; i < array.length; i++) { 8 | v.setUint8(i, array[i]); 9 | } 10 | return b; 11 | } 12 | 13 | t.arraybuffer2array = function(buffer) { 14 | var v = new DataView(buffer, 0); 15 | var a = new Array(); 16 | for (var i = 0; i < v.byteLength; i++) { 17 | a[i] = v.getUint8(i); 18 | } 19 | return a; 20 | } 21 | 22 | t.string2utf8 = function(str) { 23 | var back = []; 24 | var byteSize = 0; 25 | 26 | for (var i = 0; i < str.length; i++) { 27 | var code = str.charCodeAt(i); 28 | if (0x00 <= code && code <= 0x7f) { 29 | byteSize += 1; 30 | back.push(code); 31 | } else if (0x80 <= code && code <= 0x7ff) { 32 | byteSize += 2; 33 | back.push((192 | (31 & (code >> 6)))); 34 | back.push((128 | (63 & code))) 35 | } else if ((0x800 <= code && code <= 0xd7ff) || (0xe000 <= code && code <= 0xffff)) { 36 | byteSize += 3; 37 | back.push((224 | (15 & (code >> 12)))); 38 | back.push((128 | (63 & (code >> 6)))); 39 | back.push((128 | (63 & code))) 40 | } 41 | } 42 | 43 | for (i = 0; i < back.length; i++) { 44 | back[i] &= 0xff; 45 | } 46 | 47 | return back; 48 | }; 49 | 50 | t.utf82string = function(arr) { 51 | if (typeof arr === 'string') { 52 | return null; 53 | } 54 | 55 | var UTF = ''; 56 | for (var i = 0; i < arr.length; i++) { 57 | if (arr[i] == null) { 58 | break; 59 | } 60 | 61 | var one = arr[i].toString(2); 62 | var v = one.match(/^1+?(?=0)/); 63 | if (v && one.length == 8) { 64 | var bytesLength = v[0].length; 65 | var store = arr[i].toString(2).slice(7 - bytesLength); 66 | 67 | for (var st = 1; st < bytesLength; st++) { 68 | store += arr[st + i].toString(2).slice(2); 69 | } 70 | UTF += String.fromCharCode(parseInt(store, 2)); 71 | i += bytesLength - 1; 72 | } else { 73 | UTF += String.fromCharCode(arr[i]); 74 | } 75 | } 76 | return UTF; 77 | }; 78 | 79 | t.arrayconcat = function(a1, a2) { 80 | var b = new Array(); 81 | 82 | for (var i = 0; i < a1.length; i++) { 83 | b[i] = a1[i]; 84 | } 85 | 86 | for (var j = a1.length; j < a1.length + a2.length; j++) { 87 | b[j] = a2[j - a1.length]; 88 | } 89 | 90 | return b; 91 | }; 92 | 93 | return t; 94 | }()); 95 | 96 | // export default netutils; 97 | module.exports = netutils; -------------------------------------------------------------------------------- /proto/base.sproto: -------------------------------------------------------------------------------- 1 | .HeaderPack { 2 | protoId 0 : integer 3 | requestId 1 : integer 4 | ec 2 : integer 5 | } 6 | 7 | .BasicType { 8 | number 0 : integer 9 | string 1 : string 10 | bool 2 : boolean 11 | numberList 3 : *integer 12 | } -------------------------------------------------------------------------------- /protocol.spb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangshiqian1214/sproto-js/435117b3b33ced6f90822651cad6f3f22a60aa8d/protocol.spb -------------------------------------------------------------------------------- /sproto.js: -------------------------------------------------------------------------------- 1 | // sproto.js 解析 2 | // import netutils from "netutils" 3 | var netutils = require("./netutils"); 4 | 5 | var sproto = (function() { 6 | var t = {}; 7 | var host = {}; 8 | var header_tmp = {}; 9 | 10 | // 常量定义 11 | var SPROTO_REQUEST = 0; 12 | var SPROTO_RESPONSE = 1; 13 | 14 | // type (sproto_arg.type) 15 | var SPROTO_TINTEGER = 0; 16 | var SPROTO_TBOOLEAN = 1; 17 | var SPROTO_TSTRING = 2; 18 | var SPROTO_TDOUBLE = 3; 19 | var SPROTO_TSTRUCT = 4; 20 | 21 | // sub type of string (sproto_arg.extra) 22 | var SPROTO_TSTRING_STRING = 0; 23 | var SPROTO_TSTRING_BINARY = 1; 24 | 25 | var SPROTO_CB_ERROR = -1; 26 | var SPROTO_CB_NIL = -2; 27 | var SPROTO_CB_NOARRAY = -3; 28 | 29 | var SPROTO_TARRAY = 0x80; 30 | var CHUNK_SIZE = 1000; 31 | var SIZEOF_LENGTH = 4; 32 | var SIZEOF_HEADER = 2; 33 | var SIZEOF_FIELD = 2; 34 | 35 | var ENCODE_BUFFERSIZE = 2050; 36 | var ENCODE_MAXSIZE = 0x1000000; 37 | var ENCODE_DEEPLEVEL = 64; 38 | 39 | // js中只long只能表示到2^52-1, 0xFFFFFFFFFFFFF表示 40 | function expand64(v) { 41 | var value = v; 42 | if ((value & 0x80000000) != 0) { 43 | value = 0x0000000000000 + (value & 0xFFFFFFFF); 44 | } 45 | return value; 46 | } 47 | 48 | function hi_low_uint64(low, hi) { 49 | var value = (hi & 0xFFFFFFFF) * 0x100000000 + low; 50 | return value; 51 | } 52 | 53 | // 64位整数位移操作会将64位截成32位有符号整数 54 | function uint64_lshift(num, offset) { 55 | return num * Math.pow(2, offset); 56 | } 57 | 58 | function uint64_rshift(num, offset) { 59 | return Math.floor(num / Math.pow(2, offset)); 60 | } 61 | 62 | function toword(stream) { 63 | return (stream[0] & 0xff) | (stream[1] & 0xff) << 8; 64 | }; 65 | 66 | function todword(stream) { 67 | return ((stream[0] & 0xff) | (stream[1] & 0xff) << 8 | (stream[2] & 0xff) << 16 | (stream[3] & 0xff) << 24) >>> 0; 68 | }; 69 | 70 | function count_array(stream) { 71 | var length = todword(stream); 72 | var n = 0; 73 | stream = stream.slice(SIZEOF_LENGTH); 74 | while (length > 0) { 75 | var nsz; 76 | if (length < SIZEOF_LENGTH) { 77 | return -1; 78 | } 79 | nsz = todword(stream); 80 | nsz += SIZEOF_LENGTH; 81 | if (nsz > length) { 82 | return -1; 83 | } 84 | ++n; 85 | stream = stream.slice(nsz); 86 | length -= nsz; 87 | } 88 | return n; 89 | }; 90 | 91 | function struct_field(stream, sz) { 92 | var field, fn, header, i; 93 | if (sz < SIZEOF_LENGTH) { 94 | return -1; 95 | } 96 | 97 | fn = toword(stream); 98 | header = SIZEOF_HEADER + SIZEOF_FIELD * fn; 99 | if (sz < header) { 100 | return -1; 101 | } 102 | 103 | field = stream.slice(SIZEOF_HEADER); 104 | sz -= header; 105 | stream = stream.slice(header); 106 | for (i = 0; i < fn; i++) { 107 | var value = toword(field.slice(i * SIZEOF_FIELD + SIZEOF_HEADER)); 108 | var dsz; 109 | if (value != 0) { 110 | continue; 111 | } 112 | 113 | if (sz < SIZEOF_LENGTH) { 114 | return -1; 115 | } 116 | 117 | dsz = todword(stream); 118 | if (sz < SIZEOF_LENGTH + dsz) { 119 | return -1; 120 | } 121 | 122 | stream = stream.slice(SIZEOF_LENGTH + dsz); 123 | sz -= SIZEOF_LENGTH + dsz; 124 | } 125 | return fn; 126 | }; 127 | 128 | // stream 是arraybuffer 129 | function import_string(s, stream) { 130 | var sz = todword(stream); 131 | var buffer = ""; 132 | var arr = stream.slice(SIZEOF_LENGTH, SIZEOF_LENGTH + sz); 133 | for (var i = 0; i < arr.length; i++) { 134 | buffer += String.fromCharCode(arr[i]); 135 | } 136 | return buffer; 137 | }; 138 | 139 | function calc_pow(base, n) { 140 | if (n == 0) return 1; 141 | var r = calc_pow(base * base, Math.floor(n / 2)); 142 | if ((n & 1) != 0) { 143 | r *= base; 144 | } 145 | return r; 146 | }; 147 | 148 | function import_field(s, f, stream) { 149 | var sz, result, fn; 150 | var array = 0; 151 | var tag = -1; 152 | f.tag = -1; 153 | f.type = -1; 154 | f.name = null; 155 | f.st = null; 156 | f.key = -1; 157 | f.extra = 0; 158 | 159 | sz = todword(stream); 160 | stream = stream.slice(SIZEOF_LENGTH); 161 | result = stream.slice(sz); 162 | fn = struct_field(stream, sz); 163 | if (fn < 0) return null; 164 | 165 | stream = stream.slice(SIZEOF_HEADER); 166 | for (var i = 0; i < fn; i++) { 167 | var value; 168 | ++tag; 169 | value = toword(stream.slice(SIZEOF_FIELD * i)); 170 | if (value & 1 != 0) { 171 | tag += Math.floor(value / 2); 172 | continue; 173 | } 174 | 175 | if (tag == 0) { 176 | if (value != 0) return null; 177 | f.name = import_string(s, stream.slice(fn * SIZEOF_FIELD)); 178 | continue; 179 | } 180 | 181 | if (value == 0) return null; 182 | value = Math.floor(value / 2) - 1; 183 | switch (tag) { 184 | case 1: 185 | if (value >= SPROTO_TSTRUCT) { 186 | return null; 187 | } 188 | f.type = value; 189 | break; 190 | case 2: 191 | if (f.type == SPROTO_TINTEGER) { 192 | f.extra = calc_pow(10, value); 193 | } else if (f.type == SPROTO_TSTRING) { 194 | f.extra = value; 195 | } else { 196 | if (value >= s.type_n) { 197 | return null; 198 | } 199 | 200 | if (f.type >= 0) { 201 | return null; 202 | } 203 | 204 | f.type = SPROTO_TSTRUCT; 205 | f.st = value; 206 | } 207 | break; 208 | case 3: 209 | f.tag = value; 210 | break; 211 | case 4: 212 | if (value != 0) { 213 | array = SPROTO_TARRAY; 214 | } 215 | break; 216 | case 5: 217 | f.key = value; 218 | break; 219 | default: 220 | return null; 221 | } 222 | } 223 | if (f.tag < 0 || f.type < 0 || f.name == null) { 224 | return null; 225 | } 226 | f.type |= array; 227 | return result; 228 | }; 229 | 230 | function import_type(s, t, stream) { 231 | var result, fn, n, maxn, last; 232 | var sz = todword(stream); 233 | stream = stream.slice(SIZEOF_LENGTH); 234 | result = stream.slice(sz); 235 | fn = struct_field(stream, sz); 236 | if (fn <= 0 || fn > 2) { 237 | return null; 238 | } 239 | 240 | for (var i = 0; i < fn * SIZEOF_FIELD; i += SIZEOF_FIELD) { 241 | var v = toword(stream.slice(SIZEOF_HEADER + i)); 242 | if (v != 0) return null; 243 | } 244 | 245 | t.name = null; 246 | t.n = 0; 247 | t.base = 0; 248 | t.maxn = 0; 249 | t.f = null; 250 | stream = stream.slice(SIZEOF_HEADER + fn * SIZEOF_FIELD); 251 | t.name = import_string(s, stream); 252 | 253 | if (fn == 1) { 254 | return result; 255 | } 256 | 257 | stream = stream.slice(todword(stream) + SIZEOF_LENGTH); 258 | n = count_array(stream); 259 | if (n < 0) { 260 | return null; 261 | } 262 | 263 | stream = stream.slice(SIZEOF_LENGTH); 264 | maxn = n; 265 | last = -1; 266 | t.n = n; 267 | t.f = new Array(); 268 | for (var i = 0; i < n; i++) { 269 | var tag; 270 | t.f[i] = new Object(); 271 | var f = t.f[i]; 272 | stream = import_field(s, f, stream); 273 | if (stream == null) { 274 | return null; 275 | } 276 | 277 | tag = f.tag; 278 | if (tag <= last) { 279 | return null; 280 | } 281 | if (tag > last + 1) { 282 | ++maxn; 283 | } 284 | last = tag; 285 | } 286 | t.maxn = maxn; 287 | t.base = t.f[0].tag; 288 | n = t.f[n - 1].tag - t.base + 1; 289 | if (n != t.n) { 290 | t.base = -1; 291 | } 292 | return result; 293 | } 294 | 295 | /* 296 | .protocol { 297 | name 0 : string 298 | tag 1 : integer 299 | request 2 : integer 300 | response 3 : integer 301 | } 302 | */ 303 | function import_protocol(s, p, stream) { 304 | var result, sz, fn, tag; 305 | sz = todword(stream); 306 | stream = stream.slice(SIZEOF_LENGTH); 307 | result = stream.slice(sz); 308 | fn = struct_field(stream, sz); 309 | stream = stream.slice(SIZEOF_HEADER); 310 | p.name = null; 311 | p.tag = -1; 312 | p.p = new Array(); 313 | p.p[SPROTO_REQUEST] = null; 314 | p.p[SPROTO_RESPONSE] = null; 315 | p.confirm = 0; 316 | tag = 0; 317 | for (var i = 0; i < fn; i++, tag++) { 318 | var value = toword(stream.slice(SIZEOF_FIELD * i)); 319 | if (value & 1 != 0) { 320 | tag += Math.floor(value - 1) / 2; 321 | continue; 322 | } 323 | value = Math.floor(value / 2) - 1; 324 | switch (i) { 325 | case 0: 326 | if (value != -1) { 327 | return null; 328 | } 329 | p.name = import_string(s, stream.slice(SIZEOF_FIELD * fn)); 330 | break; 331 | case 1: 332 | if (value < 0) { 333 | return null; 334 | } 335 | p.tag = value; 336 | break; 337 | case 2: 338 | if (value < 0 || value >= s.type_n) 339 | return null; 340 | p.p[SPROTO_REQUEST] = s.type[value]; 341 | break; 342 | case 3: 343 | if (value < 0 || value > s.type_n) 344 | return null; 345 | p.p[SPROTO_RESPONSE] = s.type[value]; 346 | break; 347 | case 4: 348 | p.confirm = value; 349 | break; 350 | default: 351 | return null; 352 | } 353 | } 354 | 355 | if (p.name == null || p.tag < 0) { 356 | return null; 357 | } 358 | return result; 359 | } 360 | 361 | function create_from_bundle(s, stream, sz) { 362 | var content, typedata, protocoldata; 363 | var fn = struct_field(stream, sz); 364 | if (fn < 0 || fn > 2) 365 | return null; 366 | stream = stream.slice(SIZEOF_HEADER); 367 | content = stream.slice(fn * SIZEOF_FIELD); 368 | 369 | for (var i = 0; i < fn; i++) { 370 | var value = toword(stream.slice(i * SIZEOF_FIELD)); 371 | if (value != 0) { 372 | return null; 373 | } 374 | 375 | var n = count_array(content); 376 | if (n < 0) { 377 | return null; 378 | } 379 | 380 | if (i == 0) { 381 | typedata = content.slice(SIZEOF_LENGTH); 382 | s.type_n = n; 383 | s.type = new Array(); 384 | } else { 385 | protocoldata = content.slice(SIZEOF_LENGTH); 386 | s.protocol_n = n; 387 | s.proto = new Array(); 388 | } 389 | content = content.slice(todword(content) + SIZEOF_LENGTH); 390 | } 391 | 392 | for (var i = 0; i < s.type_n; i++) { 393 | s.type[i] = new Object(); 394 | typedata = import_type(s, s.type[i], typedata); 395 | if (typedata == null) { 396 | return null; 397 | } 398 | } 399 | 400 | for (var i = 0; i < s.protocol_n; i++) { 401 | s.proto[i] = new Object(); 402 | protocoldata = import_protocol(s, s.proto[i], protocoldata); 403 | if (protocoldata == null) { 404 | return null; 405 | } 406 | } 407 | 408 | return s; 409 | }; 410 | 411 | function sproto_dump(s) { 412 | console.log(s); 413 | }; 414 | 415 | // query 416 | function sproto_prototag(sp, name) { 417 | for (var i = 0; i < sp.protocol_n; i++) { 418 | if (name == sp.proto[i].name) { 419 | return sp.proto[i].tag; 420 | } 421 | } 422 | return -1; 423 | } 424 | 425 | // 二分查找 426 | function query_proto(sp, tag) { 427 | var begin = 0; 428 | var end = sp.protocol_n; 429 | while (begin < end) { 430 | var mid = Math.floor((begin + end) / 2); 431 | var t = sp.proto[mid].tag; 432 | if (t == tag) { 433 | return sp.proto[mid]; 434 | } 435 | 436 | if (tag > t) { 437 | begin = mid + 1; 438 | } else { 439 | end = mid; 440 | } 441 | } 442 | return null; 443 | } 444 | 445 | function sproto_protoquery(sp, proto, what) { 446 | var p = null; 447 | if (what < 0 || what > 1) { 448 | return null; 449 | } 450 | 451 | p = query_proto(sp, proto); 452 | if (p) { 453 | return p.p[what]; 454 | } 455 | return null; 456 | } 457 | 458 | function sproto_protoresponse(sp, proto) { 459 | var p = query_proto(sp, proto); 460 | return (p != null && (p.p[SPROTO_RESPONSE] || p.confirm)); 461 | } 462 | 463 | function sproto_protoname(sp, proto) { 464 | var p = query_proto(sp, proto); 465 | if (p) { 466 | return p.name; 467 | } 468 | return null; 469 | } 470 | 471 | function sproto_type(sp, type_name) { 472 | for (var i = 0; i < sp.type_n; i++) { 473 | if (type_name == sp.type[i].name) { 474 | return sp.type[i]; 475 | } 476 | } 477 | return null; 478 | } 479 | 480 | function sproto_name(st) { 481 | return st.name; 482 | } 483 | 484 | function findtag(st, tag) { 485 | var begin, end; 486 | if (st.base >= 0) { 487 | tag -= st.base; 488 | if (tag < 0 || tag > st.n) { 489 | return null; 490 | } 491 | return st.f[tag]; 492 | } 493 | 494 | begin = 0; 495 | end = st.n; 496 | while (begin < end) { 497 | var mid = Math.floor((begin + end) / 2); 498 | var f = st.f[mid]; 499 | var t = f.tag; 500 | if (t == tag) { 501 | return f; 502 | } 503 | if (tag > t) { 504 | begin = mid + 1; 505 | } else { 506 | end = mid; 507 | } 508 | } 509 | return null; 510 | } 511 | 512 | function fill_size(data, data_idx, sz) { 513 | data[data_idx] = sz & 0xff; 514 | data[data_idx + 1] = (sz >> 8) & 0xff; 515 | data[data_idx + 2] = (sz >> 16) & 0xff; 516 | data[data_idx + 3] = (sz >> 24) & 0xff; 517 | return sz + SIZEOF_LENGTH; 518 | } 519 | 520 | function encode_integer(v, data, data_idx, size) { 521 | data[data_idx + 4] = v & 0xff; 522 | data[data_idx + 5] = (v >> 8) & 0xff; 523 | data[data_idx + 6] = (v >> 16) & 0xff; 524 | data[data_idx + 7] = (v >> 24) & 0xff; 525 | return fill_size(data, data_idx, 4); 526 | } 527 | 528 | function encode_uint64(v, data, data_idx, size) { 529 | data[data_idx + 4] = v & 0xff; 530 | data[data_idx + 5] = uint64_rshift(v, 8) & 0xff; 531 | data[data_idx + 6] = uint64_rshift(v, 16) & 0xff; 532 | data[data_idx + 7] = uint64_rshift(v, 24) & 0xff; 533 | data[data_idx + 8] = uint64_rshift(v, 32) & 0xff; 534 | data[data_idx + 9] = uint64_rshift(v, 40) & 0xff; 535 | data[data_idx + 10] = uint64_rshift(v, 48) & 0xff; 536 | data[data_idx + 11] = uint64_rshift(v, 56) & 0xff; 537 | return fill_size(data, data_idx, 8); 538 | } 539 | 540 | function dec_to_bin_tail(dec, pad){ 541 | var bin = ""; 542 | var i; 543 | for (i = 0; i < pad; i++) 544 | { 545 | dec *= 2; 546 | if (dec>= 1) 547 | { 548 | dec -= 1; 549 | bin += "1"; 550 | } 551 | else 552 | { 553 | bin += "0"; 554 | } 555 | } 556 | return bin; 557 | } 558 | 559 | function dec_to_bin_head(data, len){ 560 | var result = ""; 561 | for (var i=len-1; i>=0; i--){ 562 | var mask = 1 << i; 563 | if ((mask & data) == 0){ 564 | result += "0"; 565 | } else { 566 | result += "1"; 567 | } 568 | } 569 | return result; 570 | } 571 | 572 | function get_double_hex(decString){ 573 | var sign; 574 | var signString; 575 | var exponent; 576 | var decValue = parseFloat(Math.abs(decString)); 577 | if (decString.toString().charAt(0) == '-'){ 578 | sign = 1; 579 | signString = "1"; 580 | } else { 581 | sign = 0; 582 | signString = "0"; 583 | } 584 | if (decValue == 0){ 585 | exponent = 0; 586 | } else { 587 | exponent = 1023; 588 | if (decValue >= 2){ 589 | while(decValue >= 2){ 590 | exponent++; 591 | decValue /= 2; 592 | } 593 | } else if (decValue < 1){ 594 | while (decValue<1){ 595 | exponent--; 596 | decValue *= 2; 597 | if (exponent == 0){ 598 | break; 599 | } 600 | } 601 | } 602 | if (exponent != 0) decValue -= 1; else decValue /= 2; 603 | var fractionString = dec_to_bin_tail(decValue, 52); 604 | var exponentString = dec_to_bin_head(exponent, 11); 605 | var doubleBinStr = signString + exponentString + fractionString; 606 | var doubleHexStr = ""; 607 | for (let i=0,j=0; i<8;i++,j+=8){ 608 | let m = 3 - (j%4); 609 | let hexUnit = doubleBinStr[j] * Math.pow(2, m) + doubleBinStr[j+1] * Math.pow(2, m-1) + doubleBinStr[j+2]*Math.pow(2, m-2) + doubleBinStr[j+3]*Math.pow(2, m-3); 610 | let hexDecade = doubleBinStr[j+4]*Math.pow(2,m) + doubleBinStr[j+5]*Math.pow(2,m-1) + doubleBinStr[j+6]*Math.pow(2,m-2) + doubleBinStr[j+7]*Math.pow(2,m-3); 611 | doubleHexStr = doubleHexStr + hexUnit.toString(16) + hexDecade.toString(16); 612 | } 613 | return doubleHexStr; 614 | } 615 | } 616 | 617 | function double_to_binary(v, data, data_idx) 618 | { 619 | var str = Number(v).toString(); 620 | var hexStr = get_double_hex(str); 621 | var arr = []; 622 | for(let i=0,j=0;i<8;i++,j+=2) 623 | { 624 | let dec = parseInt(hexStr[j],16)*16 + parseInt(hexStr[j+1],16); 625 | arr.push(dec); 626 | } 627 | arr.reverse(); 628 | for (let i=0; i<8; i++){ 629 | let dec = arr[i]; 630 | data[data_idx+i+4] = dec; 631 | } 632 | return fill_size(data, data_idx, 8); 633 | } 634 | 635 | function binary_to_double(data) { 636 | let buf = new Uint8Array(data); 637 | // buf.reverse(); 638 | let buf64 = new Float64Array(buf.buffer); 639 | return buf64[0]; 640 | } 641 | 642 | function encode_object(cb, args, data, data_idx) { 643 | var sz; 644 | args.buffer = data; 645 | args.buffer_idx = data_idx + SIZEOF_LENGTH; 646 | sz = cb(args); 647 | if (sz < 0) { 648 | if (sz == SPROTO_CB_NIL) { 649 | return 0; 650 | } 651 | return -1; 652 | } 653 | return fill_size(data, data_idx, sz); 654 | } 655 | 656 | function uint32_to_uint64(negative, buffer, buffer_idx) { 657 | if (negative) { 658 | buffer[buffer_idx + 4] = 0xff; 659 | buffer[buffer_idx + 5] = 0xff; 660 | buffer[buffer_idx + 6] = 0xff; 661 | buffer[buffer_idx + 7] = 0xff; 662 | } else { 663 | buffer[buffer_idx + 4] = 0; 664 | buffer[buffer_idx + 5] = 0; 665 | buffer[buffer_idx + 6] = 0; 666 | buffer[buffer_idx + 7] = 0; 667 | } 668 | } 669 | 670 | function encode_integer_array(cb, args, buffer, buffer_idx, noarray) { 671 | var intlen, index; 672 | var header_idx = buffer_idx; 673 | 674 | buffer_idx++; 675 | intlen = 4; 676 | index = 1; 677 | noarray.value = 0; 678 | 679 | for (;;) { 680 | var sz; 681 | args.value = null; 682 | args.length = 8; 683 | args.index = index; 684 | sz = cb(args); 685 | if (sz <= 0) { 686 | if (sz == SPROTO_CB_NIL) { 687 | break; 688 | } 689 | 690 | if (sz == SPROTO_CB_NOARRAY) { 691 | noarray.value = 1; 692 | break; 693 | } 694 | 695 | return null; 696 | } 697 | 698 | if (sz == 4) { 699 | var v = args.value; 700 | buffer[buffer_idx] = v & 0xff; 701 | buffer[buffer_idx + 1] = (v >> 8) & 0xff; 702 | buffer[buffer_idx + 2] = (v >> 16) & 0xff; 703 | buffer[buffer_idx + 3] = (v >> 24) & 0xff; 704 | 705 | if (intlen == 8) { 706 | uint32_to_uint64(v & 0x80000000, buffer, buffer_idx); 707 | } 708 | } else { 709 | var v; 710 | if (sz != 8) { 711 | return null; 712 | } 713 | 714 | if (intlen == 4) { 715 | buffer_idx += (index - 1) * 4; 716 | for (var i = index - 2; i >= 0; i--) { 717 | var negative; 718 | for (var j = (1 + i * 8); j < (1 + i * 8 + 4); j++) { 719 | buffer[header_idx + j] = buffer[header_idx + j - i * 4]; 720 | } 721 | negative = buffer[header_idx + 1 + i * 8 + 3] & 0x80; 722 | uint32_to_uint64(negative, buffer, buffer_idx + 1 + i * 8); 723 | } 724 | intlen = 8; 725 | } 726 | 727 | v = args.value; 728 | buffer[buffer_idx] = v & 0xff; 729 | buffer[buffer_idx + 1] = uint64_rshift(v, 8) & 0xff; 730 | buffer[buffer_idx + 2] = uint64_rshift(v, 16) & 0xff; 731 | buffer[buffer_idx + 3] = uint64_rshift(v, 24) & 0xff; 732 | buffer[buffer_idx + 4] = uint64_rshift(v, 32) & 0xff; 733 | buffer[buffer_idx + 5] = uint64_rshift(v, 40) & 0xff; 734 | buffer[buffer_idx + 6] = uint64_rshift(v, 48) & 0xff; 735 | buffer[buffer_idx + 7] = uint64_rshift(v, 56) & 0xff; 736 | } 737 | 738 | buffer_idx += intlen; 739 | index++; 740 | } 741 | 742 | if (buffer_idx == header_idx + 1) { 743 | return header_idx; 744 | } 745 | buffer[header_idx] = intlen & 0xff; 746 | return buffer_idx; 747 | } 748 | 749 | function encode_array(cb, args, data, data_idx) { 750 | var sz; 751 | var buffer = data; 752 | var buffer_idx = data_idx + SIZEOF_LENGTH; 753 | switch (args.type) { 754 | case SPROTO_TINTEGER: 755 | var noarray = {}; 756 | noarray.value = 0; 757 | buffer_idx = encode_integer_array(cb, args, buffer, buffer_idx, noarray); 758 | if (buffer_idx == null) { 759 | return -1; 760 | } 761 | 762 | if (noarray.value != 0) { 763 | return 0; 764 | } 765 | break; 766 | case SPROTO_TBOOLEAN: 767 | args.index = 1; 768 | for (;;) { 769 | var v = 0; 770 | args.value = v; 771 | args.length = 4; 772 | sz = cb(args); 773 | if (sz < 0) { 774 | if (sz == SPROTO_CB_NIL) 775 | break; 776 | if (sz == SPROTO_CB_NOARRAY) 777 | return 0; 778 | return -1; 779 | } 780 | 781 | if (sz < 1) { 782 | return -1; 783 | } 784 | 785 | buffer[buffer_idx] = (args.value == 1) ? 1 : 0; 786 | buffer_idx++; 787 | ++args.index; 788 | } 789 | break; 790 | default: 791 | args.index = 1; 792 | for (;;) { 793 | args.buffer = buffer; 794 | args.buffer_idx = buffer_idx + SIZEOF_LENGTH; 795 | sz = cb(args); 796 | if (sz < 0) { 797 | if (sz == SPROTO_CB_NIL) { 798 | break; 799 | } 800 | 801 | if (sz == SPROTO_CB_NOARRAY) { 802 | return 0; 803 | } 804 | 805 | return -1; 806 | } 807 | 808 | fill_size(buffer, buffer_idx, sz); 809 | buffer_idx += SIZEOF_LENGTH + sz; 810 | ++args.index; 811 | } 812 | break; 813 | } 814 | 815 | sz = buffer_idx - (data_idx + SIZEOF_LENGTH); 816 | // if (sz == 0) { 817 | // return 0; 818 | // } 819 | 820 | return fill_size(buffer, data_idx, sz); 821 | } 822 | 823 | function decode_array_object(cb, args, stream, sz) { 824 | var hsz; 825 | var index = 1; 826 | while (sz > 0) { 827 | if (sz < SIZEOF_LENGTH) { 828 | return -1; 829 | } 830 | 831 | hsz = todword(stream); 832 | stream = stream.slice(SIZEOF_LENGTH); 833 | sz -= SIZEOF_LENGTH; 834 | if (hsz > sz) { 835 | return -1; 836 | } 837 | 838 | args.index = index; 839 | args.value = stream; 840 | args.length = hsz; 841 | if (cb(args) != 0) { 842 | return -1; 843 | } 844 | 845 | sz -= hsz; 846 | stream = stream.slice(hsz); 847 | ++index; 848 | } 849 | return 0; 850 | } 851 | 852 | 853 | function decode_array(cb, args, stream) { 854 | var sz = todword(stream); 855 | var type = args.type; 856 | if (sz == 0) { 857 | args.index = -1; 858 | args.value = null; 859 | args.length = 0; 860 | cb(args); 861 | return 0; 862 | } 863 | 864 | stream = stream.slice(SIZEOF_LENGTH); 865 | switch (type) { 866 | case SPROTO_TINTEGER: 867 | var len = stream[0]; 868 | stream = stream.slice(1); 869 | --sz; 870 | if (len == 4) { 871 | if (sz % 4 != 0) { 872 | return -1; 873 | } 874 | for (var i = 0; i < Math.floor(sz / 4); i++) { 875 | var value = expand64(todword(stream.slice(i * 4))); 876 | args.index = i + 1; 877 | args.value = value; 878 | args.length = 8; 879 | cb(args); 880 | } 881 | } else if (len == 8) { 882 | if (sz % 8 != 0) { 883 | return -1; 884 | } 885 | 886 | for (var i = 0; i < Math.floor(sz / 8); i++) { 887 | var low = todword(stream.slice(i * 8)); 888 | var hi = todword(stream.slice(i * 8 + 4)); 889 | var value = hi_low_uint64(low, hi); 890 | args.index = i + 1; 891 | args.value = value; 892 | args.length = 8; 893 | cb(args); 894 | } 895 | } else { 896 | return -1; 897 | } 898 | break; 899 | case SPROTO_TBOOLEAN: 900 | for (var i = 0; i < sz; i++) { 901 | var value = stream[i]; 902 | args.index = i + 1; 903 | args.value = value; 904 | args.length = 8; 905 | cb(args); 906 | } 907 | break; 908 | case SPROTO_TSTRING: 909 | case SPROTO_TSTRUCT: 910 | return decode_array_object(cb, args, stream, sz); 911 | default: 912 | return -1; 913 | } 914 | return 0; 915 | } 916 | 917 | function pack_seg(src, src_idx, buffer, buffer_idx, sz, n) { 918 | var header = 0; 919 | var notzero = 0; 920 | var obuffer_idx = buffer_idx; 921 | buffer_idx++; 922 | sz--; 923 | if (sz < 0) { 924 | obuffer_idx = null; 925 | } 926 | 927 | for (var i = 0; i < 8; i++) { 928 | if (src[src_idx + i] != 0) { 929 | notzero++; 930 | header |= 1 << i; 931 | if (sz > 0) { 932 | buffer[buffer_idx] = src[src_idx + i]; 933 | ++buffer_idx; 934 | --sz; 935 | } 936 | } 937 | } 938 | 939 | if ((notzero == 7 || notzero == 6) && n > 0) { 940 | notzero = 8; 941 | } 942 | 943 | if (notzero == 8) { 944 | if (n > 0) { 945 | return 8; 946 | } else { 947 | return 10; 948 | } 949 | } 950 | 951 | if (obuffer_idx != null) { 952 | buffer[obuffer_idx] = header; 953 | } 954 | 955 | return notzero + 1; 956 | } 957 | 958 | function write_ff(src, src_idx, des, dest_idx, n) { 959 | var align8_n = (n + 7) & (~7); 960 | des[dest_idx] = 0xff; 961 | des[dest_idx + 1] = Math.floor(align8_n / 8) - 1; 962 | 963 | for (var i = 0; i < n; i++) { 964 | des[dest_idx + i + 2] = src[src_idx + i]; 965 | } 966 | 967 | for (var i = 0; i < align8_n - n; i++) { 968 | des[dest_idx + n + 2 + i] = 0; 969 | } 970 | } 971 | 972 | function sproto_pack(srcv, src_idx, bufferv, buffer_idx) { 973 | var tmp = new Array(8); 974 | var ff_srcstart, ff_desstart; 975 | var ff_srcstart_idx = 0; 976 | var ff_desstart_idx = 0; 977 | var ff_n = 0; 978 | var size = 0; 979 | var src = srcv; 980 | var buffer = bufferv; 981 | var srcsz = srcv.length; 982 | var bufsz = 1 << 30; 983 | 984 | for (var i = 0; i < srcsz; i += 8) { 985 | var n; 986 | var padding = i + 8 - srcsz; 987 | if (padding > 0) { 988 | for (var j = 0; j < 8 - padding; j++) { 989 | tmp[j] = src[src_idx + j]; 990 | } 991 | 992 | for (var j = 0; j < padding; j++) { 993 | tmp[7 - j] = 0; 994 | } 995 | 996 | src = tmp; 997 | src_idx = 0; 998 | } 999 | 1000 | n = pack_seg(src, src_idx, buffer, buffer_idx, bufsz, ff_n); 1001 | bufsz -= n; 1002 | if (n == 10) { 1003 | ff_srcstart = src; 1004 | ff_srcstart_idx = src_idx; 1005 | ff_desstart = buffer; 1006 | ff_desstart_idx = buffer_idx; 1007 | ff_n = 1; 1008 | } else if (n == 8 && ff_n > 0) { 1009 | ++ff_n; 1010 | if (ff_n == 256) { 1011 | if (bufsz >= 0) { 1012 | write_ff(ff_srcstart, ff_srcstart_idx, ff_desstart, ff_desstart_idx, 256 * 8); 1013 | } 1014 | ff_n = 0; 1015 | } 1016 | } else { 1017 | if (ff_n > 0) { 1018 | if (bufsz >= 0) { 1019 | write_ff(ff_srcstart, ff_srcstart_idx, ff_desstart, ff_desstart_idx, ff_n * 8); 1020 | } 1021 | ff_n = 0; 1022 | } 1023 | } 1024 | src_idx += 8; 1025 | buffer_idx += n; 1026 | size += n; 1027 | } 1028 | if (bufsz >= 0) { 1029 | if (ff_n == 1) { 1030 | write_ff(ff_srcstart, ff_srcstart_idx, ff_desstart, ff_desstart_idx, 8); 1031 | } else if (ff_n > 1) { 1032 | write_ff(ff_srcstart, ff_srcstart_idx, ff_desstart, ff_desstart_idx, srcsz - ff_srcstart_idx); 1033 | } 1034 | if (buffer.length > size) { 1035 | for (var i = size; i < buffer.length; i++) { 1036 | buffer[i] = 0; 1037 | } 1038 | } 1039 | } 1040 | return size; 1041 | } 1042 | 1043 | function sproto_unpack(srcv, src_idx, bufferv, buffer_idx) { 1044 | var src = srcv; 1045 | var buffer = bufferv; 1046 | var size = 0; 1047 | var srcsz = srcv.length; 1048 | var bufsz = 1 << 30; 1049 | while (srcsz > 0) { 1050 | var header = src[src_idx]; 1051 | --srcsz; 1052 | ++src_idx; 1053 | if (header == 0xff) { 1054 | var n; 1055 | if (srcsz < 0) { 1056 | return -1; 1057 | } 1058 | 1059 | n = (src[src_idx] + 1) * 8; 1060 | if (srcsz < n + 1) 1061 | return -1; 1062 | 1063 | srcsz -= n + 1; 1064 | ++src_idx; 1065 | if (bufsz >= n) { 1066 | for (var i = 0; i < n; i++) { 1067 | buffer[buffer_idx + i] = src[src_idx + i]; 1068 | } 1069 | } 1070 | 1071 | bufsz -= n; 1072 | buffer_idx += n; 1073 | src_idx += n; 1074 | size += n; 1075 | } else { 1076 | for (var i = 0; i < 8; i++) { 1077 | var nz = (header >>> i) & 1; 1078 | if (nz != 0) { 1079 | if (srcsz < 0) 1080 | return -1; 1081 | 1082 | if (bufsz > 0) { 1083 | buffer[buffer_idx] = src[src_idx]; 1084 | --bufsz; 1085 | ++buffer_idx; 1086 | } 1087 | 1088 | ++src_idx; 1089 | --srcsz; 1090 | } else { 1091 | if (bufsz > 0) { 1092 | buffer[buffer_idx] = 0; 1093 | --bufsz; 1094 | ++buffer_idx; 1095 | } 1096 | } 1097 | ++size; 1098 | } 1099 | } 1100 | } 1101 | return size; 1102 | } 1103 | 1104 | ///////////////////////导出方法/////////////////////////////// 1105 | 1106 | t.pack = function(inbuf) { 1107 | var src_idx = 0; 1108 | var buffer = new Array(); 1109 | var buffer_idx = 0; 1110 | var size = sproto_pack(inbuf, src_idx, buffer, buffer_idx); 1111 | return buffer; 1112 | }, 1113 | 1114 | t.unpack = function(inbuf) { 1115 | var src_idx = 0; 1116 | var buffer = new Array(); 1117 | var buffer_idx = 0; 1118 | var size = sproto_unpack(inbuf, src_idx, buffer, buffer_idx); 1119 | return buffer; 1120 | }, 1121 | 1122 | t.createNew = function(binsch) { 1123 | var s = {}; 1124 | var result = new Object(); 1125 | var __session = new Array(); 1126 | var enbuffer; 1127 | s.type_n = 0; 1128 | s.protocol_n = 0; 1129 | s.type = null; 1130 | s.proto = null; 1131 | s.tcache = new Map(); 1132 | s.pcache = new Map(); 1133 | var sp = create_from_bundle(s, binsch, binsch.length); 1134 | if (sp == null) return null; 1135 | 1136 | function sproto_encode(st, buffer, buffer_idx, cb, ud) { 1137 | var args = new Object(); 1138 | var header_idx = buffer_idx; 1139 | var data_idx = buffer_idx; 1140 | var header_sz = SIZEOF_HEADER + st.maxn * SIZEOF_FIELD; 1141 | var index, lasttag, datasz; 1142 | 1143 | args.ud = ud; 1144 | data_idx = header_idx + header_sz; 1145 | index = 0; 1146 | lasttag = -1; 1147 | for (var i = 0; i < st.n; i++) { 1148 | var f = st.f[i]; 1149 | var type = f.type; 1150 | var value = 0; 1151 | var sz = -1; 1152 | args.tagname = f.name; 1153 | args.tagid = f.tag; 1154 | if (f.st != null) { 1155 | args.subtype = sp.type[f.st]; 1156 | } else { 1157 | args.subtype = null; 1158 | } 1159 | 1160 | args.mainindex = f.key; 1161 | args.extra = f.extra; 1162 | var type_ret = type & SPROTO_TARRAY; 1163 | if ((type & SPROTO_TARRAY) != 0) { 1164 | args.type = type & ~SPROTO_TARRAY; 1165 | sz = encode_array(cb, args, buffer, data_idx); 1166 | } else { 1167 | args.type = type; 1168 | args.index = 0; 1169 | switch (type) { 1170 | case SPROTO_TDOUBLE: 1171 | case SPROTO_TINTEGER: 1172 | case SPROTO_TBOOLEAN: 1173 | args.value = 0; 1174 | args.length = 8; 1175 | args.buffer = buffer; 1176 | args.buffer_idx = buffer_idx; 1177 | sz = cb(args); 1178 | if (sz < 0) { 1179 | if (sz == SPROTO_CB_NIL) 1180 | continue; 1181 | if (sz == SPROTO_CB_NOARRAY) 1182 | return 0; // no array, don't encode it 1183 | return -1; // sz == SPROTO_CB_ERROR 1184 | } 1185 | if (sz == 4) { 1186 | if (args.value < 0x7fff) { 1187 | value = (args.value + 1) * 2; 1188 | sz = 2; 1189 | } else { 1190 | sz = encode_integer(args.value, buffer, data_idx, sz); 1191 | } 1192 | } else if (sz == 8) { 1193 | if (type == SPROTO_TDOUBLE){ 1194 | sz = double_to_binary(args.value, buffer, data_idx, sz) 1195 | } else { 1196 | sz = encode_uint64(args.value, buffer, data_idx, sz); 1197 | } 1198 | } else { 1199 | return -1; 1200 | } 1201 | break; 1202 | case SPROTO_TSTRUCT: 1203 | case SPROTO_TSTRING: 1204 | sz = encode_object(cb, args, buffer, data_idx); 1205 | break; 1206 | } 1207 | } 1208 | 1209 | if (sz < 0) 1210 | return -1; 1211 | 1212 | if (sz > 0) { 1213 | var record_idx, tag; 1214 | if (value == 0) { 1215 | data_idx += sz; 1216 | } 1217 | record_idx = header_idx + SIZEOF_HEADER + SIZEOF_FIELD * index; 1218 | tag = f.tag - lasttag - 1; 1219 | if (tag > 0) { 1220 | tag = (tag - 1) * 2 + 1; 1221 | if (tag > 0xffff) 1222 | return -1; 1223 | buffer[record_idx] = tag & 0xff; 1224 | buffer[record_idx + 1] = (tag >> 8) & 0xff; 1225 | ++index; 1226 | record_idx += SIZEOF_FIELD; 1227 | } 1228 | ++index; 1229 | buffer[record_idx] = value & 0xff; 1230 | buffer[record_idx + 1] = (value >> 8) & 0xff; 1231 | lasttag = f.tag; 1232 | } 1233 | } 1234 | 1235 | buffer[header_idx] = index & 0xff; 1236 | buffer[header_idx + 1] = (index >> 8) & 0xff; 1237 | 1238 | datasz = data_idx - (header_idx + header_sz); 1239 | data_idx = header_idx + header_sz; 1240 | if (index != st.maxn) { 1241 | var v = buffer.slice(data_idx, data_idx + datasz); 1242 | for (var s = 0; s < v.length; s++) { 1243 | buffer[header_idx + SIZEOF_HEADER + index * SIZEOF_FIELD + s] = v[s]; 1244 | } 1245 | var remove_size = buffer.length - (header_idx + SIZEOF_HEADER + index * SIZEOF_FIELD + v.length); 1246 | buffer.splice(header_idx + SIZEOF_HEADER + index * SIZEOF_FIELD + v.length, buffer.length); 1247 | } 1248 | 1249 | return SIZEOF_HEADER + index * SIZEOF_FIELD + datasz; 1250 | } 1251 | 1252 | function encode(args) { 1253 | var self = args.ud; 1254 | if (self.deep >= ENCODE_DEEPLEVEL) { 1255 | alert("table is too deep"); 1256 | return -1; 1257 | } 1258 | 1259 | if (self.indata[args.tagname] == null) { 1260 | return SPROTO_CB_NIL; 1261 | } 1262 | 1263 | var target = null; 1264 | if (args.index > 0) { 1265 | if (args.tagname != self.array_tag) { 1266 | self.array_tag = args.tagname; 1267 | 1268 | var tagType = typeof(self.indata[args.tagname]); 1269 | if (typeof(self.indata[args.tagname]) != "object") { 1270 | self.array_index = 0; 1271 | return SPROTO_CB_NIL; 1272 | } 1273 | 1274 | if (self.indata[args.tagname] == null || self.indata[args.tagname] == undefined) { 1275 | self.array_index = 0; 1276 | return SPROTO_CB_NOARRAY; 1277 | } 1278 | } 1279 | target = self.indata[args.tagname][args.index - 1]; 1280 | if (target == null) { 1281 | return SPROTO_CB_NIL; 1282 | } 1283 | } else { 1284 | target = self.indata[args.tagname]; 1285 | } 1286 | 1287 | switch (args.type) { 1288 | case SPROTO_TINTEGER: 1289 | { 1290 | var v, vh, isnum; 1291 | if (args.extra > 0) { 1292 | var vn = target; 1293 | v = Math.floor(vn * args.extra + 0.5); 1294 | } else { 1295 | v = target; 1296 | } 1297 | vh = uint64_rshift(v, 31); 1298 | if (vh == 0 || vh == -1) { 1299 | args.value = v >>> 0; 1300 | return 4; 1301 | } else { 1302 | args.value = v; 1303 | return 8; 1304 | } 1305 | } 1306 | case SPROTO_TDOUBLE: 1307 | { 1308 | args.value = target; 1309 | return 8; 1310 | } 1311 | case SPROTO_TBOOLEAN: 1312 | { 1313 | if (target == true) { 1314 | args.value = 1; 1315 | } else if (target == false) { 1316 | args.value = 0; 1317 | } 1318 | return 4; 1319 | } 1320 | case SPROTO_TSTRING: 1321 | { 1322 | var arr; 1323 | if (args.extra){ //传数组进来 1324 | arr = target; 1325 | } else { 1326 | var str = target; 1327 | arr = netutils.string2utf8(str); 1328 | } 1329 | 1330 | var sz = arr.length; 1331 | if (sz > args.length) { 1332 | args.length = sz; 1333 | } 1334 | for (var i = 0; i < arr.length; i++) { 1335 | args.buffer[args.buffer_idx + i] = arr[i]; 1336 | } 1337 | return sz; 1338 | } 1339 | case SPROTO_TSTRUCT: 1340 | { 1341 | var sub = new Object(); 1342 | sub.st = args.subtype; 1343 | sub.deep = self.deep + 1; 1344 | sub.indata = target; 1345 | var r = sproto_encode(args.subtype, args.buffer, args.buffer_idx, encode, sub); 1346 | if (r < 0) { 1347 | return SPROTO_CB_ERROR; 1348 | } 1349 | return r; 1350 | } 1351 | default: 1352 | alert("Invalid filed type " + args.type); 1353 | return SPROTO_CB_ERROR; 1354 | } 1355 | } 1356 | 1357 | function sproto_decode(st, data, size, cb, ud) { 1358 | var args = new Object(); 1359 | var total = size; 1360 | var stream, datastream, fn, tag; 1361 | if (size < SIZEOF_HEADER) return -1; 1362 | stream = data.slice(0); 1363 | fn = toword(stream); 1364 | stream = stream.slice(SIZEOF_HEADER); 1365 | size -= SIZEOF_HEADER; 1366 | if (size < fn * SIZEOF_FIELD) 1367 | return -1; 1368 | datastream = stream.slice(fn * SIZEOF_FIELD); 1369 | size -= fn * SIZEOF_FIELD; 1370 | args.ud = ud; 1371 | 1372 | tag = -1; 1373 | for (var i = 0; i < fn; i++) { 1374 | var currentdata = null; 1375 | var f = null; 1376 | var value = toword(stream.slice(i * SIZEOF_FIELD)); 1377 | ++tag; 1378 | if (value & 1 != 0) { 1379 | tag += Math.floor(value / 2); 1380 | continue; 1381 | } 1382 | value = Math.floor(value / 2) - 1; 1383 | currentdata = datastream.slice(0); 1384 | if (value < 0) { 1385 | var sz; 1386 | if (size < SIZEOF_LENGTH) { 1387 | return -1; 1388 | } 1389 | sz = todword(datastream); 1390 | if (size < sz + SIZEOF_LENGTH) { 1391 | return -1; 1392 | } 1393 | datastream = datastream.slice(sz + SIZEOF_LENGTH); 1394 | size -= sz + SIZEOF_LENGTH; 1395 | } 1396 | f = findtag(st, tag); 1397 | if (f == null) { 1398 | continue; 1399 | } 1400 | args.tagname = f.name; 1401 | args.tagid = f.tag; 1402 | args.type = f.type & ~SPROTO_TARRAY; 1403 | if (f.st != null) { 1404 | args.subtype = sp.type[f.st]; 1405 | } else { 1406 | args.subtype = null; 1407 | } 1408 | 1409 | args.index = 0; 1410 | args.mainindex = f.key; 1411 | args.extra = f.extra; 1412 | if (value < 0) { 1413 | if ((f.type & SPROTO_TARRAY) != 0) { 1414 | if (decode_array(cb, args, currentdata)) { 1415 | return -1; 1416 | } 1417 | } else { 1418 | switch (f.type) { 1419 | case SPROTO_TDOUBLE: 1420 | { 1421 | var sz = todword(currentdata); 1422 | if (sz == 8){ 1423 | let doubleBin = currentdata.slice(SIZEOF_LENGTH, SIZEOF_LENGTH+8); 1424 | args.value = binary_to_double(doubleBin); 1425 | args.length = 8; 1426 | cb(args); 1427 | } else { 1428 | return -1; 1429 | } 1430 | break; 1431 | } 1432 | case SPROTO_TINTEGER: 1433 | { 1434 | var sz = todword(currentdata); 1435 | if (sz == 4) { 1436 | var v = expand64(todword(currentdata.slice(SIZEOF_LENGTH))); 1437 | args.value = v; 1438 | args.length = 8; 1439 | cb(args); 1440 | } else if(sz == 8) { 1441 | var low = todword(currentdata.slice(SIZEOF_LENGTH)); 1442 | var hi = todword(currentdata.slice(SIZEOF_LENGTH + 4)); 1443 | var v = hi_low_uint64(low, hi); 1444 | args.value = v; 1445 | args.length = 8; 1446 | cb(args); 1447 | } else { 1448 | return -1; 1449 | } 1450 | break; 1451 | } 1452 | case SPROTO_TSTRING: 1453 | case SPROTO_TSTRUCT: 1454 | { 1455 | var sz = todword(currentdata); 1456 | args.value = currentdata.slice(SIZEOF_LENGTH); 1457 | args.length = sz; 1458 | if (cb(args) != 0) { 1459 | return -1; 1460 | } 1461 | break; 1462 | } 1463 | default: 1464 | return -1; 1465 | } 1466 | } 1467 | } else if (f.type != SPROTO_TINTEGER && f.type != SPROTO_TBOOLEAN) { 1468 | return -1; 1469 | } else { 1470 | args.value = value; 1471 | args.length = 8; 1472 | cb(args); 1473 | } 1474 | } 1475 | return total - size; 1476 | } 1477 | 1478 | function decode(args) { 1479 | var self = args.ud; 1480 | var value; 1481 | if (self.deep >= ENCODE_DEEPLEVEL) { 1482 | alert("the table is too deep"); 1483 | } 1484 | 1485 | if (args.index != 0) { 1486 | if (args.tagname != self.array_tag) { 1487 | self.array_tag = args.tagname; 1488 | self.result[args.tagname] = new Array(); 1489 | if (args.index < 0) { 1490 | return 0; 1491 | } 1492 | } 1493 | } 1494 | 1495 | switch (args.type) { 1496 | case SPROTO_TINTEGER: 1497 | { 1498 | if (args.extra) { 1499 | var v = args.value; 1500 | var vn = v; 1501 | value = vn / args.extra; 1502 | } else { 1503 | value = args.value; 1504 | } 1505 | break; 1506 | } 1507 | case SPROTO_TDOUBLE: 1508 | { 1509 | value = args.value; 1510 | break 1511 | } 1512 | case SPROTO_TBOOLEAN: 1513 | { 1514 | if (args.value == 1) { 1515 | value = true; 1516 | } else if (args.value == 0) { 1517 | value = false; 1518 | } else { 1519 | value = null; 1520 | } 1521 | break; 1522 | } 1523 | case SPROTO_TSTRING: 1524 | { 1525 | var arr = new Array(); 1526 | for (var i = 0; i < args.length; i++) { 1527 | arr.push(args.value[i]); 1528 | } 1529 | if (args.extra){ 1530 | value = arr; 1531 | } else { 1532 | value = netutils.utf82string(arr); 1533 | } 1534 | 1535 | break; 1536 | } 1537 | case SPROTO_TSTRUCT: 1538 | { 1539 | var sub = new Object(); 1540 | var r; 1541 | sub.deep = self.deep + 1; 1542 | sub.array_index = 0; 1543 | sub.array_tag = null; 1544 | sub.result = new Object(); 1545 | if (args.mainindex >= 0) { 1546 | sub.mainindex_tag = args.mainindex; 1547 | r = sproto_decode(args.subtype, args.value, args.length, decode, sub); 1548 | if (r < 0 || r != args.length) { 1549 | return r; 1550 | } 1551 | value = sub.result; 1552 | break; 1553 | } else { 1554 | sub.mainindex_tag = -1; 1555 | sub.key_index = 0; 1556 | r = sproto_decode(args.subtype, args.value, args.length, decode, sub); 1557 | if (r < 0) { 1558 | return SPROTO_CB_ERROR; 1559 | } 1560 | if (r != args.length) 1561 | return r; 1562 | value = sub.result; 1563 | break; 1564 | } 1565 | } 1566 | default: 1567 | alert("Invalid type"); 1568 | } 1569 | 1570 | if (args.index > 0) { 1571 | self.result[args.tagname][args.index - 1] = value; 1572 | } else { 1573 | self.result[args.tagname] = value; 1574 | } 1575 | 1576 | return 0; 1577 | } 1578 | 1579 | function querytype(sp, typename) { 1580 | if (sp.tcache.has(typename)){ 1581 | return sp.tcache.get(typename); 1582 | } 1583 | var typeinfo = sproto_type(sp, typename); 1584 | if (typeinfo){ 1585 | sp.tcache.set(typename, typeinfo); 1586 | return typeinfo; 1587 | } 1588 | return null; 1589 | } 1590 | 1591 | function protocol(sp, pname) { 1592 | var tag = null; 1593 | var name = null; 1594 | 1595 | if (typeof(pname) == "number") { 1596 | tag = pname; 1597 | name = sproto_protoname(sp, pname); 1598 | if (!name) 1599 | return null; 1600 | } else { 1601 | tag = sproto_prototag(sp, pname); 1602 | name = pname; 1603 | 1604 | if (tag === -1) return null; 1605 | } 1606 | 1607 | var request = sproto_protoquery(sp, tag, SPROTO_REQUEST); 1608 | var response = sproto_protoquery(sp, tag, SPROTO_RESPONSE); 1609 | return { 1610 | tag: tag, 1611 | name: name, 1612 | request: request, 1613 | response: response 1614 | }; 1615 | } 1616 | 1617 | function queryproto(sp, pname) { 1618 | if (sp.pcache.has(pname)){ 1619 | return sp.pcache.get(pname); 1620 | } 1621 | var protoinfo = protocol(sp, pname); 1622 | if (protoinfo){ 1623 | sp.pcache.set(protoinfo.name, protoinfo); 1624 | sp.pcache.set(protoinfo.tag, protoinfo); 1625 | return protoinfo; 1626 | } 1627 | return null; 1628 | } 1629 | 1630 | sp.queryproto = function(protocolName){ 1631 | return queryproto(sp, protocolName); 1632 | }; 1633 | sp.dump = function() { 1634 | sproto_dump(this); 1635 | } 1636 | 1637 | sp.objlen = function(type, inbuf) { 1638 | var st = null; 1639 | if (typeof(type) === "string" || typeof(type) === "number") { 1640 | st = querytype(sp, type); 1641 | if (st == null) { 1642 | return null; 1643 | } 1644 | } else { 1645 | st = type; 1646 | } 1647 | 1648 | var ud = new Object(); 1649 | ud.array_tag = null; 1650 | ud.deep = 0; 1651 | ud.result = new Object(); 1652 | return sproto_decode(st, inbuf, inbuf.length, decode, ud); 1653 | } 1654 | 1655 | sp.encode = function(type, indata) { 1656 | var self = new Object(); 1657 | 1658 | var st = null; 1659 | if (typeof(type) === "string" || typeof(type) === "number") { 1660 | st = querytype(sp, type); 1661 | if (st == null) 1662 | return null; 1663 | } else { 1664 | st = type; 1665 | } 1666 | 1667 | var tbl_index = 2; 1668 | var enbuffer = new Array(); 1669 | var buffer_idx = 0; 1670 | self.st = st; 1671 | self.tbl_index = tbl_index; 1672 | self.indata = indata; 1673 | for (;;) { 1674 | self.array_tag = null; 1675 | self.array_index = 0; 1676 | self.deep = 0; 1677 | self.iter_index = tbl_index + 1; 1678 | var r = sproto_encode(st, enbuffer, buffer_idx, encode, self); 1679 | if (r < 0) { 1680 | return null; 1681 | } else { 1682 | return enbuffer; 1683 | } 1684 | } 1685 | } 1686 | 1687 | sp.decode = function(type, inbuf) { 1688 | var st = null; 1689 | if (typeof(type) === "string" || typeof(type) === "number") { 1690 | st = querytype(sp, type); 1691 | if (st == null) { 1692 | return null; 1693 | } 1694 | } else { 1695 | st = type; 1696 | } 1697 | 1698 | var buffer = inbuf; 1699 | var sz = inbuf.length; 1700 | var ud = new Object(); 1701 | ud.array_tag = null; 1702 | ud.deep = 0; 1703 | ud.result = new Object(); 1704 | var r = sproto_decode(st, buffer, sz, decode, ud); 1705 | if (r < 0) { 1706 | return null; 1707 | } 1708 | 1709 | return ud.result; 1710 | } 1711 | 1712 | sp.pack = function(inbuf) { 1713 | return t.pack(inbuf); 1714 | } 1715 | 1716 | sp.unpack = function(inbuf) { 1717 | return t.unpack(inbuf); 1718 | } 1719 | 1720 | sp.pencode = function(type, inbuf) { 1721 | var obuf = sp.encode(type, inbuf); 1722 | if (obuf == null) { 1723 | return null; 1724 | } 1725 | return sp.pack(obuf); 1726 | } 1727 | 1728 | sp.pdecode = function(type, inbuf) { 1729 | var obuf = sp.unpack(inbuf); 1730 | if (obuf == null) { 1731 | return null; 1732 | } 1733 | return sp.decode(type, obuf); 1734 | } 1735 | 1736 | sp.host = function(packagename) { 1737 | function cla(packagename) { 1738 | packagename = packagename ? packagename : "package"; 1739 | this.proto = sp; 1740 | this.package = querytype(sp, packagename); 1741 | this.package = this.package ? this.package : "package"; 1742 | this.session = {}; 1743 | } 1744 | cla.prototype = host; 1745 | 1746 | return new cla(packagename); 1747 | } 1748 | 1749 | host.attach = function(sp) { 1750 | this.attachsp = sp; 1751 | var self = this; 1752 | return (name, args, session) => { 1753 | var proto = queryproto(sp, name); 1754 | 1755 | header_tmp.type = proto.tag; 1756 | header_tmp.session = session; 1757 | 1758 | var headerbuffer = sp.encode(self.package, header_tmp); 1759 | if (session) { 1760 | self.session[session] = proto.response ? proto.response : true; 1761 | } 1762 | 1763 | if (args) { 1764 | var databuffer = sp.encode(proto.request, args); 1765 | return sp.pack(netutils.arrayconcat(headerbuffer, databuffer)); 1766 | } else { 1767 | return sp.pack(headerbuffer); 1768 | } 1769 | } 1770 | } 1771 | 1772 | function gen_response(self, response, session) { 1773 | return function(args) { 1774 | header_tmp.type = null; 1775 | header_tmp.session = session; 1776 | var headerbuffer = self.proto.encode(self.package, header_tmp); 1777 | if (response) { 1778 | var databuffer = self.proto.encode(response, args); 1779 | return self.proto.pack(netutils.arrayconcat(headerbuffer, databuffer)); 1780 | } else { 1781 | return self.proto.pack(headerbuffer); 1782 | } 1783 | }; 1784 | } 1785 | 1786 | host.dispatch = function(buffer) { 1787 | var sp = this.proto; 1788 | var bin = sp.unpack(buffer); 1789 | header_tmp.type = null; 1790 | header_tmp.session = null; 1791 | header_tmp = sp.decode(this.package, bin); 1792 | 1793 | var used_sz = sp.objlen(this.package, bin); 1794 | var leftbuffer = bin.slice(used_sz, bin.length); 1795 | if (header_tmp.type) { 1796 | var proto = queryproto(sp, header_tmp.type); 1797 | 1798 | var result; 1799 | if (proto.request) { 1800 | result = sp.decode(proto.request, leftbuffer); 1801 | } 1802 | 1803 | if (header_tmp.session) { 1804 | return { 1805 | type: "REQUEST", 1806 | pname: proto.name, 1807 | result: result, 1808 | responseFunc: gen_response(this, proto.response, header_tmp.session), 1809 | session: header_tmp.session, 1810 | } 1811 | } else { 1812 | return { 1813 | type: "REQUEST", 1814 | pname: proto.name, 1815 | result: result, 1816 | } 1817 | } 1818 | } else { 1819 | sp = this.attachsp; 1820 | var session = header_tmp.session; 1821 | var response = this.session[session]; 1822 | delete this.session[session]; 1823 | 1824 | if (response === true) { 1825 | return { 1826 | type: "RESPONSE", 1827 | session: session, 1828 | } 1829 | } else { 1830 | var result = sp.decode(response, leftbuffer); 1831 | return { 1832 | type: "RESPONSE", 1833 | session: session, 1834 | result: result, 1835 | } 1836 | } 1837 | } 1838 | } 1839 | 1840 | return sp; 1841 | } 1842 | 1843 | return t; 1844 | }()); 1845 | 1846 | // export default sproto; 1847 | module.exports = sproto; 1848 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | var sproto = require("./sproto"); 3 | 4 | var filename = "./sproto-js/protocol.spb"; 5 | var buffer = fs.readFileSync(filename); 6 | if (buffer == null){ 7 | console.log("read File err1"); 8 | } 9 | console.log(sproto); 10 | 11 | var sp = sproto.createNew(buffer); 12 | console.log(sp); 13 | 14 | 15 | var basicType = { 16 | numberList: [] 17 | } 18 | var buffer = sp.encode("base.BasicType", basicType) 19 | console.log(buffer) 20 | 21 | // var new_buffer = [ 2,0,5,0,0,0,0,0,0,0 ] 22 | 23 | var result = sp.decode("base.BasicType", buffer) 24 | console.log(result) --------------------------------------------------------------------------------