/* lightuserdata pattern string format "ixrsmb" integer size */ static int _pattern_pack(lua_State *L) { struct pbc_pattern * pat = lua_touserdata(L,1); size_t format_sz = 0; const char * format = lua_tolstring(L,2,&format_sz); int size = lua_tointeger(L,3); char data[size]; memset(data, 0 ,size); char * ptr = data; int i; for (i=0;i<format_sz;i++) { if (format[i] >= 'a' && format[i] <='z') { ptr = _get_value(L, 4+i, ptr, format[i]); } else { if (!lua_istable(L,4+i)) { luaL_error(L,"need table for array type"); } int j; int n = lua_rawlen(L,4+i); for (j=0;j<n;j++) { lua_rawgeti(L,4+i,j); _get_array_value(L,(void *)ptr,format[i]); lua_pop(L,1); } ptr += sizeof(pbc_array); } } luaL_Buffer b; luaL_buffinit(L, &b); int cap = 128; do { char * temp = luaL_prepbuffsize(&b , cap); struct pbc_slice slice; slice.buffer = temp; slice.len = cap; int ret = pbc_pattern_pack(pat, data, &slice); if (ret < 0) { cap = cap * 2; _Free(temp); continue; } luaL_addsize(&b , slice.len); } while (0); luaL_pushresult(&b); pbc_pattern_close_arrays(pat, data); return 1; }
static void test_pattern_unpack(struct pbc_env *env, struct pbc_slice * slice) { struct person p; int r = pbc_pattern_unpack(pat, slice, &p); if (r>=0) { printf("name = %s\n",(const char *)p.name.buffer); printf("id = %d\n",p.id); printf("email = %s\n",(const char *)p.email.buffer); int n = pbc_array_size(p.phone); int i; for (i=0;i<n;i++) { struct pbc_slice * bytes = pbc_array_slice(p.phone, i); struct person_phone pp; pbc_pattern_unpack(pat_phone , bytes , &pp); printf("\tnumber = %s\n" , (const char*)pp.number.buffer); printf("\ttype = %d\n" , pp.type); } n = pbc_array_size(p.test); for (i=0;i<n;i++) { printf("test[%d] = %d\n",i, pbc_array_integer(p.test, i , NULL)); } pbc_pattern_close_arrays(pat,&p); } }
int pbc_pattern_unpack(struct pbc_pattern *pat, struct pbc_slice *s, void * output) { pbc_ctx _ctx; int r = _pbcC_open(_ctx, s->buffer, s->len); if (r <= 0) { _pbcC_close(_ctx); return r+1; } set_default(pat, output); struct context * ctx = (struct context *)_ctx; int i; for (i=0;i<ctx->number;i++) { struct _pattern_field * f = bsearch_pattern(pat, ctx->a[i].id); if (f) { char * out = (char *)output + f->offset; if (unpack_field(f->ctype , f->ptype , ctx->buffer , &ctx->a[i], out) != 0) { pbc_pattern_close_arrays(pat, output); _pbcC_close(_ctx); return -i-1; } } } _pbcC_close(_ctx); return 0; }
/* lightuserdata pattern string format "ixrsmb" integer size lightuserdata buffer integer buffer_len */ static int _pattern_unpack(lua_State *L) { struct pbc_pattern * pat = (struct pbc_pattern *)checkuserdata(L, 1); if (pat == NULL) { return luaL_error(L, "unpack pattern is NULL"); } size_t format_sz = 0; const char * format = lua_tolstring(L,2,&format_sz); int size = lua_tointeger(L,3); struct pbc_slice slice; if (lua_isstring(L,4)) { size_t buffer_len = 0; const char *buffer = luaL_checklstring(L,4,&buffer_len); slice.buffer = (void *)buffer; slice.len = buffer_len; } else { if (!lua_isuserdata(L,4)) { return luaL_error(L, "Need a userdata"); } slice.buffer = lua_touserdata(L,4); slice.len = luaL_checkinteger(L,5); } char * temp = (char *)alloca(size); int ret = pbc_pattern_unpack(pat, &slice, temp); if (ret < 0) { return 0; } lua_checkstack(L, format_sz + 3); int i; char * ptr = temp; bool array = false; for (i=0;i<format_sz;i++) { char type = format[i]; if (type >= 'a' && type <='z') { ptr = (char *)_push_value(L,ptr,type); } else { array = true; int n = pbc_array_size((struct _pbc_array *)ptr); lua_createtable(L,n,0); int j; for (j=0;j<n;j++) { _push_array(L,(struct _pbc_array *)ptr, type, j); } ptr += sizeof(pbc_array); } } if (array) { pbc_pattern_close_arrays(pat, temp); } return format_sz; }
static int register_internal(struct pbc_env * p, void *buffer, int size) { struct pbc_pattern * FIELD_T = _pbcP_new(8); F(0,name,string); F(1,id,int32); F(2,label,int32); F(3,type,int32); F(4,type_name,string); F(5,default_integer,int32); F(6,default_string,string); F(7,default_real,double); struct pbc_pattern * FILE_T = _pbcP_new(10); D(0,name,string); D(1,dependency,string_array); D(2,message_name,string_array); D(3,message_size,int32_array); D(4,message_field,message_array); D(5,enum_name,string_array); D(6,enum_size,int32_array); D(7,enum_string,string_array); D(8,enum_id,int32_array); int ret = 0; struct file_t file; int r = pbc_pattern_unpack(FILE_T, buffer, size, &file); if (r != 0) { ret = 1; goto _return; } _pbcM_sp_insert(p->files , file.name->s.str, NULL); pbc_array queue; _pbcA_open(queue); set_enums(p, &file); set_msgs(FIELD_T, p, &file, queue); _pbcB_register_fields(p, queue); _pbcA_close(queue); pbc_pattern_close_arrays(FILE_T, &file); _return: free(FIELD_T); free(FILE_T); return ret; }
/* lightuserdata pattern string format "ixrsmb" integer size lightuserdata buffer integer buffer_len */ static int _pattern_unpack(lua_State *L) { struct pbc_pattern * pat = lua_touserdata(L, 1); size_t format_sz = 0; const char * format = lua_tolstring(L,2,&format_sz); int size = lua_tointeger(L,3); struct pbc_slice slice; if (lua_isstring(L,4)) { size_t buffer_len = 0; const char *buffer = lua_tolstring(L,4,&buffer_len); slice.buffer = (void *)buffer; slice.len = buffer_len; } else { slice.buffer = lua_touserdata(L,4); slice.len = lua_tointeger(L,5); } char temp[size]; int ret = pbc_pattern_unpack(pat, &slice, temp); if (ret < 0) return 0; lua_checkstack(L, format_sz + 3); int i; char * ptr = temp; bool array = false; for (i=0;i<format_sz;i++) { char type = format[i]; if (type >= 'a' && type <='z') { ptr = _push_value(L,ptr,type); } else { array = true; int n = pbc_array_size((void *)ptr); lua_createtable(L,n,0); int j; for (j=0;j<n;j++) { _push_array(L,(void *)ptr, type, j); } } } if (array) { pbc_pattern_close_arrays(pat, temp); } return format_sz; }
/* lightuserdata pattern string format "ixrsmbp" integer size */ static int _pattern_pack(lua_State *L) { struct pbc_pattern * pat = (struct pbc_pattern *)checkuserdata(L,1); if (pat == NULL) { return luaL_error(L, "pack pattern is NULL"); } size_t format_sz = 0; const char * format = lua_tolstring(L,2,&format_sz); int size = lua_tointeger(L,3); char * data = (char *)alloca(size); // A trick , we don't need default value. zero buffer for array and message field. // pbc_pattern_set_default(pat, data); memset(data, 0 , size); char * ptr = data; int i; for (i=0;i<format_sz;i++) { if (format[i] >= 'a' && format[i] <='z') { ptr = _get_value(L, 4+i, ptr, format[i]); } else { if (!lua_istable(L,4+i)) { luaL_error(L,"need table for array type"); } int j; int n = lua_rawlen(L,4+i); for (j=0;j<n;j++) { lua_rawgeti(L,4+i,j+1); _get_array_value(L,(struct _pbc_array *)ptr,format[i]); lua_pop(L,1); } ptr += sizeof(pbc_array); } } luaL_Buffer b; luaL_buffinit(L, &b); int cap = 128; for (;;) { char * temp = (char *)luaL_prepbuffsize(&b , cap); struct pbc_slice slice; slice.buffer = temp; slice.len = cap; int ret = pbc_pattern_pack(pat, data, &slice); if (ret < 0) { cap = cap * 2; continue; } luaL_addsize(&b , slice.len); break; } luaL_pushresult(&b); pbc_pattern_close_arrays(pat, data); return 1; }
static int test_pattern_pack(struct pbc_env *env , struct pbc_slice *slice) { struct person p; /* If you don't care about default values (you will set all values by yourself) , you can also use memset(&p, 0 , sizeof(p)) instead of pbc_pattern_set_default. */ pbc_pattern_set_default(pat, &p); p.name.buffer = (void*)"Alice"; p.name.len = -1; // encode '\0' p.id = 1234; p.email.buffer = (void*)"alice@unknown"; p.email.len = -1; struct person_phone phone; phone.number.buffer = (void *)"1234567"; phone.number.len = -1; phone.type = 1; char temp[128]; struct pbc_slice phone_slice = { temp, sizeof(temp) }; int unused = pbc_pattern_pack(pat_phone, &phone , &phone_slice); if (unused < 0) { slice->len = 0; return slice->len; } pbc_array_push_slice(p.phone, &phone_slice); pbc_pattern_set_default(pat_phone, &phone); phone.number.buffer = (void *)"87654321"; phone.number.len = -1; char temp2[128]; struct pbc_slice phone_slice2 = { temp2, sizeof(temp2) }; unused = pbc_pattern_pack(pat_phone, &phone , &phone_slice2); if (unused < 0) { slice->len = 0; return slice->len; } pbc_array_push_slice(p.phone, &phone_slice2); int i; for (i=0;i<3;i++) { pbc_array_push_integer(p.test, -i*4,0); } int r = pbc_pattern_pack(pat, &p, slice); pbc_pattern_close_arrays(pat,&p); printf("pack into %d bytes\n", slice->len); return r; }