/* 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; }
/* 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; }