Simplified main parsing function.

pull/13171/head
Joshua Haberman 3 years ago
parent 2e7da49bbe
commit 69bb5d1d94
  1. 200
      upb/decode.c

@ -92,6 +92,7 @@ static const unsigned fixed64_ok = (1 << UPB_DTYPE_DOUBLE) |
(1 << UPB_DTYPE_SFIXED64);
/* Op: an action to be performed for a wire-type/field-type combination. */
#define OP_UNKNOWN -1
#define OP_SCALAR_LG2(n) (n) /* n in [0, 2, 3] => op in [0, 2, 3] */
#define OP_STRING 4
#define OP_BYTES 5
@ -101,48 +102,48 @@ static const unsigned fixed64_ok = (1 << UPB_DTYPE_DOUBLE) |
#define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */
static const int8_t varint_ops[19] = {
-1, /* field not found */
-1, /* DOUBLE */
-1, /* FLOAT */
OP_UNKNOWN, /* field not found */
OP_UNKNOWN, /* DOUBLE */
OP_UNKNOWN, /* FLOAT */
OP_SCALAR_LG2(3), /* INT64 */
OP_SCALAR_LG2(3), /* UINT64 */
OP_SCALAR_LG2(2), /* INT32 */
-1, /* FIXED64 */
-1, /* FIXED32 */
OP_UNKNOWN, /* FIXED64 */
OP_UNKNOWN, /* FIXED32 */
OP_SCALAR_LG2(0), /* BOOL */
-1, /* STRING */
-1, /* GROUP */
-1, /* MESSAGE */
-1, /* BYTES */
OP_UNKNOWN, /* STRING */
OP_UNKNOWN, /* GROUP */
OP_UNKNOWN, /* MESSAGE */
OP_UNKNOWN, /* BYTES */
OP_SCALAR_LG2(2), /* UINT32 */
OP_SCALAR_LG2(2), /* ENUM */
-1, /* SFIXED32 */
-1, /* SFIXED64 */
OP_UNKNOWN, /* SFIXED32 */
OP_UNKNOWN, /* SFIXED64 */
OP_SCALAR_LG2(2), /* SINT32 */
OP_SCALAR_LG2(3), /* SINT64 */
};
static const int8_t delim_ops[37] = {
/* For non-repeated field type. */
-1, /* field not found */
-1, /* DOUBLE */
-1, /* FLOAT */
-1, /* INT64 */
-1, /* UINT64 */
-1, /* INT32 */
-1, /* FIXED64 */
-1, /* FIXED32 */
-1, /* BOOL */
OP_STRING, /* STRING */
-1, /* GROUP */
OP_SUBMSG, /* MESSAGE */
OP_BYTES, /* BYTES */
-1, /* UINT32 */
-1, /* ENUM */
-1, /* SFIXED32 */
-1, /* SFIXED64 */
-1, /* SINT32 */
-1, /* SINT64 */
OP_UNKNOWN, /* field not found */
OP_UNKNOWN, /* DOUBLE */
OP_UNKNOWN, /* FLOAT */
OP_UNKNOWN, /* INT64 */
OP_UNKNOWN, /* UINT64 */
OP_UNKNOWN, /* INT32 */
OP_UNKNOWN, /* FIXED64 */
OP_UNKNOWN, /* FIXED32 */
OP_UNKNOWN, /* BOOL */
OP_STRING, /* STRING */
OP_UNKNOWN, /* GROUP */
OP_SUBMSG, /* MESSAGE */
OP_BYTES, /* BYTES */
OP_UNKNOWN, /* UINT32 */
OP_UNKNOWN, /* ENUM */
OP_UNKNOWN, /* SFIXED32 */
OP_UNKNOWN, /* SFIXED64 */
OP_UNKNOWN, /* SINT32 */
OP_UNKNOWN, /* SINT64 */
/* For repeated field type. */
OP_FIXPCK_LG2(3), /* REPEATED DOUBLE */
OP_FIXPCK_LG2(2), /* REPEATED FLOAT */
@ -608,6 +609,76 @@ static bool decode_tryfastdispatch(upb_decstate *d, const char **ptr,
return false;
}
UPB_FORCEINLINE
static const char *decode_wireval(upb_decstate *d, const char *ptr,
const upb_msglayout_field *field,
int wire_type, wireval *val, int *op) {
switch (wire_type) {
case UPB_WIRE_TYPE_VARINT:
ptr = decode_varint64(d, ptr, &val->uint64_val);
*op = varint_ops[field->descriptortype];
decode_munge(field->descriptortype, val);
return ptr;
case UPB_WIRE_TYPE_32BIT:
memcpy(&val->uint32_val, ptr, 4);
val->uint32_val = _upb_be_swap32(val->uint32_val);
*op = OP_SCALAR_LG2(2);
if (((1 << field->descriptortype) & fixed32_ok) == 0) *op = OP_UNKNOWN;
return ptr + 4;
case UPB_WIRE_TYPE_64BIT:
memcpy(&val->uint64_val, ptr, 8);
val->uint64_val = _upb_be_swap64(val->uint64_val);
*op = OP_SCALAR_LG2(3);
if (((1 << field->descriptortype) & fixed64_ok) == 0) *op = OP_UNKNOWN;
return ptr + 8;
case UPB_WIRE_TYPE_DELIMITED: {
int ndx = field->descriptortype;
uint64_t size;
if (_upb_getmode(field) == _UPB_MODE_ARRAY) ndx += 18;
ptr = decode_varint64(d, ptr, &size);
if (size >= INT32_MAX ||
ptr - d->end + (int32_t)size > d->limit) {
decode_err(d); /* Length overflow. */
}
*op = delim_ops[ndx];
val->size = size;
return ptr;
}
case UPB_WIRE_TYPE_START_GROUP:
val->uint32_val = field->number;
*op = OP_SUBMSG;
if (field->descriptortype != UPB_DTYPE_GROUP) *op = OP_UNKNOWN;
return ptr;
default:
decode_err(d);
}
}
UPB_FORCEINLINE
static const char *decode_skipunknown(upb_decstate *d, const char *ptr,
upb_msg *msg, int field_number,
int wire_type, wireval val,
const char **field_start) {
if (field_number == 0) decode_err(d);
if (wire_type == UPB_WIRE_TYPE_DELIMITED) ptr += val.size;
if (msg) {
if (wire_type == UPB_WIRE_TYPE_START_GROUP) {
d->unknown = *field_start;
d->unknown_msg = msg;
ptr = decode_group(d, ptr, NULL, NULL, field_number);
d->unknown_msg = NULL;
*field_start = d->unknown;
}
if (!_upb_msg_addunknown(msg, *field_start, ptr - *field_start,
&d->arena)) {
decode_err(d);
}
} else if (wire_type == UPB_WIRE_TYPE_START_GROUP) {
ptr = decode_group(d, ptr, NULL, NULL, field_number);
}
return ptr;
}
UPB_NOINLINE
static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg,
const upb_msglayout *layout) {
@ -628,51 +699,13 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg,
field = upb_find_field(d, layout, field_number, &last_field_index);
switch (wire_type) {
case UPB_WIRE_TYPE_VARINT:
ptr = decode_varint64(d, ptr, &val.uint64_val);
op = varint_ops[field->descriptortype];
decode_munge(field->descriptortype, &val);
break;
case UPB_WIRE_TYPE_32BIT:
memcpy(&val.uint32_val, ptr, 4);
val.uint32_val = _upb_be_swap32(val.uint32_val);
ptr += 4;
op = OP_SCALAR_LG2(2);
if (((1 << field->descriptortype) & fixed32_ok) == 0) goto unknown;
break;
case UPB_WIRE_TYPE_64BIT:
memcpy(&val.uint64_val, ptr, 8);
val.uint64_val = _upb_be_swap64(val.uint64_val);
ptr += 8;
op = OP_SCALAR_LG2(3);
if (((1 << field->descriptortype) & fixed64_ok) == 0) goto unknown;
break;
case UPB_WIRE_TYPE_DELIMITED: {
int ndx = field->descriptortype;
uint64_t size;
if (_upb_getmode(field) == _UPB_MODE_ARRAY) ndx += 18;
ptr = decode_varint64(d, ptr, &size);
if (size >= INT32_MAX ||
ptr - d->end + (int32_t)size > d->limit) {
decode_err(d); /* Length overflow. */
}
op = delim_ops[ndx];
val.size = size;
break;
}
case UPB_WIRE_TYPE_START_GROUP:
val.uint32_val = field_number;
op = OP_SUBMSG;
if (field->descriptortype != UPB_DTYPE_GROUP) goto unknown;
break;
case UPB_WIRE_TYPE_END_GROUP:
d->end_group = field_number;
return ptr;
default:
decode_err(d);
if (wire_type == UPB_WIRE_TYPE_END_GROUP) {
d->end_group = field_number;
return ptr;
}
ptr = decode_wireval(d, ptr, field, wire_type, &val, &op);
if (op >= 0) {
/* Known field, possibly an extension. */
upb_msg *field_msg = msg;
@ -702,25 +735,8 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg,
UPB_UNREACHABLE();
}
} else {
unknown:
/* Skip unknown field. */
if (field_number == 0) decode_err(d);
if (wire_type == UPB_WIRE_TYPE_DELIMITED) ptr += val.size;
if (msg) {
if (wire_type == UPB_WIRE_TYPE_START_GROUP) {
d->unknown = field_start;
d->unknown_msg = msg;
ptr = decode_group(d, ptr, NULL, NULL, field_number);
d->unknown_msg = NULL;
field_start = d->unknown;
}
if (!_upb_msg_addunknown(msg, field_start, ptr - field_start,
&d->arena)) {
decode_err(d);
}
} else if (wire_type == UPB_WIRE_TYPE_START_GROUP) {
ptr = decode_group(d, ptr, NULL, NULL, field_number);
}
ptr = decode_skipunknown(d, ptr, msg, field_number, wire_type, val,
&field_start);
}
if (decode_isdone(d, &ptr)) return ptr;

Loading…
Cancel
Save