pbc4hs-0.1.0.0: cbits/rmessage.c
#include "pbc.h"
#include "alloc.h"
#include "map.h"
#include "context.h"
#include "proto.h"
#include "pattern.h"
#include "varint.h"
#include <stddef.h>
#include <string.h>
struct pbc_rmessage {
struct _message * msg;
struct map_sp * index; // key -> struct value *
struct heap * heap;
};
union _var {
pbc_var var;
pbc_array array;
struct pbc_rmessage message;
} ;
struct value {
struct _field * type;
union _var v;
};
int
pbc_rmessage_next(struct pbc_rmessage *m, const char **key) {
struct value * v = (struct value *)_pbcM_sp_next(m->index, key);
if (*key == NULL) {
return 0;
}
return _pbcP_type(v->type, NULL);
}
#define SIZE_VAR (offsetof(struct value, v) + sizeof(pbc_var))
#define SIZE_ARRAY (offsetof(struct value, v) + sizeof(pbc_array))
#define SIZE_MESSAGE (offsetof(struct value, v) + sizeof(struct pbc_rmessage))
static struct value *
read_string(struct heap *h, struct atom *a,struct _field *f, uint8_t *buffer) {
const char * temp = (const char *) (buffer + a->v.s.start);
int len = a->v.s.end - a->v.s.start;
if (len > 0 && temp[len-1] == '\0') {
struct value * v = (struct value *)_pbcH_alloc(h, SIZE_VAR);
v->v.var->s.str = temp;
v->v.var->s.len = len;
return v;
} else {
struct value * v = (struct value *)_pbcH_alloc(h, SIZE_VAR + len + 1);
memcpy(((char *)v) + SIZE_VAR , temp, len);
*(((char *)v) + SIZE_VAR + len) = '\0';
v->v.var->s.str = ((char *)v) + SIZE_VAR;
v->v.var->s.len = len;
return v;
}
}
static void
read_string_var(struct heap *h, pbc_var var,struct atom *a,struct _field *f,uint8_t *buffer) {
const char * temp = (const char *) (buffer + a->v.s.start);
int len = a->v.s.end - a->v.s.start;
if (len == 0) {
var->s.str = "";
var->s.len = 0;
}
else if (temp[len-1] == '\0') {
var->s.str = temp;
var->s.len = len;
} else {
char * temp2 = (char *)_pbcH_alloc(h, len + 1);
memcpy(temp2, temp, len);
temp2[len]='\0';
var->s.str = temp2;
var->s.len = -len;
}
}
static void _pbc_rmessage_new(struct pbc_rmessage * ret , struct _message * type , void *buffer, int size, struct heap *h);
static struct value *
read_value(struct heap *h, struct _field *f, struct atom * a, uint8_t *buffer) {
struct value * v;
switch (f->type) {
case PTYPE_DOUBLE:
CHECK_BIT64(a,NULL);
v = (struct value *)_pbcH_alloc(h, SIZE_VAR);
v->v.var->real = read_double(a);
break;
case PTYPE_FLOAT:
CHECK_BIT32(a,NULL);
v = (struct value *)_pbcH_alloc(h, SIZE_VAR);
v->v.var->real = (double) read_float(a);
break;
case PTYPE_ENUM:
CHECK_VARINT(a,NULL);
v = (struct value *)_pbcH_alloc(h, SIZE_VAR);
v->v.var->e.id = a->v.i.low;
v->v.var->e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , a->v.i.low);
break;
case PTYPE_INT64:
case PTYPE_UINT64:
case PTYPE_INT32:
case PTYPE_UINT32:
case PTYPE_BOOL:
CHECK_VARINT(a,NULL);
v = (struct value *)_pbcH_alloc(h, SIZE_VAR);
v->v.var->integer = a->v.i;
break;
case PTYPE_FIXED32:
case PTYPE_SFIXED32:
CHECK_BIT32(a,NULL);
v = (struct value *)_pbcH_alloc(h, SIZE_VAR);
v->v.var->integer = a->v.i;
break;
case PTYPE_FIXED64:
case PTYPE_SFIXED64:
CHECK_BIT64(a,NULL);
v = (struct value *)_pbcH_alloc(h, SIZE_VAR);
v->v.var->integer = a->v.i;
break;
case PTYPE_SINT32:
CHECK_VARINT(a,NULL);
v = (struct value *)_pbcH_alloc(h, SIZE_VAR);
v->v.var->integer = a->v.i;
_pbcV_dezigzag32(&(v->v.var->integer));
break;
case PTYPE_SINT64:
CHECK_VARINT(a,NULL);
v = (struct value *)_pbcH_alloc(h, SIZE_VAR);
v->v.var->integer = a->v.i;
_pbcV_dezigzag64(&(v->v.var->integer));
break;
case PTYPE_STRING:
CHECK_LEND(a,NULL);
v = read_string(h,a,f,buffer);
break;
case PTYPE_BYTES:
CHECK_LEND(a,NULL);
v = (struct value *)_pbcH_alloc(h, SIZE_VAR);
v->v.var->s.str = (const char *)(buffer + a->v.s.start);
v->v.var->s.len = a->v.s.end - a->v.s.start;
break;
case PTYPE_MESSAGE:
CHECK_LEND(a,NULL);
v = (struct value *)_pbcH_alloc(h, SIZE_MESSAGE);
_pbc_rmessage_new(&(v->v.message), f->type_name.m ,
buffer + a->v.s.start ,
a->v.s.end - a->v.s.start,h);
break;
default:
return NULL;
}
v->type = f;
return v;
}
static void
push_value_packed(struct _message * type, pbc_array array, struct _field *f, struct atom * aa, uint8_t *buffer) {
int n = _pbcP_unpack_packed((uint8_t *)buffer + aa->v.s.start, aa->v.s.end - aa->v.s.start,
f->type , array);
if (n<=0) {
// todo : error
type->env->lasterror = "Unpack packed field error";
return;
}
if (f->type == PTYPE_ENUM) {
int i;
for (i=0;i<n;i++) {
union _pbc_var * v = (union _pbc_var *)_pbcA_index_p(array, i);
int id = v->integer.low;
v->e.id = id;
v->e.name = (const char*)_pbcM_ip_query(f->type_name.e->id , id);
}
}
}
static void
push_value_array(struct heap *h, pbc_array array, struct _field *f, struct atom * a, uint8_t *buffer) {
pbc_var v;
switch (f->type) {
case PTYPE_DOUBLE:
v->real = read_double(a);
break;
case PTYPE_FLOAT:
v->real = (double) read_float(a);
break;
case PTYPE_ENUM:
v->e.id = a->v.i.low;
v->e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , a->v.i.low);
break;
case PTYPE_INT64:
case PTYPE_UINT64:
case PTYPE_INT32:
case PTYPE_UINT32:
case PTYPE_FIXED32:
case PTYPE_FIXED64:
case PTYPE_SFIXED32:
case PTYPE_SFIXED64:
case PTYPE_BOOL:
v->integer = a->v.i;
break;
case PTYPE_SINT32:
v->integer = a->v.i;
_pbcV_dezigzag32(&(v->integer));
break;
case PTYPE_SINT64:
v->integer = a->v.i;
_pbcV_dezigzag64(&(v->integer));
break;
case PTYPE_STRING:
CHECK_LEND(a, );
read_string_var(h,v,a,f,buffer);
break;
case PTYPE_BYTES:
CHECK_LEND(a, );
v->s.str = (const char *)(buffer + a->v.s.start);
v->s.len = a->v.s.end - a->v.s.start;
break;
case PTYPE_MESSAGE: {
CHECK_LEND(a, );
struct pbc_rmessage message;
_pbc_rmessage_new(&message, f->type_name.m ,
buffer + a->v.s.start ,
a->v.s.end - a->v.s.start,h);
if (message.msg == NULL) {
return;
}
v->p[0] = message.msg;
v->p[1] = message.index;
break;
}
default:
return;
}
_pbcA_push(array,v);
}
static void
_pbc_rmessage_new(struct pbc_rmessage * ret , struct _message * type , void *buffer, int size , struct heap *h) {
if (size == 0) {
ret->msg = type;
ret->index = _pbcM_sp_new(0 , h);
ret->heap = h;
return;
}
pbc_ctx _ctx;
int count = _pbcC_open(_ctx,buffer,size);
if (count <= 0) {
type->env->lasterror = "rmessage decode context error";
memset(ret , 0, sizeof(*ret));
return;
}
struct context * ctx = (struct context *)_ctx;
ret->msg = type;
ret->index = _pbcM_sp_new(count, h);
ret->heap = h;
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(type->id , id);
if (f) {
if (f->label == LABEL_REPEATED || f->label == LABEL_PACKED) {
struct value * v;
void ** vv = _pbcM_sp_query_insert(ret->index, f->name);
if (*vv == NULL) {
v = (struct value *)_pbcH_alloc(h, SIZE_ARRAY);
v->type = f;
_pbcA_open_heap(v->v.array,ret->heap);
*vv = v;
} else {
v= (struct value *)*vv;
}
if (f->label == LABEL_PACKED) {
push_value_packed(type, v->v.array , f , &(ctx->a[i]), (uint8_t *)buffer);
if (pbc_array_size(v->v.array) == 0) {
type->env->lasterror = "rmessage decode packed data error";
*vv = NULL;
}
} else {
push_value_array(h,v->v.array , f, &(ctx->a[i]), (uint8_t *)buffer);
if (pbc_array_size(v->v.array) == 0) {
type->env->lasterror = "rmessage decode repeated data error";
*vv = NULL;
}
}
} else {
struct value * v = read_value(h, f, &(ctx->a[i]), (uint8_t *)buffer);
if (v) {
_pbcM_sp_insert(ret->index, f->name, v);
} else {
type->env->lasterror = "rmessage decode data error";
}
}
}
}
_pbcC_close(_ctx);
}
struct pbc_rmessage *
pbc_rmessage_new(struct pbc_env * env, const char * type_name , struct pbc_slice * slice) {
struct _message * msg = _pbcP_get_message(env, type_name);
if (msg == NULL) {
env->lasterror = "Proto not found";
return NULL;
}
struct pbc_rmessage temp;
struct heap * h = _pbcH_new(slice->len);
_pbc_rmessage_new(&temp, msg , slice->buffer, slice->len , h);
if (temp.msg == NULL) {
_pbcH_delete(h);
return NULL;
}
struct pbc_rmessage *m = (struct pbc_rmessage *)_pbcH_alloc(temp.heap, sizeof(*m));
*m = temp;
return m;
}
void
pbc_rmessage_delete(struct pbc_rmessage * m) {
if (m) {
_pbcH_delete(m->heap);
}
}
const char *
pbc_rmessage_string(struct pbc_rmessage * m , const char *key , int index, int *sz) {
struct value * v = (struct value *)_pbcM_sp_query(m->index,key);
int type = 0;
pbc_var var;
if (v == NULL) {
type = _pbcP_message_default(m->msg, key, var);
} else {
if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) {
_pbcA_index(v->v.array, index, var);
} else {
var[0] = v->v.var[0];
}
type = v->type->type;
}
if (type == PTYPE_ENUM) {
if (sz) {
*sz = strlen(var->e.name);
}
return var->e.name;
}
if (sz) {
int len = var->s.len;
if (len<0) {
len = - len;
}
*sz = len;
}
return var->s.str;
}
uint32_t
pbc_rmessage_integer(struct pbc_rmessage *m , const char *key , int index, uint32_t *hi) {
struct value * v = (struct value *)_pbcM_sp_query(m->index,key);
pbc_var var;
int type = 0;
if (v == NULL) {
type = _pbcP_message_default(m->msg, key, var);
} else {
if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) {
_pbcA_index(v->v.array, index, var);
} else {
var[0] = v->v.var[0];
}
type = v->type->type;
}
if (type == PTYPE_ENUM) {
if (hi) {
*hi = 0;
}
return var->e.id;
}
if (hi) {
*hi = var->integer.hi;
}
return var->integer.low;
}
double
pbc_rmessage_real(struct pbc_rmessage * m, const char *key , int index) {
struct value * v = (struct value *)_pbcM_sp_query(m->index,key);
pbc_var var;
if (v == NULL) {
_pbcP_message_default(m->msg, key, var);
} else {
if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) {
_pbcA_index(v->v.array, index, var);
} else {
return v->v.var->real;
}
}
return var->real;
}
struct pbc_rmessage *
pbc_rmessage_message(struct pbc_rmessage * rm, const char *key, int index) {
struct value * v = (struct value *)_pbcM_sp_query(rm->index,key);
if (v == NULL) {
struct _field * f = (struct _field *)_pbcM_sp_query(rm->msg->name, key);
if (f == NULL) {
rm->msg->env->lasterror = "Invalid key for sub-message";
// invalid key
return NULL;
}
struct _message * m = f->type_name.m;
if (m->def == NULL) {
// m->def will be free at the end (pbc_delete).
m->def = (struct pbc_rmessage *)malloc(sizeof(struct pbc_rmessage));
m->def->msg = m;
m->def->index = NULL;
}
return m->def;
} else {
if (v->type->label == LABEL_REPEATED) {
return (struct pbc_rmessage *)_pbcA_index_p(v->v.array,index);
} else {
return &(v->v.message);
}
}
}
int
pbc_rmessage_size(struct pbc_rmessage *m, const char *key) {
struct value * v = (struct value *)_pbcM_sp_query(m->index,key);
if (v == NULL) {
return 0;
}
if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) {
return pbc_array_size(v->v.array);
} else {
return 1;
}
}