update sproto. support encode empty table

This commit is contained in:
Cloud Wu
2016-04-07 10:12:30 +08:00
parent dd7e962c94
commit 69b5bd8c13
4 changed files with 78 additions and 42 deletions

View File

@@ -210,13 +210,13 @@ Each integer number must be serialized in little-endian format.
The sproto message must be a user defined type struct, and a struct is encoded in three parts. The header, the field part, and the data part.
The tag and small integer or boolean will be encoded in field part, and others are in data part.
All the fields must be encoded in ascending order (by tag). The tags of fields can be discontinuous, if a field is nil. (default value in lua), don't encode it in message.
All the fields must be encoded in ascending order (by tag, base 0). The tags of fields can be discontinuous, if a field is nil. (default value in lua), don't encode it in message.
The header is a 16bit integer. It is the number of fields.
Each field in field part is a 16bit integer (n). If n is zero, that means the field data is encoded in data part ;
If n is even (and not zero), the value of this field is n/2-1 ;
If n is even (and not zero), the value of this field is n/2-1 , and the tag increases 1;
If n is odd, that means the tags is not continuous, and we should add current tag by (n+1)/2 .

View File

@@ -126,7 +126,7 @@ encode(const struct sproto_arg *args) {
lua_replace(L, self->array_index);
}
self->array_index = 0;
return 0;
return SPROTO_CB_NOARRAY;
}
if (!lua_istable(L, -1)) {
return luaL_error(L, ".*%s(%d) should be a table (Is a %s)",
@@ -147,7 +147,7 @@ encode(const struct sproto_arg *args) {
// iterate end
lua_pushnil(L);
lua_replace(L, self->iter_index);
return 0;
return SPROTO_CB_NIL;
}
lua_insert(L, -2);
lua_replace(L, self->iter_index);
@@ -159,7 +159,7 @@ encode(const struct sproto_arg *args) {
}
if (lua_isnil(L, -1)) {
lua_pop(L,1);
return 0;
return SPROTO_CB_NIL;
}
switch (args->type) {
case SPROTO_TINTEGER: {
@@ -203,10 +203,10 @@ encode(const struct sproto_arg *args) {
str = lua_tolstring(L, -1, &sz);
}
if (sz > args->length)
return -1;
return SPROTO_CB_ERROR;
memcpy(args->value, str, sz);
lua_pop(L,1);
return sz + 1; // The length of empty string is 1.
return sz;
}
case SPROTO_TSTRUCT: {
struct encode_ud sub;
@@ -226,6 +226,8 @@ encode(const struct sproto_arg *args) {
sub.iter_index = sub.tbl_index + 1;
r = sproto_encode(args->subtype, args->value, args->length, encode, &sub);
lua_settop(L, top-1); // pop the value
if (r < 0)
return SPROTO_CB_ERROR;
return r;
}
default:
@@ -309,7 +311,7 @@ decode(const struct sproto_arg *args) {
lua_State *L = self->L;
if (self->deep >= ENCODE_DEEPLEVEL)
return luaL_error(L, "The table is too deep");
if (args->index > 0) {
if (args->index != 0) {
// It's array
if (args->tagname != self->array_tag) {
self->array_tag = args->tagname;
@@ -321,6 +323,10 @@ decode(const struct sproto_arg *args) {
} else {
self->array_index = lua_gettop(L);
}
if (args->index < 0) {
// It's a empty array, return now.
return 0;
}
}
}
switch (args->type) {
@@ -355,9 +361,10 @@ decode(const struct sproto_arg *args) {
sub.key_index = lua_gettop(L);
r = sproto_decode(args->subtype, args->value, args->length, decode, &sub);
if (r < 0 || r != args->length)
if (r < 0)
return SPROTO_CB_ERROR;
if (r != args->length)
return r;
// assert(args->index > 0);
lua_pushvalue(L, sub.key_index);
if (lua_isnil(L, -1)) {
luaL_error(L, "Can't find main index (tag=%d) in [%s]", args->mainindex, args->tagname);
@@ -370,7 +377,9 @@ decode(const struct sproto_arg *args) {
sub.mainindex_tag = -1;
sub.key_index = 0;
r = sproto_decode(args->subtype, args->value, args->length, decode, &sub);
if (r < 0 || r != args->length)
if (r < 0)
return SPROTO_CB_ERROR;
if (r != args->length)
return r;
lua_settop(L, sub.result_index);
break;

View File

@@ -677,10 +677,10 @@ encode_object(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int si
args->value = data+SIZEOF_LENGTH;
args->length = size-SIZEOF_LENGTH;
sz = cb(args);
if (sz <= 0)
return sz;
if (args->type == SPROTO_TSTRING) {
--sz; // the length of null string is 1
if (sz < 0) {
if (sz == SPROTO_CB_NIL)
return 0;
return -1; // sz == SPROTO_CB_ERROR
}
assert(sz <= size-SIZEOF_LENGTH); // verify buffer overflow
return fill_size(data, sz);
@@ -702,7 +702,7 @@ uint32_to_uint64(int negative, uint8_t *buffer) {
}
static uint8_t *
encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffer, int size) {
encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffer, int size, int *noarray) {
uint8_t * header = buffer;
int intlen;
int index;
@@ -712,6 +712,8 @@ encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffe
size--;
intlen = sizeof(uint32_t);
index = 1;
*noarray = 0;
for (;;) {
int sz;
union {
@@ -722,10 +724,15 @@ encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffe
args->length = sizeof(u);
args->index = index;
sz = cb(args);
if (sz < 0)
return NULL;
if (sz == 0) // nil object, end of array
break;
if (sz <= 0) {
if (sz == SPROTO_CB_NIL) // nil object, end of array
break;
if (sz == SPROTO_CB_NOARRAY) { // no array, don't encode it
*noarray = 1;
break;
}
return NULL; // sz == SPROTO_CB_ERROR
}
if (size < sizeof(uint64_t))
return NULL;
if (sz == sizeof(uint32_t)) {
@@ -790,11 +797,17 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
size -= SIZEOF_LENGTH;
buffer = data + SIZEOF_LENGTH;
switch (args->type) {
case SPROTO_TINTEGER:
buffer = encode_integer_array(cb,args,buffer,size);
case SPROTO_TINTEGER: {
int noarray;
buffer = encode_integer_array(cb,args,buffer,size, &noarray);
if (buffer == NULL)
return -1;
if (noarray) {
return 0;
}
break;
}
case SPROTO_TBOOLEAN:
args->index = 1;
for (;;) {
@@ -802,10 +815,13 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
args->value = &v;
args->length = sizeof(v);
sz = cb(args);
if (sz < 0)
return -1;
if (sz == 0) // nil object , end of array
break;
if (sz < 0) {
if (sz == SPROTO_CB_NIL) // nil object , end of array
break;
if (sz == SPROTO_CB_NOARRAY) // no array, don't encode it
return 0;
return -1; // sz == SPROTO_CB_ERROR
}
if (size < 1)
return -1;
buffer[0] = v ? 1: 0;
@@ -823,12 +839,13 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
args->value = buffer+SIZEOF_LENGTH;
args->length = size;
sz = cb(args);
if (sz == 0)
break;
if (sz < 0)
return -1;
if (args->type == SPROTO_TSTRING) {
--sz;
if (sz < 0) {
if (sz == SPROTO_CB_NIL) {
break;
}
if (sz == SPROTO_CB_NOARRAY) // no array, don't encode it
return 0;
return -1; // sz == SPROTO_CB_ERROR
}
fill_size(buffer, sz);
buffer += SIZEOF_LENGTH+sz;
@@ -838,8 +855,6 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
break;
}
sz = buffer - (data + SIZEOF_LENGTH);
if (sz == 0) // empty array
return 0;
return fill_size(data, sz);
}
@@ -885,10 +900,13 @@ sproto_encode(const struct sproto_type *st, void * buffer, int size, sproto_call
args.value = &u;
args.length = sizeof(u);
sz = cb(&args);
if (sz < 0)
return -1;
if (sz == 0) // nil object
continue;
if (sz < 0) {
if (sz == SPROTO_CB_NIL)
continue;
if (sz == SPROTO_CB_NOARRAY) // no array, don't encode it
return 0;
return -1; // sz == SPROTO_CB_ERROR
}
if (sz == sizeof(uint32_t)) {
if (u.u32 < 0x7fff) {
value = (u.u32+1) * 2;
@@ -985,13 +1003,18 @@ decode_array(sproto_callback cb, struct sproto_arg *args, uint8_t * stream) {
uint32_t sz = todword(stream);
int type = args->type;
int i;
if (sz == 0) {
// It's empty array, call cb with index == -1 to create the empty array.
args->index = -1;
args->value = NULL;
args->length = 0;
cb(args);
return 0;
}
stream += SIZEOF_LENGTH;
switch (type) {
case SPROTO_TINTEGER: {
int len;
if (sz < 1)
return -1;
len = *stream;
int len = *stream;
++stream;
--sz;
if (len == sizeof(uint32_t)) {

View File

@@ -14,6 +14,10 @@ struct sproto_type;
#define SPROTO_TSTRING 2
#define SPROTO_TSTRUCT 3
#define SPROTO_CB_ERROR -1
#define SPROTO_CB_NIL -2
#define SPROTO_CB_NOARRAY -3
struct sproto * sproto_create(const void * proto, size_t sz);
void sproto_release(struct sproto *);