├── .gitignore ├── LICENSE ├── README.md ├── modules └── sproto │ ├── SCsub │ ├── config.py │ ├── gd_sproto.cpp │ ├── gd_sproto.h │ ├── register_types.cpp │ └── register_types.h ├── test └── test_sproto │ ├── c2s.spb │ ├── choose.tscn │ ├── engine.cfg │ ├── icon.png │ ├── icon.png.flags │ ├── main.gd │ └── main.tscn └── thirdparty └── sproto ├── msvcint.h ├── sproto.c └── sproto.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 zhangshiqian1214 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | godot-sproto模块: 2 | ================= 3 | 4 | sproto是云风发布的一个类似protobuf序列化库,支持integer, boolean, string, struct , array, map这几种类型 5 | 在脚本语言里面做序列化会相对方便 6 | 7 | 下载: 8 | ----------------- 9 | 1. git clone https://github.com/zhangshiqian1214/godot-module.git 10 | 2.cp -r godot-modules/modules/* godot/modules 11 | cp -r godot-modules/thirdparty/* godot/thirdparty 12 | cp -r godot-modules/test godot/ 13 | 3. scons 14 | 15 | usage: 16 | ------------------ 17 | ```lua 18 | var sproto 19 | var sprotoObj 20 | func _ready(): 21 | sproto = Sproto.new() 22 | var f = File.new() 23 | if f.open("res://c2s.spb", File.READ) == OK : 24 | var filebuf = f.get_buffer(f.get_len()) 25 | sprotoObj = sproto.new_proto(buffer) 26 | sproto.save_proto(sprotoObj, 1) 27 | pass 28 | 29 | func _on_test_pressed(): 30 | var typeObj = sproto.query_type(sprotoObj, "Person") 31 | var defaultData = sproto.get_default(typeObj) 32 | print("defaultData:", defaultData) 33 | 34 | var person = { 35 | name = "Alice", 36 | id = 10000, 37 | cash = 3.1415926, 38 | myphone = {"number": "01234567890", "type": 3}, 39 | phone = [ 40 | { "number": "123456789", "type": 1 }, 41 | { "number": "87654321", "type": 2 }, 42 | ], 43 | skills = [1, 2, 3, 4], 44 | actvityNames = [], 45 | taskIds = [], 46 | } 47 | 48 | var buf = sproto.encode(typeObj, person) 49 | print("buf.sz:", buf.size()) 50 | 51 | var outdata = sproto.decode(typeObj, buf) 52 | print("decode outdata:", outdata) 53 | 54 | var packbuf = sproto.pack(buf) 55 | print("packbuf.sz:", packbuf.size()) 56 | 57 | var unpackBuf = sproto.unpack(packbuf) 58 | print("unpackBuf.sz:", unpackBuf.size()) 59 | -------------------------------------------------------------------------------- /modules/sproto/SCsub: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | Import('env') 4 | Import('env_modules') 5 | 6 | # Thirdparty source files 7 | 8 | env_sproto = env_modules.Clone() 9 | 10 | #if (env["sproto"] != "system"): # builtin 11 | thirdparty_dir = "#thirdparty/sproto/" 12 | thirdparty_sources = [ 13 | "sproto.c", 14 | ] 15 | thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] 16 | 17 | env_sproto.add_source_files(env.modules_sources, thirdparty_sources) 18 | env_sproto.Append(CPPPATH = [thirdparty_dir]) 19 | 20 | env_sproto.add_source_files(env.modules_sources,"*.cpp") 21 | 22 | Export('env') -------------------------------------------------------------------------------- /modules/sproto/config.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def can_build(platform): 4 | return True 5 | 6 | 7 | def configure(env): 8 | pass 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /modules/sproto/gd_sproto.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "gd_sproto.h" 4 | 5 | extern "C" { 6 | #include "thirdparty/sproto/sproto.h" 7 | }; 8 | 9 | #define ENCODE_MAXSIZE 0x1000000 10 | #define ENCODE_DEEPLEVEL 64 11 | 12 | Sproto::Sproto() 13 | { 14 | m_cacheSprotoIndex = 0; 15 | m_cacheSprotoTypeIndex = 0; 16 | } 17 | 18 | Sproto::~Sproto() 19 | { 20 | clear_sprotos(); 21 | } 22 | 23 | //err: < 0 24 | int Sproto::new_proto(const ByteArray& buffer) 25 | { 26 | struct sproto* sp; 27 | sp = sproto_create(buffer.read().ptr(), buffer.size()); 28 | if (sp){ 29 | int index = set_sproto_ptr(sp); 30 | return index; 31 | } 32 | ERR_EXPLAIN("create new sproto error"); 33 | return -1; 34 | } 35 | 36 | int Sproto::delete_proto(int sproto_ptr) 37 | { 38 | struct sproto* sp = get_sproto_ptr(sproto_ptr); 39 | if (sp == NULL){ 40 | ERR_EXPLAIN("delete sproto error, sproto_ptr:" + String::num(sproto_ptr)); 41 | return -1; 42 | } 43 | sproto_release(sp); 44 | del_sproto_ptr(sproto_ptr); 45 | return 0; 46 | } 47 | 48 | int Sproto::save_proto(int sproto_ptr, int saveindex) 49 | { 50 | struct sproto* sp = get_sproto_ptr(sproto_ptr); 51 | if (sp == NULL) 52 | { 53 | ERR_EXPLAIN("save_proto sproto NULL, sproto_ptr:" + String::num(sproto_ptr)); 54 | return -1; 55 | } 56 | if (saveindex < 0 || saveindex >= MAX_GLOBALSPROTO) 57 | { 58 | ERR_EXPLAIN("save_proto saveindex err, saveindex:" + String::num(saveindex)); 59 | return -1; 60 | } 61 | g_sproto[saveindex] = sp; 62 | return 0; 63 | } 64 | 65 | int Sproto::load_proto(int saveindex) 66 | { 67 | struct sproto* sp; 68 | if (saveindex < 0 || saveindex >= MAX_GLOBALSPROTO) 69 | { 70 | ERR_EXPLAIN("load_proto saveindex err, saveindex:" + String::num(saveindex)); 71 | return -1; 72 | } 73 | sp = g_sproto[saveindex]; 74 | if (sp == NULL) 75 | { 76 | ERR_EXPLAIN("load_proto sproto NULL, saveindex:" + String::num(saveindex)); 77 | return -1; 78 | } 79 | int index = set_sproto_ptr(sp); 80 | return index; 81 | } 82 | 83 | int Sproto::dump_proto(int sproto_ptr) 84 | { 85 | struct sproto* sp = get_sproto_ptr(sproto_ptr); 86 | if (sp == NULL) 87 | { 88 | ERR_EXPLAIN("dump_proto sproto NULL, sproto_ptr:" + String::num(sproto_ptr)); 89 | return -1; 90 | } 91 | sproto_dump(sp); 92 | return 0; 93 | } 94 | 95 | int Sproto::query_type(int sproto_ptr, const String& type_name) 96 | { 97 | struct sproto_type* st; 98 | struct sproto* sp = get_sproto_ptr(sproto_ptr); 99 | if (sp == NULL){ 100 | ERR_EXPLAIN("query_type query sproto_type err sproto_ptr:" + String::num(sproto_ptr)); 101 | return -1; 102 | } 103 | 104 | st = sproto_type(sp, type_name.utf8().get_data()); 105 | if (st == NULL){ 106 | ERR_EXPLAIN("query_type sproto_type err sproto_ptr:" + String::num(sproto_ptr) + " type_name:" + type_name); 107 | return -1; 108 | } 109 | int index = set_sproto_type_ptr(st); 110 | 111 | return index; 112 | } 113 | 114 | Array Sproto::protocol(int sproto_ptr, const Variant& pname) 115 | { 116 | Array ret; 117 | int t; 118 | int tag; 119 | struct sproto_type * request; 120 | struct sproto_type * response; 121 | struct sproto * sp = get_sproto_ptr(sproto_ptr); 122 | if (sp == NULL){ 123 | ERR_EXPLAIN("protocol sproto NULL, sproto_ptr:" + String::num(sproto_ptr)); 124 | ret.push_back(-1); 125 | return ret; 126 | } 127 | if (pname.is_num()){ 128 | const char * name; 129 | tag = pname.operator int(); 130 | name = sproto_protoname(sp, tag); 131 | if (name == NULL) 132 | ret.push_back(-1); 133 | return ret; 134 | ret.push_back(pname); 135 | } 136 | else{ 137 | const char * name = pname.operator String().utf8().get_data(); 138 | if (name == NULL){ 139 | ret.push_back(-1); 140 | return ret; 141 | } 142 | tag = sproto_prototag(sp, name); 143 | if (tag < 0){ 144 | ret.push_back(-1); 145 | return ret; 146 | } 147 | ret.push_back(tag); 148 | } 149 | request = sproto_protoquery(sp, tag, SPROTO_REQUEST); 150 | if (request == NULL){ 151 | ret.push_back(Variant()); 152 | } 153 | else{ 154 | int request_index = set_sproto_type_ptr(request); 155 | ret.push_back(request_index); 156 | } 157 | response = sproto_protoquery(sp, tag, SPROTO_RESPONSE); 158 | if (response == NULL){ 159 | ret.push_back(Variant()); 160 | } 161 | else 162 | { 163 | int response_index = set_sproto_type_ptr(response); 164 | ret.push_back(response_index); 165 | } 166 | return ret; 167 | } 168 | 169 | static int 170 | encode_default(const struct sproto_arg *args) 171 | { 172 | Dictionary& dict = *(Dictionary *) args->ud; 173 | Variant value; 174 | if (args->index > 0) { 175 | if (args->mainindex > 0) 176 | value = Dictionary(true); 177 | else 178 | value = Array(true); 179 | 180 | dict[args->tagname] = value; 181 | return SPROTO_CB_NOARRAY; 182 | } else { 183 | switch(args->type) { 184 | case SPROTO_TINTEGER: 185 | value = 0; 186 | break; 187 | case SPROTO_TBOOLEAN: 188 | value = false; 189 | break; 190 | case SPROTO_TSTRING: 191 | value = ""; 192 | break; 193 | case SPROTO_TSTRUCT: 194 | Dictionary sub(true); 195 | sub["__type"] = sproto_name(args->subtype); 196 | value = sub; 197 | 198 | char dummy[64]; 199 | sproto_encode(args->subtype, dummy, sizeof(dummy), encode_default, &sub); 200 | break; 201 | } 202 | dict[args->tagname] = value; 203 | return SPROTO_CB_NIL; 204 | } 205 | } 206 | 207 | Dictionary Sproto::get_default(int sproto_type_ptr) 208 | { 209 | int ret; 210 | char dummy[64]; 211 | struct sproto_type* st = get_sproto_type_ptr(sproto_type_ptr); 212 | if (st == NULL) 213 | { 214 | ERR_EXPLAIN("protocol sproto_type NULL, sproto_ptr:" + String::num(sproto_type_ptr)); 215 | return Dictionary(true); 216 | } 217 | Dictionary dict(true); 218 | dict["__type"] = sproto_name(st); 219 | ret = sproto_encode(st, dummy, sizeof(dummy), encode_default, &dict); 220 | if (ret < 0){ 221 | int sz = sizeof(dummy) * 2; 222 | Vector vstr; 223 | vstr.resize(sz); 224 | char * tmp = vstr.ptr(); 225 | for (;;) { 226 | ret = sproto_encode(st, tmp, sz, encode_default, &dict); 227 | if (ret >= 0) 228 | break; 229 | sz *= 2; 230 | vstr.resize(sz); 231 | tmp = vstr.ptr(); 232 | } 233 | } 234 | 235 | return dict; 236 | } 237 | 238 | struct encode_ud { 239 | struct sproto_type *st; 240 | Variant value; 241 | const char *source_tag; 242 | Variant source; 243 | int deep; 244 | }; 245 | 246 | static int 247 | encode_callback(const struct sproto_arg * args) 248 | { 249 | struct encode_ud * self = (struct encode_ud*) args->ud; 250 | Variant& value = self->value; 251 | Variant source = self->source; 252 | if (self->deep >= ENCODE_DEEPLEVEL){ 253 | ERR_EXPLAIN("The table is too deep"); 254 | return SPROTO_CB_ERROR; 255 | } 256 | 257 | if (args->index > 0){ 258 | if (args->tagname != self->source_tag){ 259 | // a new array 260 | self->source_tag = args->tagname; 261 | bool r_valid; 262 | source = value.get(args->tagname, &r_valid); 263 | if (source.get_type() == Variant::NIL) 264 | return SPROTO_CB_NOARRAY; 265 | //return SPROTO_CB_NIL; 266 | if (source.get_type() != Variant::DICTIONARY && source.get_type() != Variant::ARRAY) { 267 | ERR_FAIL_V(SPROTO_CB_NOARRAY); 268 | } 269 | self->source = source; 270 | } 271 | int index = args->index - 1; 272 | if (args->mainindex >= 0){ 273 | // todo: check the key is equal to mainindex value 274 | if(source.get_type() == Variant::DICTIONARY) { 275 | Dictionary dict = source; 276 | if(index >= dict.size()) 277 | return 0; 278 | const Variant *K=NULL; 279 | while((K=dict.next(K))) { 280 | if(index-- == 0) { 281 | source = dict[*K]; 282 | break; 283 | } 284 | } 285 | } 286 | else if (source.get_type() == Variant::ARRAY){ 287 | Array array = source; 288 | if(index >= array.size()) 289 | return SPROTO_CB_NIL; 290 | source = array[index]; 291 | } 292 | } else { 293 | if(source.get_type() == Variant::DICTIONARY) { 294 | Dictionary dict = source; 295 | if(!dict.has(index)) 296 | return SPROTO_CB_NIL; 297 | source = dict[index]; 298 | } 299 | else if(source.get_type() == Variant::ARRAY) { 300 | Array array = source; 301 | if(index >= array.size()) 302 | return SPROTO_CB_NIL; 303 | source = array[index]; 304 | } 305 | } 306 | } else { 307 | if(value.get_type() != Variant::DICTIONARY && value.get_type() != Variant::ARRAY) { 308 | ERR_EXPLAIN(String(args->tagname) 309 | + "(" 310 | + String::num(args->tagid) 311 | + ") should be a dict/array (Is a " 312 | + value.get_type_name(value.get_type()) 313 | + ")" 314 | ); 315 | ERR_FAIL_V(SPROTO_CB_ERROR); 316 | } 317 | if(value.get_type() == Variant::DICTIONARY) { 318 | Dictionary dict = value; 319 | if(!dict.has(args->tagname)) 320 | return SPROTO_CB_NIL; 321 | source = dict[args->tagname]; 322 | } 323 | else if(value.get_type() == Variant::ARRAY) { 324 | Array array = value; 325 | int idx = atoi(args->tagname); 326 | if(idx >= array.size()) 327 | return SPROTO_CB_NIL; 328 | source = array[idx]; 329 | } 330 | } 331 | 332 | if(source.get_type() == Variant::NIL) 333 | return 0; 334 | 335 | switch (args->type) { 336 | case SPROTO_TINTEGER: { 337 | if (source.get_type() != Variant::INT && source.get_type() != Variant::REAL) { 338 | ERR_EXPLAIN(String(args->tagname) 339 | + "(" 340 | + String::num(args->tagid) 341 | + ") should be a int/real (Is a " 342 | + source.get_type_name(source.get_type()) 343 | + ")" 344 | ); 345 | ERR_FAIL_V(SPROTO_CB_ERROR); 346 | } 347 | long v = (double) source; 348 | // notice: godot only support 32bit integer 349 | long vh = v >> 31; 350 | if (vh == 0 || vh == -1) { 351 | if(args->length < 4) 352 | return -1; 353 | *(unsigned int *)args->value = (unsigned int)v; 354 | return 4; 355 | } 356 | else { 357 | *(unsigned long *)args->value = (unsigned long)v; 358 | if(args->length < 8) 359 | return -1; 360 | return 8; 361 | } 362 | } 363 | case SPROTO_TBOOLEAN: { 364 | if(source.get_type() != Variant::BOOL) { 365 | ERR_EXPLAIN(String(args->tagname) 366 | + "(" 367 | + String::num(args->tagid) 368 | + ") should be a bool (Is a " 369 | + source.get_type_name(source.get_type()) 370 | + ")" 371 | ); 372 | ERR_FAIL_V(SPROTO_CB_ERROR); 373 | } 374 | bool v = source; 375 | *(int *)args->value = v; 376 | return 4; 377 | } 378 | case SPROTO_TSTRING: { 379 | if(source.get_type() != Variant::STRING) { 380 | ERR_EXPLAIN(String(args->tagname) 381 | + "(" 382 | + String::num(args->tagid) 383 | + ") should be a string (Is a " 384 | + source.get_type_name(source.get_type()) 385 | + ")" 386 | ); 387 | ERR_FAIL_V(SPROTO_CB_ERROR); 388 | } 389 | String v = source; 390 | CharString utf8 = v.utf8(); 391 | size_t sz = utf8.length(); 392 | if(sz > args->length) 393 | return -1; 394 | memcpy(args->value, utf8.get_data(), sz); 395 | //printf("%s -> %d bytes\n", args->tagname, sz + 1); 396 | return sz; // The length of empty string is 1. 397 | } 398 | case SPROTO_TSTRUCT: { 399 | struct encode_ud sub; 400 | sub.value = source; 401 | int r; 402 | if(source.get_type() != Variant::DICTIONARY && source.get_type() != Variant::ARRAY) { 403 | ERR_EXPLAIN(String(args->tagname) 404 | + "(" 405 | + String::num(args->tagid) 406 | + ") should be a dict/array (Is a " 407 | + source.get_type_name(source.get_type()) 408 | + ")" 409 | ); 410 | ERR_FAIL_V(SPROTO_CB_ERROR); 411 | } 412 | sub.st = args->subtype; 413 | sub.deep = self->deep + 1; 414 | r = sproto_encode(args->subtype, args->value, args->length, encode_callback, &sub); 415 | //if (r < 0) 416 | //ERR_FAIL_V(SPROTO_CB_ERROR); 417 | return r; 418 | } 419 | default: 420 | ERR_EXPLAIN("Invalid field type: " + String::num(args->type)); 421 | ERR_FAIL_V(SPROTO_CB_ERROR); 422 | } 423 | return SPROTO_CB_ERROR; 424 | } 425 | 426 | ByteArray Sproto::encode(int sproto_type_ptr, const Dictionary& data) 427 | { 428 | ByteArray result; 429 | struct sproto_type* st = get_sproto_type_ptr(sproto_type_ptr); 430 | if (st == NULL) 431 | { 432 | ERR_EXPLAIN("encode sproto_type NULL, sproto_ptr:" + String::num(sproto_type_ptr)); 433 | ERR_FAIL_COND_V(st == NULL, ByteArray()); 434 | //return ByteArray(); 435 | } 436 | result.resize(1024); 437 | ByteArray::Write w = result.write(); 438 | struct encode_ud self; 439 | self.value = data; 440 | self.st = st; 441 | for (;;){ 442 | self.deep = 0; 443 | int r = sproto_encode(self.st, w.ptr(), result.size(), encode_callback, &self); 444 | w = ByteArray::Write(); 445 | if (r < 0){ 446 | result.resize(result.size() * 2); 447 | ByteArray::Write w = result.write(); 448 | } else { 449 | result.resize(r); 450 | break; 451 | } 452 | } 453 | 454 | return result; 455 | } 456 | 457 | struct decode_ud { 458 | const char * array_tag; 459 | Variant result; 460 | Variant array; 461 | Variant key; 462 | int deep; 463 | int mainindex_tag; 464 | }; 465 | 466 | static int decode_callback(const struct sproto_arg *args){ 467 | struct decode_ud * self = (struct decode_ud*) args->ud; 468 | Variant& result = self->result; 469 | Variant& array = self->array; 470 | Variant value; 471 | if (args->index != 0){ 472 | // It's array 473 | if (args->tagname != self->array_tag) { 474 | self->array_tag = args->tagname; 475 | Dictionary object = result.operator Dictionary(); 476 | if(!object.has(args->tagname)) { 477 | if(args->mainindex >= 0) { 478 | array = Dictionary(true); 479 | } else { 480 | array = Array(true); 481 | } 482 | object[args->tagname] = array; 483 | } else { 484 | array = object[args->tagname]; 485 | } 486 | if (args->index < 0) { 487 | // It's a empty array, return now. 488 | return 0; 489 | } 490 | } 491 | } 492 | switch(args->type) { 493 | case SPROTO_TINTEGER:{ 494 | // notice: in lua 5.2, 52bit integer support (not 64) 495 | value = (*(int *)args->value); 496 | break; 497 | } 498 | case SPROTO_TBOOLEAN:{ 499 | value = (bool) (*(unsigned long *)args->value); 500 | break; 501 | } 502 | case SPROTO_TSTRING:{ 503 | String str; 504 | str.parse_utf8((const char *) args->value, args->length); 505 | value = str; 506 | break; 507 | } 508 | case SPROTO_TSTRUCT:{ 509 | struct decode_ud sub; 510 | int r; 511 | value = Dictionary(true); 512 | 513 | sub.result = value; 514 | sub.deep = self->deep + 1; 515 | if (args->mainindex >= 0){ 516 | // This struct will set into a map, so mark the main index tag. 517 | sub.mainindex_tag = args->mainindex; 518 | r = sproto_decode(args->subtype, args->value, args->length, decode_callback, &sub); 519 | if (r < 0) 520 | return SPROTO_CB_ERROR; 521 | if (r != args->length) 522 | return r; 523 | self->array.set(sub.key, value); 524 | return 0; 525 | } else { 526 | sub.mainindex_tag = -1; 527 | r = sproto_decode(args->subtype, args->value, args->length, decode_callback, &sub); 528 | if (r < 0) 529 | return SPROTO_CB_ERROR; 530 | if (r != args->length) 531 | return r; 532 | break; 533 | } 534 | } 535 | default: 536 | ERR_EXPLAIN("Invalid type:" + String::num(args->type) + " tag_name:" + args->tagname); 537 | break; 538 | } 539 | 540 | /*if (value.get_type() == Variant::NIL) 541 | { 542 | return SPROTO_CB_NOARRAY; 543 | }*/ 544 | 545 | if (args->index > 0){ 546 | Array object = self->array.operator Array(); 547 | object.append(value); 548 | } else { 549 | if (self->mainindex_tag == args->tagid) { 550 | self->key = value; 551 | } 552 | Dictionary object = self->result.operator Dictionary(); 553 | object[args->tagname] = value; 554 | } 555 | return 0; 556 | } 557 | 558 | Array Sproto::decode(int sproto_type_ptr, const ByteArray& buffer) 559 | { 560 | Array result(true); 561 | Dictionary outdata(true); 562 | struct sproto_type* st = get_sproto_type_ptr(sproto_type_ptr); 563 | if (st == NULL) 564 | { 565 | ERR_EXPLAIN("decode sproto_type NULL, sproto_ptr:" + String::num(sproto_type_ptr)); 566 | ERR_FAIL_COND_V(st == NULL, result); 567 | //return ByteArray(); 568 | } 569 | struct decode_ud self; 570 | self.result = outdata; 571 | self.deep = 0; 572 | self.mainindex_tag = -1; 573 | ByteArray::Read r = buffer.read(); 574 | 575 | int ret = sproto_decode(st, r.ptr(), buffer.size(), decode_callback, &self); 576 | if (ret < 0){ 577 | ERR_EXPLAIN("decode fatal err, sproto_ptr:" + String::num(sproto_type_ptr) + " ret:" + String::num(ret)); 578 | result.push_back(ret); 579 | return result; 580 | } 581 | result.push_back(ret); 582 | result.push_back(outdata); 583 | return result; 584 | } 585 | 586 | #define ENCODE_BUFFERSIZE 2050 587 | #define ENCODE_MAXSIZE 0x1000000 588 | 589 | static void 590 | expand_buffer(ByteArray& buffer, int nsz) 591 | { 592 | if (nsz > ENCODE_MAXSIZE) { 593 | ERR_EXPLAIN("expand_buffer err, object is too large (>" + String::num(ENCODE_MAXSIZE) + ")"); 594 | return; 595 | } 596 | buffer.resize(nsz); 597 | return; 598 | } 599 | 600 | ByteArray Sproto::pack(const ByteArray& buffer) 601 | { 602 | ByteArray result; 603 | int bytes; 604 | int sz = buffer.size(); 605 | ByteArray::Read r = buffer.read(); 606 | const void * buf = r.ptr(); 607 | int maxsz = (sz + 2047) / 2048 * 2 + sz; 608 | if (m_packBuffer.size() < maxsz) 609 | expand_buffer(m_packBuffer, maxsz); 610 | 611 | ByteArray::Write w = m_packBuffer.write(); 612 | void * output = w.ptr(); 613 | 614 | bytes = sproto_pack(buf, sz, output, maxsz); 615 | if (bytes > maxsz) { 616 | ERR_EXPLAIN("pack err, return size = " + String::num(bytes)); 617 | return ByteArray(); 618 | } 619 | 620 | result.resize(bytes); 621 | r = m_packBuffer.read(); 622 | w = result.write(); 623 | memcpy(w.ptr(), r.ptr(), bytes); 624 | return result; 625 | } 626 | 627 | ByteArray Sproto::unpack(const ByteArray& buffer) 628 | { 629 | ByteArray result; 630 | int sz = buffer.size(); 631 | ByteArray::Read r = buffer.read(); 632 | const void *buf = r.ptr(); 633 | ByteArray::Write w = m_unpackBuffer.write(); 634 | void *output = w.ptr(); 635 | int osz = m_unpackBuffer.size(); 636 | int ret = sproto_unpack(buf, sz, output, osz); 637 | if (ret < 0) { 638 | ERR_EXPLAIN("Invalid unpack stream"); 639 | return ByteArray(); 640 | } 641 | if (ret > osz){ 642 | w = ByteArray::Write(); 643 | expand_buffer(m_unpackBuffer, ret); 644 | w = m_unpackBuffer.write(); 645 | output = w.ptr(); 646 | ret = sproto_unpack(buf, sz, output, ret); 647 | if (ret < 0) { 648 | ERR_EXPLAIN("Invalid unpack stream"); 649 | return ByteArray(); 650 | } 651 | } 652 | r = m_unpackBuffer.read(); 653 | result.resize(ret); 654 | w = result.write(); 655 | memcpy(w.ptr(), r.ptr(), ret); 656 | return result; 657 | } 658 | 659 | int Sproto::set_sproto_ptr(struct sproto* ptr) 660 | { 661 | SprotoIndexMap::Element* element = m_cacheSprotoIndexMap.find(ptr); 662 | if (element != NULL) 663 | { 664 | return element->value(); 665 | } 666 | 667 | m_cacheSprotoIndex++; 668 | m_cacheSprotoIndexMap[ptr] = m_cacheSprotoIndex; 669 | m_cacheIndexSprotoMap[m_cacheSprotoIndex] = ptr; 670 | return m_cacheSprotoIndex; 671 | } 672 | 673 | int Sproto::set_sproto_type_ptr(struct sproto_type* ptr) 674 | { 675 | SprotoTypeIndexMap::Element* element = m_cacheSprotoTypeIndexMap.find(ptr); 676 | if (element != NULL) 677 | { 678 | return element->value(); 679 | } 680 | m_cacheSprotoTypeIndex++; 681 | m_cacheSprotoTypeIndexMap[ptr] = m_cacheSprotoTypeIndex; 682 | m_cacheIndexSprotoTypeMap[m_cacheSprotoTypeIndex] = ptr; 683 | return m_cacheSprotoTypeIndex; 684 | } 685 | 686 | struct sproto* Sproto::get_sproto_ptr(int sproto_ptr) 687 | { 688 | IndexSprotoMap::Element* element = m_cacheIndexSprotoMap.find(sproto_ptr); 689 | if (element != NULL) 690 | { 691 | return element->value(); 692 | } 693 | return NULL; 694 | } 695 | 696 | struct sproto_type* Sproto::get_sproto_type_ptr(int sproto_type_ptr) 697 | { 698 | IndexSprotoTypeMap::Element* element = m_cacheIndexSprotoTypeMap.find(sproto_type_ptr); 699 | if (element != NULL) 700 | { 701 | return element->value(); 702 | } 703 | return NULL; 704 | } 705 | 706 | void Sproto::del_sproto_ptr(int sproto_ptr) 707 | { 708 | struct sproto* sp = get_sproto_ptr(sproto_ptr); 709 | if (sp == NULL){ 710 | return; 711 | } 712 | m_cacheIndexSprotoMap.erase(sproto_ptr); 713 | m_cacheSprotoIndexMap.erase(sp); 714 | 715 | m_cacheSprotoTypeIndexMap.clear(); 716 | m_cacheIndexSprotoTypeMap.clear(); 717 | } 718 | 719 | void Sproto::del_sproto_type_ptr(int sproto_type_ptr) 720 | { 721 | struct sproto_type* st = get_sproto_type_ptr(sproto_type_ptr); 722 | if (st == NULL){ 723 | return; 724 | } 725 | m_cacheIndexSprotoTypeMap.erase(sproto_type_ptr); 726 | m_cacheSprotoTypeIndexMap.erase(st); 727 | } 728 | 729 | void Sproto::clear_sprotos() 730 | { 731 | for(SprotoIndexMap::Element *E=m_cacheSprotoIndexMap.front(); E; E=E->next()){ 732 | struct sproto* sp = E->key(); 733 | if (sp != NULL) 734 | sproto_release(sp); 735 | } 736 | m_cacheSprotoIndexMap.clear(); 737 | m_cacheIndexSprotoMap.clear(); 738 | m_cacheSprotoTypeIndexMap.clear(); 739 | m_cacheIndexSprotoTypeMap.clear(); 740 | } 741 | 742 | void Sproto::_bind_methods() 743 | { 744 | ObjectTypeDB::bind_method(_MD("new_proto", "buffer"),&Sproto::new_proto); 745 | ObjectTypeDB::bind_method(_MD("delete_proto", "sproto_ptr"),&Sproto::delete_proto); 746 | ObjectTypeDB::bind_method(_MD("save_proto", "sproto_ptr", "saveindex"),&Sproto::save_proto); 747 | ObjectTypeDB::bind_method(_MD("load_proto", "saveindex"),&Sproto::load_proto); 748 | ObjectTypeDB::bind_method(_MD("dump_proto", "sproto_ptr"),&Sproto::dump_proto); 749 | 750 | ObjectTypeDB::bind_method(_MD("query_type", "sproto_ptr", "type_name"),&Sproto::query_type); 751 | ObjectTypeDB::bind_method(_MD("protocol", "sproto_ptr", "tag"),&Sproto::protocol); 752 | ObjectTypeDB::bind_method(_MD("get_default", "sproto_ptr"),&Sproto::get_default); 753 | ObjectTypeDB::bind_method(_MD("decode", "sproto_type_ptr", "buffer"),&Sproto::decode); 754 | ObjectTypeDB::bind_method(_MD("encode", "sproto_type_ptr", "data"),&Sproto::encode); 755 | ObjectTypeDB::bind_method(_MD("pack", "buffer"),&Sproto::pack); 756 | ObjectTypeDB::bind_method(_MD("unpack", "buffer"),&Sproto::unpack); 757 | 758 | BIND_CONSTANT(REQUEST); 759 | BIND_CONSTANT(RESPONSE); 760 | } -------------------------------------------------------------------------------- /modules/sproto/gd_sproto.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangshiqian1214/godot-module/7fa3013ef14616aec1b0c6fcf675ad30af6fb922/modules/sproto/gd_sproto.h -------------------------------------------------------------------------------- /modules/sproto/register_types.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************/ 2 | /* register_script_types.cpp */ 3 | /*************************************************/ 4 | /* This file is part of: */ 5 | /* GODOT ENGINE */ 6 | /*************************************************/ 7 | /* Source code within this file is: */ 8 | /* (c) 2007-2010 Juan Linietsky, Ariel Manzur */ 9 | /* All Rights Reserved. */ 10 | /*************************************************/ 11 | #include "register_types.h" 12 | #include "gd_sproto.h" 13 | 14 | void register_sproto_types() 15 | { 16 | ObjectTypeDB::register_type(); 17 | } 18 | 19 | void unregister_sproto_types() 20 | { 21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /modules/sproto/register_types.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************/ 2 | /* register_types.h */ 3 | /*************************************************************************/ 4 | /* This file is part of: */ 5 | /* GODOT ENGINE */ 6 | /* http://www.godotengine.org */ 7 | /*************************************************************************/ 8 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ 9 | /* */ 10 | /* Permission is hereby granted, free of charge, to any person obtaining */ 11 | /* a copy of this software and associated documentation files (the */ 12 | /* "Software"), to deal in the Software without restriction, including */ 13 | /* without limitation the rights to use, copy, modify, merge, publish, */ 14 | /* distribute, sublicense, and/or sell copies of the Software, and to */ 15 | /* permit persons to whom the Software is furnished to do so, subject to */ 16 | /* the following conditions: */ 17 | /* */ 18 | /* The above copyright notice and this permission notice shall be */ 19 | /* included in all copies or substantial portions of the Software. */ 20 | /* */ 21 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 22 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 23 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ 24 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ 25 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ 26 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ 27 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 28 | /*************************************************************************/ 29 | void register_sproto_types(); 30 | void unregister_sproto_types(); -------------------------------------------------------------------------------- /test/test_sproto/c2s.spb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangshiqian1214/godot-module/7fa3013ef14616aec1b0c6fcf675ad30af6fb922/test/test_sproto/c2s.spb -------------------------------------------------------------------------------- /test/test_sproto/choose.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene format=1] 2 | 3 | [node name="Node" type="Node"] 4 | 5 | [node name="WindowDialog" type="WindowDialog" parent="."] 6 | 7 | focus/ignore_mouse = false 8 | focus/stop_mouse = true 9 | size_flags/horizontal = 2 10 | size_flags/vertical = 2 11 | margin/left = 1.0 12 | margin/top = 23.0 13 | margin/right = 340.0 14 | margin/bottom = 221.0 15 | popup/exclusive = false 16 | window/title = "Choose" 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/test_sproto/engine.cfg: -------------------------------------------------------------------------------- 1 | [application] 2 | 3 | name="AutoProto" 4 | main_scene="res://main.tscn" 5 | icon="res://icon.png" 6 | 7 | [display] 8 | 9 | width=480 10 | height=320 11 | -------------------------------------------------------------------------------- /test/test_sproto/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangshiqian1214/godot-module/7fa3013ef14616aec1b0c6fcf675ad30af6fb922/test/test_sproto/icon.png -------------------------------------------------------------------------------- /test/test_sproto/icon.png.flags: -------------------------------------------------------------------------------- 1 | gen_mipmaps=false 2 | -------------------------------------------------------------------------------- /test/test_sproto/main.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Panel 3 | 4 | # member variables here, example: 5 | # var a=2 6 | # var b="textvar" 7 | 8 | var sproto 9 | var c2s_sproto_ptr 10 | 11 | func _ready(): 12 | # Called every time the node is added to the scene. 13 | # Initialization here 14 | var f = File.new() 15 | sproto = Sproto.new() 16 | if f.open("res://c2s.spb", File.READ) == OK : 17 | var buffer = f.get_buffer(f.get_len()) 18 | c2s_sproto_ptr = sproto.new_proto(buffer) 19 | print("c2s_sproto_ptr:", c2s_sproto_ptr) 20 | sproto.save_proto(c2s_sproto_ptr, 1) 21 | 22 | pass 23 | 24 | 25 | func _on_ChooseBtn_pressed(): 26 | #get_tree().change_scene("res://choose.tscn") 27 | 28 | pass # replace with function body 29 | 30 | 31 | func _on_Gen_pressed(): 32 | var type_ptr = sproto.query_type(c2s_sproto_ptr, "Person") 33 | print("Person type_ptr:", type_ptr) 34 | var data = sproto.get_default(type_ptr) 35 | print("data:", data) 36 | var person = { 37 | name = "Alice", 38 | id = 10000, 39 | cash = 3.1415926, 40 | myphone = {"number": "01234567890", "type": 3}, 41 | phone = [ 42 | { "number": "123456789", "type": 1 }, 43 | { "number": "87654321", "type": 2 }, 44 | ], 45 | skills = [1, 2, 3, 4], 46 | actvityNames = [], 47 | taskIds = [], 48 | } 49 | var buf = sproto.encode(type_ptr, person) 50 | print("buf.sz:", buf.size()) 51 | 52 | var outdata = sproto.decode(type_ptr, buf) 53 | print("decode outdata:", outdata) 54 | 55 | var packbuf = sproto.pack(buf) 56 | print("packbuf.sz:", packbuf.size()) 57 | 58 | var unpackBuf = sproto.unpack(packbuf) 59 | print("unpackBuf.sz:", unpackBuf.size()) 60 | 61 | pass # replace with function body 62 | -------------------------------------------------------------------------------- /test/test_sproto/main.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=1] 2 | 3 | [ext_resource path="res://main.gd" type="Script" id=1] 4 | 5 | [node name="Panel" type="Panel"] 6 | 7 | focus/ignore_mouse = false 8 | focus/stop_mouse = true 9 | size_flags/horizontal = 2 10 | size_flags/vertical = 2 11 | margin/left = 0.0 12 | margin/top = 0.0 13 | margin/right = 480.0 14 | margin/bottom = 320.0 15 | script/script = ExtResource( 1 ) 16 | 17 | [node name="ChooseBtn" type="Button" parent="."] 18 | 19 | focus/ignore_mouse = false 20 | focus/stop_mouse = true 21 | size_flags/horizontal = 2 22 | size_flags/vertical = 2 23 | margin/left = 343.0 24 | margin/top = 55.0 25 | margin/right = 439.0 26 | margin/bottom = 82.0 27 | toggle_mode = false 28 | enabled_focus_mode = 2 29 | shortcut = null 30 | text = "choose" 31 | flat = false 32 | 33 | [node name="FilePathLine" type="LineEdit" parent="."] 34 | 35 | focus/ignore_mouse = false 36 | focus/stop_mouse = true 37 | size_flags/horizontal = 2 38 | size_flags/vertical = 2 39 | margin/left = 18.0 40 | margin/top = 54.0 41 | margin/right = 307.0 42 | margin/bottom = 82.0 43 | text = "input file path" 44 | placeholder/alpha = 0.6 45 | expand_to_len = false 46 | focus_mode = 2 47 | caret/caret_blink = false 48 | caret/caret_blink_speed = 0.65 49 | 50 | [node name="Gen" type="Button" parent="."] 51 | 52 | focus/ignore_mouse = false 53 | focus/stop_mouse = true 54 | size_flags/horizontal = 2 55 | size_flags/vertical = 2 56 | margin/left = 30.0 57 | margin/top = 139.0 58 | margin/right = 198.0 59 | margin/bottom = 196.0 60 | toggle_mode = false 61 | enabled_focus_mode = 2 62 | shortcut = null 63 | text = "Gen" 64 | flat = false 65 | 66 | [node name="GenAll" type="Button" parent="."] 67 | 68 | focus/ignore_mouse = false 69 | focus/stop_mouse = true 70 | size_flags/horizontal = 2 71 | size_flags/vertical = 2 72 | margin/left = 254.0 73 | margin/top = 138.0 74 | margin/right = 409.0 75 | margin/bottom = 198.0 76 | toggle_mode = false 77 | enabled_focus_mode = 2 78 | shortcut = null 79 | text = "Gen All" 80 | flat = false 81 | 82 | [connection signal="pressed" from="ChooseBtn" to="." method="_on_ChooseBtn_pressed"] 83 | 84 | [connection signal="pressed" from="Gen" to="." method="_on_Gen_pressed"] 85 | 86 | 87 | -------------------------------------------------------------------------------- /thirdparty/sproto/msvcint.h: -------------------------------------------------------------------------------- 1 | #ifndef msvc_int_h 2 | #define msvc_int_h 3 | 4 | #ifdef _MSC_VER 5 | # define inline __inline 6 | # ifndef _MSC_STDINT_H_ 7 | # if (_MSC_VER < 1300) 8 | typedef signed char int8_t; 9 | typedef signed short int16_t; 10 | typedef signed int int32_t; 11 | typedef unsigned char uint8_t; 12 | typedef unsigned short uint16_t; 13 | typedef unsigned int uint32_t; 14 | # else 15 | typedef signed __int8 int8_t; 16 | typedef signed __int16 int16_t; 17 | typedef signed __int32 int32_t; 18 | typedef unsigned __int8 uint8_t; 19 | typedef unsigned __int16 uint16_t; 20 | typedef unsigned __int32 uint32_t; 21 | # endif 22 | typedef signed __int64 int64_t; 23 | typedef unsigned __int64 uint64_t; 24 | # endif 25 | 26 | #else 27 | 28 | #include 29 | 30 | #endif 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /thirdparty/sproto/sproto.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "msvcint.h" 6 | 7 | #include "sproto.h" 8 | 9 | #define SPROTO_TARRAY 0x80 10 | #define CHUNK_SIZE 1000 11 | #define SIZEOF_LENGTH 4 12 | #define SIZEOF_HEADER 2 13 | #define SIZEOF_FIELD 2 14 | 15 | struct field { 16 | int tag; 17 | int type; 18 | const char * name; 19 | struct sproto_type * st; 20 | int key; 21 | int decimal; 22 | }; 23 | 24 | struct sproto_type { 25 | const char * name; 26 | int n; 27 | int base; 28 | int maxn; 29 | struct field *f; 30 | }; 31 | 32 | struct protocol { 33 | const char *name; 34 | int tag; 35 | struct sproto_type * p[2]; 36 | }; 37 | 38 | struct chunk { 39 | struct chunk * next; 40 | }; 41 | 42 | struct pool { 43 | struct chunk * header; 44 | struct chunk * current; 45 | int current_used; 46 | }; 47 | 48 | struct sproto { 49 | struct pool memory; 50 | int type_n; 51 | int protocol_n; 52 | struct sproto_type * type; 53 | struct protocol * proto; 54 | }; 55 | 56 | static void 57 | pool_init(struct pool *p) { 58 | p->header = NULL; 59 | p->current = NULL; 60 | p->current_used = 0; 61 | } 62 | 63 | static void 64 | pool_release(struct pool *p) { 65 | struct chunk * tmp = p->header; 66 | while (tmp) { 67 | struct chunk * n = tmp->next; 68 | free(tmp); 69 | tmp = n; 70 | } 71 | } 72 | 73 | static void * 74 | pool_newchunk(struct pool *p, size_t sz) { 75 | struct chunk * t = malloc(sz + sizeof(struct chunk)); 76 | if (t == NULL) 77 | return NULL; 78 | t->next = p->header; 79 | p->header = t; 80 | return t+1; 81 | } 82 | 83 | static void * 84 | pool_alloc(struct pool *p, size_t sz) { 85 | // align by 8 86 | sz = (sz + 7) & ~7; 87 | if (sz >= CHUNK_SIZE) { 88 | return pool_newchunk(p, sz); 89 | } 90 | if (p->current == NULL) { 91 | if (pool_newchunk(p, CHUNK_SIZE) == NULL) 92 | return NULL; 93 | p->current = p->header; 94 | } 95 | if (sz + p->current_used <= CHUNK_SIZE) { 96 | void * ret = (char *)(p->current+1) + p->current_used; 97 | p->current_used += sz; 98 | return ret; 99 | } 100 | 101 | if (sz >= p->current_used) { 102 | return pool_newchunk(p, sz); 103 | } else { 104 | void * ret = pool_newchunk(p, CHUNK_SIZE); 105 | p->current = p->header; 106 | p->current_used = sz; 107 | return ret; 108 | } 109 | } 110 | 111 | static inline int 112 | toword(const uint8_t * p) { 113 | return p[0] | p[1]<<8; 114 | } 115 | 116 | static inline uint32_t 117 | todword(const uint8_t *p) { 118 | return p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24; 119 | } 120 | 121 | static int 122 | count_array(const uint8_t * stream) { 123 | uint32_t length = todword(stream); 124 | int n = 0; 125 | stream += SIZEOF_LENGTH; 126 | while (length > 0) { 127 | uint32_t nsz; 128 | if (length < SIZEOF_LENGTH) 129 | return -1; 130 | nsz = todword(stream); 131 | nsz += SIZEOF_LENGTH; 132 | if (nsz > length) 133 | return -1; 134 | ++n; 135 | stream += nsz; 136 | length -= nsz; 137 | } 138 | 139 | return n; 140 | } 141 | 142 | static int 143 | struct_field(const uint8_t * stream, size_t sz) { 144 | const uint8_t * field; 145 | int fn, header, i; 146 | if (sz < SIZEOF_LENGTH) 147 | return -1; 148 | fn = toword(stream); 149 | header = SIZEOF_HEADER + SIZEOF_FIELD * fn; 150 | if (sz < header) 151 | return -1; 152 | field = stream + SIZEOF_HEADER; 153 | sz -= header; 154 | stream += header; 155 | for (i=0;imemory, sz+1); 176 | memcpy(buffer, stream+SIZEOF_LENGTH, sz); 177 | buffer[sz] = '\0'; 178 | return buffer; 179 | } 180 | 181 | static int 182 | calc_pow(int base, int n) { 183 | if (n == 0) 184 | return 1; 185 | int r = calc_pow(base * base , n / 2); 186 | if (n&1) { 187 | r *= base; 188 | } 189 | return r; 190 | } 191 | 192 | static const uint8_t * 193 | import_field(struct sproto *s, struct field *f, const uint8_t * stream) { 194 | uint32_t sz; 195 | const uint8_t * result; 196 | int fn; 197 | int i; 198 | int array = 0; 199 | int tag = -1; 200 | f->tag = -1; 201 | f->type = -1; 202 | f->name = NULL; 203 | f->st = NULL; 204 | f->key = -1; 205 | f->decimal = 0; 206 | 207 | sz = todword(stream); 208 | stream += SIZEOF_LENGTH; 209 | result = stream + sz; 210 | fn = struct_field(stream, sz); 211 | if (fn < 0) 212 | return NULL; 213 | stream += SIZEOF_HEADER; 214 | for (i=0;iname = import_string(s, stream + fn * SIZEOF_FIELD); 226 | continue; 227 | } 228 | if (value == 0) 229 | return NULL; 230 | value = value/2 - 1; 231 | switch(tag) { 232 | case 1: // buildin 233 | if (value >= SPROTO_TSTRUCT) 234 | return NULL; // invalid buildin type 235 | f->type = value; 236 | break; 237 | case 2: // type index 238 | if (f->type == SPROTO_TINTEGER) { 239 | f->decimal = calc_pow(10, value); 240 | } else { 241 | if (value >= s->type_n) 242 | return NULL; // invalid type index 243 | if (f->type >= 0) 244 | return NULL; 245 | f->type = SPROTO_TSTRUCT; 246 | f->st = &s->type[value]; 247 | } 248 | break; 249 | case 3: // tag 250 | f->tag = value; 251 | break; 252 | case 4: // array 253 | if (value) 254 | array = SPROTO_TARRAY; 255 | break; 256 | case 5: // key 257 | f->key = value; 258 | break; 259 | default: 260 | return NULL; 261 | } 262 | } 263 | if (f->tag < 0 || f->type < 0 || f->name == NULL) 264 | return NULL; 265 | f->type |= array; 266 | 267 | return result; 268 | } 269 | 270 | /* 271 | .type { 272 | .field { 273 | name 0 : string 274 | buildin 1 : integer 275 | type 2 : integer 276 | tag 3 : integer 277 | array 4 : boolean 278 | } 279 | name 0 : string 280 | fields 1 : *field 281 | } 282 | */ 283 | static const uint8_t * 284 | import_type(struct sproto *s, struct sproto_type *t, const uint8_t * stream) { 285 | const uint8_t * result; 286 | uint32_t sz = todword(stream); 287 | int i; 288 | int fn; 289 | int n; 290 | int maxn; 291 | int last; 292 | stream += SIZEOF_LENGTH; 293 | result = stream + sz; 294 | fn = struct_field(stream, sz); 295 | if (fn <= 0 || fn > 2) 296 | return NULL; 297 | for (i=0;iname = import_string(s, stream); 306 | if (fn == 1) { 307 | return result; 308 | } 309 | stream += todword(stream)+SIZEOF_LENGTH; // second data 310 | n = count_array(stream); 311 | if (n<0) 312 | return NULL; 313 | stream += SIZEOF_LENGTH; 314 | maxn = n; 315 | last = -1; 316 | t->n = n; 317 | t->f = pool_alloc(&s->memory, sizeof(struct field) * n); 318 | for (i=0;if[i]; 321 | stream = import_field(s, f, stream); 322 | if (stream == NULL) 323 | return NULL; 324 | tag = f->tag; 325 | if (tag <= last) 326 | return NULL; // tag must in ascending order 327 | if (tag > last+1) { 328 | ++maxn; 329 | } 330 | last = tag; 331 | } 332 | t->maxn = maxn; 333 | t->base = t->f[0].tag; 334 | n = t->f[n-1].tag - t->base + 1; 335 | if (n != t->n) { 336 | t->base = -1; 337 | } 338 | return result; 339 | } 340 | 341 | /* 342 | .protocol { 343 | name 0 : string 344 | tag 1 : integer 345 | request 2 : integer 346 | response 3 : integer 347 | } 348 | */ 349 | static const uint8_t * 350 | import_protocol(struct sproto *s, struct protocol *p, const uint8_t * stream) { 351 | const uint8_t * result; 352 | uint32_t sz = todword(stream); 353 | int fn; 354 | int i; 355 | int tag; 356 | stream += SIZEOF_LENGTH; 357 | result = stream + sz; 358 | fn = struct_field(stream, sz); 359 | stream += SIZEOF_HEADER; 360 | p->name = NULL; 361 | p->tag = -1; 362 | p->p[SPROTO_REQUEST] = NULL; 363 | p->p[SPROTO_RESPONSE] = NULL; 364 | tag = 0; 365 | for (i=0;iname = import_string(s, stream + SIZEOF_FIELD *fn); 378 | break; 379 | case 1: // tag 380 | if (value < 0) { 381 | return NULL; 382 | } 383 | p->tag = value; 384 | break; 385 | case 2: // request 386 | if (value < 0 || value>=s->type_n) 387 | return NULL; 388 | p->p[SPROTO_REQUEST] = &s->type[value]; 389 | break; 390 | case 3: // response 391 | if (value < 0 || value>=s->type_n) 392 | return NULL; 393 | p->p[SPROTO_RESPONSE] = &s->type[value]; 394 | break; 395 | default: 396 | return NULL; 397 | } 398 | } 399 | 400 | if (p->name == NULL || p->tag<0) { 401 | return NULL; 402 | } 403 | 404 | return result; 405 | } 406 | 407 | static struct sproto * 408 | create_from_bundle(struct sproto *s, const uint8_t * stream, size_t sz) { 409 | const uint8_t * content; 410 | const uint8_t * typedata = NULL; 411 | const uint8_t * protocoldata = NULL; 412 | int fn = struct_field(stream, sz); 413 | int i; 414 | if (fn < 0 || fn > 2) 415 | return NULL; 416 | 417 | stream += SIZEOF_HEADER; 418 | content = stream + fn*SIZEOF_FIELD; 419 | 420 | for (i=0;itype_n = n; 431 | s->type = pool_alloc(&s->memory, n * sizeof(*s->type)); 432 | } else { 433 | protocoldata = content+SIZEOF_LENGTH; 434 | s->protocol_n = n; 435 | s->proto = pool_alloc(&s->memory, n * sizeof(*s->proto)); 436 | } 437 | content += todword(content) + SIZEOF_LENGTH; 438 | } 439 | 440 | for (i=0;itype_n;i++) { 441 | typedata = import_type(s, &s->type[i], typedata); 442 | if (typedata == NULL) { 443 | return NULL; 444 | } 445 | } 446 | for (i=0;iprotocol_n;i++) { 447 | protocoldata = import_protocol(s, &s->proto[i], protocoldata); 448 | if (protocoldata == NULL) { 449 | return NULL; 450 | } 451 | } 452 | 453 | return s; 454 | } 455 | 456 | struct sproto * 457 | sproto_create(const void * proto, size_t sz) { 458 | struct pool mem; 459 | struct sproto * s; 460 | pool_init(&mem); 461 | s = pool_alloc(&mem, sizeof(*s)); 462 | if (s == NULL) 463 | return NULL; 464 | memset(s, 0, sizeof(*s)); 465 | s->memory = mem; 466 | if (create_from_bundle(s, proto, sz) == NULL) { 467 | pool_release(&s->memory); 468 | return NULL; 469 | } 470 | return s; 471 | } 472 | 473 | void 474 | sproto_release(struct sproto * s) { 475 | if (s == NULL) 476 | return; 477 | pool_release(&s->memory); 478 | } 479 | 480 | void 481 | sproto_dump(struct sproto *s) { 482 | int i,j; 483 | static const char * buildin[] = { 484 | "integer", 485 | "boolean", 486 | "string", 487 | }; 488 | printf("=== %d types ===\n", s->type_n); 489 | for (i=0;itype_n;i++) { 490 | struct sproto_type *t = &s->type[i]; 491 | printf("%s\n", t->name); 492 | for (j=0;jn;j++) { 493 | char array[2] = { 0, 0 }; 494 | const char * type_name = NULL; 495 | struct field *f = &t->f[j]; 496 | if (f->type & SPROTO_TARRAY) { 497 | array[0] = '*'; 498 | } else { 499 | array[0] = 0; 500 | } 501 | { 502 | int t = f->type & ~SPROTO_TARRAY; 503 | if (t == SPROTO_TSTRUCT) { 504 | type_name = f->st->name; 505 | } else { 506 | assert(tkey >= 0) { 511 | printf("\t%s (%d) %s%s(%d)\n", f->name, f->tag, array, type_name, f->key); 512 | } else { 513 | printf("\t%s (%d) %s%s\n", f->name, f->tag, array, type_name); 514 | } 515 | } 516 | } 517 | printf("=== %d protocol ===\n", s->protocol_n); 518 | for (i=0;iprotocol_n;i++) { 519 | struct protocol *p = &s->proto[i]; 520 | if (p->p[SPROTO_REQUEST]) { 521 | printf("\t%s (%d) request:%s", p->name, p->tag, p->p[SPROTO_REQUEST]->name); 522 | } else { 523 | printf("\t%s (%d) request:(null)", p->name, p->tag); 524 | } 525 | if (p->p[SPROTO_RESPONSE]) { 526 | printf(" response:%s", p->p[SPROTO_RESPONSE]->name); 527 | } 528 | printf("\n"); 529 | } 530 | } 531 | 532 | // query 533 | int 534 | sproto_prototag(const struct sproto *sp, const char * name) { 535 | int i; 536 | for (i=0;iprotocol_n;i++) { 537 | if (strcmp(name, sp->proto[i].name) == 0) { 538 | return sp->proto[i].tag; 539 | } 540 | } 541 | return -1; 542 | } 543 | 544 | static struct protocol * 545 | query_proto(const struct sproto *sp, int tag) { 546 | int begin = 0, end = sp->protocol_n; 547 | while(beginproto[mid].tag; 550 | if (t==tag) { 551 | return &sp->proto[mid]; 552 | } 553 | if (tag > t) { 554 | begin = mid+1; 555 | } else { 556 | end = mid; 557 | } 558 | } 559 | return NULL; 560 | } 561 | 562 | struct sproto_type * 563 | sproto_protoquery(const struct sproto *sp, int proto, int what) { 564 | struct protocol * p; 565 | if (what <0 || what >1) { 566 | return NULL; 567 | } 568 | p = query_proto(sp, proto); 569 | if (p) { 570 | return p->p[what]; 571 | } 572 | return NULL; 573 | } 574 | 575 | const char * 576 | sproto_protoname(const struct sproto *sp, int proto) { 577 | struct protocol * p = query_proto(sp, proto); 578 | if (p) { 579 | return p->name; 580 | } 581 | return NULL; 582 | } 583 | 584 | struct sproto_type * 585 | sproto_type(const struct sproto *sp, const char * type_name) { 586 | int i; 587 | for (i=0;itype_n;i++) { 588 | if (strcmp(type_name, sp->type[i].name) == 0) { 589 | return &sp->type[i]; 590 | } 591 | } 592 | return NULL; 593 | } 594 | 595 | const char * 596 | sproto_name(struct sproto_type * st) { 597 | return st->name; 598 | } 599 | 600 | static struct field * 601 | findtag(const struct sproto_type *st, int tag) { 602 | int begin, end; 603 | if (st->base >=0 ) { 604 | tag -= st->base; 605 | if (tag < 0 || tag >= st->n) 606 | return NULL; 607 | return &st->f[tag]; 608 | } 609 | begin = 0; 610 | end = st->n; 611 | while (begin < end) { 612 | int mid = (begin+end)/2; 613 | struct field *f = &st->f[mid]; 614 | int t = f->tag; 615 | if (t == tag) { 616 | return f; 617 | } 618 | if (tag > t) { 619 | begin = mid + 1; 620 | } else { 621 | end = mid; 622 | } 623 | } 624 | return NULL; 625 | } 626 | 627 | // encode & decode 628 | // sproto_callback(void *ud, int tag, int type, struct sproto_type *, void *value, int length) 629 | // return size, -1 means error 630 | 631 | static inline int 632 | fill_size(uint8_t * data, int sz) { 633 | data[0] = sz & 0xff; 634 | data[1] = (sz >> 8) & 0xff; 635 | data[2] = (sz >> 16) & 0xff; 636 | data[3] = (sz >> 24) & 0xff; 637 | return sz + SIZEOF_LENGTH; 638 | } 639 | 640 | static int 641 | encode_integer(uint32_t v, uint8_t * data, int size) { 642 | if (size < SIZEOF_LENGTH + sizeof(v)) 643 | return -1; 644 | data[4] = v & 0xff; 645 | data[5] = (v >> 8) & 0xff; 646 | data[6] = (v >> 16) & 0xff; 647 | data[7] = (v >> 24) & 0xff; 648 | return fill_size(data, sizeof(v)); 649 | } 650 | 651 | static int 652 | encode_uint64(uint64_t v, uint8_t * data, int size) { 653 | if (size < SIZEOF_LENGTH + sizeof(v)) 654 | return -1; 655 | data[4] = v & 0xff; 656 | data[5] = (v >> 8) & 0xff; 657 | data[6] = (v >> 16) & 0xff; 658 | data[7] = (v >> 24) & 0xff; 659 | data[8] = (v >> 32) & 0xff; 660 | data[9] = (v >> 40) & 0xff; 661 | data[10] = (v >> 48) & 0xff; 662 | data[11] = (v >> 56) & 0xff; 663 | return fill_size(data, sizeof(v)); 664 | } 665 | 666 | /* 667 | //#define CB(tagname,type,index,subtype,value,length) cb(ud, tagname,type,index,subtype,value,length) 668 | 669 | static int 670 | do_cb(sproto_callback cb, void *ud, const char *tagname, int type, int index, struct sproto_type *subtype, void *value, int length) { 671 | if (subtype) { 672 | if (type >= 0) { 673 | printf("callback: tag=%s[%d], subtype[%s]:%d\n",tagname,index, subtype->name, type); 674 | } else { 675 | printf("callback: tag=%s[%d], subtype[%s]\n",tagname,index, subtype->name); 676 | } 677 | } else if (index > 0) { 678 | printf("callback: tag=%s[%d]\n",tagname,index); 679 | } else if (index == 0) { 680 | printf("callback: tag=%s\n",tagname); 681 | } else { 682 | printf("callback: tag=%s [mainkey]\n",tagname); 683 | } 684 | return cb(ud, tagname,type,index,subtype,value,length); 685 | } 686 | #define CB(tagname,type,index,subtype,value,length) do_cb(cb,ud, tagname,type,index,subtype,value,length) 687 | */ 688 | 689 | static int 690 | encode_object(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int size) { 691 | int sz; 692 | if (size < SIZEOF_LENGTH) 693 | return -1; 694 | args->value = data+SIZEOF_LENGTH; 695 | args->length = size-SIZEOF_LENGTH; 696 | sz = cb(args); 697 | if (sz < 0) { 698 | if (sz == SPROTO_CB_NIL) 699 | return 0; 700 | return -1; // sz == SPROTO_CB_ERROR 701 | } 702 | assert(sz <= size-SIZEOF_LENGTH); // verify buffer overflow 703 | return fill_size(data, sz); 704 | } 705 | 706 | static inline void 707 | uint32_to_uint64(int negative, uint8_t *buffer) { 708 | if (negative) { 709 | buffer[4] = 0xff; 710 | buffer[5] = 0xff; 711 | buffer[6] = 0xff; 712 | buffer[7] = 0xff; 713 | } else { 714 | buffer[4] = 0; 715 | buffer[5] = 0; 716 | buffer[6] = 0; 717 | buffer[7] = 0; 718 | } 719 | } 720 | 721 | static uint8_t * 722 | encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffer, int size, int *noarray) { 723 | uint8_t * header = buffer; 724 | int intlen; 725 | int index; 726 | if (size < 1) 727 | return NULL; 728 | buffer++; 729 | size--; 730 | intlen = sizeof(uint32_t); 731 | index = 1; 732 | *noarray = 0; 733 | 734 | for (;;) { 735 | int sz; 736 | union { 737 | uint64_t u64; 738 | uint32_t u32; 739 | } u; 740 | args->value = &u; 741 | args->length = sizeof(u); 742 | args->index = index; 743 | sz = cb(args); 744 | if (sz <= 0) { 745 | if (sz == SPROTO_CB_NIL) // nil object, end of array 746 | break; 747 | if (sz == SPROTO_CB_NOARRAY) { // no array, don't encode it 748 | *noarray = 1; 749 | break; 750 | } 751 | return NULL; // sz == SPROTO_CB_ERROR 752 | } 753 | if (size < sizeof(uint64_t)) 754 | return NULL; 755 | if (sz == sizeof(uint32_t)) { 756 | uint32_t v = u.u32; 757 | buffer[0] = v & 0xff; 758 | buffer[1] = (v >> 8) & 0xff; 759 | buffer[2] = (v >> 16) & 0xff; 760 | buffer[3] = (v >> 24) & 0xff; 761 | 762 | if (intlen == sizeof(uint64_t)) { 763 | uint32_to_uint64(v & 0x80000000, buffer); 764 | } 765 | } else { 766 | uint64_t v; 767 | if (sz != sizeof(uint64_t)) 768 | return NULL; 769 | if (intlen == sizeof(uint32_t)) { 770 | int i; 771 | // rearrange 772 | size -= (index-1) * sizeof(uint32_t); 773 | if (size < sizeof(uint64_t)) 774 | return NULL; 775 | buffer += (index-1) * sizeof(uint32_t); 776 | for (i=index-2;i>=0;i--) { 777 | int negative; 778 | memcpy(header+1+i*sizeof(uint64_t), header+1+i*sizeof(uint32_t), sizeof(uint32_t)); 779 | negative = header[1+i*sizeof(uint64_t)+3] & 0x80; 780 | uint32_to_uint64(negative, header+1+i*sizeof(uint64_t)); 781 | } 782 | intlen = sizeof(uint64_t); 783 | } 784 | 785 | v = u.u64; 786 | buffer[0] = v & 0xff; 787 | buffer[1] = (v >> 8) & 0xff; 788 | buffer[2] = (v >> 16) & 0xff; 789 | buffer[3] = (v >> 24) & 0xff; 790 | buffer[4] = (v >> 32) & 0xff; 791 | buffer[5] = (v >> 40) & 0xff; 792 | buffer[6] = (v >> 48) & 0xff; 793 | buffer[7] = (v >> 56) & 0xff; 794 | } 795 | 796 | size -= intlen; 797 | buffer += intlen; 798 | index++; 799 | } 800 | 801 | if (buffer == header + 1) { 802 | return header; 803 | } 804 | *header = (uint8_t)intlen; 805 | return buffer; 806 | } 807 | 808 | static int 809 | encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int size) { 810 | uint8_t * buffer; 811 | int sz; 812 | if (size < SIZEOF_LENGTH) 813 | return -1; 814 | size -= SIZEOF_LENGTH; 815 | buffer = data + SIZEOF_LENGTH; 816 | switch (args->type) { 817 | case SPROTO_TINTEGER: { 818 | int noarray; 819 | buffer = encode_integer_array(cb,args,buffer,size, &noarray); 820 | if (buffer == NULL) 821 | return -1; 822 | 823 | if (noarray) { 824 | return 0; 825 | } 826 | break; 827 | } 828 | case SPROTO_TBOOLEAN: 829 | args->index = 1; 830 | for (;;) { 831 | int v = 0; 832 | args->value = &v; 833 | args->length = sizeof(v); 834 | sz = cb(args); 835 | if (sz < 0) { 836 | if (sz == SPROTO_CB_NIL) // nil object , end of array 837 | break; 838 | if (sz == SPROTO_CB_NOARRAY) // no array, don't encode it 839 | return 0; 840 | return -1; // sz == SPROTO_CB_ERROR 841 | } 842 | if (size < 1) 843 | return -1; 844 | buffer[0] = v ? 1: 0; 845 | size -= 1; 846 | buffer += 1; 847 | ++args->index; 848 | } 849 | break; 850 | default: 851 | args->index = 1; 852 | for (;;) { 853 | if (size < SIZEOF_LENGTH) 854 | return -1; 855 | size -= SIZEOF_LENGTH; 856 | args->value = buffer+SIZEOF_LENGTH; 857 | args->length = size; 858 | sz = cb(args); 859 | if (sz < 0) { 860 | if (sz == SPROTO_CB_NIL) { 861 | break; 862 | } 863 | if (sz == SPROTO_CB_NOARRAY) // no array, don't encode it 864 | return 0; 865 | return -1; // sz == SPROTO_CB_ERROR 866 | } 867 | fill_size(buffer, sz); 868 | buffer += SIZEOF_LENGTH+sz; 869 | size -=sz; 870 | ++args->index; 871 | } 872 | break; 873 | } 874 | sz = buffer - (data + SIZEOF_LENGTH); 875 | return fill_size(data, sz); 876 | } 877 | 878 | int 879 | sproto_encode(const struct sproto_type *st, void * buffer, int size, sproto_callback cb, void *ud) { 880 | struct sproto_arg args; 881 | uint8_t * header = buffer; 882 | uint8_t * data; 883 | int header_sz = SIZEOF_HEADER + st->maxn * SIZEOF_FIELD; 884 | int i; 885 | int index; 886 | int lasttag; 887 | int datasz; 888 | if (size < header_sz) 889 | return -1; 890 | args.ud = ud; 891 | data = header + header_sz; 892 | size -= header_sz; 893 | index = 0; 894 | lasttag = -1; 895 | for (i=0;in;i++) { 896 | struct field *f = &st->f[i]; 897 | int type = f->type; 898 | int value = 0; 899 | int sz = -1; 900 | args.tagname = f->name; 901 | args.tagid = f->tag; 902 | args.subtype = f->st; 903 | args.mainindex = f->key; 904 | args.decimal = f->decimal; 905 | if (type & SPROTO_TARRAY) { 906 | args.type = type & ~SPROTO_TARRAY; 907 | sz = encode_array(cb, &args, data, size); 908 | } else { 909 | args.type = type; 910 | args.index = 0; 911 | switch(type) { 912 | case SPROTO_TINTEGER: 913 | case SPROTO_TBOOLEAN: { 914 | union { 915 | uint64_t u64; 916 | uint32_t u32; 917 | } u; 918 | args.value = &u; 919 | args.length = sizeof(u); 920 | sz = cb(&args); 921 | if (sz < 0) { 922 | if (sz == SPROTO_CB_NIL) 923 | continue; 924 | if (sz == SPROTO_CB_NOARRAY) // no array, don't encode it 925 | return 0; 926 | return -1; // sz == SPROTO_CB_ERROR 927 | } 928 | if (sz == sizeof(uint32_t)) { 929 | if (u.u32 < 0x7fff) { 930 | value = (u.u32+1) * 2; 931 | sz = 2; // sz can be any number > 0 932 | } else { 933 | sz = encode_integer(u.u32, data, size); 934 | } 935 | } else if (sz == sizeof(uint64_t)) { 936 | sz= encode_uint64(u.u64, data, size); 937 | } else { 938 | return -1; 939 | } 940 | break; 941 | } 942 | case SPROTO_TSTRUCT: 943 | case SPROTO_TSTRING: 944 | sz = encode_object(cb, &args, data, size); 945 | break; 946 | } 947 | } 948 | if (sz < 0) 949 | return -1; 950 | if (sz > 0) { 951 | uint8_t * record; 952 | int tag; 953 | if (value == 0) { 954 | data += sz; 955 | size -= sz; 956 | } 957 | record = header+SIZEOF_HEADER+SIZEOF_FIELD*index; 958 | tag = f->tag - lasttag - 1; 959 | if (tag > 0) { 960 | // skip tag 961 | tag = (tag - 1) * 2 + 1; 962 | if (tag > 0xffff) 963 | return -1; 964 | record[0] = tag & 0xff; 965 | record[1] = (tag >> 8) & 0xff; 966 | ++index; 967 | record += SIZEOF_FIELD; 968 | } 969 | ++index; 970 | record[0] = value & 0xff; 971 | record[1] = (value >> 8) & 0xff; 972 | lasttag = f->tag; 973 | } 974 | } 975 | header[0] = index & 0xff; 976 | header[1] = (index >> 8) & 0xff; 977 | 978 | datasz = data - (header + header_sz); 979 | data = header + header_sz; 980 | if (index != st->maxn) { 981 | memmove(header + SIZEOF_HEADER + index * SIZEOF_FIELD, data, datasz); 982 | } 983 | return SIZEOF_HEADER + index * SIZEOF_FIELD + datasz; 984 | } 985 | 986 | static int 987 | decode_array_object(sproto_callback cb, struct sproto_arg *args, uint8_t * stream, int sz) { 988 | uint32_t hsz; 989 | int index = 1; 990 | while (sz > 0) { 991 | if (sz < SIZEOF_LENGTH) 992 | return -1; 993 | hsz = todword(stream); 994 | stream += SIZEOF_LENGTH; 995 | sz -= SIZEOF_LENGTH; 996 | if (hsz > sz) 997 | return -1; 998 | args->index = index; 999 | args->value = stream; 1000 | args->length = hsz; 1001 | if (cb(args)) 1002 | return -1; 1003 | sz -= hsz; 1004 | stream += hsz; 1005 | ++index; 1006 | } 1007 | return 0; 1008 | } 1009 | 1010 | static inline uint64_t 1011 | expand64(uint32_t v) { 1012 | uint64_t value = v; 1013 | if (value & 0x80000000) { 1014 | value |= (uint64_t)~0 << 32 ; 1015 | } 1016 | return value; 1017 | } 1018 | 1019 | static int 1020 | decode_array(sproto_callback cb, struct sproto_arg *args, uint8_t * stream) { 1021 | uint32_t sz = todword(stream); 1022 | int type = args->type; 1023 | int i; 1024 | if (sz == 0) { 1025 | // It's empty array, call cb with index == -1 to create the empty array. 1026 | args->index = -1; 1027 | args->value = NULL; 1028 | args->length = 0; 1029 | cb(args); 1030 | return 0; 1031 | } 1032 | stream += SIZEOF_LENGTH; 1033 | switch (type) { 1034 | case SPROTO_TINTEGER: { 1035 | int len = *stream; 1036 | ++stream; 1037 | --sz; 1038 | if (len == sizeof(uint32_t)) { 1039 | if (sz % sizeof(uint32_t) != 0) 1040 | return -1; 1041 | for (i=0;iindex = i+1; 1044 | args->value = &value; 1045 | args->length = sizeof(value); 1046 | cb(args); 1047 | } 1048 | } else if (len == sizeof(uint64_t)) { 1049 | if (sz % sizeof(uint64_t) != 0) 1050 | return -1; 1051 | for (i=0;iindex = i+1; 1056 | args->value = &value; 1057 | args->length = sizeof(value); 1058 | cb(args); 1059 | } 1060 | } else { 1061 | return -1; 1062 | } 1063 | break; 1064 | } 1065 | case SPROTO_TBOOLEAN: 1066 | for (i=0;iindex = i+1; 1069 | args->value = &value; 1070 | args->length = sizeof(value); 1071 | cb(args); 1072 | } 1073 | break; 1074 | case SPROTO_TSTRING: 1075 | case SPROTO_TSTRUCT: 1076 | return decode_array_object(cb, args, stream, sz); 1077 | default: 1078 | return -1; 1079 | } 1080 | return 0; 1081 | } 1082 | 1083 | int 1084 | sproto_decode(const struct sproto_type *st, const void * data, int size, sproto_callback cb, void *ud) { 1085 | struct sproto_arg args; 1086 | int total = size; 1087 | uint8_t * stream; 1088 | uint8_t * datastream; 1089 | int fn; 1090 | int i; 1091 | int tag; 1092 | if (size < SIZEOF_HEADER) 1093 | return -1; 1094 | // debug print 1095 | // printf("sproto_decode[%p] (%s)\n", ud, st->name); 1096 | stream = (void *)data; 1097 | fn = toword(stream); 1098 | stream += SIZEOF_HEADER; 1099 | size -= SIZEOF_HEADER ; 1100 | if (size < fn * SIZEOF_FIELD) 1101 | return -1; 1102 | datastream = stream + fn * SIZEOF_FIELD; 1103 | size -= fn * SIZEOF_FIELD; 1104 | args.ud = ud; 1105 | 1106 | tag = -1; 1107 | for (i=0;iname; 1132 | args.tagid = f->tag; 1133 | args.type = f->type & ~SPROTO_TARRAY; 1134 | args.subtype = f->st; 1135 | args.index = 0; 1136 | args.mainindex = f->key; 1137 | args.decimal = f->decimal; 1138 | if (value < 0) { 1139 | if (f->type & SPROTO_TARRAY) { 1140 | if (decode_array(cb, &args, currentdata)) { 1141 | return -1; 1142 | } 1143 | } else { 1144 | switch (f->type) { 1145 | case SPROTO_TINTEGER: { 1146 | uint32_t sz = todword(currentdata); 1147 | if (sz == sizeof(uint32_t)) { 1148 | uint64_t v = expand64(todword(currentdata + SIZEOF_LENGTH)); 1149 | args.value = &v; 1150 | args.length = sizeof(v); 1151 | cb(&args); 1152 | } else if (sz != sizeof(uint64_t)) { 1153 | return -1; 1154 | } else { 1155 | uint32_t low = todword(currentdata + SIZEOF_LENGTH); 1156 | uint32_t hi = todword(currentdata + SIZEOF_LENGTH + sizeof(uint32_t)); 1157 | uint64_t v = (uint64_t)low | (uint64_t) hi << 32; 1158 | args.value = &v; 1159 | args.length = sizeof(v); 1160 | cb(&args); 1161 | } 1162 | break; 1163 | } 1164 | case SPROTO_TSTRING: 1165 | case SPROTO_TSTRUCT: { 1166 | uint32_t sz = todword(currentdata); 1167 | args.value = currentdata+SIZEOF_LENGTH; 1168 | args.length = sz; 1169 | if (cb(&args)) 1170 | return -1; 1171 | break; 1172 | } 1173 | default: 1174 | return -1; 1175 | } 1176 | } 1177 | } else if (f->type != SPROTO_TINTEGER && f->type != SPROTO_TBOOLEAN) { 1178 | return -1; 1179 | } else { 1180 | uint64_t v = value; 1181 | args.value = &v; 1182 | args.length = sizeof(v); 1183 | cb(&args); 1184 | } 1185 | } 1186 | return total - size; 1187 | } 1188 | 1189 | // 0 pack 1190 | 1191 | static int 1192 | pack_seg(const uint8_t *src, uint8_t * buffer, int sz, int n) { 1193 | uint8_t header = 0; 1194 | int notzero = 0; 1195 | int i; 1196 | uint8_t * obuffer = buffer; 1197 | ++buffer; 1198 | --sz; 1199 | if (sz < 0) 1200 | obuffer = NULL; 1201 | 1202 | for (i=0;i<8;i++) { 1203 | if (src[i] != 0) { 1204 | notzero++; 1205 | header |= 1< 0) { 1207 | *buffer = src[i]; 1208 | ++buffer; 1209 | --sz; 1210 | } 1211 | } 1212 | } 1213 | if ((notzero == 7 || notzero == 6) && n > 0) { 1214 | notzero = 8; 1215 | } 1216 | if (notzero == 8) { 1217 | if (n > 0) { 1218 | return 8; 1219 | } else { 1220 | return 10; 1221 | } 1222 | } 1223 | if (obuffer) { 1224 | *obuffer = header; 1225 | } 1226 | return notzero + 1; 1227 | } 1228 | 1229 | static inline void 1230 | write_ff(const uint8_t * src, uint8_t * des, int n) { 1231 | int i; 1232 | int align8_n = (n+7)&(~7); 1233 | 1234 | des[0] = 0xff; 1235 | des[1] = align8_n/8 - 1; 1236 | memcpy(des+2, src, n); 1237 | for(i=0; i< align8_n-n; i++){ 1238 | des[n+2+i] = 0; 1239 | } 1240 | } 1241 | 1242 | int 1243 | sproto_pack(const void * srcv, int srcsz, void * bufferv, int bufsz) { 1244 | uint8_t tmp[8]; 1245 | int i; 1246 | const uint8_t * ff_srcstart = NULL; 1247 | uint8_t * ff_desstart = NULL; 1248 | int ff_n = 0; 1249 | int size = 0; 1250 | const uint8_t * src = srcv; 1251 | uint8_t * buffer = bufferv; 1252 | for (i=0;i 0) { 1256 | int j; 1257 | memcpy(tmp, src, 8-padding); 1258 | for (j=0;j0) { 1271 | ++ff_n; 1272 | if (ff_n == 256) { 1273 | if (bufsz >= 0) { 1274 | write_ff(ff_srcstart, ff_desstart, 256*8); 1275 | } 1276 | ff_n = 0; 1277 | } 1278 | } else { 1279 | if (ff_n > 0) { 1280 | if (bufsz >= 0) { 1281 | write_ff(ff_srcstart, ff_desstart, ff_n*8); 1282 | } 1283 | ff_n = 0; 1284 | } 1285 | } 1286 | src += 8; 1287 | buffer += n; 1288 | size += n; 1289 | } 1290 | if(bufsz >= 0){ 1291 | if(ff_n == 1) 1292 | write_ff(ff_srcstart, ff_desstart, 8); 1293 | else if (ff_n > 1) 1294 | write_ff(ff_srcstart, ff_desstart, srcsz - (intptr_t)(ff_srcstart - (const uint8_t*)srcv)); 1295 | } 1296 | return size; 1297 | } 1298 | 1299 | int 1300 | sproto_unpack(const void * srcv, int srcsz, void * bufferv, int bufsz) { 1301 | const uint8_t * src = srcv; 1302 | uint8_t * buffer = bufferv; 1303 | int size = 0; 1304 | while (srcsz > 0) { 1305 | uint8_t header = src[0]; 1306 | --srcsz; 1307 | ++src; 1308 | if (header == 0xff) { 1309 | int n; 1310 | if (srcsz < 0) { 1311 | return -1; 1312 | } 1313 | n = (src[0] + 1) * 8; 1314 | if (srcsz < n + 1) 1315 | return -1; 1316 | srcsz -= n + 1; 1317 | ++src; 1318 | if (bufsz >= n) { 1319 | memcpy(buffer, src, n); 1320 | } 1321 | bufsz -= n; 1322 | buffer += n; 1323 | src += n; 1324 | size += n; 1325 | } else { 1326 | int i; 1327 | for (i=0;i<8;i++) { 1328 | int nz = (header >> i) & 1; 1329 | if (nz) { 1330 | if (srcsz < 0) 1331 | return -1; 1332 | if (bufsz > 0) { 1333 | *buffer = *src; 1334 | --bufsz; 1335 | ++buffer; 1336 | } 1337 | ++src; 1338 | --srcsz; 1339 | } else { 1340 | if (bufsz > 0) { 1341 | *buffer = 0; 1342 | --bufsz; 1343 | ++buffer; 1344 | } 1345 | } 1346 | ++size; 1347 | } 1348 | } 1349 | } 1350 | return size; 1351 | } 1352 | -------------------------------------------------------------------------------- /thirdparty/sproto/sproto.h: -------------------------------------------------------------------------------- 1 | #ifndef sproto_h 2 | #define sproto_h 3 | 4 | #include 5 | 6 | struct sproto; 7 | struct sproto_type; 8 | 9 | #define SPROTO_REQUEST 0 10 | #define SPROTO_RESPONSE 1 11 | 12 | #define SPROTO_TINTEGER 0 13 | #define SPROTO_TBOOLEAN 1 14 | #define SPROTO_TSTRING 2 15 | #define SPROTO_TSTRUCT 3 16 | 17 | #define SPROTO_CB_ERROR -1 18 | #define SPROTO_CB_NIL -2 19 | #define SPROTO_CB_NOARRAY -3 20 | 21 | struct sproto * sproto_create(const void * proto, size_t sz); 22 | void sproto_release(struct sproto *); 23 | 24 | int sproto_prototag(const struct sproto *, const char * name); 25 | const char * sproto_protoname(const struct sproto *, int proto); 26 | // SPROTO_REQUEST(0) : request, SPROTO_RESPONSE(1): response 27 | struct sproto_type * sproto_protoquery(const struct sproto *, int proto, int what); 28 | 29 | struct sproto_type * sproto_type(const struct sproto *, const char * type_name); 30 | 31 | int sproto_pack(const void * src, int srcsz, void * buffer, int bufsz); 32 | int sproto_unpack(const void * src, int srcsz, void * buffer, int bufsz); 33 | 34 | struct sproto_arg { 35 | void *ud; 36 | const char *tagname; 37 | int tagid; 38 | int type; 39 | struct sproto_type *subtype; 40 | void *value; 41 | int length; 42 | int index; // array base 1 43 | int mainindex; // for map 44 | int decimal; // for decimal 45 | }; 46 | 47 | typedef int (*sproto_callback)(const struct sproto_arg *args); 48 | 49 | int sproto_decode(const struct sproto_type *, const void * data, int size, sproto_callback cb, void *ud); 50 | int sproto_encode(const struct sproto_type *, void * buffer, int size, sproto_callback cb, void *ud); 51 | 52 | // for debug use 53 | void sproto_dump(struct sproto *); 54 | const char * sproto_name(struct sproto_type *); 55 | 56 | #endif 57 | --------------------------------------------------------------------------------