#include "pbc.h" #include "context.h" #include "alloc.h" #include "varint.h" #include "map.h" #include "proto.h" #include #include #include #ifndef _MSC_VER #include #endif #define WMESSAGE_SIZE 64 struct pbc_wmessage { struct _message *type; uint8_t * buffer; uint8_t * ptr; uint8_t * endptr; pbc_array sub; struct map_sp *packed; struct heap * heap; }; struct _packed { int id; int ptype; pbc_array data; }; static struct pbc_wmessage * _wmessage_new(struct heap *h, struct _message *msg) { struct pbc_wmessage * m = (struct pbc_wmessage *)_pbcH_alloc(h, sizeof(*m)); m->type = msg; m->buffer = (uint8_t *)_pbcH_alloc(h, WMESSAGE_SIZE); m->ptr = m->buffer; m->endptr = m->buffer + WMESSAGE_SIZE; _pbcA_open_heap(m->sub, h); m->packed = NULL; m->heap = h; return m; } struct pbc_wmessage * pbc_wmessage_new(struct pbc_env * env, const char *type_name) { struct _message * msg = _pbcP_get_message(env, type_name); if (msg == NULL) return NULL; struct heap *h = _pbcH_new(0); return _wmessage_new(h, msg); } void pbc_wmessage_delete(struct pbc_wmessage *m) { if (m) { _pbcH_delete(m->heap); } } static void _expand_message(struct pbc_wmessage *m, int sz) { if (m->ptr + sz > m->endptr) { int cap = m->endptr - m->buffer; sz = m->ptr + sz - m->buffer; do { cap = cap * 2; } while ( sz > cap ) ; int old_size = m->ptr - m->buffer; uint8_t * buffer = (uint8_t *)_pbcH_alloc(m->heap, cap); memcpy(buffer, m->buffer, old_size); m->ptr = buffer + (m->ptr - m->buffer); m->endptr = buffer + cap; m->buffer = buffer; } } static struct _packed * _get_packed(struct pbc_wmessage *m , struct _field *f , const char *key) { if (m->packed == NULL) { m->packed = _pbcM_sp_new(4, m->heap); } void ** v = _pbcM_sp_query_insert(m->packed , key); if (*v == NULL) { *v = _pbcH_alloc(m->heap, sizeof(struct _packed)); struct _packed *p = (struct _packed *)*v; p->id = f->id; p->ptype = f->type; _pbcA_open_heap(p->data, m->heap); return p; } return (struct _packed *)*v; } static void _packed_integer(struct pbc_wmessage *m, struct _field *f, const char *key , uint32_t low, uint32_t hi) { struct _packed * packed = _get_packed(m,f,key); pbc_var var; var->integer.low = low; var->integer.hi = hi; _pbcA_push(packed->data , var); } static void _packed_real(struct pbc_wmessage *m, struct _field *f, const char *key , double v) { struct _packed * packed = _get_packed(m,f,key); pbc_var var; var->real = v; _pbcA_push(packed->data , var); } static inline void int64_encode(uint32_t low, uint32_t hi , uint8_t * buffer) { buffer[0] = (uint8_t)(low & 0xff); buffer[1] = (uint8_t)(low >> 8 & 0xff); buffer[2] = (uint8_t)(low >> 16 & 0xff); buffer[3] = (uint8_t)(low >> 24 & 0xff); buffer[4] = (uint8_t)(hi & 0xff); buffer[5] = (uint8_t)(hi >> 8 & 0xff); buffer[6] = (uint8_t)(hi >> 16 & 0xff); buffer[7] = (uint8_t)(hi >> 24 & 0xff); } static inline void int32_encode(uint32_t low, uint8_t * buffer) { buffer[0] = (uint8_t)(low & 0xff); buffer[1] = (uint8_t)(low >> 8 & 0xff); buffer[2] = (uint8_t)(low >> 16 & 0xff); buffer[3] = (uint8_t)(low >> 24 & 0xff); } int pbc_wmessage_integer(struct pbc_wmessage *m, const char *key, uint32_t low, uint32_t hi) { struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); if (f==NULL) { // todo : error m->type->env->lasterror = "wmessage_interger query key error"; return -1; } if (f->label == LABEL_PACKED) { _packed_integer(m , f, key , low, hi); return 0; } if (f->label == LABEL_OPTIONAL) { if (f->type == PTYPE_ENUM) { if (low == f->default_v->e.id) return 0; } else { if (low == f->default_v->integer.low && hi == f->default_v->integer.hi) { return 0; } } } int id = f->id << 3; _expand_message(m,20); switch (f->type) { case PTYPE_INT64: case PTYPE_UINT64: case PTYPE_INT32: id |= WT_VARINT; m->ptr += _pbcV_encode32(id, m->ptr); m->ptr += _pbcV_encode((uint64_t)low | (uint64_t)hi << 32 , m->ptr); break; case PTYPE_UINT32: case PTYPE_ENUM: case PTYPE_BOOL: id |= WT_VARINT; m->ptr += _pbcV_encode32(id, m->ptr); m->ptr += _pbcV_encode32(low, m->ptr); break; case PTYPE_FIXED64: case PTYPE_SFIXED64: id |= WT_BIT64; m->ptr += _pbcV_encode32(id, m->ptr); int64_encode(low,hi,m->ptr); m->ptr += 8; break; case PTYPE_FIXED32: case PTYPE_SFIXED32: id |= WT_BIT32; m->ptr += _pbcV_encode32(id, m->ptr); int32_encode(low,m->ptr); m->ptr += 4; break; case PTYPE_SINT32: id |= WT_VARINT; m->ptr += _pbcV_encode32(id, m->ptr); m->ptr += _pbcV_zigzag32(low, m->ptr); break; case PTYPE_SINT64: id |= WT_VARINT; m->ptr += _pbcV_encode32(id, m->ptr); m->ptr += _pbcV_zigzag((uint64_t)low | (uint64_t)hi << 32 , m->ptr); break; } return 0; } int pbc_wmessage_real(struct pbc_wmessage *m, const char *key, double v) { struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); if (f == NULL) { // todo : error m->type->env->lasterror = "wmessage_real query key error"; return -1; } if (f->label == LABEL_PACKED) { _packed_real(m , f, key , v); return 0; } if (f->label == LABEL_OPTIONAL) { if (v == f->default_v->real) return 0; } int id = f->id << 3; _expand_message(m,18); switch (f->type) { case PTYPE_FLOAT: { id |= WT_BIT32; m->ptr += _pbcV_encode32(id, m->ptr); float_encode(v , m->ptr); m->ptr += 4; break; } case PTYPE_DOUBLE: id |= WT_BIT64; m->ptr += _pbcV_encode32(id, m->ptr); double_encode(v , m->ptr); m->ptr += 8; break; } return 0; } int pbc_wmessage_string(struct pbc_wmessage *m, const char *key, const char * v, int len) { struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); if (f == NULL) { // todo : error m->type->env->lasterror = "wmessage_string query key error"; return -1; } bool varlen = false; if (len <=0) { varlen = true; // -1 for add '\0' len = strlen(v) - len; } if (f->label == LABEL_PACKED) { if (f->type == PTYPE_ENUM) { char * temp = (char *)alloca(len + 1); if (!varlen || v[len] != '\0') { memcpy(temp,v,len); temp[len]='\0'; v = temp; } int enum_id = 0; int err = _pbcM_si_query(f->type_name.e->name, v , &enum_id); if (err) { // todo : error , invalid enum m->type->env->lasterror = "wmessage_string packed invalid enum"; free(temp); return -1; } _packed_integer(m , f, key , enum_id , 0); } return 0; } if (f->label == LABEL_OPTIONAL) { if (f->type == PTYPE_ENUM) { if (strncmp(v , f->default_v->e.name, len) == 0 && f->default_v->e.name[len] =='\0') { return 0; } } else if (f->type == PTYPE_STRING) { if (len == f->default_v->s.len && strcmp(v, f->default_v->s.str) == 0) { return 0; } } } int id = f->id << 3; _expand_message(m,20); switch (f->type) { case PTYPE_ENUM : { char * temp = (char *)malloc(len+1); if (!varlen || v[len] != '\0') { memcpy(temp,v,len); temp[len]='\0'; v = temp; } int enum_id = 0; int err = _pbcM_si_query(f->type_name.e->name, v, &enum_id); if (err) { // todo : error , enum invalid m->type->env->lasterror = "wmessage_string invalid enum"; free(temp); return -1; } id |= WT_VARINT; m->ptr += _pbcV_encode32(id, m->ptr); m->ptr += _pbcV_encode32(enum_id, m->ptr); break; } case PTYPE_STRING: case PTYPE_BYTES: id |= WT_LEND; m->ptr += _pbcV_encode32(id, m->ptr); m->ptr += _pbcV_encode32(len, m->ptr); _expand_message(m,len); memcpy(m->ptr , v , len); m->ptr += len; break; } return 0; } struct pbc_wmessage * pbc_wmessage_message(struct pbc_wmessage *m, const char *key) { struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); if (f == NULL) { // todo : error m->type->env->lasterror = "wmessage_message query key error"; return NULL; } pbc_var var; var->p[0] = _wmessage_new(m->heap, f->type_name.m); var->p[1] = f; _pbcA_push(m->sub , var); return (struct pbc_wmessage *)var->p[0]; } static void _pack_packed_64(struct _packed *p,struct pbc_wmessage *m) { int n = pbc_array_size(p->data); int len = n * 8; int i; pbc_var var; _expand_message(m,10 + len); m->ptr += _pbcV_encode32(len, m->ptr); switch (p->ptype) { case PTYPE_DOUBLE: for (i=0;idata, i, var); double_encode(var->real , m->ptr + i * 8); } break; default: for (i=0;idata, i, var); int64_encode(var->integer.low , var->integer.hi, m->ptr + i * 8); } break; } m->ptr += len; } static void _pack_packed_32(struct _packed *p,struct pbc_wmessage *m) { int n = pbc_array_size(p->data); int len = n * 4; int i; pbc_var var; _expand_message(m,10 + len); m->ptr += _pbcV_encode32(len, m->ptr); switch (p->ptype) { case PTYPE_FLOAT: for (i=0;idata, i, var); float_encode(var->real , m->ptr + i * 8); } break; default: for (i=0;idata, i, var); int32_encode(var->integer.low , m->ptr + i * 8); } break; } m->ptr += len; } static void _pack_packed_varint(struct _packed *p,struct pbc_wmessage *m) { int n = pbc_array_size(p->data); int offset = m->ptr - m->buffer; int len = n * 2; if (p->ptype == PTYPE_BOOL) { len = n; } int i; pbc_var var; _expand_message(m,10 + len); int len_len = _pbcV_encode32(len, m->ptr); m->ptr += len_len; switch (p->ptype) { case PTYPE_INT64: case PTYPE_UINT64: for (i=0;idata, i, var); _expand_message(m,10); m->ptr += _pbcV_encode((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , m->ptr); } break; case PTYPE_INT32: case PTYPE_BOOL: case PTYPE_UINT32: case PTYPE_ENUM: for (i=0;idata, i, var); _expand_message(m,10); m->ptr += _pbcV_encode32(var->integer.low , m->ptr); } break; case PTYPE_SINT32: for (i=0;idata, i, var); _expand_message(m,10); m->ptr += _pbcV_zigzag32(var->integer.low, m->ptr); } break; case PTYPE_SINT64: for (i=0;idata, i, var); _expand_message(m,10); m->ptr += _pbcV_zigzag((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , m->ptr); } break; default: // error memset(m->ptr , 0 , n); m->ptr += n; m->type->env->lasterror = "wmessage type error when pack packed"; break; } int end_offset = m->ptr - m->buffer; int end_len = end_offset - (offset + len_len); if (end_len != len) { uint8_t temp[10]; int end_len_len = _pbcV_encode32(end_len, temp); if (end_len_len != len_len) { _expand_message(m, end_len_len); memmove(m->buffer + offset + end_len_len , m->buffer + offset + len_len , end_len); m->ptr += end_len_len - len_len; } memcpy(m->buffer + offset , temp, end_len_len); } } static void _pack_packed(void *p, void *ud) { struct _packed *packed = (struct _packed *)p; struct pbc_wmessage * m = (struct pbc_wmessage *)ud; int id = packed->id << 3 | WT_LEND; _expand_message(m,10); m->ptr += _pbcV_encode32(id, m->ptr); switch(packed->ptype) { case PTYPE_DOUBLE: case PTYPE_FIXED64: case PTYPE_SFIXED64: _pack_packed_64(packed,m); break; case PTYPE_FLOAT: case PTYPE_FIXED32: case PTYPE_SFIXED32: _pack_packed_32(packed,m); break; default: _pack_packed_varint(packed,m); break; } } void * pbc_wmessage_buffer(struct pbc_wmessage *m, struct pbc_slice *slice) { if (m->packed) { _pbcM_sp_foreach_ud(m->packed , _pack_packed, m); } int i; int n = pbc_array_size(m->sub); for (i=0;isub, i , var); struct pbc_slice s; pbc_wmessage_buffer((struct pbc_wmessage *)var->p[0] , &s); if (s.buffer) { struct _field * f = (struct _field *)var->p[1]; int id = f->id << 3 | WT_LEND; _expand_message(m,20+s.len); m->ptr += _pbcV_encode32(id, m->ptr); m->ptr += _pbcV_encode32(s.len, m->ptr); memcpy(m->ptr, s.buffer, s.len); m->ptr += s.len; } } slice->buffer = m->buffer; slice->len = m->ptr - m->buffer; return m->buffer; }