Added support for unknown fields to upb_msg.

After this CL, upb passes all existing proto3 conformance tests.
However the conformance suite is missing a lot of cases and should
be fleshed out.
pull/13171/head
Josh Haberman 6 years ago
parent ea19fa4ed6
commit a105c015b1
  1. 8
      upb/decode.c
  2. 8
      upb/encode.c
  3. 32
      upb/msg.c
  4. 3
      upb/msg.h

@ -130,9 +130,7 @@ static void upb_set32(void *msg, size_t ofs, uint32_t val) {
static bool upb_append_unknown(upb_decstate *d, upb_decframe *frame, static bool upb_append_unknown(upb_decstate *d, upb_decframe *frame,
const char *start) { const char *start) {
UPB_UNUSED(d); upb_msg_addunknown(frame->msg, start, d->ptr - start);
UPB_UNUSED(frame);
UPB_UNUSED(start);
return true; return true;
} }
@ -545,7 +543,9 @@ static bool upb_decode_field(upb_decstate *d, upb_decframe *frame) {
} }
} else { } else {
CHK(field_number != 0); CHK(field_number != 0);
return upb_skip_unknownfielddata(d, frame, field_number, wire_type); CHK(upb_skip_unknownfielddata(d, frame, field_number, wire_type));
CHK(upb_append_unknown(d, frame, field_start));
return true;
} }
} }

@ -331,6 +331,8 @@ bool upb_encode_message(upb_encstate *e, const char *msg,
const upb_msglayout *m, size_t *size) { const upb_msglayout *m, size_t *size) {
int i; int i;
size_t pre_len = e->limit - e->ptr; size_t pre_len = e->limit - e->ptr;
const char *unknown;
size_t unknown_size;
for (i = m->field_count - 1; i >= 0; i--) { for (i = m->field_count - 1; i >= 0; i--) {
const upb_msglayout_field *f = &m->fields[i]; const upb_msglayout_field *f = &m->fields[i];
@ -357,6 +359,12 @@ bool upb_encode_message(upb_encstate *e, const char *msg,
} }
} }
unknown = upb_msg_getunknown(msg, &unknown_size);
if (unknown) {
upb_put_bytes(e, unknown, unknown_size);
}
*size = (e->limit - e->ptr) - pre_len; *size = (e->limit - e->ptr) - pre_len;
return true; return true;
} }

@ -113,8 +113,12 @@ static upb_ctype_t upb_fieldtotabtype(upb_fieldtype_t type) {
/* Used when a message is not extendable. */ /* Used when a message is not extendable. */
typedef struct { typedef struct {
/* TODO(haberman): add unknown fields. */ /* TODO(haberman): use pointer tagging so we we are slim when known unknown
* fields are not present. */
upb_arena *arena; upb_arena *arena;
char *unknown;
size_t unknown_len;
size_t unknown_size;
} upb_msg_internal; } upb_msg_internal;
/* Used when a message is extendable. */ /* Used when a message is extendable. */
@ -141,6 +145,25 @@ static upb_msg_internal_withext *upb_msg_getinternalwithext(
return VOIDPTR_AT(msg, -sizeof(upb_msg_internal_withext)); return VOIDPTR_AT(msg, -sizeof(upb_msg_internal_withext));
} }
void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len) {
upb_msg_internal* in = upb_msg_getinternal(msg);
if (len > in->unknown_size - in->unknown_len) {
upb_alloc *alloc = upb_arena_alloc(in->arena);
size_t need = in->unknown_size + len;
size_t newsize = UPB_MAX(in->unknown_size * 2, need);
in->unknown = upb_realloc(alloc, in->unknown, in->unknown_size, newsize);
in->unknown_size = newsize;
}
memcpy(in->unknown + in->unknown_len, data, len);
in->unknown_len += len;
}
const char *upb_msg_getunknown(upb_msg *msg, size_t *len) {
upb_msg_internal* in = upb_msg_getinternal(msg);
*len = in->unknown_len;
return in->unknown;
}
static const upb_msglayout_field *upb_msg_checkfield(int field_index, static const upb_msglayout_field *upb_msg_checkfield(int field_index,
const upb_msglayout *l) { const upb_msglayout *l) {
UPB_ASSERT(field_index >= 0 && field_index < l->field_count); UPB_ASSERT(field_index >= 0 && field_index < l->field_count);
@ -165,6 +188,7 @@ static size_t upb_msg_sizeof(const upb_msglayout *l) {
upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a) { upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a) {
upb_alloc *alloc = upb_arena_alloc(a); upb_alloc *alloc = upb_arena_alloc(a);
void *mem = upb_malloc(alloc, upb_msg_sizeof(l)); void *mem = upb_malloc(alloc, upb_msg_sizeof(l));
upb_msg_internal *in;
upb_msg *msg; upb_msg *msg;
if (!mem) { if (!mem) {
@ -177,7 +201,11 @@ upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a) {
memset(msg, 0, l->size); memset(msg, 0, l->size);
/* Initialize internal members. */ /* Initialize internal members. */
upb_msg_getinternal(msg)->arena = a; in = upb_msg_getinternal(msg);
in->arena = a;
in->unknown = NULL;
in->unknown_len = 0;
in->unknown_size = 0;
if (l->extendable) { if (l->extendable) {
upb_msg_getinternalwithext(msg, l)->extdict = NULL; upb_msg_getinternalwithext(msg, l)->extdict = NULL;

@ -154,6 +154,9 @@ upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a);
/* Returns the arena for the given message. */ /* Returns the arena for the given message. */
upb_arena *upb_msg_arena(const upb_msg *msg); upb_arena *upb_msg_arena(const upb_msg *msg);
void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len);
const char *upb_msg_getunknown(upb_msg *msg, size_t *len);
/* Read-only message API. Can be safely called by anyone. */ /* Read-only message API. Can be safely called by anyone. */
/* Returns the value associated with this field: /* Returns the value associated with this field:

Loading…
Cancel
Save