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.
248 lines
5.8 KiB
248 lines
5.8 KiB
7 years ago
|
|
||
|
#include "upb/decode.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;
|
||
|
|
||
|
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));
|
||
|
}
|
||
|
|
||
|
bool upb_append_unknown(const char **ptr, const char *start, const char *limit,
|
||
|
char *msg) {
|
||
|
UPB_UNUSED(limit);
|
||
|
UPB_UNUSED(msg);
|
||
|
*ptr = limit;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool upb_decode_field(const char **ptr, const char *limit, char *msg,
|
||
|
const upb_msglayout_msginit_v1 *l, upb_env *env) {
|
||
|
uint32_t tag;
|
||
|
uint32_t wire_type;
|
||
|
uint32_t field_number;
|
||
|
const char *p = *ptr;
|
||
|
const char *field_start = p;
|
||
|
const upb_msglayout_fieldinit_v1 *f;
|
||
|
|
||
|
if (!upb_decode_varint32(&p, 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);
|
||
|
|
||
|
switch (wire_type) {
|
||
|
case UPB_WIRE_TYPE_VARINT: {
|
||
|
uint64_t val;
|
||
|
if (!upb_decode_varint(&p, limit, &val)) {
|
||
|
upb_decode_seterr(env, "Error decoding varint value.\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (!f) {
|
||
|
return upb_append_unknown(ptr, field_start, p, msg);
|
||
|
}
|
||
|
|
||
|
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, p, msg);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case UPB_WIRE_TYPE_64BIT: {
|
||
|
uint64_t val;
|
||
|
if (!upb_decode_64bit(&p, limit, &val)) {
|
||
|
upb_decode_seterr(env, "Error decoding 64bit value.\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (!f) {
|
||
|
return upb_append_unknown(ptr, field_start, p, msg);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case UPB_WIRE_TYPE_32BIT: {
|
||
|
uint32_t val;
|
||
|
if (!upb_decode_32bit(&p, limit, &val)) {
|
||
|
upb_decode_seterr(env, "Error decoding 32bit value.\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (!f) {
|
||
|
return upb_append_unknown(ptr, field_start, p, msg);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case UPB_WIRE_TYPE_DELIMITED: {
|
||
|
upb_stringview val;
|
||
|
if (!upb_decode_string(&p, limit, &val)) {
|
||
|
upb_decode_seterr(env, "Error decoding delimited value.\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (!f) {
|
||
|
return upb_append_unknown(ptr, field_start, p, msg);
|
||
|
}
|
||
|
|
||
|
memcpy(msg + f->offset, &val, sizeof(val));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (f->oneof_index != UPB_NOT_IN_ONEOF) {
|
||
|
upb_set32(msg, l->oneofs[f->oneof_index].case_offset, f->number);
|
||
|
}
|
||
|
|
||
|
*ptr = p;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool upb_decode(upb_stringview buf, void *msg_void,
|
||
|
const upb_msglayout_msginit_v1 *l, upb_env *env) {
|
||
|
char *msg = msg_void;
|
||
|
const char *ptr = buf.data;
|
||
|
const char *limit = ptr + buf.size;
|
||
|
|
||
|
while (ptr < limit) {
|
||
|
if (!upb_decode_field(&ptr, limit, msg, l, env)) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|