diff --git a/build/lua-protobuf/pb.c b/build/lua-protobuf/pb.c index f429863c..4a95892b 100644 --- a/build/lua-protobuf/pb.c +++ b/build/lua-protobuf/pb.c @@ -1,3 +1,12 @@ +#ifdef _MSC_VER +# define _CRT_SECURE_NO_WARNINGS +# define _CRT_NONSTDC_NO_WARNINGS +# pragma warning(disable: 4244) /* int -> char */ +# pragma warning(disable: 4706) /* = in if condition */ +# pragma warning(disable: 4709) /* comma in array index */ +# pragma warning(disable: 4127) /* const in if condition */ +#endif + #define PB_STATIC_API #include "pb.h" @@ -21,9 +30,10 @@ PB_NS_BEGIN #define check_buffer(L,idx) ((pb_Buffer*)luaL_checkudata(L,idx,PB_BUFFER)) #define test_buffer(L,idx) ((pb_Buffer*)luaL_testudata(L,idx,PB_BUFFER)) -#define check_slice(L,idx) ((lpb_SliceEx*)luaL_checkudata(L,idx,PB_SLICE)) -#define test_slice(L,idx) ((lpb_SliceEx*)luaL_testudata(L,idx,PB_SLICE)) -#define return_self(L) { lua_settop(L, 1); return 1; } +#define check_slice(L,idx) ((pb_Slice*)luaL_checkudata(L,idx,PB_SLICE)) +#define test_slice(L,idx) ((pb_Slice*)luaL_testudata(L,idx,PB_SLICE)) +#define push_slice(L,s) lua_pushlstring((L), (s).p, pb_len((s))) +#define return_self(L) { return lua_settop(L, 1), 1; } #if LUA_VERSION_NUM < 502 #include @@ -82,7 +92,7 @@ static void *luaL_testudata(lua_State *L, int idx, const char *type) { static int luaL_fileresult(lua_State *L, int stat, const char *fname) { int en = errno; - if (stat) { lua_pushboolean(L, 1); return 1; } + if (stat) return lua_pushboolean(L, 1), 1; lua_pushnil(L); lua_pushfstring(L, "%s: %s", fname, strerror(en)); /*if (fname) lua_pushfstring(L, "%s: %s", fname, strerror(en)); @@ -101,53 +111,81 @@ static int luaL_fileresult(lua_State *L, int stat, const char *fname) { # define lua53_rawgetp lua_rawgetp #else /* not Lua 5.3 */ static int lua53_getfield(lua_State *L, int idx, const char *field) -{ lua_getfield(L, idx, field); return lua_type(L, -1); } +{ return lua_getfield(L, idx, field), lua_type(L, -1); } static int lua53_rawgeti(lua_State *L, int idx, lua_Integer i) -{ lua_rawgeti(L, idx, i); return lua_type(L, -1); } +{ return lua_rawgeti(L, idx, i), lua_type(L, -1); } static int lua53_rawgetp(lua_State *L, int idx, const void *p) -{ lua_rawgetp(L, idx, p); return lua_type(L, -1); } +{ return lua_rawgetp(L, idx, p), lua_type(L, -1); } #endif /* protobuf global state */ -#define default_state(L) ((pb_State*)default_lstate(L)) +#define lpbS_state(LS) ((LS)->state) +#define lpb_name(LS,s) pb_name(lpbS_state(LS), (s), &(LS)->cache) +static const pb_State *global_state = NULL; static const char state_name[] = PB_STATE; enum lpb_Int64Mode { LPB_NUMBER, LPB_STRING, LPB_HEXSTRING }; enum lpb_DefMode { LPB_DEFDEF, LPB_COPYDEF, LPB_METADEF, LPB_NODEF }; typedef struct lpb_State { - pb_State base; + const pb_State *state; + pb_State local; + pb_Cache cache; pb_Buffer buffer; int defs_index; + int enc_hooks_index; + int dec_hooks_index; + unsigned use_dec_hooks : 1; + unsigned use_enc_hooks : 1; unsigned enum_as_value : 1; unsigned default_mode : 2; /* lpb_DefMode */ unsigned int64_mode : 2; /* lpb_Int64Mode */ + unsigned encode_default_values : 1; + unsigned decode_default_array : 1; + unsigned decode_default_message : 1; + unsigned encode_order : 1; } lpb_State; -static void lpb_pushdeftable(lua_State *L, lpb_State *LS) { - if (LS->defs_index != LUA_NOREF) - lua_rawgeti(L, LUA_REGISTRYINDEX, LS->defs_index); - else { +static int lpb_reftable(lua_State *L, int ref) { + if (ref != LUA_NOREF) { + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + return ref; + } else { lua_newtable(L); lua_pushvalue(L, -1); - LS->defs_index = luaL_ref(L, LUA_REGISTRYINDEX); + return luaL_ref(L, LUA_REGISTRYINDEX); } } +static void lpb_pushdeftable(lua_State *L, lpb_State *LS) +{ LS->defs_index = lpb_reftable(L, LS->defs_index); } + +static void lpb_pushenchooktable(lua_State *L, lpb_State *LS) +{ LS->enc_hooks_index = lpb_reftable(L, LS->enc_hooks_index); } + +static void lpb_pushdechooktable(lua_State *L, lpb_State *LS) +{ LS->dec_hooks_index = lpb_reftable(L, LS->dec_hooks_index); } + static int Lpb_delete(lua_State *L) { lpb_State *LS = (lpb_State*)luaL_testudata(L, 1, PB_STATE); if (LS != NULL) { - pb_free(&LS->base); + const pb_State *GS = global_state; + pb_free(&LS->local); + if (&LS->local == GS) + global_state = NULL; + LS->state = NULL; pb_resetbuffer(&LS->buffer); luaL_unref(L, LUA_REGISTRYINDEX, LS->defs_index); + luaL_unref(L, LUA_REGISTRYINDEX, LS->enc_hooks_index); + luaL_unref(L, LUA_REGISTRYINDEX, LS->dec_hooks_index); } return 0; } -static lpb_State *default_lstate(lua_State *L) { +LUALIB_API lpb_State *lpb_lstate(lua_State *L) { lpb_State *LS; if (lua53_rawgetp(L, LUA_REGISTRYINDEX, state_name) == LUA_TUSERDATA) { LS = (lpb_State*)lua_touserdata(L, -1); @@ -157,7 +195,10 @@ static lpb_State *default_lstate(lua_State *L) { LS = (lpb_State*)lua_newuserdata(L, sizeof(lpb_State)); memset(LS, 0, sizeof(lpb_State)); LS->defs_index = LUA_NOREF; - pb_init(&LS->base); + LS->enc_hooks_index = LUA_NOREF; + LS->dec_hooks_index = LUA_NOREF; + LS->state = &LS->local; + pb_init(&LS->local); pb_initbuffer(&LS->buffer); luaL_setmetatable(L, PB_STATE); lua_rawsetp(L, LUA_REGISTRYINDEX, state_name); @@ -167,7 +208,7 @@ static lpb_State *default_lstate(lua_State *L) { static int Lpb_state(lua_State *L) { int top = lua_gettop(L); - default_lstate(L); + lpb_lstate(L); lua_rawgetp(L, LUA_REGISTRYINDEX, state_name); if (top != 0) { if (lua_isnil(L, 1)) @@ -184,16 +225,6 @@ static int Lpb_state(lua_State *L) { /* protobuf util routines */ -typedef struct lpb_SliceEx { - pb_Slice base; - const char *head; -} lpb_SliceEx; - -static int lpb_offset(lpb_SliceEx *s) { return (int)(s->base.p-s->head) + 1; } - -static lpb_SliceEx lpb_initext(pb_Slice s) -{ lpb_SliceEx ext; ext.base = s, ext.head = s.p; return ext; } - static void lpb_addlength(lua_State *L, pb_Buffer *b, size_t len) { if (pb_addlength(b, len) == 0) luaL_error(L, "encode bytes fail"); } @@ -229,37 +260,35 @@ static int argcheck(lua_State *L, int cond, int idx, const char *fmt, ...) { static pb_Slice lpb_toslice(lua_State *L, int idx) { int type = lua_type(L, idx); - pb_Slice ret = { NULL, NULL }; if (type == LUA_TSTRING) { size_t len; const char *s = lua_tolstring(L, idx, &len); - ret = pb_lslice(s, len); + return pb_lslice(s, len); } else if (type == LUA_TUSERDATA) { pb_Buffer *buffer; - lpb_SliceEx *s; + pb_Slice *s; if ((buffer = test_buffer(L, idx)) != NULL) - ret = pb_result(buffer); + return pb_result(buffer); else if ((s = test_slice(L, idx)) != NULL) - ret = s->base; + return *s; } - return ret; + return pb_slice(NULL); } -static pb_Slice lpb_checkslice(lua_State *L, int idx) { +LUALIB_API pb_Slice lpb_checkslice(lua_State *L, int idx) { pb_Slice ret = lpb_toslice(L, idx); if (ret.p == NULL) typeerror(L, idx, "string/buffer/slice"); return ret; } -static void lpb_readbytes(lua_State *L, lpb_SliceEx *s, lpb_SliceEx *pv) { +static void lpb_readbytes(lua_State *L, pb_Slice *s, pb_Slice *pv) { uint64_t len = 0; - if (pb_readvarint64(&s->base, &len) == 0 || len > PB_MAX_SIZET) + if (pb_readvarint64(s, &len) == 0 || len > PB_MAX_SIZET) luaL_error(L, "invalid bytes length: %d (at offset %d)", - (int)len, lpb_offset(s)); - if (pb_readslice(&s->base, (size_t)len, &pv->base) == 0 && len != 0) - luaL_error(L, "un-finished bytes (len %d at offset %d)", - (int)len, lpb_offset(s)); - pv->head = s->head; + (int)len, pb_pos(*s)+1); + if (pb_readslice(s, (size_t)len, pv) == 0 && len != 0) + luaL_error(L, "unfinished bytes (len %d at offset %d)", + (int)len, pb_pos(*s)+1); } static int lpb_hexchar(char ch) { @@ -319,7 +348,7 @@ static uint64_t lpb_checkinteger(lua_State *L, int idx) { } static void lpb_pushinteger(lua_State *L, int64_t n, int mode) { - if (mode != LPB_NUMBER && (n < INT_MIN || n > INT_MAX)) { + if (mode != LPB_NUMBER && (n < INT_MIN || n > UINT_MAX)) { char buff[32], *p = buff + sizeof(buff) - 1; int neg = n < 0; uint64_t un = neg ? ~(uint64_t)n + 1 : (uint64_t)n; @@ -341,11 +370,11 @@ static void lpb_pushinteger(lua_State *L, int64_t n, int mode) { } typedef union lpb_Value { - lpb_SliceEx s[1]; - uint32_t u32; - uint64_t u64; + pb_Slice s[1]; + uint32_t u32; + uint64_t u64; lua_Integer lint; - lua_Number lnum; + lua_Number lnum; } lpb_Value; static int lpb_addtype(lua_State *L, pb_Buffer *b, int idx, int type, size_t *plen) { @@ -414,9 +443,9 @@ static int lpb_addtype(lua_State *L, pb_Buffer *b, int idx, int type, size_t *pl if (v.u64 != 0) len = 0; break; case PB_Tbytes: case PB_Tstring: - v.s->base = lpb_toslice(L, idx); - if ((ret = (v.s->base.p != NULL))) len = pb_addbytes(b, v.s->base); - if (pb_len(v.s->base) != 0) len = 0; + *v.s = lpb_toslice(L, idx); + if ((ret = (v.s->p != NULL))) len = pb_addbytes(b, *v.s); + if (pb_len(*v.s) != 0) len = 0; expected = LUA_TSTRING; break; default: @@ -428,15 +457,15 @@ static int lpb_addtype(lua_State *L, pb_Buffer *b, int idx, int type, size_t *pl return ret ? 0 : expected; } -static void lpb_readtype(lua_State *L, lpb_State *LS, int type, lpb_SliceEx *s) { +static void lpb_readtype(lua_State *L, lpb_State *LS, int type, pb_Slice *s) { lpb_Value v; switch (type) { #define pushinteger(n) lpb_pushinteger((L), (n), LS->int64_mode) case PB_Tbool: case PB_Tenum: case PB_Tint32: case PB_Tuint32: case PB_Tsint32: case PB_Tint64: case PB_Tuint64: case PB_Tsint64: - if (pb_readvarint64(&s->base, &v.u64) == 0) - luaL_error(L, "invalid varint value at offset %d", lpb_offset(s)); + if (pb_readvarint64(s, &v.u64) == 0) + luaL_error(L, "invalid varint value at offset %d", pb_pos(*s)+1); switch (type) { case PB_Tbool: lua_pushboolean(L, v.u64 != 0); break; /*case PB_Tenum: pushinteger(v.u64); break; [> NOT REACHED <]*/ @@ -451,8 +480,8 @@ static void lpb_readtype(lua_State *L, lpb_State *LS, int type, lpb_SliceEx *s) case PB_Tfloat: case PB_Tfixed32: case PB_Tsfixed32: - if (pb_readfixed32(&s->base, &v.u32) == 0) - luaL_error(L, "invalid fixed32 value at offset %d", lpb_offset(s)); + if (pb_readfixed32(s, &v.u32) == 0) + luaL_error(L, "invalid fixed32 value at offset %d", pb_pos(*s)+1); switch (type) { case PB_Tfloat: lua_pushnumber(L, pb_decode_float(v.u32)); break; case PB_Tfixed32: pushinteger(v.u32); break; @@ -462,8 +491,8 @@ static void lpb_readtype(lua_State *L, lpb_State *LS, int type, lpb_SliceEx *s) case PB_Tdouble: case PB_Tfixed64: case PB_Tsfixed64: - if (pb_readfixed64(&s->base, &v.u64) == 0) - luaL_error(L, "invalid fixed64 value at offset %d", lpb_offset(s)); + if (pb_readfixed64(s, &v.u64) == 0) + luaL_error(L, "invalid fixed64 value at offset %d", pb_pos(*s)+1); switch (type) { case PB_Tdouble: lua_pushnumber(L, pb_decode_double(v.u64)); break; case PB_Tfixed64: pushinteger(v.u64); break; @@ -474,7 +503,7 @@ static void lpb_readtype(lua_State *L, lpb_State *LS, int type, lpb_SliceEx *s) case PB_Tstring: case PB_Tmessage: lpb_readbytes(L, s, v.s); - lua_pushlstring(L, v.s->base.p, pb_len(v.s->base)); + push_slice(L, *v.s); break; default: luaL_error(L, "unknown type %s (%d)", pb_typename(type, NULL), type); @@ -517,9 +546,6 @@ static int io_write(lua_State *L, FILE *f, int idx) { } static int Lio_read(lua_State *L) { -#if defined(WINAPI_FAMILY_PARTITION) - return luaL_error(L, "unsupport api in uwp platform"); -#else const char *fname = luaL_optstring(L, 1, NULL); FILE *fp = stdin; int ret; @@ -534,26 +560,18 @@ static int Lio_read(lua_State *L) { else (void)setmode(fileno(stdin), O_TEXT); if (ret != LUA_OK) { lua_pushnil(L); lua_insert(L, -2); return 2; } return 1; -#endif } static int Lio_write(lua_State *L) { -#if defined(WINAPI_FAMILY_PARTITION) - return luaL_error(L, "unsupport api in uwp platform"); -#else int res; (void)setmode(fileno(stdout), O_BINARY); res = io_write(L, stdout, 1); fflush(stdout); (void)setmode(fileno(stdout), O_TEXT); return res; -#endif } static int Lio_dump(lua_State *L) { -#if defined(WINAPI_FAMILY_PARTITION) - return luaL_error(L, "unsupport api in uwp platform"); -#else int res; const char *fname = luaL_checkstring(L, 1); FILE *fp = fopen(fname, "wb"); @@ -561,7 +579,6 @@ static int Lio_dump(lua_State *L) { res = io_write(L, fp, 2); fclose(fp); return res; -#endif } LUALIB_API int luaopen_pb_io(lua_State *L) { @@ -581,44 +598,44 @@ LUALIB_API int luaopen_pb_io(lua_State *L) { /* protobuf integer conversion */ static int Lconv_encode_int32(lua_State *L) { - unsigned mode = default_lstate(L)->int64_mode; + unsigned mode = lpb_lstate(L)->int64_mode; uint64_t v = pb_expandsig((int32_t)lpb_checkinteger(L, 1)); lpb_pushinteger(L, v, mode); return 1; } static int Lconv_encode_uint32(lua_State *L) { - unsigned mode = default_lstate(L)->int64_mode; + unsigned mode = lpb_lstate(L)->int64_mode; lpb_pushinteger(L, (uint32_t)lpb_checkinteger(L, 1), mode); return 1; } static int Lconv_encode_sint32(lua_State *L) { - unsigned mode = default_lstate(L)->int64_mode; + unsigned mode = lpb_lstate(L)->int64_mode; lpb_pushinteger(L, pb_encode_sint32((int32_t)lpb_checkinteger(L, 1)), mode); return 1; } static int Lconv_decode_sint32(lua_State *L) { - unsigned mode = default_lstate(L)->int64_mode; + unsigned mode = lpb_lstate(L)->int64_mode; lpb_pushinteger(L, pb_decode_sint32((uint32_t)lpb_checkinteger(L, 1)), mode); return 1; } static int Lconv_encode_sint64(lua_State *L) { - unsigned mode = default_lstate(L)->int64_mode; + unsigned mode = lpb_lstate(L)->int64_mode; lpb_pushinteger(L, pb_encode_sint64(lpb_checkinteger(L, 1)), mode); return 1; } static int Lconv_decode_sint64(lua_State *L) { - unsigned mode = default_lstate(L)->int64_mode; + unsigned mode = lpb_lstate(L)->int64_mode; lpb_pushinteger(L, pb_decode_sint64(lpb_checkinteger(L, 1)), mode); return 1; } static int Lconv_encode_float(lua_State *L) { - unsigned mode = default_lstate(L)->int64_mode; + unsigned mode = lpb_lstate(L)->int64_mode; lpb_pushinteger(L, pb_encode_float((float)luaL_checknumber(L, 1)), mode); return 1; } @@ -629,7 +646,7 @@ static int Lconv_decode_float(lua_State *L) { } static int Lconv_encode_double(lua_State *L) { - unsigned mode = default_lstate(L)->int64_mode; + unsigned mode = lpb_lstate(L)->int64_mode; lpb_pushinteger(L, pb_encode_double(luaL_checknumber(L, 1)), mode); return 1; } @@ -664,21 +681,11 @@ LUALIB_API int luaopen_pb_conv(lua_State *L) { /* protobuf encode routine */ -static int lpb_typefmt(const char *fmt) { - switch (*fmt) { - case 'b': return PB_Tbool; - case 'f': return PB_Tfloat; - case 'F': return PB_Tdouble; - case 'i': return PB_Tint32; - case 'j': return PB_Tsint32; - case 'u': return PB_Tuint32; - case 'x': return PB_Tfixed32; - case 'y': return PB_Tsfixed32; - case 'I': return PB_Tint64; - case 'J': return PB_Tsint64; - case 'U': return PB_Tuint64; - case 'X': return PB_Tfixed64; - case 'Y': return PB_Tsfixed64; +static int lpb_typefmt(int fmt) { + switch (fmt) { +#define X(name,type,fmt) case fmt: return PB_T##name; + PB_TYPES(X) +#undef X } return -1; } @@ -708,7 +715,7 @@ static int lpb_packfmt(lua_State *L, int idx, pb_Buffer *b, const char **pfmt, i return idx; case '\0': default: - argcheck(L, (type = lpb_typefmt(fmt)) >= 0, + argcheck(L, (type = lpb_typefmt(*fmt)) >= 0, 1, "invalid formater: '%c'", *fmt); ltype = lpb_addtype(L, b, idx, type, NULL); argcheck(L, ltype == 0, idx, "%s expected for type '%s', got %s", @@ -741,6 +748,33 @@ static int Lpb_tohex(lua_State *L) { return 1; } +static int Lpb_fromhex(lua_State *L) { + pb_Slice s = lpb_checkslice(L, 1); + lua_Integer r[2] = { 1, -1 }; + luaL_Buffer lb; + int curr = 0, idx = 0, num; + rangerelat(L, 2, r, pb_len(s)); + luaL_buffinit(L, &lb); + for (; r[0] <= r[1]; ++r[0]) { + switch (num = s.p[r[0]-1]) { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': num -= '0'; break; + case 'A': case 'a': num = 10; break; + case 'B': case 'b': num = 11; break; + case 'C': case 'c': num = 12; break; + case 'D': case 'd': num = 13; break; + case 'E': case 'e': num = 14; break; + case 'F': case 'f': num = 15; break; + default: continue; + } + curr = curr<<4 | num; + if (++idx % 2 == 0) luaL_addchar(&lb, curr), curr = 0; + } + luaL_pushresult(&lb); + return 1; +} + static int Lpb_result(lua_State *L) { pb_Slice s = lpb_checkslice(L, 1); lua_Integer r[2] = {1, -1}, range = rangerelat(L, 2, r, pb_len(s)); @@ -758,6 +792,12 @@ static int Lbuf_new(lua_State *L) { return 1; } +static int Lbuf_delete(lua_State *L) { + pb_Buffer *buf = test_buffer(L, 1); + if (buf) pb_resetbuffer(buf); + return 0; +} + static int Lbuf_libcall(lua_State *L) { int i, top = lua_gettop(L); pb_Buffer *buf = (pb_Buffer*)lua_newuserdata(L, sizeof(pb_Buffer)); @@ -777,7 +817,7 @@ static int Lbuf_tostring(lua_State *L) { static int Lbuf_reset(lua_State *L) { pb_Buffer *buf = check_buffer(L, 1); int i, top = lua_gettop(L); - pb_resetbuffer(buf); + pb_bufflen(buf) = 0; for (i = 2; i <= top; ++i) pb_addslice(buf, lpb_checkslice(L, i)); return_self(L); @@ -799,7 +839,7 @@ static int Lbuf_pack(lua_State *L) { lua_settop(L, 1); else { pb_Slice ret = pb_result(pb); - lua_pushlstring(L, ret.p, pb_len(ret)); + push_slice(L, ret); pb_resetbuffer(pb); } return 1; @@ -809,9 +849,10 @@ LUALIB_API int luaopen_pb_buffer(lua_State *L) { luaL_Reg libs[] = { { "__tostring", Lbuf_tostring }, { "__len", Lbuf_len }, - { "__gc", Lbuf_reset }, - { "delete", Lbuf_reset }, + { "__gc", Lbuf_delete }, + { "delete", Lbuf_delete }, { "tohex", Lpb_tohex }, + { "fromhex", Lpb_fromhex }, { "result", Lpb_result }, #define ENTRY(name) { #name, Lbuf_##name } ENTRY(new), @@ -838,17 +879,16 @@ LUALIB_API int luaopen_pb_buffer(lua_State *L) { #define LPB_INITSTACKLEN 2 typedef struct lpb_Slice { - lpb_SliceEx curr; - lpb_SliceEx *buff; + pb_Slice curr; + pb_Slice *buff; size_t used; size_t size; - lpb_SliceEx init_buff[LPB_INITSTACKLEN]; + pb_Slice init_buff[LPB_INITSTACKLEN]; } lpb_Slice; static void lpb_resetslice(lua_State *L, lpb_Slice *s, size_t size) { if (size == sizeof(lpb_Slice)) { - if (s->buff != s->init_buff) - free(s->buff); + if (s->buff != s->init_buff) free(s->buff); memset(s, 0, sizeof(lpb_Slice)); s->buff = s->init_buff; s->size = LPB_INITSTACKLEN; @@ -857,24 +897,24 @@ static void lpb_resetslice(lua_State *L, lpb_Slice *s, size_t size) { lua_rawsetp(L, LUA_REGISTRYINDEX, s); } -static lpb_SliceEx lpb_checkview(lua_State *L, int idx, lpb_SliceEx *ps) { +static pb_Slice lpb_checkview(lua_State *L, int idx, pb_Slice *ps) { pb_Slice src = lpb_checkslice(L, idx); lua_Integer r[2] = {1, -1}, range = rangerelat(L, idx+1, r, pb_len(src)); - lpb_SliceEx ret; - if (ps) ps->base = src, ps->head = src.p; - ret.base.p = src.p + r[0] - 1; - ret.base.end = ret.base.p + range; - ret.head = src.p; + pb_Slice ret; + if (ps) *ps = src, ps->start = src.p; + ret.p = src.p + r[0] - 1; + ret.end = ret.p + range; + ret.start = src.p; return ret; } -static void lpb_enterview(lua_State *L, lpb_Slice *s, lpb_SliceEx view) { +static void lpb_enterview(lua_State *L, lpb_Slice *s, pb_Slice view) { if (s->used >= s->size) { size_t newsize = s->size * 2; - lpb_SliceEx *oldp = s->buff != s->init_buff ? s->buff : NULL; - lpb_SliceEx *newp = (lpb_SliceEx*)realloc(oldp, newsize*sizeof(lpb_SliceEx)); + pb_Slice *oldp = s->buff != s->init_buff ? s->buff : NULL; + pb_Slice *newp = (pb_Slice*)realloc(oldp, newsize*sizeof(pb_Slice)); if (newp == NULL) { luaL_error(L, "out of memory"); return; } - if (oldp == NULL) memcpy(newp, s->buff, s->used*sizeof(lpb_SliceEx)); + if (oldp == NULL) memcpy(newp, s->buff, s->used*sizeof(pb_Slice)); s->buff = newp; s->size = newsize; } @@ -889,7 +929,7 @@ static void lpb_initslice(lua_State *L, int idx, lpb_Slice *s, size_t size) { s->size = LPB_INITSTACKLEN; } if (!lua_isnoneornil(L, idx)) { - lpb_SliceEx base, view = lpb_checkview(L, idx, &base); + pb_Slice base, view = lpb_checkview(L, idx, &base); s->curr = base; if (size == sizeof(lpb_Slice)) lpb_enterview(L, s, view); lua_pushvalue(L, idx); @@ -897,36 +937,36 @@ static void lpb_initslice(lua_State *L, int idx, lpb_Slice *s, size_t size) { } } -static int lpb_unpackscalar(lua_State *L, int *pidx, int top, int fmt, lpb_SliceEx *s) { - unsigned mode = default_lstate(L)->int64_mode; +static int lpb_unpackscalar(lua_State *L, int *pidx, int top, int fmt, pb_Slice *s) { + unsigned mode = lpb_lstate(L)->int64_mode; lpb_Value v; switch (fmt) { case 'v': - if (pb_readvarint64(&s->base, &v.u64) == 0) - luaL_error(L, "invalid varint value at offset %d", lpb_offset(s)); + if (pb_readvarint64(s, &v.u64) == 0) + luaL_error(L, "invalid varint value at offset %d", pb_pos(*s)+1); lpb_pushinteger(L, v.u64, mode); break; case 'd': - if (pb_readfixed32(&s->base, &v.u32) == 0) - luaL_error(L, "invalid fixed32 value at offset %d", lpb_offset(s)); + if (pb_readfixed32(s, &v.u32) == 0) + luaL_error(L, "invalid fixed32 value at offset %d", pb_pos(*s)+1); lpb_pushinteger(L, v.u32, mode); break; case 'q': - if (pb_readfixed64(&s->base, &v.u64) == 0) - luaL_error(L, "invalid fixed64 value at offset %d", lpb_offset(s)); + if (pb_readfixed64(s, &v.u64) == 0) + luaL_error(L, "invalid fixed64 value at offset %d", pb_pos(*s)+1); lpb_pushinteger(L, v.u64, mode); break; case 's': - if (pb_readbytes(&s->base, &v.s->base) == 0) - luaL_error(L, "invalid bytes value at offset %d", lpb_offset(s)); - lua_pushlstring(L, v.s->base.p, pb_len(v.s->base)); + if (pb_readbytes(s, v.s) == 0) + luaL_error(L, "invalid bytes value at offset %d", pb_pos(*s)+1); + push_slice(L, *v.s); break; case 'c': argcheck(L, *pidx <= top, 1, "format argument exceed"); - v.lint = luaL_checkinteger(L, *pidx++); - if (pb_readslice(&s->base, (size_t)v.lint, &v.s->base) == 0) - luaL_error(L, "invalid sub string at offset %d", lpb_offset(s)); - lua_pushlstring(L, v.s->base.p, pb_len(v.s->base)); + v.lint = luaL_checkinteger(L, (*pidx)++); + if (pb_readslice(s, (size_t)v.lint, v.s) == 0) + luaL_error(L, "invalid sub string at offset %d", pb_pos(*s)+1); + push_slice(L, *v.s); break; default: return 0; @@ -934,24 +974,24 @@ static int lpb_unpackscalar(lua_State *L, int *pidx, int top, int fmt, lpb_Slice return 1; } -static int lpb_unpackloc(lua_State *L, int *pidx, int top, int fmt, lpb_SliceEx *s, int *prets) { +static int lpb_unpackloc(lua_State *L, int *pidx, int top, int fmt, pb_Slice *s, int *prets) { lua_Integer li; - size_t len = s->base.end - s->head; + size_t len = s->end - s->start; switch (fmt) { case '@': - lua_pushinteger(L, lpb_offset(s)); + lua_pushinteger(L, pb_pos(*s)+1); ++*prets; break; case '*': case '+': argcheck(L, *pidx <= top, 1, "format argument exceed"); if (fmt == '*') - li = posrelat(luaL_checkinteger(L, *pidx++), len); + li = posrelat(luaL_checkinteger(L, (*pidx)++), len); else - li = lpb_offset(s) + luaL_checkinteger(L, *pidx++); + li = pb_pos(*s) + luaL_checkinteger(L, (*pidx)++) + 1; if (li == 0) li = 1; if (li > (lua_Integer)len) li = (lua_Integer)len + 1; - s->base.p = s->head + li - 1; + s->p = s->start + li - 1; break; default: @@ -960,17 +1000,17 @@ static int lpb_unpackloc(lua_State *L, int *pidx, int top, int fmt, lpb_SliceEx return 1; } -static int lpb_unpackfmt(lua_State *L, int idx, const char *fmt, lpb_SliceEx *s) { +static int lpb_unpackfmt(lua_State *L, int idx, const char *fmt, pb_Slice *s) { int rets = 0, top = lua_gettop(L), type; for (; *fmt != '\0'; ++fmt) { if (lpb_unpackloc(L, &idx, top, *fmt, s, &rets)) continue; - if (s->base.p >= s->base.end) { lua_pushnil(L); return rets + 1; } + if (s->p >= s->end) return lua_pushnil(L), rets + 1; luaL_checkstack(L, 1, "too many values"); if (!lpb_unpackscalar(L, &idx, top, *fmt, s)) { - argcheck(L, (type = lpb_typefmt(fmt)) >= 0, + argcheck(L, (type = lpb_typefmt(*fmt)) >= 0, 1, "invalid formater: '%c'", *fmt); - lpb_readtype(L, default_lstate(L), type, s); + lpb_readtype(L, lpb_lstate(L), type, s); } ++rets; } @@ -978,7 +1018,7 @@ static int lpb_unpackfmt(lua_State *L, int idx, const char *fmt, lpb_SliceEx *s) } static lpb_Slice *check_lslice(lua_State *L, int idx) { - lpb_SliceEx *s = check_slice(L, idx); + pb_Slice *s = check_slice(L, idx); argcheck(L, lua_rawlen(L, 1) == sizeof(lpb_Slice), idx, "unsupport operation for raw mode slice"); return (lpb_Slice*)s; @@ -989,6 +1029,7 @@ static int Lslice_new(lua_State *L) { lua_settop(L, 3); s = (lpb_Slice*)lua_newuserdata(L, sizeof(lpb_Slice)); lpb_initslice(L, 1, s, sizeof(lpb_Slice)); + if (s->curr.p == NULL) s->curr = pb_lslice("", 0); luaL_setmetatable(L, PB_SLICE); return 1; } @@ -1003,7 +1044,7 @@ static int Lslice_libcall(lua_State *L) { } static int Lslice_reset(lua_State *L) { - lpb_Slice *s = check_lslice(L, 1); + lpb_Slice *s = (lpb_Slice*)check_slice(L, 1); size_t size = lua_rawlen(L, 1); lpb_resetslice(L, s, size); if (!lua_isnoneornil(L, 2)) @@ -1012,30 +1053,30 @@ static int Lslice_reset(lua_State *L) { } static int Lslice_tostring(lua_State *L) { - lpb_SliceEx *s = check_slice(L, 1); + pb_Slice *s = check_slice(L, 1); lua_pushfstring(L, "pb.Slice: %p%s", s, lua_rawlen(L, 1) == sizeof(lpb_Slice) ? "" : " (raw)"); return 1; } static int Lslice_len(lua_State *L) { - lpb_SliceEx *s = check_slice(L, 1); - lua_pushinteger(L, (lua_Integer)pb_len(s->base)); - lua_pushinteger(L, (lua_Integer)lpb_offset(s)); + pb_Slice *s = check_slice(L, 1); + lua_pushinteger(L, (lua_Integer)pb_len(*s)); + lua_pushinteger(L, (lua_Integer)pb_pos(*s)+1); return 2; } static int Lslice_unpack(lua_State *L) { - lpb_SliceEx view, *s = test_slice(L, 1); + pb_Slice view, *s = test_slice(L, 1); const char *fmt = luaL_checkstring(L, 2); - if (s == NULL) view = lpb_initext(lpb_checkslice(L, 1)), s = &view; + if (s == NULL) view = lpb_checkslice(L, 1), s = &view; return lpb_unpackfmt(L, 3, fmt, s); } static int Lslice_level(lua_State *L) { lpb_Slice *s = check_lslice(L, 1); if (!lua_isnoneornil(L, 2)) { - lpb_SliceEx *se; + pb_Slice *se; lua_Integer level = posrelat(luaL_checkinteger(L, 2), s->used); if (level > (lua_Integer)s->used) return 0; @@ -1043,9 +1084,9 @@ static int Lslice_level(lua_State *L) { se = &s->curr; else se = &s->buff[level]; - lua_pushinteger(L, (lua_Integer)(se->base.p - s->buff[0].head) + 1); - lua_pushinteger(L, (lua_Integer)(se->head - s->buff[0].head) + 1); - lua_pushinteger(L, (lua_Integer)(se->base.end - s->buff[0].head)); + lua_pushinteger(L, (lua_Integer)(se->p - s->buff[0].start) + 1); + lua_pushinteger(L, (lua_Integer)(se->start - s->buff[0].start) + 1); + lua_pushinteger(L, (lua_Integer)(se->end - s->buff[0].start)); return 3; } lua_pushinteger(L, s->used); @@ -1054,18 +1095,18 @@ static int Lslice_level(lua_State *L) { static int Lslice_enter(lua_State *L) { lpb_Slice *s = check_lslice(L, 1); - lpb_SliceEx view; + pb_Slice view; if (lua_isnoneornil(L, 2)) { - argcheck(L, pb_readbytes(&s->curr.base, &view.base) != 0, - 1, "bytes wireformat expected at offset %d", lpb_offset(&s->curr)); - view.head = view.base.p; + argcheck(L, pb_readbytes(&s->curr, &view) != 0, + 1, "bytes wireformat expected at offset %d", pb_pos(s->curr)+1); + view.start = view.p; lpb_enterview(L, s, view); } else { lua_Integer r[] = {1, -1}; - lua_Integer range = rangerelat(L, 2, r, s->curr.base.end - s->curr.head); - view.base.p = s->curr.head + r[0] - 1; - view.base.end = view.base.p + range; - view.head = s->curr.head; + lua_Integer range = rangerelat(L, 2, r, pb_len(s->curr)); + view.p = s->curr.start + r[0] - 1; + view.end = view.p + range; + view.start = s->curr.p; lpb_enterview(L, s, view); } return_self(L); @@ -1090,8 +1131,8 @@ static int Lslice_leave(lua_State *L) { } LUALIB_API int lpb_newslice(lua_State *L, const char *s, size_t len) { - lpb_SliceEx *S = (lpb_SliceEx*)lua_newuserdata(L, sizeof(lpb_SliceEx)); - *S = lpb_initext(pb_lslice(s, len)); + pb_Slice *ls = (pb_Slice*)lua_newuserdata(L, sizeof(pb_Slice)); + *ls = pb_lslice(s, len); luaL_setmetatable(L, PB_SLICE); return 1; } @@ -1103,6 +1144,7 @@ LUALIB_API int luaopen_pb_slice(lua_State *L) { { "__gc", Lslice_reset }, { "delete", Lslice_reset }, { "tohex", Lpb_tohex }, + { "fromhex", Lpb_fromhex }, { "result", Lpb_result }, #define ENTRY(name) { #name, Lslice_##name } ENTRY(new), @@ -1129,83 +1171,87 @@ LUALIB_API int luaopen_pb_slice(lua_State *L) { /* high level typeinfo/encode/decode routines */ -static pb_Type *lpb_type(pb_State *S, const char *name) { - pb_Type *t; - if (name == NULL || *name == '.') - t = pb_type(S, pb_name(S, name)); +static int lpb_pushdeffield(lua_State *L, lpb_State *LS, const pb_Field *f, int is_proto3); + +LUALIB_API const pb_Type *lpb_type(lpb_State *LS, pb_Slice s) { + const pb_Type *t; + if (s.p == NULL || *s.p == '.') + t = pb_type(lpbS_state(LS), lpb_name(LS, s)); else { pb_Buffer b; pb_initbuffer(&b); - pb_addchar(&b, '.'); - pb_addslice(&b, pb_slice(name)); - pb_addchar(&b, '\0'); - t = pb_type(S, pb_name(S, pb_buffer(&b))); + *pb_prepbuffsize(&b, 1) = '.'; + pb_addsize(&b, 1); + pb_addslice(&b, s); + t = pb_type(lpbS_state(LS), pb_name(lpbS_state(LS),pb_result(&b),NULL)); pb_resetbuffer(&b); } return t; } -static pb_Field *lpb_checkfield(lua_State *L, int idx, pb_Type *t) { +static const pb_Field *lpb_field(lua_State *L, int idx, const pb_Type *t) { + lpb_State *LS = lpb_lstate(L); int isint, number = (int)lua_tointegerx(L, idx, &isint); if (isint) return pb_field(t, number); - return pb_fname(t, pb_name(default_state(L), luaL_checkstring(L, idx))); + return pb_fname(t, lpb_name(LS, lpb_checkslice(L, idx))); } static int Lpb_load(lua_State *L) { - pb_State *S = default_state(L); - lpb_SliceEx s = lpb_initext(lpb_checkslice(L, 1)); - lua_pushboolean(L, pb_load(S, &s.base) == PB_OK); - lua_pushinteger(L, lpb_offset(&s)); + lpb_State *LS = lpb_lstate(L); + pb_Slice s = lpb_checkslice(L, 1); + int r = pb_load(&LS->local, &s); + if (r == PB_OK) global_state = &LS->local; + lua_pushboolean(L, r == PB_OK); + lua_pushinteger(L, pb_pos(s)+1); return 2; } static int Lpb_loadfile(lua_State *L) { -#if defined(WINAPI_FAMILY_PARTITION) - return luaL_error(L, "unsupport api in uwp platform"); -#else - pb_State *S = default_state(L); + lpb_State *LS = lpb_lstate(L); const char *filename = luaL_checkstring(L, 1); size_t size; pb_Buffer b; - lpb_SliceEx s; + pb_Slice s; int ret; FILE *fp = fopen(filename, "rb"); if (fp == NULL) return luaL_fileresult(L, 0, filename); pb_initbuffer(&b); do { - void *d = pb_prepbuffsize(&b, BUFSIZ); - if (d == NULL) { fclose(fp); return luaL_error(L, "out of memory"); } + char *d = pb_prepbuffsize(&b, BUFSIZ); + if (d == NULL) return fclose(fp), luaL_error(L, "out of memory"); size = fread(d, 1, BUFSIZ, fp); pb_addsize(&b, size); } while (size == BUFSIZ); fclose(fp); - s = lpb_initext(pb_result(&b)); - ret = pb_load(S, &s.base); + s = pb_result(&b); + ret = pb_load(&LS->local, &s); + if (ret == PB_OK) global_state = &LS->local; pb_resetbuffer(&b); lua_pushboolean(L, ret == PB_OK); - lua_pushinteger(L, lpb_offset(&s)); + lua_pushinteger(L, pb_pos(s)+1); return 2; -#endif } -static int lpb_pushtype(lua_State *L, pb_Type *t) { +static int lpb_pushtype(lua_State *L, const pb_Type *t) { if (t == NULL) return 0; - lua_pushstring(L, (char*)t->name); - lua_pushstring(L, (char*)t->basename); + lua_pushstring(L, (const char*)t->name); + lua_pushstring(L, (const char*)t->basename); lua_pushstring(L, t->is_map ? "map" : t->is_enum ? "enum" : "message"); return 3; } -static int lpb_pushfield(lua_State *L, pb_Type *t, pb_Field *f) { +static int lpb_pushfield(lua_State *L, const pb_Type *t, const pb_Field *f) { if (f == NULL) return 0; - lua_pushstring(L, (char*)f->name); + lua_pushstring(L, (const char*)f->name); lua_pushinteger(L, f->number); - lua_pushstring(L, f->type ? (char*)f->type->name : + lua_pushstring(L, f->type ? + (const char*)f->type->name : pb_typename(f->type_id, "")); - lua_pushstring(L, (char*)f->default_value); - lua_pushstring(L, f->repeated ? f->packed ? "packed" : "repeated" - : "optional"); + lua_pushstring(L, (const char*)f->default_value); + lua_pushstring(L, f->repeated ? + (f->packed ? "packed" : "repeated") : + "optional"); if (f->oneof_idx > 0) { lua_pushstring(L, (const char*)pb_oneofname(t, f->oneof_idx)); lua_pushinteger(L, f->oneof_idx-1); @@ -1215,11 +1261,11 @@ static int lpb_pushfield(lua_State *L, pb_Type *t, pb_Field *f) { } static int Lpb_typesiter(lua_State *L) { - pb_State *S = default_state(L); - pb_Type *t = lpb_type(S, lua_tostring(L, 2)); + lpb_State *LS = lpb_lstate(L); + const pb_Type *t = lpb_type(LS, lpb_toslice(L, 2)); if ((t == NULL && !lua_isnoneornil(L, 2))) return 0; - pb_nexttype(S, &t); + pb_nexttype(lpbS_state(LS), &t); return lpb_pushtype(L, t); } @@ -1231,9 +1277,9 @@ static int Lpb_types(lua_State *L) { } static int Lpb_fieldsiter(lua_State *L) { - pb_State *S = default_state(L); - pb_Type *t = lpb_type(S, luaL_checkstring(L, 1)); - pb_Field *f = pb_fname(t, pb_name(S, lua_tostring(L, 2))); + lpb_State *LS = lpb_lstate(L); + const pb_Type *t = lpb_type(LS, lpb_checkslice(L, 1)); + const pb_Field *f = pb_fname(t, lpb_name(LS, lpb_toslice(L, 2))); if ((f == NULL && !lua_isnoneornil(L, 2)) || !pb_nextfield(t, &f)) return 0; return lpb_pushfield(L, t, f); @@ -1247,95 +1293,123 @@ static int Lpb_fields(lua_State *L) { } static int Lpb_type(lua_State *L) { - pb_State *S = default_state(L); - pb_Type *t = lpb_type(S, luaL_checkstring(L, 1)); + lpb_State *LS = lpb_lstate(L); + const pb_Type *t = lpb_type(LS, lpb_checkslice(L, 1)); if (t == NULL || t->is_dead) return 0; return lpb_pushtype(L, t); } static int Lpb_field(lua_State *L) { - pb_State *S = default_state(L); - pb_Type *t = lpb_type(S, luaL_checkstring(L, 1)); - return lpb_pushfield(L, t, lpb_checkfield(L, 2, t)); + lpb_State *LS = lpb_lstate(L); + const pb_Type *t = lpb_type(LS, lpb_checkslice(L, 1)); + return lpb_pushfield(L, t, lpb_field(L, 2, t)); } static int Lpb_enum(lua_State *L) { - lpb_State *LS = default_lstate(L); - pb_Type *t = lpb_type(&LS->base, luaL_checkstring(L, 1)); - pb_Field *f = lpb_checkfield(L, 2, t); + lpb_State *LS = lpb_lstate(L); + const pb_Type *t = lpb_type(LS, lpb_checkslice(L, 1)); + const pb_Field *f = lpb_field(L, 2, t); if (f == NULL) return 0; if (lua_type(L, 2) == LUA_TNUMBER) - lua_pushstring(L, (char*)f->name); + lua_pushstring(L, (const char*)f->name); else lpb_pushinteger(L, f->number, LS->int64_mode); return 1; } -static int lpb_pushdefault(lua_State *L, lpb_State *LS, pb_Field *f, int is_proto3) { - pb_Type *type = f->type; +static void lpb_newtypetable(lua_State *L, const pb_Type *t, int with_repeat) { + const pb_Field *f = NULL; + if (t == NULL) { lua_newtable(L); return; } + lua_createtable(L, 0, t->field_count - t->oneof_field + t->oneof_count*2); + if (!with_repeat) return; + while (pb_nextfield(t, &f)) { + if (f->repeated) { + lua_newtable(L); + lua_setfield(L, -2, (const char*)f->name); + } + } +} + +static int lpb_pushdefmsg(lua_State *L, lpb_State *LS, const pb_Type *t) { + const pb_Field *f = NULL; + if (t == NULL) return 0; + lpb_newtypetable(L, t, 0); + while (pb_nextfield(t, &f)) + if (!f->oneof_idx && lpb_pushdeffield(L, LS, f, t->is_proto3)) + lua_setfield(L, -2, (const char*)f->name); + return 1; +} + +static int lpb_pushdeffield(lua_State *L, lpb_State *LS, const pb_Field *f, int is_proto3) { int ret = 0; + const pb_Type *type; char *end; if (f == NULL) return 0; - if (is_proto3 && f->repeated) { lua_newtable(L); return 1; } + if (f->repeated) return is_proto3 ? (lua_newtable(L), 1) : 0; switch (f->type_id) { case PB_Tbytes: case PB_Tstring: if (f->default_value) - ret = 1, lua_pushstring(L, (char*)f->default_value); + ret = 1, lua_pushstring(L, (const char*)f->default_value); else if (is_proto3) ret = 1, lua_pushliteral(L, ""); break; case PB_Tenum: + if ((type = f ? f->type : NULL) == NULL) return 0; if ((f = pb_fname(type, f->default_value)) != NULL) { if (LS->enum_as_value) ret = 1, lpb_pushinteger(L, f->number, LS->int64_mode); else - ret = 1, lua_pushstring(L, (char*)f->name); + ret = 1, lua_pushstring(L, (const char*)f->name); } else if (is_proto3) { if ((f = pb_field(type, 0)) == NULL || LS->enum_as_value) ret = 1, lua_pushinteger(L, 0); else - ret = 1, lua_pushstring(L, (char*)f->name); + ret = 1, lua_pushstring(L, (const char*)f->name); } break; case PB_Tmessage: + if (LS->decode_default_message) + return lpb_pushdefmsg(L, LS, f->type); return 0; case PB_Tbool: if (f->default_value) { - if (f->default_value == pb_name(&LS->base, "true")) + if (f->default_value == lpb_name(LS, pb_slice("true"))) ret = 1, lua_pushboolean(L, 1); - else if (f->default_value == pb_name(&LS->base, "false")) + else if (f->default_value == lpb_name(LS, pb_slice("false"))) ret = 1, lua_pushboolean(L, 0); } else if (is_proto3) ret = 1, lua_pushboolean(L, 0); break; case PB_Tdouble: case PB_Tfloat: if (f->default_value) { - lua_Number ln = (lua_Number)strtod((char*)f->default_value, &end); - if ((char*)f->default_value == end) return 0; + lua_Number ln = (lua_Number)strtod((const char*)f->default_value, &end); + if ((const char*)f->default_value == end) return 0; ret = 1, lua_pushnumber(L, ln); } else if (is_proto3) ret = 1, lua_pushnumber(L, 0.0); break; default: if (f->default_value) { - lua_Integer li = (lua_Integer)strtol((char*)f->default_value, &end, 10); - if ((char*)f->default_value == end) return 0; + lua_Integer li = (lua_Integer)strtol((const char*)f->default_value, &end, 10); + if ((const char*)f->default_value == end) return 0; ret = 1, lpb_pushinteger(L, li, LS->int64_mode); } else if (is_proto3) ret = 1, lua_pushinteger(L, 0); } return ret; } -static void lpb_pushdefaults(lua_State *L, lpb_State *LS, pb_Type *t) { +static void lpb_pushdefmeta(lua_State *L, lpb_State *LS, const pb_Type *t) { lpb_pushdeftable(L, LS); if (lua53_rawgetp(L, -1, t) != LUA_TTABLE) { - pb_Field *f = NULL; + const pb_Field *f = NULL; lua_pop(L, 1); - lua_newtable(L); - while (pb_nextfield(t, &f)) { - if (!f->repeated && lpb_pushdefault(L, LS, f, t->is_proto3)) - lua_setfield(L, -2, (char*)f->name); - } + lpb_newtypetable(L, t, 0); + while (pb_nextfield(t, &f)) + if (!f->oneof_idx /* not oneof */ + && f->type_id != PB_Tmessage /* not message */ + && !f->repeated /* not repeated */ + && lpb_pushdeffield(L, LS, f, t->is_proto3)) + lua_setfield(L, -2, (const char*)f->name); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); lua_pushvalue(L, -1); @@ -1344,7 +1418,7 @@ static void lpb_pushdefaults(lua_State *L, lpb_State *LS, pb_Type *t) { lua_remove(L, -2); } -static void lpb_cleardefaults(lua_State *L, lpb_State *LS, pb_Type *t) { +static void lpb_cleardefmeta(lua_State *L, lpb_State *LS, const pb_Type *t) { lpb_pushdeftable(L, LS); lua_pushnil(L); lua_rawsetp(L, -2, t); @@ -1352,31 +1426,100 @@ static void lpb_cleardefaults(lua_State *L, lpb_State *LS, pb_Type *t) { } static int Lpb_defaults(lua_State *L) { - lpb_State *LS = default_lstate(L); - pb_Type *t = lpb_type(&LS->base, luaL_checkstring(L, 1)); + lpb_State *LS = lpb_lstate(L); + const pb_Type *t = lpb_type(LS, lpb_checkslice(L, 1)); int clear = lua_toboolean(L, 2); - lpb_pushdefaults(L, LS, t); - if (clear) lpb_cleardefaults(L, LS, t); + if (t == NULL) luaL_argerror(L, 1, "type not found"); + lpb_pushdefmeta(L, LS, t); + if (clear) lpb_cleardefmeta(L, LS, t); + return 1; +} + +static int Lpb_hook(lua_State *L) { + lpb_State *LS = lpb_lstate(L); + const pb_Type *t = lpb_type(LS, lpb_checkslice(L, 1)); + int type = lua_type(L, 2); + if (t == NULL) luaL_argerror(L, 1, "type not found"); + if (type != LUA_TNONE && type != LUA_TNIL && type != LUA_TFUNCTION) + typeerror(L, 2, "function"); + lua_settop(L, 2); + lpb_pushdechooktable(L, LS); + lua_rawgetp(L, 3, t); + if (type != LUA_TNONE) { + lua_pushvalue(L, 2); + lua_rawsetp(L, 3, t); + } + return 1; +} + +static int Lpb_encode_hook(lua_State *L) { + lpb_State *LS = lpb_lstate(L); + const pb_Type *t = lpb_type(LS, lpb_checkslice(L, 1)); + int type = lua_type(L, 2); + if (t == NULL) luaL_argerror(L, 1, "type not found"); + if (type != LUA_TNONE && type != LUA_TNIL && type != LUA_TFUNCTION) + typeerror(L, 2, "function"); + lua_settop(L, 2); + lpb_pushenchooktable(L, LS); + lua_rawgetp(L, 3, t); + if (type != LUA_TNONE) { + lua_pushvalue(L, 2); + lua_rawsetp(L, 3, t); + } return 1; } static int Lpb_clear(lua_State *L) { - lpb_State *LS = default_lstate(L); - pb_State *S = &LS->base; + lpb_State *LS = lpb_lstate(L); + pb_State *S = (pb_State*)LS->state; pb_Type *t; if (lua_isnoneornil(L, 1)) { - pb_free(S), pb_init(S); + pb_free(&LS->local), pb_init(&LS->local); luaL_unref(L, LUA_REGISTRYINDEX, LS->defs_index); LS->defs_index = LUA_NOREF; + luaL_unref(L, LUA_REGISTRYINDEX, LS->enc_hooks_index); + LS->enc_hooks_index = LUA_NOREF; + luaL_unref(L, LUA_REGISTRYINDEX, LS->dec_hooks_index); + LS->dec_hooks_index = LUA_NOREF; return 0; } - t = lpb_type(S, luaL_checkstring(L, 1)); - if (lua_isnoneornil(L, 2)) pb_deltype(S, t); - else pb_delfield(S, t, lpb_checkfield(L, 2, t)); - lpb_cleardefaults(L, LS, t); + LS->state = &LS->local; + t = (pb_Type*)lpb_type(LS, lpb_checkslice(L, 1)); + if (lua_isnoneornil(L, 2)) pb_deltype(&LS->local, t); + else pb_delfield(&LS->local, t, (pb_Field*)lpb_field(L, 2, t)); + LS->state = S; + lpb_cleardefmeta(L, LS, t); return 0; } +static int Lpb_typefmt(lua_State *L) { + pb_Slice s = lpb_checkslice(L, 1); + const char *r = NULL; + char buf[2] = {0}; + int type; + if (pb_len(s) == 1) + r = pb_typename(type = lpb_typefmt(*s.p), "!"); + else if (lpb_type(lpb_lstate(L), s)) + r = "message", type = PB_TBYTES; + else if ((type = pb_typebyname(s.p, PB_Tmessage)) != PB_Tmessage) { + switch (type) { +#define X(name,type,fmt) case PB_T##name: buf[0] = fmt, r = buf; break; + PB_TYPES(X) +#undef X + } + type = pb_wtypebytype(type); + } else if ((type = pb_wtypebyname(s.p, PB_Tmessage)) != PB_Tmessage) { + switch (type) { +#define X(id,name,fmt) case PB_T##id: buf[0] = fmt, r = buf; break; + PB_WIRETYPES(X) +#undef X + } + } + lua_pushstring(L, r ? r : "!"); + lua_pushinteger(L, type); + return 2; +} + /* protobuf encode */ @@ -1384,36 +1527,49 @@ typedef struct lpb_Env { lua_State *L; lpb_State *LS; pb_Buffer *b; - lpb_SliceEx *s; + pb_Slice *s; } lpb_Env; -static void lpb_encode (lpb_Env *e, pb_Type *t); +static void lpbE_encode (lpb_Env *e, const pb_Type *t); -static void lpb_checktable(lua_State *L, pb_Field *f) { +static void lpb_checktable(lua_State *L, const pb_Field *f) { argcheck(L, lua_istable(L, -1), 2, "table expected at field '%s', got %s", - (char*)f->name, luaL_typename(L, -1)); + (const char*)f->name, luaL_typename(L, -1)); } -static void lpbE_enum(lpb_Env *e, pb_Field *f) { +static void lpb_useenchooks(lua_State *L, lpb_State *LS, const pb_Type *t) { + lpb_pushenchooktable(L, LS); + if (lua53_rawgetp(L, -1, t) != LUA_TNIL) { + lua_pushvalue(L, -3); + lua_call(L, 1, 1); + if (!lua_isnil(L, -1)) { + lua_pushvalue(L, -1); + lua_replace(L, -4); + } + } + lua_pop(L, 2); +} + +static void lpbE_enum(lpb_Env *e, const pb_Field *f) { lua_State *L = e->L; pb_Buffer *b = e->b; - pb_Field *ev; + const pb_Field *ev; int type = lua_type(L, -1); if (type == LUA_TNUMBER) pb_addvarint64(b, (uint64_t)lua_tonumber(L, -1)); else if ((ev = pb_fname(f->type, - pb_name(&e->LS->base, lua_tostring(L, -1)))) != NULL) + lpb_name(e->LS, lpb_toslice(L, -1)))) != NULL) pb_addvarint32(b, ev->number); else if (type != LUA_TSTRING) argcheck(L, 0, 2, "number/string expected at field '%s', got %s", - (char*)f->name, luaL_typename(L, -1)); + (const char*)f->name, luaL_typename(L, -1)); else argcheck(L, 0, 2, "can not encode unknown enum '%s' at field '%s'", - lua_tostring(L, -1), (char*)f->name); + lua_tostring(L, -1), (const char*)f->name); } -static void lpbE_field(lpb_Env *e, pb_Field *f, size_t *plen) { +static void lpbE_field(lpb_Env *e, const pb_Field *f, size_t *plen) { lua_State *L = e->L; pb_Buffer *b = e->b; size_t len; @@ -1421,13 +1577,15 @@ static void lpbE_field(lpb_Env *e, pb_Field *f, size_t *plen) { if (plen) *plen = 0; switch (f->type_id) { case PB_Tenum: + if (e->LS->use_enc_hooks) lpb_useenchooks(L, e->LS, f->type); lpbE_enum(e, f); break; case PB_Tmessage: + if (e->LS->use_enc_hooks) lpb_useenchooks(L, e->LS, f->type); lpb_checktable(L, f); len = pb_bufflen(b); - lpb_encode(e, f->type); + lpbE_encode(e, f->type); lpb_addlength(L, b, len); break; @@ -1436,101 +1594,112 @@ static void lpbE_field(lpb_Env *e, pb_Field *f, size_t *plen) { argcheck(L, ltype == 0, 2, "%s expected for field '%s', got %s", lua_typename(L, ltype), - (char*)f->name, luaL_typename(L, -1)); + (const char*)f->name, luaL_typename(L, -1)); } } -static void lpbE_tagfield(lpb_Env *e, pb_Field *f, size_t *plen) { - size_t klen = pb_addvarint32(e->b, +static void lpbE_tagfield(lpb_Env *e, const pb_Field *f, int ignorezero) { + size_t hlen = pb_addvarint32(e->b, pb_pair(f->number, pb_wtypebytype(f->type_id))); - lpbE_field(e, f, plen); - if (plen && *plen != 0) *plen += klen; + size_t ignoredlen; + lpbE_field(e, f, &ignoredlen); + if (!e->LS->encode_default_values && ignoredlen != 0 && ignorezero) + e->b->size -= (unsigned)(ignoredlen + hlen); } -static void lpbE_map(lpb_Env *e, pb_Field *f) { +static void lpbE_map(lpb_Env *e, const pb_Field *f) { lua_State *L = e->L; - pb_Field *kf = pb_field(f->type, 1); - pb_Field *vf = pb_field(f->type, 2); + const pb_Field *kf = pb_field(f->type, 1); + const pb_Field *vf = pb_field(f->type, 2); if (kf == NULL || vf == NULL) return; lpb_checktable(L, f); lua_pushnil(L); while (lua_next(L, -2)) { - size_t len, ignoredlen; + size_t len; pb_addvarint32(e->b, pb_pair(f->number, PB_TBYTES)); len = pb_bufflen(e->b); lua_pushvalue(L, -2); - lpbE_tagfield(e, kf, &ignoredlen); - e->b->size -= ignoredlen; + lpbE_tagfield(e, kf, 1); lua_pop(L, 1); - lpbE_tagfield(e, vf, &ignoredlen); - e->b->size -= ignoredlen; + lpbE_tagfield(e, vf, 1); lua_pop(L, 1); lpb_addlength(L, e->b, len); } } -static void lpbE_repeated(lpb_Env *e, pb_Field *f) { +static void lpbE_repeated(lpb_Env *e, const pb_Field *f) { lua_State *L = e->L; pb_Buffer *b = e->b; int i; lpb_checktable(L, f); if (f->packed) { - size_t len; + size_t len, bufflen = pb_bufflen(b); pb_addvarint32(b, pb_pair(f->number, PB_TBYTES)); len = pb_bufflen(b); for (i = 1; lua53_rawgeti(L, -1, i) != LUA_TNIL; ++i) { lpbE_field(e, f, NULL); lua_pop(L, 1); } - lpb_addlength(L, b, len); + if (i == 1) + pb_bufflen(b) = bufflen; + else + lpb_addlength(L, b, len); } else { for (i = 1; lua53_rawgeti(L, -1, i) != LUA_TNIL; ++i) { - lpbE_tagfield(e, f, NULL); + lpbE_tagfield(e, f, 0); lua_pop(L, 1); } } lua_pop(L, 1); } -static void lpb_encode(lpb_Env *e, pb_Type *t) { +static void lpb_encode_onefield(lpb_Env *e, const pb_Type *t, const pb_Field *f) { + if (f->type && f->type->is_map) + lpbE_map(e, f); + else if (f->repeated) + lpbE_repeated(e, f); + else if (!f->type || !f->type->is_dead) + lpbE_tagfield(e, f, t->is_proto3 && !f->oneof_idx); +} + +static void lpbE_encode(lpb_Env *e, const pb_Type *t) { lua_State *L = e->L; luaL_checkstack(L, 3, "message too many levels"); - lua_pushnil(L); - while (lua_next(L, -2)) { - if (lua_type(L, -2) == LUA_TSTRING) { - pb_Field *f = pb_fname(t, - pb_name(&e->LS->base, lua_tostring(L, -2))); - if (f == NULL) - /* skip */; - else if (f->type && f->type->is_map) - lpbE_map(e, f); - else if (f->repeated) - lpbE_repeated(e, f); - else if (!f->type || !f->type->is_dead) { - size_t ignoredlen; - lpbE_tagfield(e, f, &ignoredlen); - if (t->is_proto3 && !f->oneof_idx) - e->b->size -= ignoredlen; + if (e->LS->encode_order) { + const pb_Field *f = NULL; + while (pb_nextfield(t, &f)) { + if (lua53_getfield(L, -1, (const char*)f->name) != LUA_TNIL) + lpb_encode_onefield(e, t, f); + lua_pop(L, 1); + } + } else { + lua_pushnil(L); + while (lua_next(L, -2)) { + if (lua_type(L, -2) == LUA_TSTRING) { + const pb_Field *f = + pb_fname(t, lpb_name(e->LS, lpb_toslice(L, -2))); + if (f != NULL) lpb_encode_onefield(e, t, f); } + lua_pop(L, 1); } - lua_pop(L, 1); } } static int Lpb_encode(lua_State *L) { - lpb_State *LS = default_lstate(L); - pb_Type *t = lpb_type(&LS->base, luaL_checkstring(L, 1)); + lpb_State *LS = lpb_lstate(L); + const pb_Type *t = lpb_type(LS, lpb_checkslice(L, 1)); lpb_Env e; argcheck(L, t!=NULL, 1, "type '%s' does not exists", lua_tostring(L, 1)); luaL_checktype(L, 2, LUA_TTABLE); e.L = L, e.LS = LS, e.b = test_buffer(L, 3); if (e.b == NULL) pb_resetbuffer(e.b = &LS->buffer); lua_pushvalue(L, 2); - lpb_encode(&e, t); + if (e.LS->use_enc_hooks) lpb_useenchooks(L, e.LS, t); + lpbE_encode(&e, t); if (e.b != &LS->buffer) lua_settop(L, 3); else { - lua_pushlstring(L, e.b->buff, e.b->size); + lua_pushlstring(L, pb_buffer(e.b), pb_bufflen(e.b)); pb_resetbuffer(e.b); } return 1; @@ -1539,73 +1708,64 @@ static int Lpb_encode(lua_State *L) { /* protobuf decode */ -#define lpb_withinput(e, ns, stmt) ((e)->s = (ns), (stmt), (e)->s = s) +#define lpb_withinput(e,ns,stmt) ((e)->s = (ns), (stmt), (e)->s = s) -static int lpb_decode(lpb_Env *e, pb_Type *t); +static int lpbD_message(lpb_Env *e, const pb_Type *t); -static void lpb_pushtypetable(lua_State *L, lpb_State *LS, pb_Type *t) { - pb_Field *f = NULL; - int mode = t ? LS->default_mode : LPB_NODEF; - lua_newtable(L); - switch (t && t->is_proto3 && mode == LPB_DEFDEF ? LPB_COPYDEF : mode) { +static void lpb_usedechooks(lua_State *L, lpb_State *LS, const pb_Type *t) { + lpb_pushdechooktable(L, LS); + if (lua53_rawgetp(L, -1, t) != LUA_TNIL) { + lua_pushvalue(L, -3); + lua_call(L, 1, 1); + if (!lua_isnil(L, -1)) { + lua_pushvalue(L, -1); + lua_replace(L, -4); + } + } + lua_pop(L, 2); +} + +static void lpb_pushtypetable(lua_State *L, lpb_State *LS, const pb_Type *t) { + int mode = LS->default_mode; + switch (t->is_proto3 && mode == LPB_DEFDEF ? LPB_COPYDEF : mode) { case LPB_COPYDEF: - while (pb_nextfield(t, &f)) - if (!f->oneof_idx && lpb_pushdefault(L, LS, f, t->is_proto3)) - lua_setfield(L, -2, (char*)f->name); + lpb_pushdefmsg(L, LS, t); break; case LPB_METADEF: - while (pb_nextfield(t, &f)) { - if (f->repeated) { - lua_newtable(L); - lua_setfield(L, -2, (char*)f->name); - } - } - lpb_pushdefaults(L, LS, t); + lpb_newtypetable(L, t, t->is_proto3); + lpb_pushdefmeta(L, LS, t); lua_setmetatable(L, -2); break; default: /* no default value */ + lpb_newtypetable(L, t, LS->decode_default_array); break; } } -static void lpb_fetchtable(lpb_Env *e, pb_Field *f, pb_Type *t) { +static void lpb_fetchtable(lpb_Env *e, const pb_Field *f) { lua_State *L = e->L; - if (lua53_getfield(L, -1, (char*)f->name) == LUA_TNIL) { + if (lua53_getfield(L, -1, (const char*)f->name) == LUA_TNIL) { lua_pop(L, 1); - lpb_pushtypetable(L, e->LS, t); + lua_newtable(L); lua_pushvalue(L, -1); - lua_setfield(L, -3, (char*)f->name); + lua_setfield(L, -3, (const char*)f->name); } } -static int lpbD_mismatch(lua_State *L, pb_Field *f, lpb_SliceEx *s, uint32_t tag) { - return luaL_error(L, - "type mismatch for field '%s' at offset %d, " - "%s expected for type %s, got %s", - (char*)f->name, - lpb_offset(s), - pb_wtypename(pb_wtypebytype(f->type_id), NULL), - pb_typename(f->type_id, NULL), - pb_wtypename(pb_gettype(tag), NULL)); -} - -static void lpbD_field(lpb_Env *e, pb_Field *f, uint32_t tag) { +static void lpbD_rawfield(lpb_Env *e, const pb_Field *f) { lua_State *L = e->L; - lpb_SliceEx sv, *s = e->s; - pb_Field *ev = NULL; + pb_Slice sv, *s = e->s; + const pb_Field *ev = NULL; uint64_t u64; - - if (!f->packed && pb_wtypebytype(f->type_id) != (int)pb_gettype(tag)) - lpbD_mismatch(L, f, s, tag); - switch (f->type_id) { case PB_Tenum: - if (pb_readvarint64(&s->base, &u64) == 0) - luaL_error(L, "invalid varint value at offset %d", lpb_offset(s)); - if (!default_lstate(L)->enum_as_value) + if (pb_readvarint64(s, &u64) == 0) + luaL_error(L, "invalid varint value at offset %d", pb_pos(*s)+1); + if (!lpb_lstate(L)->enum_as_value) ev = pb_field(f->type, (int32_t)u64); - if (ev) lua_pushstring(L, (char*)ev->name); - else lpb_pushinteger(L, (lua_Integer)u64, default_lstate(L)->int64_mode); + if (ev) lua_pushstring(L, (const char*)ev->name); + else lpb_pushinteger(L, (lua_Integer)u64, lpb_lstate(L)->int64_mode); + if (e->LS->use_dec_hooks) lpb_usedechooks(L, e->LS, f->type); break; case PB_Tmessage: @@ -1614,7 +1774,7 @@ static void lpbD_field(lpb_Env *e, pb_Field *f, uint32_t tag) { lua_pushnil(L); else { lpb_pushtypetable(L, e->LS, f->type); - lpb_withinput(e, &sv, lpb_decode(e, f->type)); + lpb_withinput(e, &sv, lpbD_message(e, f->type)); } break; @@ -1623,17 +1783,34 @@ static void lpbD_field(lpb_Env *e, pb_Field *f, uint32_t tag) { } } -static void lpbD_map(lpb_Env *e, pb_Field *f) { +static void lpbD_checktype(lpb_Env *e, const pb_Field *f, uint32_t tag) { + if (pb_wtypebytype(f->type_id) == (int)pb_gettype(tag)) return; + luaL_error(e->L, + "type mismatch for %s%sfield '%s' at offset %d, " + "%s expected for type %s, got %s", + f->packed ? "packed " : "", f->repeated ? "repeated " : "", + (const char*)f->name, + pb_pos(*e->s)+1, + pb_wtypename(pb_wtypebytype(f->type_id), NULL), + pb_typename(f->type_id, NULL), + pb_wtypename(pb_gettype(tag), NULL)); +} + +static void lpbD_field(lpb_Env *e, const pb_Field *f, uint32_t tag) { + lpbD_checktype(e, f, tag); + lpbD_rawfield(e, f); +} + +static void lpbD_map(lpb_Env *e, const pb_Field *f) { lua_State *L = e->L; - lpb_SliceEx p, *s = e->s; - int mask = 0, top = lua_gettop(L) + 1; + pb_Slice p, *s = e->s; + int mask = 0, top = lua_gettop(L); uint32_t tag; - lpb_fetchtable(e, f, NULL); lpb_readbytes(L, s, &p); if (f->type == NULL) return; lua_pushnil(L); lua_pushnil(L); - while (pb_readvarint32(&p.base, &tag)) { + while (pb_readvarint32(&p, &tag)) { int n = pb_gettag(tag); if (n == 1 || n == 2) { mask |= n; @@ -1641,80 +1818,85 @@ static void lpbD_map(lpb_Env *e, pb_Field *f) { lua_replace(L, top+n); } } - if ((mask & 1) == 0 - && lpb_pushdefault(L, e->LS, pb_field(f->type, 1), 1)) { - lua_replace(L, top + 1); - mask |= 1; - } - if ((mask & 2) == 0 - && lpb_pushdefault(L, e->LS, pb_field(f->type, 2), 1)) { - lua_replace(L, top + 2); - mask |= 2; - } + if (!(mask & 1) && lpb_pushdeffield(L, e->LS, pb_field(f->type, 1), 1)) + lua_replace(L, top + 1), mask |= 1; + if (!(mask & 2) && lpb_pushdeffield(L, e->LS, pb_field(f->type, 2), 1)) + lua_replace(L, top + 2), mask |= 2; if (mask == 3) lua_rawset(L, -3); else lua_pop(L, 2); - lua_pop(L, 1); } -static void lpbD_repeated(lpb_Env *e, pb_Field *f, uint32_t tag) { +static void lpbD_repeated(lpb_Env *e, const pb_Field *f, uint32_t tag) { lua_State *L = e->L; - lpb_fetchtable(e, f, NULL); - if (f->packed && pb_gettype(tag) == PB_TBYTES) { + if (pb_gettype(tag) != PB_TBYTES + || (!f->packed && pb_wtypebytype(f->type_id) == PB_TBYTES)) { + lpbD_field(e, f, tag); + lua_rawseti(L, -2, (lua_Integer)lua_rawlen(L, -2) + 1); + } else { int len = (int)lua_rawlen(L, -1); - lpb_SliceEx p, *s = e->s; + pb_Slice p, *s = e->s; lpb_readbytes(L, s, &p); - while (p.base.p < p.base.end) { - lpb_withinput(e, &p, lpbD_field(e, f, tag)); + while (p.p < p.end) { + lpb_withinput(e, &p, lpbD_rawfield(e, f)); lua_rawseti(L, -2, ++len); } - } else { - lpbD_field(e, f, tag); - lua_rawseti(L, -2, (lua_Integer)lua_rawlen(L, -2) + 1); } - lua_pop(L, 1); } -static int lpb_decode(lpb_Env *e, pb_Type *t) { +static int lpbD_message(lpb_Env *e, const pb_Type *t) { lua_State *L = e->L; - lpb_SliceEx *s = e->s; + pb_Slice *s = e->s; uint32_t tag; - while (pb_readvarint32(&s->base, &tag)) { - pb_Field *f = pb_field(t, pb_gettag(tag)); + luaL_checkstack(L, t->field_count * 2, "not enough stack space for fields"); + while (pb_readvarint32(s, &tag)) { + const pb_Field *f = pb_field(t, pb_gettag(tag)); if (f == NULL) - pb_skipvalue(&s->base, tag); - else if (f->type && f->type->is_map) + pb_skipvalue(s, tag); + else if (f->type && f->type->is_map) { + lpb_fetchtable(e, f); + lpbD_checktype(e, f, tag); lpbD_map(e, f); - else if (f->repeated) + lua_pop(L, 1); + } else if (f->repeated) { + lpb_fetchtable(e, f); lpbD_repeated(e, f, tag); - else { - lua_pushstring(L, (char*)f->name); + lua_pop(L, 1); + } else { + lua_pushstring(L, (const char*)f->name); + if (f->oneof_idx) { + lua_pushstring(L, (const char*)pb_oneofname(t, f->oneof_idx)); + lua_pushvalue(L, -2); + lua_rawset(L, -4); + } lpbD_field(e, f, tag); lua_rawset(L, -3); } } + if (e->LS->use_dec_hooks) lpb_usedechooks(L, e->LS, t); return 1; } -static int lpb_decode_ex(lua_State *L, lpb_SliceEx s) { - lpb_State *LS = default_lstate(L); - pb_Type *t = lpb_type(&LS->base, luaL_checkstring(L, 1)); +static int lpbD_decode(lua_State *L, pb_Slice s, int start) { + lpb_State *LS = lpb_lstate(L); + const pb_Type *t = lpb_type(LS, lpb_checkslice(L, 1)); lpb_Env e; argcheck(L, t!=NULL, 1, "type '%s' does not exists", lua_tostring(L, 1)); - lua_settop(L, 3); - if (!lua_istable(L, 3)) { + lua_settop(L, start); + if (!lua_istable(L, start)) { lua_pop(L, 1); lpb_pushtypetable(L, LS, t); } e.L = L, e.LS = LS, e.s = &s; - return lpb_decode(&e, t); + return lpbD_message(&e, t); } static int Lpb_decode(lua_State *L) { - lpb_SliceEx s = lua_isnoneornil(L, 2) ? lpb_initext(pb_lslice(NULL, 0)) - : lpb_initext(lpb_checkslice(L, 2)); - return lpb_decode_ex(L, s); + return lpbD_decode(L, lua_isnoneornil(L, 2) ? + pb_lslice(NULL, 0) : + lpb_checkslice(L, 2), 3); } + /* pb module interface */ static int Lpb_option(lua_State *L) { @@ -1728,6 +1910,18 @@ static int Lpb_option(lua_State *L) { X(6, no_default_values, LS->default_mode = LPB_NODEF) \ X(7, use_default_values, LS->default_mode = LPB_COPYDEF) \ X(8, use_default_metatable, LS->default_mode = LPB_METADEF) \ + X(9, enable_hooks, LS->use_dec_hooks = 1) \ + X(10, disable_hooks, LS->use_dec_hooks = 0) \ + X(11, enable_enchooks, LS->use_enc_hooks = 1) \ + X(12, disable_enchooks, LS->use_enc_hooks = 0) \ + X(13, encode_default_values,LS->encode_default_values = 1) \ + X(14, no_encode_default_values,LS->encode_default_values = 0) \ + X(15, decode_default_array, LS->decode_default_array = 1) \ + X(16, no_decode_default_array, LS->decode_default_array = 0) \ + X(17, encode_order, LS->encode_order = 1) \ + X(18, no_encode_order, LS->encode_order = 0) \ + X(19, decode_default_message, LS->decode_default_message = 1) \ + X(20, no_decode_default_message, LS->decode_default_message = 0) \ static const char *opts[] = { #define X(ID,NAME,CODE) #NAME, @@ -1735,7 +1929,7 @@ static int Lpb_option(lua_State *L) { #undef X NULL }; - lpb_State *LS = default_lstate(L); + lpb_State *LS = lpb_lstate(L); switch (luaL_checkoption(L, 1, NULL, opts)) { #define X(ID,NAME,CODE) case ID: CODE; break; OPTS(X) @@ -1759,9 +1953,13 @@ LUALIB_API int luaopen_pb(lua_State *L) { ENTRY(fields), ENTRY(type), ENTRY(field), + ENTRY(typefmt), ENTRY(enum), ENTRY(defaults), + ENTRY(hook), + ENTRY(encode_hook), ENTRY(tohex), + ENTRY(fromhex), ENTRY(result), ENTRY(option), ENTRY(state), @@ -1783,14 +1981,47 @@ LUALIB_API int luaopen_pb(lua_State *L) { } static int Lpb_decode_unsafe(lua_State *L) { - return lpb_decode_ex(L, - lpb_initext(pb_lslice( - (const char*)lua_touserdata(L, 2), - (size_t)luaL_checkinteger(L, 3)))); + const char *data = (const char *)lua_touserdata(L, 2); + size_t size = (size_t)luaL_checkinteger(L, 3); + if (data == NULL) typeerror(L, 2, "userdata"); + return lpbD_decode(L, pb_lslice(data, size), 4); +} + +static int Lpb_slice_unsafe(lua_State *L) { + const char *data = (const char *)lua_touserdata(L, 1); + size_t size = (size_t)luaL_checkinteger(L, 2); + if (data == NULL) typeerror(L, 1, "userdata"); + return lpb_newslice(L, data, size); +} + +static int Lpb_touserdata(lua_State *L) { + pb_Slice s = lpb_toslice(L, 1); + lua_pushlightuserdata(L, (void*)s.p); + lua_pushinteger(L, pb_len(s)); + return 2; +} + +static int Lpb_use(lua_State *L) { + const char *opts[] = { "global", "local", NULL }; + lpb_State *LS = lpb_lstate(L); + const pb_State *GS = global_state; + switch (luaL_checkoption(L, 1, NULL, opts)) { + case 0: if (GS) LS->state = GS; break; + case 1: LS->state = &LS->local; break; + } + lua_pushboolean(L, GS != NULL); + return 1; } -LUALIB_API int luaopen_pb_decode_unsafe(lua_State *L) { - lua_pushcfunction(L, Lpb_decode_unsafe); +LUALIB_API int luaopen_pb_unsafe(lua_State *L) { + luaL_Reg libs[] = { + { "decode", Lpb_decode_unsafe }, + { "slice", Lpb_slice_unsafe }, + { "touserdata", Lpb_touserdata }, + { "use", Lpb_use }, + { NULL, NULL } + }; + luaL_newlib(L, libs); return 1; } @@ -1798,5 +2029,6 @@ LUALIB_API int luaopen_pb_decode_unsafe(lua_State *L) { PB_NS_END /* cc: flags+='-O3 -ggdb -pedantic -std=c90 -Wall -Wextra --coverage' - * maccc: flags+='-v -shared -undefined dynamic_lookup' output='pb.so' - * win32cc: flags+='-s -mdll -DLUA_BUILD_AS_DLL ' output='pb.dll' libs+='-llua53' */ + * maccc: flags+='-ggdb -shared -undefined dynamic_lookup' output='pb.so' + * win32cc: flags+='-s -mdll -DLUA_BUILD_AS_DLL ' output='pb.dll' libs+='-llua54' */ +