├── LICENSE ├── Makefile ├── README.md ├── serialize.c ├── test.lua └── test2.lua /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 codingnow.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all : serialize 2 | 3 | linux : serialize.so 4 | 5 | serialize.so : serialize.c 6 | gcc -Wall -g -o $@ -fPIC --shared $^ 7 | 8 | serialize : serialize.c 9 | gcc -Wall -g -o $@.dll --shared $^ -I/usr/local/include -L/usr/local/bin -llua53 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ```lua 2 | serialize = require "serialize" 3 | 4 | -- pack serialize lua objects into a lightuserdata (use malloc internal) 5 | -- It support type : nil , number , boolean, lightuserdata , string , table (without recursion) 6 | bin = serialize.pack (...) 7 | 8 | -- You can append some objects end of the binary block packed before 9 | serialize.append(bin, ...) 10 | 11 | -- unpack extract ... from bin, and free the memory. 12 | -- You can only unpack binary block once. 13 | serialize.unpack(bin) 14 | 15 | -- You can use serialize.serialize(bin) to serialize them to one block 16 | -- You can send the block to the other process. 17 | local block, length = serialize.serialize(bin) 18 | serialize.deserialize(block) 19 | ``` -------------------------------------------------------------------------------- /serialize.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define TYPE_NIL 0 9 | #define TYPE_BOOLEAN 1 10 | // hibits 0 false 1 true 11 | 12 | #define TYPE_NUMBER 2 13 | // hibits 0 : 0 , 1: byte, 2:word, 4: dword, 6: qword, 8 : double 14 | #define TYPE_NUMBER_ZERO 0 15 | #define TYPE_NUMBER_BYTE 1 16 | #define TYPE_NUMBER_WORD 2 17 | #define TYPE_NUMBER_DWORD 4 18 | #define TYPE_NUMBER_QWORD 6 19 | #define TYPE_NUMBER_REAL 8 20 | 21 | #define TYPE_USERDATA 3 22 | #define TYPE_SHORT_STRING 4 23 | // hibits 0~31 : len 24 | #define TYPE_LONG_STRING 5 25 | #define TYPE_TABLE 6 26 | 27 | #define MAX_COOKIE 32 28 | #define COMBINE_TYPE(t,v) ((t) | (v) << 3) 29 | 30 | #define BLOCK_SIZE 128 31 | #define MAX_DEPTH 32 32 | 33 | struct block { 34 | struct block * next; 35 | char buffer[BLOCK_SIZE]; 36 | }; 37 | 38 | struct write_block { 39 | struct block * head; 40 | int len; 41 | struct block * current; 42 | int ptr; 43 | }; 44 | 45 | struct read_block { 46 | char * buffer; 47 | struct block * current; 48 | int len; 49 | int ptr; 50 | }; 51 | 52 | inline static struct block * 53 | blk_alloc(void) { 54 | struct block *b = malloc(sizeof(struct block)); 55 | b->next = NULL; 56 | return b; 57 | } 58 | 59 | inline static void 60 | wb_push(struct write_block *b, const void *buf, int sz) { 61 | const char * buffer = buf; 62 | if (b->ptr == BLOCK_SIZE) { 63 | _again: 64 | b->current = b->current->next = blk_alloc(); 65 | b->ptr = 0; 66 | } 67 | if (b->ptr <= BLOCK_SIZE - sz) { 68 | memcpy(b->current->buffer + b->ptr, buffer, sz); 69 | b->ptr+=sz; 70 | b->len+=sz; 71 | } else { 72 | int copy = BLOCK_SIZE - b->ptr; 73 | memcpy(b->current->buffer + b->ptr, buffer, copy); 74 | buffer += copy; 75 | b->len += copy; 76 | sz -= copy; 77 | goto _again; 78 | } 79 | } 80 | 81 | static void 82 | wb_init(struct write_block *wb , struct block *b) { 83 | if (b==NULL) { 84 | wb->head = blk_alloc(); 85 | wb->len = 0; 86 | wb->current = wb->head; 87 | wb->ptr = 0; 88 | wb_push(wb, &wb->len, sizeof(wb->len)); 89 | } else { 90 | wb->head = b; 91 | int * plen = (int *)b->buffer; 92 | int sz = *plen; 93 | wb->len = sz; 94 | while (b->next) { 95 | sz -= BLOCK_SIZE; 96 | b = b->next; 97 | } 98 | wb->current = b; 99 | wb->ptr = sz; 100 | } 101 | } 102 | 103 | static struct block * 104 | wb_close(struct write_block *b) { 105 | b->current = b->head; 106 | b->ptr = 0; 107 | wb_push(b, &b->len, sizeof(b->len)); 108 | b->current = NULL; 109 | return b->head; 110 | } 111 | 112 | static void 113 | wb_free(struct write_block *wb) { 114 | struct block *blk = wb->head; 115 | while (blk) { 116 | struct block * next = blk->next; 117 | free(blk); 118 | blk = next; 119 | } 120 | wb->head = NULL; 121 | wb->current = NULL; 122 | wb->ptr = 0; 123 | wb->len = 0; 124 | } 125 | 126 | static void 127 | rball_init(struct read_block * rb, char * buffer) { 128 | rb->buffer = buffer; 129 | rb->current = NULL; 130 | uint8_t header[4]; 131 | memcpy(header,buffer,4); 132 | rb->len = header[0] | header[1] <<8 | header[2] << 16 | header[3] << 24; 133 | rb->ptr = 4; 134 | rb->len -= rb->ptr; 135 | } 136 | 137 | static int 138 | rb_init(struct read_block *rb, struct block *b) { 139 | rb->buffer = NULL; 140 | rb->current = b; 141 | memcpy(&(rb->len),b->buffer,sizeof(rb->len)); 142 | rb->ptr = sizeof(rb->len); 143 | rb->len -= rb->ptr; 144 | return rb->len; 145 | } 146 | 147 | static void * 148 | rb_read(struct read_block *rb, void *buffer, int sz) { 149 | if (rb->len < sz) { 150 | return NULL; 151 | } 152 | 153 | if (rb->buffer) { 154 | int ptr = rb->ptr; 155 | rb->ptr += sz; 156 | rb->len -= sz; 157 | return rb->buffer + ptr; 158 | } 159 | 160 | if (rb->ptr == BLOCK_SIZE) { 161 | struct block * next = rb->current->next; 162 | free(rb->current); 163 | rb->current = next; 164 | rb->ptr = 0; 165 | } 166 | 167 | int copy = BLOCK_SIZE - rb->ptr; 168 | 169 | if (sz <= copy) { 170 | void * ret = rb->current->buffer + rb->ptr; 171 | rb->ptr += sz; 172 | rb->len -= sz; 173 | return ret; 174 | } 175 | 176 | char * tmp = buffer; 177 | 178 | memcpy(tmp, rb->current->buffer + rb->ptr, copy); 179 | sz -= copy; 180 | tmp += copy; 181 | rb->len -= copy; 182 | 183 | for (;;) { 184 | struct block * next = rb->current->next; 185 | free(rb->current); 186 | rb->current = next; 187 | 188 | if (sz < BLOCK_SIZE) { 189 | memcpy(tmp, rb->current->buffer, sz); 190 | rb->ptr = sz; 191 | rb->len -= sz; 192 | return buffer; 193 | } 194 | memcpy(tmp, rb->current->buffer, BLOCK_SIZE); 195 | sz -= BLOCK_SIZE; 196 | tmp += BLOCK_SIZE; 197 | rb->len -= BLOCK_SIZE; 198 | } 199 | } 200 | 201 | static void 202 | rb_close(struct read_block *rb) { 203 | while (rb->current) { 204 | struct block * next = rb->current->next; 205 | free(rb->current); 206 | rb->current = next; 207 | } 208 | rb->len = 0; 209 | rb->ptr = 0; 210 | } 211 | 212 | static inline void 213 | wb_nil(struct write_block *wb) { 214 | int n = TYPE_NIL; 215 | wb_push(wb, &n, 1); 216 | } 217 | 218 | static inline void 219 | wb_boolean(struct write_block *wb, int boolean) { 220 | int n = COMBINE_TYPE(TYPE_BOOLEAN , boolean ? 1 : 0); 221 | wb_push(wb, &n, 1); 222 | } 223 | 224 | static inline void 225 | wb_integer(struct write_block *wb, lua_Integer v) { 226 | int type = TYPE_NUMBER; 227 | if (v == 0) { 228 | uint8_t n = COMBINE_TYPE(type , TYPE_NUMBER_ZERO); 229 | wb_push(wb, &n, 1); 230 | } else if (v != (int32_t)v) { 231 | uint8_t n = COMBINE_TYPE(type , TYPE_NUMBER_QWORD); 232 | int64_t v64 = v; 233 | wb_push(wb, &n, 1); 234 | wb_push(wb, &v64, sizeof(v64)); 235 | } else if (v < 0) { 236 | int32_t v32 = (int32_t)v; 237 | uint8_t n = COMBINE_TYPE(type , TYPE_NUMBER_DWORD); 238 | wb_push(wb, &n, 1); 239 | wb_push(wb, &v32, sizeof(v32)); 240 | } else if (v<0x100) { 241 | uint8_t n = COMBINE_TYPE(type , TYPE_NUMBER_BYTE); 242 | wb_push(wb, &n, 1); 243 | uint8_t byte = (uint8_t)v; 244 | wb_push(wb, &byte, sizeof(byte)); 245 | } else if (v<0x10000) { 246 | uint8_t n = COMBINE_TYPE(type , TYPE_NUMBER_WORD); 247 | wb_push(wb, &n, 1); 248 | uint16_t word = (uint16_t)v; 249 | wb_push(wb, &word, sizeof(word)); 250 | } else { 251 | uint8_t n = COMBINE_TYPE(type , TYPE_NUMBER_DWORD); 252 | wb_push(wb, &n, 1); 253 | uint32_t v32 = (uint32_t)v; 254 | wb_push(wb, &v32, sizeof(v32)); 255 | } 256 | } 257 | 258 | static inline void 259 | wb_real(struct write_block *wb, double v) { 260 | uint8_t n = COMBINE_TYPE(TYPE_NUMBER , TYPE_NUMBER_REAL); 261 | wb_push(wb, &n, 1); 262 | wb_push(wb, &v, sizeof(v)); 263 | } 264 | 265 | static inline void 266 | wb_pointer(struct write_block *wb, void *v) { 267 | int n = TYPE_USERDATA; 268 | wb_push(wb, &n, 1); 269 | wb_push(wb, &v, sizeof(v)); 270 | } 271 | 272 | static inline void 273 | wb_string(struct write_block *wb, const char *str, int len) { 274 | if (len < MAX_COOKIE) { 275 | int n = COMBINE_TYPE(TYPE_SHORT_STRING, len); 276 | wb_push(wb, &n, 1); 277 | if (len > 0) { 278 | wb_push(wb, str, len); 279 | } 280 | } else { 281 | int n; 282 | if (len < 0x10000) { 283 | n = COMBINE_TYPE(TYPE_LONG_STRING, 2); 284 | wb_push(wb, &n, 1); 285 | uint16_t x = (uint16_t) len; 286 | wb_push(wb, &x, 2); 287 | } else { 288 | n = COMBINE_TYPE(TYPE_LONG_STRING, 4); 289 | wb_push(wb, &n, 1); 290 | uint32_t x = (uint32_t) len; 291 | wb_push(wb, &x, 4); 292 | } 293 | wb_push(wb, str, len); 294 | } 295 | } 296 | 297 | static void pack_one(lua_State *L, struct write_block *b, int index, int depth); 298 | 299 | static int 300 | wb_table_array(lua_State *L, struct write_block * wb, int index, int depth) { 301 | int array_size = lua_rawlen(L,index); 302 | if (array_size >= MAX_COOKIE-1) { 303 | int n = COMBINE_TYPE(TYPE_TABLE, MAX_COOKIE-1); 304 | wb_push(wb, &n, 1); 305 | wb_integer(wb, array_size); 306 | } else { 307 | int n = COMBINE_TYPE(TYPE_TABLE, array_size); 308 | wb_push(wb, &n, 1); 309 | } 310 | 311 | int i; 312 | for (i=1;i<=array_size;i++) { 313 | lua_rawgeti(L,index,i); 314 | pack_one(L, wb, -1, depth); 315 | lua_pop(L,1); 316 | } 317 | 318 | return array_size; 319 | } 320 | 321 | static void 322 | wb_table_hash(lua_State *L, struct write_block * wb, int index, int depth, int array_size) { 323 | lua_pushnil(L); 324 | while (lua_next(L, index) != 0) { 325 | if (lua_type(L,-2) == LUA_TNUMBER) { 326 | if (lua_isinteger(L, -2)) { 327 | lua_Integer x = lua_tointeger(L,-2); 328 | if (x>0 && x<=array_size) { 329 | lua_pop(L,1); 330 | continue; 331 | } 332 | } 333 | } 334 | pack_one(L,wb,-2,depth); 335 | pack_one(L,wb,-1,depth); 336 | lua_pop(L, 1); 337 | } 338 | wb_nil(wb); 339 | } 340 | 341 | static void 342 | wb_table(lua_State *L, struct write_block *wb, int index, int depth) { 343 | luaL_checkstack(L,LUA_MINSTACK,NULL); 344 | if (index < 0) { 345 | index = lua_gettop(L) + index + 1; 346 | } 347 | int array_size = wb_table_array(L, wb, index, depth); 348 | wb_table_hash(L, wb, index, depth, array_size); 349 | } 350 | 351 | #if LUA_VERSION_NUM < 503 352 | 353 | static int 354 | lua_isinteger(lua_State *L, int index) { 355 | int32_t x = (int32_t)lua_tointeger(L,index); 356 | lua_Number n = lua_tonumber(L,index); 357 | return ((lua_Number)x==n); 358 | } 359 | 360 | #endif 361 | 362 | static void 363 | pack_one(lua_State *L, struct write_block *b, int index, int depth) { 364 | if (depth > MAX_DEPTH) { 365 | wb_free(b); 366 | luaL_error(L, "serialize can't pack too depth table"); 367 | } 368 | int type = lua_type(L,index); 369 | switch(type) { 370 | case LUA_TNIL: 371 | wb_nil(b); 372 | break; 373 | case LUA_TNUMBER: { 374 | if (lua_isinteger(L, index)) { 375 | lua_Integer x = lua_tointeger(L,index); 376 | wb_integer(b, x); 377 | } else { 378 | lua_Number n = lua_tonumber(L,index); 379 | wb_real(b,n); 380 | } 381 | break; 382 | } 383 | case LUA_TBOOLEAN: 384 | wb_boolean(b, lua_toboolean(L,index)); 385 | break; 386 | case LUA_TSTRING: { 387 | size_t sz = 0; 388 | const char *str = lua_tolstring(L,index,&sz); 389 | wb_string(b, str, (int)sz); 390 | break; 391 | } 392 | case LUA_TLIGHTUSERDATA: 393 | wb_pointer(b, lua_touserdata(L,index)); 394 | break; 395 | case LUA_TTABLE: { 396 | if (index < 0) { 397 | index = lua_gettop(L) + index + 1; 398 | } 399 | wb_table(L, b, index, depth+1); 400 | break; 401 | } 402 | default: 403 | wb_free(b); 404 | luaL_error(L, "Unsupport type %s to serialize", lua_typename(L, type)); 405 | } 406 | } 407 | 408 | static void 409 | pack_from(lua_State *L, struct write_block *b, int from) { 410 | int n = lua_gettop(L) - from; 411 | int i; 412 | for (i=1;i<=n;i++) { 413 | pack_one(L, b , from + i, 0); 414 | } 415 | } 416 | 417 | static int 418 | lpack(lua_State *L) { 419 | struct write_block b; 420 | wb_init(&b, NULL); 421 | pack_from(L,&b,0); 422 | struct block * ret = wb_close(&b); 423 | lua_pushlightuserdata(L,ret); 424 | return 1; 425 | } 426 | 427 | static int 428 | lappend(lua_State *L) { 429 | struct write_block b; 430 | wb_init(&b, lua_touserdata(L,1)); 431 | pack_from(L,&b,1); 432 | struct block * ret = wb_close(&b); 433 | lua_pushlightuserdata(L,ret); 434 | return 1; 435 | } 436 | 437 | static inline void 438 | invalid_stream_line(lua_State *L, struct read_block *rb, int line) { 439 | int len = rb->len; 440 | luaL_error(L, "Invalid serialize stream %d (line:%d)", len, line); 441 | } 442 | 443 | #define invalid_stream(L,rb) invalid_stream_line(L,rb,__LINE__) 444 | 445 | static lua_Integer 446 | get_integer(lua_State *L, struct read_block *rb, int cookie) { 447 | switch (cookie) { 448 | case TYPE_NUMBER_ZERO: 449 | return 0; 450 | case TYPE_NUMBER_BYTE: { 451 | uint8_t n = 0; 452 | uint8_t * pn = rb_read(rb, &n, sizeof(n)); 453 | if (pn == NULL) 454 | invalid_stream(L,rb); 455 | n = *pn; 456 | return n; 457 | } 458 | case TYPE_NUMBER_WORD: { 459 | uint16_t n = 0; 460 | uint16_t * pn = rb_read(rb, &n, sizeof(n)); 461 | if (pn == NULL) 462 | invalid_stream(L,rb); 463 | memcpy(&n, pn, sizeof(n)); 464 | return n; 465 | } 466 | case TYPE_NUMBER_DWORD: { 467 | int32_t n = 0; 468 | int32_t * pn = rb_read(rb, &n, sizeof(n)); 469 | if (pn == NULL) 470 | invalid_stream(L,rb); 471 | memcpy(&n, pn, sizeof(n)); 472 | return n; 473 | } 474 | case TYPE_NUMBER_QWORD: { 475 | int64_t n=0; 476 | int64_t * pn = rb_read(rb, &n, sizeof(n)); 477 | if (pn == NULL) 478 | invalid_stream(L,rb); 479 | memcpy(&n, pn, sizeof(n)); 480 | return n; 481 | } 482 | default: 483 | invalid_stream(L,rb); 484 | return 0; 485 | } 486 | } 487 | 488 | static double 489 | get_real(lua_State *L, struct read_block *rb) { 490 | double n = 0; 491 | double * pn = rb_read(rb, &n, sizeof(n)); 492 | if (pn == NULL) 493 | invalid_stream(L,rb); 494 | memcpy(&n, pn, sizeof(n)); 495 | return n; 496 | } 497 | 498 | static void * 499 | get_pointer(lua_State *L, struct read_block *rb) { 500 | void * userdata = 0; 501 | void ** v = (void **)rb_read(rb,&userdata,sizeof(userdata)); 502 | if (v == NULL) { 503 | invalid_stream(L,rb); 504 | } 505 | return *v; 506 | } 507 | 508 | static void 509 | get_buffer(lua_State *L, struct read_block *rb, int len) { 510 | char tmp[len]; 511 | char * p = rb_read(rb,tmp,len); 512 | if (p == NULL) { 513 | invalid_stream(L, rb); 514 | } 515 | lua_pushlstring(L,p,len); 516 | } 517 | 518 | static void unpack_one(lua_State *L, struct read_block *rb); 519 | 520 | static void 521 | unpack_table(lua_State *L, struct read_block *rb, int array_size) { 522 | if (array_size == MAX_COOKIE-1) { 523 | uint8_t type = 0; 524 | uint8_t *t = rb_read(rb, &type, sizeof(type)); 525 | if (t==NULL) { 526 | invalid_stream(L,rb); 527 | } 528 | type = *t; 529 | int cookie = type >> 3; 530 | if ((type & 7) != TYPE_NUMBER || cookie == TYPE_NUMBER_REAL) { 531 | invalid_stream(L,rb); 532 | } 533 | array_size = get_integer(L,rb,cookie); 534 | } 535 | luaL_checkstack(L,LUA_MINSTACK,NULL); 536 | lua_createtable(L,array_size,0); 537 | int i; 538 | for (i=1;i<=array_size;i++) { 539 | unpack_one(L,rb); 540 | lua_rawseti(L,-2,i); 541 | } 542 | for (;;) { 543 | unpack_one(L,rb); 544 | if (lua_isnil(L,-1)) { 545 | lua_pop(L,1); 546 | return; 547 | } 548 | unpack_one(L,rb); 549 | lua_rawset(L,-3); 550 | } 551 | } 552 | 553 | static void 554 | push_value(lua_State *L, struct read_block *rb, int type, int cookie) { 555 | switch(type) { 556 | case TYPE_NIL: 557 | lua_pushnil(L); 558 | break; 559 | case TYPE_BOOLEAN: 560 | lua_pushboolean(L,cookie); 561 | break; 562 | case TYPE_NUMBER: 563 | if (cookie == TYPE_NUMBER_REAL) { 564 | lua_pushnumber(L,get_real(L,rb)); 565 | } else { 566 | lua_pushinteger(L, get_integer(L, rb, cookie)); 567 | } 568 | break; 569 | case TYPE_USERDATA: 570 | lua_pushlightuserdata(L,get_pointer(L,rb)); 571 | break; 572 | case TYPE_SHORT_STRING: 573 | get_buffer(L,rb,cookie); 574 | break; 575 | case TYPE_LONG_STRING: { 576 | uint32_t len = 0; 577 | if (cookie == 2) { 578 | uint16_t *plen = rb_read(rb, &len, 2); 579 | if (plen == NULL) { 580 | invalid_stream(L,rb); 581 | } 582 | uint16_t n; 583 | memcpy(&n, plen, sizeof(n)); 584 | get_buffer(L,rb,n); 585 | } else { 586 | if (cookie != 4) { 587 | invalid_stream(L,rb); 588 | } 589 | uint32_t *plen = rb_read(rb, &len, 4); 590 | if (plen == NULL) { 591 | invalid_stream(L,rb); 592 | } 593 | uint32_t n; 594 | memcpy(&n, plen, sizeof(n)); 595 | get_buffer(L,rb,n); 596 | } 597 | break; 598 | } 599 | case TYPE_TABLE: { 600 | unpack_table(L,rb,cookie); 601 | break; 602 | } 603 | default: { 604 | invalid_stream(L,rb); 605 | break; 606 | } 607 | } 608 | } 609 | 610 | static void 611 | unpack_one(lua_State *L, struct read_block *rb) { 612 | uint8_t type = 0; 613 | uint8_t *t = rb_read(rb, &type, sizeof(type)); 614 | if (t==NULL) { 615 | invalid_stream(L, rb); 616 | } 617 | type = *t; 618 | push_value(L, rb, type & 0x7, type>>3); 619 | } 620 | 621 | static int 622 | lunpack(lua_State *L) { 623 | struct block * blk = lua_touserdata(L,1); 624 | if (blk == NULL) { 625 | return luaL_error(L, "Need a block to unpack"); 626 | } 627 | lua_settop(L,0); 628 | struct read_block rb; 629 | rb_init(&rb, blk); 630 | 631 | int i; 632 | for (i=0;;i++) { 633 | if (i%8==7) { 634 | luaL_checkstack(L,LUA_MINSTACK,NULL); 635 | } 636 | uint8_t type = 0; 637 | uint8_t *t = rb_read(&rb, &type, 1); 638 | if (t==NULL) 639 | break; 640 | push_value(L, &rb, *t & 0x7, *t>>3); 641 | } 642 | 643 | rb_close(&rb); 644 | 645 | return lua_gettop(L); 646 | } 647 | 648 | static int 649 | _dump_mem(const char * buffer, int len, int size) { 650 | int i; 651 | for (i=0;ibuffer ,sizeof(len)); 665 | len -= sizeof(len); 666 | printf("Len = %d\n",len); 667 | len = _dump_mem(b->buffer + sizeof(len), BLOCK_SIZE - sizeof(len) , len); 668 | while (len > 0) { 669 | b=b->next; 670 | len = _dump_mem(b->buffer, BLOCK_SIZE , len); 671 | } 672 | printf("\n"); 673 | return 0; 674 | } 675 | 676 | static int 677 | lserialize(lua_State *L) { 678 | struct block *b = lua_touserdata(L,1); 679 | if (b==NULL) { 680 | return luaL_error(L, "dump null pointer"); 681 | } 682 | 683 | uint32_t len = 0; 684 | memcpy(&len, b->buffer ,sizeof(len)); 685 | 686 | uint8_t * buffer = malloc(len); 687 | uint8_t * ptr = buffer; 688 | int sz = len; 689 | while(len>0) { 690 | if (len >= BLOCK_SIZE) { 691 | memcpy(ptr, b->buffer, BLOCK_SIZE); 692 | ptr += BLOCK_SIZE; 693 | len -= BLOCK_SIZE; 694 | } else { 695 | memcpy(ptr, b->buffer, len); 696 | break; 697 | } 698 | b = b->next; 699 | } 700 | 701 | buffer[0] = sz & 0xff; 702 | buffer[1] = (sz>>8) & 0xff; 703 | buffer[2] = (sz>>16) & 0xff; 704 | buffer[3] = (sz>>24) & 0xff; 705 | 706 | lua_pushlightuserdata(L, buffer); 707 | lua_pushinteger(L, sz); 708 | 709 | return 2; 710 | } 711 | 712 | static void 713 | deserialize_buffer(lua_State *L, void * buffer) { 714 | struct read_block rb; 715 | rball_init(&rb, buffer); 716 | 717 | int i; 718 | for (i=0;;i++) { 719 | if (i%16==15) { 720 | lua_checkstack(L,i); 721 | } 722 | uint8_t type = 0; 723 | uint8_t *t = rb_read(&rb, &type, 1); 724 | if (t==NULL) 725 | break; 726 | push_value(L, &rb, *t & 0x7, *t>>3); 727 | } 728 | } 729 | 730 | static int 731 | ldeserialize(lua_State *L) { 732 | void * buffer = lua_touserdata(L,1); 733 | if (buffer == NULL) { 734 | return luaL_error(L, "deserialize null pointer"); 735 | } 736 | 737 | lua_settop(L,0); 738 | deserialize_buffer(L, buffer); 739 | 740 | // Need not free buffer 741 | 742 | return lua_gettop(L); 743 | } 744 | 745 | static int 746 | seristring(lua_State *L) { 747 | struct write_block b; 748 | wb_init(&b, NULL); 749 | pack_from(L,&b,0); 750 | struct block * ret = wb_close(&b); 751 | lua_settop(L,0); 752 | lua_pushlightuserdata(L,ret); 753 | lserialize(L); 754 | wb_free(&b); 755 | void *buffer = lua_touserdata(L, -2); 756 | int sz = lua_tointeger(L, -1); 757 | lua_pushlstring(L, buffer, sz); 758 | free(buffer); 759 | return 1; 760 | } 761 | 762 | static int 763 | deseristring(lua_State *L) { 764 | const char * buffer = luaL_checkstring(L, 1); 765 | deserialize_buffer(L, (void *)buffer); 766 | 767 | return lua_gettop(L) - 1; 768 | } 769 | 770 | int 771 | luaopen_serialize(lua_State *L) { 772 | luaL_Reg l[] = { 773 | { "pack", lpack }, 774 | { "unpack", lunpack }, 775 | { "append", lappend }, 776 | { "serialize", lserialize }, 777 | { "deserialize", ldeserialize }, 778 | { "serialize_string", seristring }, 779 | { "deseristring_string", deseristring }, 780 | { "dump", _dump }, 781 | { NULL, NULL }, 782 | }; 783 | luaL_newlib(L,l); 784 | return 1; 785 | } 786 | -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | s = require "serialize" 2 | 3 | b = s.pack{[10] = {1,2}} 4 | s.dump(b) 5 | bb = s.unpack(b) 6 | for k,v in pairs(bb[10]) do 7 | print(k,v) 8 | end 9 | 10 | --[[ 11 | 12 | a = s.pack { hello={3,4}, false, 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9 } 13 | 14 | s.dump(a) 15 | 16 | a = s.append(a, 42,4.2,-1,1000,80000,"hello",true,false,nil,"1234567890123456789012345678901234567890") 17 | 18 | s.dump(a) 19 | print(a) 20 | 21 | function pr(t,...) 22 | for k,v in pairs(t) do 23 | print(k,v) 24 | end 25 | print(...) 26 | end 27 | 28 | print ("------") 29 | 30 | local seri, length = s.serialize(a) 31 | print(seri, length) 32 | 33 | pr(s.unpack(a)) 34 | 35 | print("-------") 36 | 37 | pr(s.deserialize(seri)) 38 | ]] 39 | 40 | a = s.serialize_string( 1,2,3,4,5 ) 41 | print(#a, s.deseristring_string(a)) 42 | -------------------------------------------------------------------------------- /test2.lua: -------------------------------------------------------------------------------- 1 | local s = require "serialize" 2 | 3 | addressbook = { 4 | name = "Alice", 5 | id = 12345, 6 | phone = { 7 | { number = "1301234567" }, 8 | { number = "87654321", type = "WORK" }, 9 | } 10 | } 11 | 12 | for i=1,100000 do 13 | local u = s.pack (addressbook) 14 | local t = s.unpack(u) 15 | end 16 | --------------------------------------------------------------------------------