pbc4hs-0.1.0.0: cbits/decode.c
#include "pbc.h"
#include "alloc.h"
#include "context.h"
#include "proto.h"
#include "varint.h"
#include <assert.h>
static const char * TYPENAME[] = {
"invalid", // 0
"integer", // 1
"real", // 2
"boolean", // 3
"enum", // 4
"string", // 5
"message", // 6
"fixed64", // 7
"fixed32", // 8
"bytes", // 9
"int64", // 10
"uint", // 11
};
static int
call_unknown(pbc_decoder f, void * ud, int id, struct atom *a, uint8_t * start) {
union pbc_value v;
switch (a->wire_id & 7) {
case WT_VARINT:
v.i.low = a->v.i.low;
v.i.hi = a->v.i.hi;
f(ud, PBC_INT, TYPENAME[PBC_INT], &v, id , NULL);
break;
case WT_BIT64:
v.i.low = a->v.i.low;
v.i.hi = a->v.i.hi;
f(ud, PBC_FIXED64, TYPENAME[PBC_FIXED64], &v, id , NULL);
break;
case WT_LEND:
v.s.buffer = (char*)start + a->v.s.start;
v.s.len = a->v.s.end - a->v.s.start;
f(ud, PBC_BYTES, TYPENAME[PBC_BYTES], &v, id , NULL);
break;
case WT_BIT32:
v.i.low = a->v.i.low;
v.i.hi = 0;
f(ud, PBC_FIXED32, TYPENAME[PBC_FIXED32], &v, id , NULL);
break;
default:
return 1;
}
return 0;
}
static int
call_type(pbc_decoder pd, void * ud, struct _field *f, struct atom *a, uint8_t * start) {
union pbc_value v;
const char * type_name = NULL;
int type = _pbcP_type(f, &type_name);
assert(type != 0);
if (type_name == NULL) {
type_name = TYPENAME[type & ~PBC_REPEATED];
}
switch (f->type) {
case PTYPE_DOUBLE:
CHECK_BIT64(a, -1);
v.f = read_double(a);
break;
case PTYPE_FLOAT:
CHECK_BIT32(a, -1);
v.f = (double) read_float(a);
break;
case PTYPE_ENUM:
CHECK_VARINT(a, -1);
v.e.id = a->v.i.low;
v.e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , v.e.id);
break;
case PTYPE_INT64:
case PTYPE_UINT64:
CHECK_VARINT(a, -1);
v.i.low = a->v.i.low;
v.i.hi = a->v.i.hi;
break;
case PTYPE_FIXED64:
case PTYPE_SFIXED64:
CHECK_BIT64(a, -1);
v.i.low = a->v.i.low;
v.i.hi = a->v.i.hi;
break;
case PTYPE_INT32:
case PTYPE_UINT32:
case PTYPE_BOOL:
CHECK_VARINT(a, -1);
v.i.low = a->v.i.low;
v.i.hi = 0;
break;
case PTYPE_FIXED32:
case PTYPE_SFIXED32:
CHECK_BIT32(a, -1);
v.i.low = a->v.i.low;
v.i.hi = 0;
break;
case PTYPE_SINT32:
CHECK_VARINT(a, -1);
v.i.low = a->v.i.low;
v.i.hi = a->v.i.hi;
_pbcV_dezigzag32((struct longlong *)&(v.i));
break;
case PTYPE_SINT64:
CHECK_VARINT(a, -1);
v.i.low = a->v.i.low;
v.i.hi = a->v.i.hi;
_pbcV_dezigzag64((struct longlong *)&(v.i));
break;
case PTYPE_STRING:
case PTYPE_BYTES:
case PTYPE_MESSAGE:
CHECK_LEND(a, -1);
v.s.buffer = start + a->v.s.start;
v.s.len = a->v.s.end - a->v.s.start;
break;
default:
assert(0);
break;
}
pd(ud, type, type_name, &v, f->id, f->name);
return 0;
}
static int
call_array(pbc_decoder pd, void * ud, struct _field *f, uint8_t * buffer , int size) {
union pbc_value v;
const char * type_name = NULL;
int type = _pbcP_type(f, &type_name);
assert(type != 0);
if (type_name == NULL) {
type_name = TYPENAME[type & ~PBC_REPEATED];
}
v.i.hi = 0;
int i;
switch(f->type) {
case PTYPE_DOUBLE:
if (size % 8 != 0) {
return -1;
}
for (i=0;i<size;i+=8) {
union {
double d;
uint64_t i64;
} u;
u.i64 = (uint64_t)buffer[i] |
(uint64_t)buffer[i+1] << 8 |
(uint64_t)buffer[i+2] << 16 |
(uint64_t)buffer[i+3] << 24 |
(uint64_t)buffer[i+4] << 32 |
(uint64_t)buffer[i+5] << 40 |
(uint64_t)buffer[i+6] << 48 |
(uint64_t)buffer[i+7] << 56;
v.f = u.d;
pd(ud, type , type_name, &v, f->id, f->name);
}
return size/8;
case PTYPE_FLOAT:
if (size % 4 != 0)
return -1;
for (i=0;i<size;i+=4) {
union {
float f;
uint32_t i32;
} u;
u.i32 = (uint32_t)buffer[i] |
(uint32_t)buffer[i+1] << 8 |
(uint32_t)buffer[i+2] << 16 |
(uint32_t)buffer[i+3] << 24;
v.f = (double)u.f;
pd(ud, type , type_name, &v, f->id, f->name);
}
return size/4;
case PTYPE_FIXED32:
case PTYPE_SFIXED32:
if (size % 4 != 0)
return -1;
for (i=0;i<size;i+=4) {
v.i.low = (uint32_t)buffer[i] |
(uint32_t)buffer[i+1] << 8 |
(uint32_t)buffer[i+2] << 16 |
(uint32_t)buffer[i+3] << 24;
pd(ud, type , type_name, &v, f->id, f->name);
}
return size/4;
case PTYPE_FIXED64:
case PTYPE_SFIXED64:
if (size % 8 != 0)
return -1;
for (i=0;i<size;i+=8) {
v.i.low = (uint32_t)buffer[i] |
(uint32_t)buffer[i+1] << 8 |
(uint32_t)buffer[i+2] << 16 |
(uint32_t)buffer[i+3] << 24;
v.i.hi = (uint32_t)buffer[i+4] |
(uint32_t)buffer[i+5] << 8 |
(uint32_t)buffer[i+6] << 16 |
(uint32_t)buffer[i+7] << 24;
pd(ud, type , type_name, &v, f->id, f->name);
}
return size/8;
case PTYPE_INT64:
case PTYPE_UINT64:
case PTYPE_INT32:
case PTYPE_UINT32:
case PTYPE_BOOL: {
int n = 0;
while (size > 0) {
int len;
if (size >= 10) {
len = _pbcV_decode(buffer, (struct longlong *)&(v.i));
} else {
uint8_t temp[10];
memcpy(temp, buffer, size);
len = _pbcV_decode(buffer, (struct longlong *)&(v.i));
if (len > size)
return -1;
}
pd(ud, type , type_name, &v, f->id, f->name);
buffer += len;
size -= len;
++n;
}
return n;
}
case PTYPE_ENUM: {
int n = 0;
while (size > 0) {
int len;
if (size >= 10) {
len = _pbcV_decode(buffer, (struct longlong *)&(v.i));
} else {
uint8_t temp[10];
memcpy(temp, buffer, size);
len = _pbcV_decode(buffer, (struct longlong *)&(v.i));
if (len > size)
return -1;
}
v.e.id = v.i.low;
v.e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , v.i.low);
pd(ud, type , type_name, &v, f->id, f->name);
buffer += len;
size -= len;
++n;
}
return n;
}
case PTYPE_SINT32: {
int n = 0;
while (size > 0) {
int len;
if (size >= 10) {
len = _pbcV_decode(buffer, (struct longlong *)&(v.i));
_pbcV_dezigzag32((struct longlong *)&(v.i));
} else {
uint8_t temp[10];
memcpy(temp, buffer, size);
len = _pbcV_decode(buffer, (struct longlong *)&(v.i));
if (len > size)
return -1;
_pbcV_dezigzag32((struct longlong *)&(v.i));
}
pd(ud, type , type_name, &v, f->id, f->name);
buffer += len;
size -= len;
++n;
}
return n;
}
case PTYPE_SINT64: {
int n = 0;
while (size > 0) {
int len;
if (size >= 10) {
len = _pbcV_decode(buffer, (struct longlong *)&(v.i));
_pbcV_dezigzag64((struct longlong *)&(v.i));
} else {
uint8_t temp[10];
memcpy(temp, buffer, size);
len = _pbcV_decode(buffer, (struct longlong *)&(v.i));
if (len > size)
return -1;
_pbcV_dezigzag64((struct longlong *)&(v.i));
}
pd(ud, type , type_name, &v, f->id, f->name);
buffer += len;
size -= len;
++n;
}
return n;
}
default:
return -1;
}
}
int
pbc_decode(struct pbc_env * env, const char * type_name , struct pbc_slice * slice, pbc_decoder pd, void *ud) {
struct _message * msg = _pbcP_get_message(env, type_name);
if (msg == NULL) {
env->lasterror = "Proto not found";
return -1;
}
if (slice->len == 0) {
return 0;
}
pbc_ctx _ctx;
int count = _pbcC_open(_ctx,slice->buffer,slice->len);
if (count <= 0) {
env->lasterror = "decode context error";
_pbcC_close(_ctx);
return count - 1;
}
struct context * ctx = (struct context *)_ctx;
uint8_t * start = (uint8_t *)slice->buffer;
int i;
for (i=0;i<ctx->number;i++) {
int id = ctx->a[i].wire_id >> 3;
struct _field * f = (struct _field *)_pbcM_ip_query(msg->id , id);
if (f==NULL) {
int err = call_unknown(pd,ud,id,&ctx->a[i],start);
if (err) {
_pbcC_close(_ctx);
return -i-1;
}
} else if (f->label == LABEL_PACKED) {
struct atom * a = &ctx->a[i];
int n = call_array(pd, ud, f , start + a->v.s.start , a->v.s.end - a->v.s.start);
if (n < 0) {
_pbcC_close(_ctx);
return -i-1;
}
} else {
if (call_type(pd,ud,f,&ctx->a[i],start) != 0) {
_pbcC_close(_ctx);
return -i-1;
}
}
}
_pbcC_close(_ctx);
return ctx->number;
}