Rip out more stuff that belongs in higher layers.

pull/13171/head
Joshua Haberman 16 years ago
parent 537ca81ada
commit 446d7c27ee
  1. 59
      pbstream.c
  2. 70
      pbstream.h

@ -183,10 +183,8 @@ static pbstream_status_t get_MESSAGE(struct pbstream_parse_state *s, char *buf,
s->offset = d->v.delimited.offset; /* skip past only the tag. */
RESIZE_DYNARRAY(s->stack, s->stack_len+1);
struct pbstream_parse_stack_frame *frame = DYNARRAY_GET_TOP(s->stack);
frame->message_descriptor = d->field_descriptor->d.message;
frame->message_descriptor = d->field_descriptor->message;
frame->end_offset = d->v.delimited.offset + d->v.delimited.len;
int num_seen_fields = frame->message_descriptor->num_seen_fields;
INIT_DYNARRAY(frame->seen_fields, num_seen_fields, num_seen_fields);
return PBSTREAM_STATUS_OK;
}
@ -245,42 +243,14 @@ static pbstream_status_t parse_unknown_value(
return PBSTREAM_STATUS_OK;
}
#define NONFATAL_ERROR(s, code) do { \
if(s->ignore_nonfatal_errors) { \
if(s->error_callback) s->error_callback(s, code); \
} else return code; } while (0)
static struct pbstream_field_descriptor *find_field_descriptor(
struct pbstream_message_descriptor* md,
pbstream_field_number_t field_number)
{
/* Likely will want to replace linear search with something better. */
for (int i = 0; i < md->fields_len; i++)
if (md->fields[i].field_number == field_number) return &md->fields[i];
/* TODO */
return NULL;
}
pbstream_status_t process_message_end(struct pbstream_parse_state *s)
{
struct pbstream_parse_stack_frame *frame = DYNARRAY_GET_TOP(s->stack);
/* A submessage that doesn't end exactly on a field boundary indicates
* corruption. */
if(unlikely(s->offset != frame->end_offset))
return PBSTREAM_ERROR_BAD_SUBMESSAGE_END;
/* Check required fields. */
struct pbstream_message_descriptor *md = frame->message_descriptor;
for(int i = 0; i < md->fields_len; i++) {
struct pbstream_field_descriptor *fd = &md->fields[i];
if(fd->seen_field_num && !frame->seen_fields[fd->seen_field_num] &&
fd->cardinality == PBSTREAM_CARDINALITY_REQUIRED) {
NONFATAL_ERROR(s, PBSTREAM_ERROR_MISSING_REQUIRED_FIELD);
}
}
RESIZE_DYNARRAY(s->stack, s->stack_len-1);
return PBSTREAM_STATUS_OK;
}
/* Parses and processes the next value from buf (but not past end). */
pbstream_status_t parse_field(struct pbstream_parse_state *s, char *buf,
pbstream_field_number_t *fieldnum,
@ -292,26 +262,29 @@ pbstream_status_t parse_field(struct pbstream_parse_state *s, char *buf,
struct pbstream_tag tag;
struct pbstream_field_descriptor *fd;
struct pbstream_type_info *info;
pbstream_status_t unknown_value_status;
char *b = buf;
if(unlikely(s->offset >= frame->end_offset)) return process_message_end(s);
if(unlikely(s->offset >= frame->end_offset)) {
/* If the end offset isn't an exact field boundary, the pb is corrupt. */
if(unlikely(s->offset != frame->end_offset))
return PBSTREAM_ERROR_BAD_SUBMESSAGE_END;
RESIZE_DYNARRAY(s->stack, s->stack_len-1);
return PBSTREAM_STATUS_SUBMESSAGE_END;
}
CHECK(parse_tag(&b, &tag));
size_t val_offset = s->offset + (b-buf);
fd = find_field_descriptor(md, tag.field_number);
if(unlikely(!fd)) goto unknown_value;
if(unlikely(!fd)) {
unknown_value_status = PBSTREAM_ERROR_UNKNOWN_VALUE;
goto unknown_value;
}
info = &type_info[fd->type];
/* Check type and cardinality. */
if(unlikely(tag.wire_type != info->expected_wire_type)) {
NONFATAL_ERROR(s, PBSTREAM_ERROR_MISMATCHED_TYPE);
unknown_value_status = PBSTREAM_ERROR_MISMATCHED_TYPE;
goto unknown_value;
}
if(fd->seen_field_num > 0) {
if(unlikely(frame->seen_fields[fd->seen_field_num]))
NONFATAL_ERROR(s, PBSTREAM_ERROR_DUPLICATE_FIELD);
frame->seen_fields[fd->seen_field_num] = true;
}
*fieldnum = tag.field_number;
val->field_descriptor = fd;
@ -322,5 +295,5 @@ unknown_value:
wv->type = tag.wire_type;
CHECK(parse_unknown_value(&b, val_offset, wv));
s->offset += (b-buf);
return PBSTREAM_STATUS_OK;
return unknown_value_status;
}

@ -40,13 +40,6 @@ typedef enum pbstream_wire_type {
PBSTREAM_WIRE_TYPE_32BIT = 5,
} pbstream_wire_type_t;
/* Each field must have a cardinality that is one of the following. */
typedef enum pbstream_cardinality {
PBSTREAM_CARDINALITY_OPTIONAL, /* must appear 0 or 1 times */
PBSTREAM_CARDINALITY_REQUIRED, /* must appear exactly 1 time */
PBSTREAM_CARDINALITY_REPEATED, /* may appear 0 or more times */
} pbstream_cardinality_t;
typedef int32_t pbstream_field_number_t;
/* A deserialized value as described in a .proto file. */
@ -88,53 +81,20 @@ struct pbstream_wire_value {
} v;
};
/* The definition of an enum as defined in a pbstream. For example:
* Corpus {
* UNIVERSAL = 0;
* WEB = 1;
* IMAGES = 2;
* LOCAL = 3;
* NEWS = 4;
* }
*/
struct pbstream_enum_descriptor {
char *name;
struct enum_value {
char *name;
int value;
} value;
DEFINE_DYNARRAY(values, struct enum_value);
};
/* The definition of a field as defined in a pbstream (within a message).
* For example:
* required int32 a = 1;
*/
struct pbstream_field_descriptor {
pbstream_field_number_t field_number;
char *name;
pbstream_type_t type;
pbstream_cardinality_t cardinality;
struct pbstream_value *default_value; /* NULL if none */
/* Index into the "seen" list for the message. -1 for repeated fields (for
* which we have no need to track whether it's been seen). */
int seen_field_num;
union extra_data {
struct pbstream_enum_descriptor *_enum;
struct pbstream_message_descriptor *message;
} d;
struct pbstream_message_descriptor *message; /* if type == MESSAGE */
};
/* A message as defined by the "message" construct in a .proto file. */
typedef int pbstream_fieldset_t; /* TODO */
struct pbstream_message_descriptor {
char *name; /* does not include package name or parent message names */
char *full_name;
int num_seen_fields; /* fields we have to track "seen" information for */
DEFINE_DYNARRAY(fields, struct pbstream_field_descriptor);
DEFINE_DYNARRAY(messages, struct pbstream_message_descriptor);
DEFINE_DYNARRAY(enums, struct pbstream_enum_descriptor);
pbstream_fieldset_t fieldset;
};
/* Callback for when an error occurred.
@ -144,47 +104,37 @@ struct pbstream_message_descriptor {
* parsing cannot continue. */
typedef enum pbstream_status {
PBSTREAM_STATUS_OK = 0,
PBSTREAM_STATUS_INCOMPLETE = 1, /* buffer ended in the middle of a field */
PBSTREAM_STATUS_SUBMESSAGE_END = 1,
/** FATAL ERRORS: these indicate corruption, and cannot be recovered. */
// A varint did not terminate before hitting 64 bits.
PBSTREAM_ERROR_UNTERMINATED_VARINT,
PBSTREAM_ERROR_UNTERMINATED_VARINT = -1,
// A submessage ended in the middle of data.
PBSTREAM_ERROR_BAD_SUBMESSAGE_END,
PBSTREAM_ERROR_BAD_SUBMESSAGE_END = -2,
// Encountered a "group" on the wire (deprecated and unsupported).
PBSTREAM_ERROR_GROUP,
PBSTREAM_ERROR_GROUP = -3,
/** NONFATAL ERRORS: the input was invalid, but we can continue if desired. */
// A field marked "required" was not present. */
PBSTREAM_ERROR_MISSING_REQUIRED_FIELD,
// An optional or required field appeared more than once.
PBSTREAM_ERROR_DUPLICATE_FIELD,
// A value was encountered that was not defined in the .proto file.
PBSTREAM_ERROR_UNKNOWN_VALUE = 2,
// A field was encoded with the wrong wire type.
PBSTREAM_ERROR_MISMATCHED_TYPE,
PBSTREAM_ERROR_MISMATCHED_TYPE = 3,
} pbstream_status_t;
struct pbstream_parse_state;
typedef void (*pbstream_error_callback_t)(struct pbstream_parse_state *s,
pbstream_status_t error);
struct pbstream_parse_stack_frame {
struct pbstream_message_descriptor *message_descriptor;
int end_offset; /* unknown for the top frame, so we set to INT_MAX */
/* Tracks whether we've seen non-repeated fields. */
DEFINE_DYNARRAY(seen_fields, bool);
};
/* The stream parser's state. */
struct pbstream_parse_state {
pbstream_error_callback_t error_callback;
size_t offset;
bool ignore_nonfatal_errors;
void *user_data;
DEFINE_DYNARRAY(stack, struct pbstream_parse_stack_frame);
};

Loading…
Cancel
Save