#include "pbc.h" #include "alloc.h" #include "map.h" #include "context.h" #include "proto.h" #include "pattern.h" #include "varint.h" #include #include 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;iinteger.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;inumber;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; } }