From 563325435753fae01d2b45cceba8b9d14c8a7aad Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Thu, 10 Jun 2010 09:14:31 -0700 Subject: Implement proper type checking again. --- src/upb.c | 28 ++++++++++++++++++++++++++++ src/upb.h | 12 ++++++++++++ src/upb_decoder.c | 11 ++++++----- src/upb_string.h | 2 +- 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/upb.c b/src/upb.c index bd41613..189dfe4 100644 --- a/src/upb.c +++ b/src/upb.c @@ -11,6 +11,34 @@ #include "upb.h" +#define alignof(t) offsetof(struct { char c; t x; }, x) +#define TYPE_INFO(wire_type, ctype, allows_delimited) \ + {alignof(ctype), sizeof(ctype), wire_type, \ + (1 << wire_type) | (allows_delimited << UPB_WIRE_TYPE_DELIMITED), \ + #ctype}, + +upb_type_info upb_types[] = { + {0, 0, 0, ""} // There is no type 0. + TYPE_INFO(UPB_WIRE_TYPE_64BIT, double, 1), // DOUBLE + TYPE_INFO(UPB_WIRE_TYPE_32BIT, float, 1), // FLOAT + TYPE_INFO(UPB_WIRE_TYPE_VARINT, int64_t, 1), // INT64 + TYPE_INFO(UPB_WIRE_TYPE_VARINT, uint64_t, 1), // UINT64 + TYPE_INFO(UPB_WIRE_TYPE_VARINT, int32_t, 1), // INT32 + TYPE_INFO(UPB_WIRE_TYPE_64BIT, uint64_t, 1), // FIXED64 + TYPE_INFO(UPB_WIRE_TYPE_32BIT, uint32_t, 1), // FIXED32 + TYPE_INFO(UPB_WIRE_TYPE_VARINT, bool, 1), // BOOL + TYPE_INFO(UPB_WIRE_TYPE_DELIMITED, void*, 1), // STRING + TYPE_INFO(UPB_WIRE_TYPE_START_GROUP, void*, 0), // GROUP + TYPE_INFO(UPB_WIRE_TYPE_DELIMITED, void*, 1), // MESSAGE + TYPE_INFO(UPB_WIRE_TYPE_DELIMITED, void*, 1), // BYTES + TYPE_INFO(UPB_WIRE_TYPE_VARINT, uint32_t, 1), // UINT32 + TYPE_INFO(UPB_WIRE_TYPE_VARINT, uint32_t, 1), // ENUM + TYPE_INFO(UPB_WIRE_TYPE_32BIT, int32_t, 1), // SFIXED32 + TYPE_INFO(UPB_WIRE_TYPE_64BIT, int64_t, 1), // SFIXED64 + TYPE_INFO(UPB_WIRE_TYPE_VARINT, int32_t, 1), // SINT32 + TYPE_INFO(UPB_WIRE_TYPE_VARINT, int64_t, 1), // SINT64 +}; + void upb_seterr(upb_status *status, enum upb_status_code code, const char *msg, ...) { diff --git a/src/upb.h b/src/upb.h index 1681763..6bf548c 100644 --- a/src/upb.h +++ b/src/upb.h @@ -98,6 +98,18 @@ INLINE bool upb_isstringtype(upb_field_type_t type) { return type == UPB_TYPE(STRING) || type == UPB_TYPE(BYTES); } +// Info for a given field type. +typedef struct { + uint8_t align; + uint8_t size; + upb_wire_type_t native_wire_type; + uint8_t allowed_wire_types; // For packable fields, also allows delimited. + char *ctype; +} upb_type_info; + +// A static array of info about all of the field types, indexed by type number. +extern upb_type_info upb_types[]; + // The number of a field, eg. "optional string foo = 3". typedef int32_t upb_field_number_t; diff --git a/src/upb_decoder.c b/src/upb_decoder.c index 5d352c2..c54a21a 100644 --- a/src/upb_decoder.c +++ b/src/upb_decoder.c @@ -12,9 +12,10 @@ #define UPB_GROUP_END_OFFSET UINT32_MAX +// Returns true if the give wire type and field type combination is valid, +// taking into account both packed and non-packed encodings. static bool upb_check_type(upb_wire_type_t wt, upb_field_type_t ft) { - // Fake implementation. - return ft + wt > 3; + return (1 << wt) & upb_types[ft].allowed_wire_types; } /* Functions to read wire values. *********************************************/ @@ -348,8 +349,8 @@ upb_fielddef *upb_decoder_getdef(upb_decoder *d) bool upb_decoder_getval(upb_decoder *d, upb_valueptr val) { - int expected_type_for_field = 0; - if(expected_type_for_field == UPB_WIRE_TYPE_DELIMITED) { + upb_wire_type_t native_wire_type = upb_types[d->field->type].native_wire_type; + if(native_wire_type == UPB_WIRE_TYPE_DELIMITED) { // A string, bytes, or a length-delimited submessage. The latter isn't // technically a string, but can be gotten as one to perform lazy parsing. d->str = upb_string_tryrecycle(d->str); @@ -385,7 +386,7 @@ bool upb_decoder_getval(upb_decoder *d, upb_valueptr val) uint32_t bytes_available; uint32_t bytes_consumed; const uint8_t *buf = upb_decoder_getbuf(d, &bytes_available); - switch(expected_type_for_field) { + switch(native_wire_type) { case UPB_WIRE_TYPE_VARINT: if((bytes_consumed = upb_get_v_uint32(buf, val.uint32)) > 10) goto err; if(d->field->type == UPB_TYPE(SINT64)) *val.int64 = upb_zzdec_64(*val.int64); diff --git a/src/upb_string.h b/src/upb_string.h index 9a3957c..eab7f54 100644 --- a/src/upb_string.h +++ b/src/upb_string.h @@ -70,7 +70,7 @@ INLINE upb_strlen_t upb_string_len(upb_string *str) { return str->len; } // upb_string_endread is called(). No other functions may be called on the // string during this window except upb_string_len(). INLINE const char *upb_string_getrobuf(upb_string *str) { return str->ptr; } -INLINE void upb_string_endread(upb_string *str); +INLINE void upb_string_endread(upb_string *str) {} // Attempts to recycle the string "str" so it may be reused and have different // data written to it. The returned string is either "str" if it could be -- cgit v1.2.3