Protocol Buffers - Google's data interchange format (grpc依赖)
https://developers.google.com/protocol-buffers/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
419 lines
11 KiB
419 lines
11 KiB
|
|
#include "upb/decode.h" |
|
#include "upb/structs.int.h" |
|
|
|
typedef enum { |
|
UPB_WIRE_TYPE_VARINT = 0, |
|
UPB_WIRE_TYPE_64BIT = 1, |
|
UPB_WIRE_TYPE_DELIMITED = 2, |
|
UPB_WIRE_TYPE_START_GROUP = 3, |
|
UPB_WIRE_TYPE_END_GROUP = 4, |
|
UPB_WIRE_TYPE_32BIT = 5 |
|
} upb_wiretype_t; |
|
|
|
typedef struct { |
|
upb_env *env; |
|
/* Current decoding pointer. Points to the beginning of a field until we |
|
* have finished decoding the whole field. */ |
|
const char *ptr; |
|
} upb_decstate; |
|
|
|
typedef struct { |
|
int32_t group_number; /* 0 if we are not parsing a group. */ |
|
char *msg; |
|
const upb_msglayout_msginit_v1 *m; |
|
const char *limit; |
|
} upb_decframe; |
|
|
|
#define CHK(x) if (!(x)) { return false; } |
|
|
|
static void upb_decode_seterr(upb_env *env, const char *msg) { |
|
upb_status status = UPB_STATUS_INIT; |
|
upb_status_seterrmsg(&status, msg); |
|
upb_env_reporterror(env, &status); |
|
} |
|
|
|
static bool upb_decode_varint(const char **ptr, const char *limit, |
|
uint64_t *val) { |
|
uint8_t byte = 0x80; |
|
int bitpos = 0; |
|
const char *p = *ptr; |
|
*val = 0; |
|
|
|
while (byte & 0x80) { |
|
if (bitpos == 70 || p == limit) { |
|
return false; |
|
} |
|
|
|
byte = *p; |
|
*val |= (uint64_t)(byte & 0x7F) << bitpos; |
|
p++; |
|
bitpos += 7; |
|
} |
|
|
|
*ptr = p; |
|
return true; |
|
} |
|
|
|
static bool upb_decode_varint32(const char **ptr, const char *limit, |
|
uint32_t *val) { |
|
uint64_t u64; |
|
if (!upb_decode_varint(ptr, limit, &u64) || u64 > UINT32_MAX) { |
|
return false; |
|
} else { |
|
*val = u64; |
|
return true; |
|
} |
|
} |
|
|
|
static const upb_msglayout_fieldinit_v1 *upb_find_field( |
|
const upb_msglayout_msginit_v1 *l, uint32_t field_number) { |
|
/* Lots of optimization opportunities here. */ |
|
int i; |
|
for (i = 0; i < l->field_count; i++) { |
|
if (l->fields[i].number == field_number) { |
|
return &l->fields[i]; |
|
} |
|
} |
|
|
|
return NULL; /* Unknown field. */ |
|
} |
|
|
|
static bool upb_decode_64bit(const char **ptr, const char *limit, |
|
uint64_t *val) { |
|
if (limit - *ptr < 8) { |
|
return false; |
|
} else { |
|
memcpy(val, *ptr, 8); |
|
*ptr += 8; |
|
return true; |
|
} |
|
} |
|
|
|
static bool upb_decode_32bit(const char **ptr, const char *limit, |
|
uint32_t *val) { |
|
if (limit - *ptr < 4) { |
|
return false; |
|
} else { |
|
memcpy(val, *ptr, 4); |
|
*ptr += 4; |
|
return true; |
|
} |
|
} |
|
|
|
static int32_t upb_zzdec_32(uint32_t n) { |
|
return (n >> 1) ^ -(int32_t)(n & 1); |
|
} |
|
|
|
static int64_t upb_zzdec_64(uint64_t n) { |
|
return (n >> 1) ^ -(int64_t)(n & 1); |
|
} |
|
|
|
static bool upb_decode_string(const char **ptr, const char *limit, |
|
upb_stringview *val) { |
|
uint32_t len; |
|
|
|
if (!upb_decode_varint32(ptr, limit, &len) || |
|
limit - *ptr < len) { |
|
return false; |
|
} |
|
|
|
*val = upb_stringview_make(*ptr, len); |
|
*ptr += len; |
|
return true; |
|
} |
|
|
|
static void upb_set32(void *msg, size_t ofs, uint32_t val) { |
|
memcpy((char*)msg + ofs, &val, sizeof(val)); |
|
} |
|
|
|
static bool upb_append_unknownfield(const char **ptr, const char *start, |
|
const char *limit, char *msg) { |
|
UPB_UNUSED(limit); |
|
UPB_UNUSED(msg); |
|
*ptr = limit; |
|
return true; |
|
} |
|
|
|
static bool upb_decode_unknownfielddata(upb_decstate *d, const char *ptr, |
|
const char *limit, char *msg, |
|
const upb_msglayout_msginit_v1 *l) { |
|
do { |
|
switch (wire_type) { |
|
case UPB_WIRE_TYPE_VARINT: |
|
CHK(upb_decode_varint(&ptr, limit, &val)); |
|
break; |
|
case UPB_WIRE_TYPE_32BIT: |
|
CHK(upb_decode_32bit(&ptr, limit, &val)); |
|
break; |
|
case UPB_WIRE_TYPE_64BIT: |
|
CHK(upb_decode_64bit(&ptr, limit, &val)); |
|
break; |
|
case UPB_WIRE_TYPE_DELIMITED: { |
|
upb_stringview val; |
|
CHK(upb_decode_string(&ptr, limit, &val)); |
|
} |
|
case UPB_WIRE_TYPE_START_GROUP: |
|
depth++; |
|
continue; |
|
case UPB_WIRE_TYPE_END_GROUP: |
|
depth--; |
|
continue; |
|
} |
|
|
|
UPB_ASSERT(depth == 0); |
|
upb_append_unknown(msg, l, d->ptr, ptr); |
|
d->ptr = ptr; |
|
return true; |
|
} while (true); |
|
} |
|
|
|
static bool upb_decode_knownfield(upb_decstate *d, const char *ptr, |
|
const char *limit, char *msg, |
|
const upb_msglayout_msginit_v1 *l, |
|
const upb_msglayout_fieldinit_v1 *l) { |
|
switch (wire_type) { |
|
case UPB_WIRE_TYPE_VARINT: |
|
return upb_decode_varintfield(d, ptr, limit, msg, l, f); |
|
case UPB_WIRE_TYPE_32BIT: |
|
return upb_decode_32bitfield(d, ptr, limit, msg, l, f); |
|
case UPB_WIRE_TYPE_64BIT: |
|
return upb_decode_64bitfield(d, ptr, limit, msg, l, f); |
|
case UPB_WIRE_TYPE_DELIMITED: |
|
return upb_decode_delimitedfield(d, ptr, limit, msg, l, f); |
|
case UPB_WIRE_TYPE_START_GROUP: |
|
case UPB_WIRE_TYPE_END_GROUP: |
|
} |
|
} |
|
|
|
|
|
static bool upb_decode_field(upb_decstate *d, const char *limit, char *msg, |
|
const upb_msglayout_msginit_v1 *l) { |
|
uint32_t tag; |
|
uint32_t wire_type; |
|
uint32_t field_number; |
|
const char *ptr = d->ptr; |
|
const upb_msglayout_fieldinit_v1 *f; |
|
|
|
if (!upb_decode_varint32(&ptr, limit, &tag)) { |
|
upb_decode_seterr(env, "Error decoding tag.\n"); |
|
return false; |
|
} |
|
|
|
wire_type = tag & 0x7; |
|
field_number = tag >> 3; |
|
|
|
if (field_number == 0) { |
|
return false; |
|
} |
|
|
|
f = upb_find_field(l, field_number); |
|
|
|
if (f) { |
|
return upb_decode_knownfield(d, ptr, limit, msg, l, f); |
|
} else { |
|
return upb_decode_unknownfield(d, ptr, limit, msg, l); |
|
} |
|
|
|
if (f->label == UPB_LABEL_REPEATED) { |
|
arr = upb_getarray(msg, f, env); |
|
} |
|
|
|
switch (wire_type) { |
|
case UPB_WIRE_TYPE_VARINT: { |
|
uint64_t val; |
|
if (!upb_decode_varint(&ptr, limit, &val)) { |
|
upb_decode_seterr(env, "Error decoding varint value.\n"); |
|
return false; |
|
} |
|
|
|
if (!f) { |
|
return upb_append_unknown(ptr, field_start, ptr, msg); |
|
} |
|
|
|
if (f->label == UPB_LABEL_REPEATED) { |
|
upb_array *arr = upb_getarray(msg, f, env); |
|
switch (f->type) { |
|
case UPB_DESCRIPTOR_TYPE_INT64: |
|
case UPB_DESCRIPTOR_TYPE_UINT64: |
|
memcpy(arr->data, &val, sizeof(val)); |
|
arr->len++; |
|
break; |
|
case UPB_DESCRIPTOR_TYPE_INT32: |
|
case UPB_DESCRIPTOR_TYPE_UINT32: |
|
case UPB_DESCRIPTOR_TYPE_ENUM: { |
|
uint32_t val32 = val; |
|
memcpy(arr->data, &val32, sizeof(val32)); |
|
arr->len++; |
|
break; |
|
} |
|
case UPB_DESCRIPTOR_TYPE_SINT32: { |
|
int32_t decoded = upb_zzdec_32(val); |
|
memcpy(arr->data, &decoded, sizeof(decoded)); |
|
arr->len++; |
|
break; |
|
} |
|
case UPB_DESCRIPTOR_TYPE_SINT64: { |
|
int64_t decoded = upb_zzdec_64(val); |
|
memcpy(arr->data, &decoded, sizeof(decoded)); |
|
arr->len++; |
|
break; |
|
} |
|
default: |
|
return upb_append_unknown(ptr, field_start, ptr, msg); |
|
} |
|
} else { |
|
switch (f->type) { |
|
case UPB_DESCRIPTOR_TYPE_INT64: |
|
case UPB_DESCRIPTOR_TYPE_UINT64: |
|
memcpy(msg + f->offset, &val, sizeof(val)); |
|
break; |
|
case UPB_DESCRIPTOR_TYPE_INT32: |
|
case UPB_DESCRIPTOR_TYPE_UINT32: |
|
case UPB_DESCRIPTOR_TYPE_ENUM: { |
|
uint32_t val32 = val; |
|
memcpy(msg + f->offset, &val32, sizeof(val32)); |
|
break; |
|
} |
|
case UPB_DESCRIPTOR_TYPE_SINT32: { |
|
int32_t decoded = upb_zzdec_32(val); |
|
memcpy(msg + f->offset, &decoded, sizeof(decoded)); |
|
break; |
|
} |
|
case UPB_DESCRIPTOR_TYPE_SINT64: { |
|
int64_t decoded = upb_zzdec_64(val); |
|
memcpy(msg + f->offset, &decoded, sizeof(decoded)); |
|
break; |
|
} |
|
default: |
|
return upb_append_unknown(ptr, field_start, ptr, msg); |
|
} |
|
} |
|
|
|
break; |
|
} |
|
case UPB_WIRE_TYPE_64BIT: { |
|
uint64_t val; |
|
if (!upb_decode_64bit(&ptr, limit, &val)) { |
|
upb_decode_seterr(env, "Error decoding 64bit value.\n"); |
|
return false; |
|
} |
|
|
|
if (!f) { |
|
return upb_append_unknown(ptr, field_start, ptr, msg); |
|
} |
|
|
|
switch (f->type) { |
|
case UPB_DESCRIPTOR_TYPE_DOUBLE: |
|
case UPB_DESCRIPTOR_TYPE_FIXED64: |
|
case UPB_DESCRIPTOR_TYPE_SFIXED64: |
|
memcpy(msg + f->offset, &val, sizeof(val)); |
|
default: |
|
return upb_append_unknown(ptr, field_start, ptr, msg); |
|
} |
|
|
|
break; |
|
} |
|
case UPB_WIRE_TYPE_32BIT: { |
|
uint32_t val; |
|
if (!upb_decode_32bit(&ptr, limit, &val)) { |
|
upb_decode_seterr(env, "Error decoding 32bit value.\n"); |
|
return false; |
|
} |
|
|
|
if (!f) { |
|
return upb_append_unknown(ptr, field_start, ptr, msg); |
|
} |
|
|
|
switch (f->type) { |
|
case UPB_DESCRIPTOR_TYPE_FLOAT: |
|
case UPB_DESCRIPTOR_TYPE_FIXED32: |
|
case UPB_DESCRIPTOR_TYPE_SFIXED32: |
|
memcpy(msg + f->offset, &val, sizeof(val)); |
|
default: |
|
return upb_append_unknown(ptr, field_start, ptr, msg); |
|
} |
|
|
|
break; |
|
} |
|
case UPB_WIRE_TYPE_DELIMITED: { |
|
upb_stringview val; |
|
if (!upb_decode_string(&ptr, limit, &val)) { |
|
upb_decode_seterr(env, "Error decoding delimited value.\n"); |
|
return false; |
|
} |
|
|
|
if (!f) { |
|
return upb_append_unknown(ptr, field_start, ptr, msg); |
|
} |
|
|
|
switch (f->type) { |
|
case UPB_DESCRIPTOR_TYPE_STRING: |
|
case UPB_DESCRIPTOR_TYPE_BYTES: |
|
memcpy(msg + f->offset, &val, sizeof(val)); |
|
break; |
|
case UPB_DESCRIPTOR_TYPE_INT64: |
|
case UPB_DESCRIPTOR_TYPE_UINT64: { |
|
memcpy(msg + f->offset, &val, sizeof(val)); |
|
break; |
|
case UPB_DESCRIPTOR_TYPE_INT32: |
|
case UPB_DESCRIPTOR_TYPE_UINT32: |
|
case UPB_DESCRIPTOR_TYPE_ENUM: { |
|
uint32_t val32 = val; |
|
memcpy(msg + f->offset, &val32, sizeof(val32)); |
|
break; |
|
} |
|
case UPB_DESCRIPTOR_TYPE_SINT32: { |
|
int32_t decoded = upb_zzdec_32(val); |
|
memcpy(msg + f->offset, &decoded, sizeof(decoded)); |
|
break; |
|
} |
|
case UPB_DESCRIPTOR_TYPE_SINT64: |
|
case UPB_DESCRIPTOR_TYPE_FLOAT: |
|
case UPB_DESCRIPTOR_TYPE_FIXED32: |
|
case UPB_DESCRIPTOR_TYPE_SFIXED32: |
|
/* |
|
case UPB_DESCRIPTOR_TYPE_MESSAGE: { |
|
upb_decode_message(val, |
|
} |
|
*/ |
|
default: |
|
return upb_append_unknown(ptr, field_start, ptr, msg); |
|
} |
|
|
|
break; |
|
} |
|
} |
|
|
|
if (f->oneof_index != UPB_NOT_IN_ONEOF) { |
|
upb_set32(msg, l->oneofs[f->oneof_index].case_offset, f->number); |
|
} |
|
|
|
d->ptr = ptr; |
|
return true; |
|
} |
|
|
|
static bool upb_decode_message(upb_decstate *d, upb_decframe *frame) { |
|
while (d->ptr < frame->limit) { |
|
if (!upb_decode_field(d, frame)) { |
|
return false; |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool upb_decode(upb_stringview buf, void *msg, |
|
const upb_msglayout_msginit_v1 *l, upb_env *env) { |
|
upb_decstate state; |
|
state.ptr = buf.data; |
|
state.env = env; |
|
|
|
upb_decframe frame; |
|
frame.msg = msg; |
|
frame.l = l; |
|
frame.group_number = 0; |
|
frame.limit = buf.data + buf.size |
|
|
|
return upb_decode_message(&state, &frame); |
|
}
|
|
|