Ported more cases of wire format parsing to upb_WireReader.

PiperOrigin-RevId: 498502557
pull/13171/head
Joshua Haberman 2 years ago committed by Copybara-Service
parent a9f9bfea75
commit 7cd8f6c940
  1. 1
      BUILD
  2. 2
      python/BUILD
  3. 169
      python/unknown_fields.c
  4. 4
      upb/message/accessors.c
  5. 3
      upb/util/BUILD
  6. 61
      upb/util/compare.c
  7. 31
      upb/wire/decode.c
  8. 18
      upb/wire/eps_copy_input_stream.h
  9. 8
      upb/wire/reader.c
  10. 44
      upb/wire/reader.h

@ -951,6 +951,7 @@ cc_library(
":message_internal",
":mini_table_internal",
":port",
":wire_reader",
":wire_types",
"@utf8_range",
],

@ -221,12 +221,14 @@ py_extension(
deps = [
"//:collections",
"//:descriptor_upb_proto_reflection",
"//:eps_copy_input_stream",
"//:hash",
"//:port",
"//:reflection",
"//:textformat",
"//:upb",
"//:wire",
"//:wire_reader",
"//:wire_types",
"//upb/util:compare",
"//upb/util:def_to_proto",

@ -29,21 +29,10 @@
#include "python/message.h"
#include "python/protobuf.h"
#include "upb/wire/eps_copy_input_stream.h"
#include "upb/wire/reader.h"
#include "upb/wire/types.h"
static const char* PyUpb_DecodeVarint(const char* ptr, const char* end,
uint64_t* val) {
*val = 0;
for (int i = 0; ptr < end && i < 10; i++, ptr++) {
uint64_t byte = (uint8_t)*ptr;
*val |= (byte & 0x7f) << (i * 7);
if ((byte & 0x80) == 0) {
return ptr + 1;
}
}
return NULL;
}
// -----------------------------------------------------------------------------
// UnknownFieldSet
// -----------------------------------------------------------------------------
@ -66,60 +55,6 @@ PyUpb_UnknownFieldSet* PyUpb_UnknownFieldSet_NewBare(void) {
return self;
}
// Generic functions to skip a value or group.
static const char* PyUpb_UnknownFieldSet_SkipGroup(const char* ptr,
const char* end,
int group_number);
static const char* PyUpb_UnknownFieldSet_SkipField(const char* ptr,
const char* end,
uint32_t tag) {
int field_number = tag >> 3;
int wire_type = tag & 7;
switch (wire_type) {
case kUpb_WireType_Varint: {
uint64_t val;
return PyUpb_DecodeVarint(ptr, end, &val);
}
case kUpb_WireType_64Bit:
if (end - ptr < 8) return NULL;
return ptr + 8;
case kUpb_WireType_32Bit:
if (end - ptr < 4) return NULL;
return ptr + 4;
case kUpb_WireType_Delimited: {
uint64_t size;
ptr = PyUpb_DecodeVarint(ptr, end, &size);
if (!ptr || end - ptr < size) return NULL;
return ptr + size;
}
case kUpb_WireType_StartGroup:
return PyUpb_UnknownFieldSet_SkipGroup(ptr, end, field_number);
case kUpb_WireType_EndGroup:
return NULL;
default:
assert(0);
return NULL;
}
}
static const char* PyUpb_UnknownFieldSet_SkipGroup(const char* ptr,
const char* end,
int group_number) {
uint32_t end_tag = (group_number << 3) | kUpb_WireType_EndGroup;
while (true) {
if (ptr == end) return NULL;
uint64_t tag;
ptr = PyUpb_DecodeVarint(ptr, end, &tag);
if (!ptr) return NULL;
if (tag == end_tag) return ptr;
ptr = PyUpb_UnknownFieldSet_SkipField(ptr, end, tag);
if (!ptr) return NULL;
}
return ptr;
}
// For MessageSet the established behavior is for UnknownFieldSet to interpret
// the MessageSet wire format:
// message MessageSet {
@ -143,40 +78,43 @@ enum {
};
static const char* PyUpb_UnknownFieldSet_BuildMessageSetItem(
PyUpb_UnknownFieldSet* self, const char* ptr, const char* end) {
PyUpb_UnknownFieldSet* self, upb_EpsCopyInputStream* stream,
const char* ptr) {
PyUpb_ModuleState* s = PyUpb_ModuleState_Get();
int type_id = 0;
PyObject* msg = NULL;
while (true) {
if (ptr == end) goto err;
uint64_t tag;
ptr = PyUpb_DecodeVarint(ptr, end, &tag);
while (!upb_EpsCopyInputStream_IsDone(stream, &ptr)) {
uint32_t tag;
ptr = upb_WireReader_ReadTag(ptr, &tag);
if (!ptr) goto err;
switch (tag) {
case kUpb_MessageSet_EndItemTag:
goto done;
case kUpb_MessageSet_TypeIdTag: {
uint64_t tmp;
ptr = PyUpb_DecodeVarint(ptr, end, &tmp);
ptr = upb_WireReader_ReadVarint(ptr, &tmp);
if (!ptr) goto err;
if (!type_id) type_id = tmp;
break;
}
case kUpb_MessageSet_MessageTag: {
uint64_t size;
ptr = PyUpb_DecodeVarint(ptr, end, &size);
if (!ptr || end - ptr < size) goto err;
int size;
ptr = upb_WireReader_ReadSize(ptr, &size);
if (!upb_EpsCopyInputStream_CheckDataSizeAvailable(stream, ptr, size)) {
goto err;
}
const char* str = ptr;
ptr = upb_EpsCopyInputStream_ReadStringAliased(stream, &str, size);
if (!msg) {
msg = PyBytes_FromStringAndSize(ptr, size);
msg = PyBytes_FromStringAndSize(str, size);
if (!msg) goto err;
} else {
// already saw a message here so deliberately skipping the duplicate
}
ptr += size;
break;
}
default:
ptr = PyUpb_UnknownFieldSet_SkipField(ptr, end, tag);
ptr = upb_WireReader_SkipValue(ptr, tag, stream);
if (!ptr) goto err;
}
}
@ -198,19 +136,21 @@ err:
}
static const char* PyUpb_UnknownFieldSet_BuildMessageSet(
PyUpb_UnknownFieldSet* self, const char* ptr, const char* end) {
PyUpb_UnknownFieldSet* self, upb_EpsCopyInputStream* stream,
const char* ptr) {
self->fields = PyList_New(0);
while (ptr < end) {
uint64_t tag;
ptr = PyUpb_DecodeVarint(ptr, end, &tag);
while (!upb_EpsCopyInputStream_IsDone(stream, &ptr)) {
uint32_t tag;
ptr = upb_WireReader_ReadTag(ptr, &tag);
if (!ptr) goto err;
if (tag == kUpb_MessageSet_StartItemTag) {
ptr = PyUpb_UnknownFieldSet_BuildMessageSetItem(self, ptr, end);
ptr = PyUpb_UnknownFieldSet_BuildMessageSetItem(self, stream, ptr);
} else {
ptr = PyUpb_UnknownFieldSet_SkipField(ptr, end, tag);
ptr = upb_WireReader_SkipValue(ptr, tag, stream);
}
if (!ptr) goto err;
}
if (upb_EpsCopyInputStream_IsError(stream)) goto err;
return ptr;
err:
@ -220,46 +160,50 @@ err:
}
static const char* PyUpb_UnknownFieldSet_Build(PyUpb_UnknownFieldSet* self,
const char* ptr, const char* end,
upb_EpsCopyInputStream* stream,
const char* ptr,
int group_number);
static const char* PyUpb_UnknownFieldSet_BuildValue(
PyUpb_UnknownFieldSet* self, const char* ptr, const char* end,
int field_number, int wire_type, int group_number, PyObject** data) {
PyUpb_UnknownFieldSet* self, upb_EpsCopyInputStream* stream,
const char* ptr, int field_number, int wire_type, int group_number,
PyObject** data) {
switch (wire_type) {
case kUpb_WireType_Varint: {
uint64_t val;
ptr = PyUpb_DecodeVarint(ptr, end, &val);
ptr = upb_WireReader_ReadVarint(ptr, &val);
if (!ptr) return NULL;
*data = PyLong_FromUnsignedLongLong(val);
return ptr;
}
case kUpb_WireType_64Bit: {
if (end - ptr < 8) return NULL;
uint64_t val;
memcpy(&val, ptr, 8);
ptr = upb_WireReader_ReadFixed64(ptr, &val);
*data = PyLong_FromUnsignedLongLong(val);
return ptr + 8;
return ptr;
}
case kUpb_WireType_32Bit: {
if (end - ptr < 4) return NULL;
uint32_t val;
memcpy(&val, ptr, 4);
ptr = upb_WireReader_ReadFixed32(ptr, &val);
*data = PyLong_FromUnsignedLongLong(val);
return ptr + 4;
return ptr;
}
case kUpb_WireType_Delimited: {
uint64_t size;
ptr = PyUpb_DecodeVarint(ptr, end, &size);
if (!ptr || end - ptr < size) return NULL;
*data = PyBytes_FromStringAndSize(ptr, size);
return ptr + size;
int size;
ptr = upb_WireReader_ReadSize(ptr, &size);
if (!upb_EpsCopyInputStream_CheckDataSizeAvailable(stream, ptr, size)) {
return NULL;
}
const char* str = ptr;
ptr = upb_EpsCopyInputStream_ReadStringAliased(stream, &str, size);
*data = PyBytes_FromStringAndSize(str, size);
return ptr;
}
case kUpb_WireType_StartGroup: {
PyUpb_UnknownFieldSet* sub = PyUpb_UnknownFieldSet_NewBare();
if (!sub) return NULL;
*data = &sub->ob_base;
return PyUpb_UnknownFieldSet_Build(sub, ptr, end, field_number);
return PyUpb_UnknownFieldSet_Build(sub, stream, ptr, field_number);
}
default:
assert(0);
@ -271,22 +215,23 @@ static const char* PyUpb_UnknownFieldSet_BuildValue(
// For non-MessageSet we just build the unknown fields exactly as they exist on
// the wire.
static const char* PyUpb_UnknownFieldSet_Build(PyUpb_UnknownFieldSet* self,
const char* ptr, const char* end,
upb_EpsCopyInputStream* stream,
const char* ptr,
int group_number) {
PyUpb_ModuleState* s = PyUpb_ModuleState_Get();
self->fields = PyList_New(0);
while (ptr < end) {
uint64_t tag;
ptr = PyUpb_DecodeVarint(ptr, end, &tag);
while (!upb_EpsCopyInputStream_IsDone(stream, &ptr)) {
uint32_t tag;
ptr = upb_WireReader_ReadTag(ptr, &tag);
if (!ptr) goto err;
PyObject* data = NULL;
int field_number = tag >> 3;
int wire_type = tag & 7;
int field_number = upb_WireReader_GetFieldNumber(tag);
int wire_type = upb_WireReader_GetWireType(tag);
if (wire_type == kUpb_WireType_EndGroup) {
if (field_number != group_number) return NULL;
return ptr;
}
ptr = PyUpb_UnknownFieldSet_BuildValue(self, ptr, end, field_number,
ptr = PyUpb_UnknownFieldSet_BuildValue(self, stream, ptr, field_number,
wire_type, group_number, &data);
if (!ptr) {
Py_XDECREF(data);
@ -298,6 +243,7 @@ static const char* PyUpb_UnknownFieldSet_Build(PyUpb_UnknownFieldSet* self,
PyList_Append(self->fields, field);
Py_DECREF(field);
}
if (upb_EpsCopyInputStream_IsError(stream)) goto err;
return ptr;
err:
@ -324,14 +270,15 @@ static PyObject* PyUpb_UnknownFieldSet_New(PyTypeObject* type, PyObject* args,
const char* ptr = upb_Message_GetUnknown(msg, &size);
if (size == 0) return &self->ob_base;
const char* end = ptr + size;
upb_EpsCopyInputStream stream;
upb_EpsCopyInputStream_Init(&stream, &ptr, size, true);
const upb_MessageDef* msgdef = PyUpb_Message_GetMsgdef(py_msg);
bool ok;
if (upb_MessageDef_IsMessageSet(msgdef)) {
ok = PyUpb_UnknownFieldSet_BuildMessageSet(self, ptr, end) == end;
ok = PyUpb_UnknownFieldSet_BuildMessageSet(self, &stream, ptr) != NULL;
} else {
ok = PyUpb_UnknownFieldSet_Build(self, ptr, end, -1) == end;
ok = PyUpb_UnknownFieldSet_Build(self, &stream, ptr, -1) != NULL;
}
if (!ok) {

@ -169,14 +169,14 @@ upb_FindUnknownRet upb_MiniTable_FindUnknown(const upb_Message* msg,
if (field_number == upb_WireReader_GetFieldNumber(tag)) {
ret.status = kUpb_FindUnknown_Ok;
ret.ptr = upb_EpsCopyInputStream_GetAliasedPtr(&stream, unknown_begin);
ptr = upb_WireReader_SkipValue(ptr, tag, depth_limit, &stream);
ptr = _upb_WireReader_SkipValue(ptr, tag, depth_limit, &stream);
// Because we know that the input is a flat buffer, it is safe to perform
// pointer arithmetic on aliased pointers.
ret.len = upb_EpsCopyInputStream_GetAliasedPtr(&stream, ptr) - ret.ptr;
return ret;
}
ptr = upb_WireReader_SkipValue(ptr, tag, depth_limit, &stream);
ptr = _upb_WireReader_SkipValue(ptr, tag, depth_limit, &stream);
if (!ptr) return upb_FindUnknownRet_ParseError();
}
ret.status = kUpb_FindUnknown_NotPresent;

@ -107,9 +107,10 @@ cc_library(
hdrs = ["compare.h"],
visibility = ["//visibility:public"],
deps = [
"//:eps_copy_input_stream",
"//:port",
"//:reflection",
"//:wire",
"//:wire_reader",
"//:wire_types",
],
)

@ -27,6 +27,8 @@
#include "upb/util/compare.h"
#include "upb/wire/eps_copy_input_stream.h"
#include "upb/wire/reader.h"
#include "upb/wire/types.h"
// Must be last.
@ -53,7 +55,7 @@ struct upb_UnknownFields {
};
typedef struct {
const char* end;
upb_EpsCopyInputStream stream;
upb_Arena* arena;
upb_UnknownField* tmp;
size_t tmp_size;
@ -76,25 +78,6 @@ static void upb_UnknownFields_Grow(upb_UnknownField_Context* ctx,
*end = *base + new;
}
static const char* upb_UnknownFields_ParseVarint(const char* ptr,
const char* limit,
uint64_t* val) {
uint8_t byte;
int bitpos = 0;
*val = 0;
do {
// Unknown field data must be valid.
UPB_ASSERT(bitpos < 70 && ptr < limit);
byte = *ptr;
*val |= (uint64_t)(byte & 0x7F) << bitpos;
ptr++;
bitpos += 7;
} while (byte & 0x80);
return ptr;
}
// We have to implement our own sort here, since qsort() is not an in-order
// sort. Here we use merge sort, the simplest in-order sort.
static void upb_UnknownFields_Merge(upb_UnknownField* arr, size_t start,
@ -151,11 +134,11 @@ static upb_UnknownFields* upb_UnknownFields_DoBuild(
const char* ptr = *buf;
uint32_t last_tag = 0;
bool sorted = true;
while (ptr < ctx->end) {
uint64_t tag;
ptr = upb_UnknownFields_ParseVarint(ptr, ctx->end, &tag);
while (!upb_EpsCopyInputStream_IsDone(&ctx->stream, &ptr)) {
uint32_t tag;
ptr = upb_WireReader_ReadTag(ptr, &tag);
UPB_ASSERT(tag <= UINT32_MAX);
int wire_type = tag & 7;
int wire_type = upb_WireReader_GetWireType(tag);
if (wire_type == kUpb_WireType_EndGroup) break;
if (tag < last_tag) sorted = false;
last_tag = tag;
@ -169,25 +152,22 @@ static upb_UnknownFields* upb_UnknownFields_DoBuild(
switch (wire_type) {
case kUpb_WireType_Varint:
ptr = upb_UnknownFields_ParseVarint(ptr, ctx->end, &field->data.varint);
ptr = upb_WireReader_ReadVarint(ptr, &field->data.varint);
break;
case kUpb_WireType_64Bit:
UPB_ASSERT(ctx->end - ptr >= 8);
memcpy(&field->data.uint64, ptr, 8);
ptr += 8;
ptr = upb_WireReader_ReadFixed64(ptr, &field->data.uint64);
break;
case kUpb_WireType_32Bit:
UPB_ASSERT(ctx->end - ptr >= 4);
memcpy(&field->data.uint32, ptr, 4);
ptr += 4;
ptr = upb_WireReader_ReadFixed32(ptr, &field->data.uint32);
break;
case kUpb_WireType_Delimited: {
uint64_t size;
ptr = upb_UnknownFields_ParseVarint(ptr, ctx->end, &size);
UPB_ASSERT(ctx->end - ptr >= size);
field->data.delimited.data = ptr;
int size;
ptr = upb_WireReader_ReadSize(ptr, &size);
const char* s_ptr = ptr;
ptr = upb_EpsCopyInputStream_ReadStringAliased(&ctx->stream, &s_ptr,
size);
field->data.delimited.data = s_ptr;
field->data.delimited.size = size;
ptr += size;
break;
}
case kUpb_WireType_StartGroup:
@ -216,11 +196,12 @@ static upb_UnknownFields* upb_UnknownFields_DoBuild(
// Builds a upb_UnknownFields data structure from the binary data in buf.
static upb_UnknownFields* upb_UnknownFields_Build(upb_UnknownField_Context* ctx,
const char* buf,
const char* ptr,
size_t size) {
ctx->end = buf + size;
upb_UnknownFields* fields = upb_UnknownFields_DoBuild(ctx, &buf);
UPB_ASSERT(buf == ctx->end);
upb_EpsCopyInputStream_Init(&ctx->stream, &ptr, size, true);
upb_UnknownFields* fields = upb_UnknownFields_DoBuild(ctx, &ptr);
UPB_ASSERT(upb_EpsCopyInputStream_IsDone(&ctx->stream, &ptr) &&
!upb_EpsCopyInputStream_IsError(&ctx->stream));
return fields;
}

@ -35,6 +35,7 @@
#include "upb/wire/common_internal.h"
#include "upb/wire/decode_internal.h"
#include "upb/wire/eps_copy_input_stream.h"
#include "upb/wire/reader.h"
#include "upb/wire/swap_internal.h"
#include "upb/wire/types.h"
@ -370,27 +371,21 @@ static const char* _upb_Decoder_DecodeFixedPacked(
// Note: if/when the decoder supports multi-buffer input, we will need to
// handle buffer seams here.
if (_upb_IsLittleEndian()) {
memcpy(mem, ptr, val->size);
ptr += val->size;
ptr = upb_EpsCopyInputStream_Copy(&d->input, ptr, mem, val->size);
} else {
const char* end = ptr + val->size;
int delta = upb_EpsCopyInputStream_PushLimit(&d->input, ptr, val->size);
char* dst = mem;
while (ptr < end) {
while (!_upb_Decoder_IsDone(d, &ptr)) {
if (lg2 == 2) {
uint32_t val;
memcpy(&val, ptr, sizeof(val));
val = _upb_BigEndian_Swap32(val);
memcpy(dst, &val, sizeof(val));
ptr = upb_WireReader_ReadFixed32(ptr, dst);
dst += 4;
} else {
UPB_ASSERT(lg2 == 3);
uint64_t val;
memcpy(&val, ptr, sizeof(val));
val = _upb_BigEndian_Swap64(val);
memcpy(dst, &val, sizeof(val));
ptr = upb_WireReader_ReadFixed64(ptr, dst);
dst += 8;
}
ptr += 1 << lg2;
dst += 1 << lg2;
}
upb_EpsCopyInputStream_PopLimit(&d->input, ptr, delta);
}
return ptr;
@ -1027,21 +1022,17 @@ static const char* _upb_Decoder_DecodeWireValue(upb_Decoder* d, const char* ptr,
_upb_Decoder_Munge(field->descriptortype, val);
return ptr;
case kUpb_WireType_32Bit:
memcpy(&val->uint32_val, ptr, 4);
val->uint32_val = _upb_BigEndian_Swap32(val->uint32_val);
*op = kUpb_DecodeOp_Scalar4Byte;
if (((1 << field->descriptortype) & kFixed32OkMask) == 0) {
*op = kUpb_DecodeOp_UnknownField;
}
return ptr + 4;
return upb_WireReader_ReadFixed32(ptr, &val->uint32_val);
case kUpb_WireType_64Bit:
memcpy(&val->uint64_val, ptr, 8);
val->uint64_val = _upb_BigEndian_Swap64(val->uint64_val);
*op = kUpb_DecodeOp_Scalar8Byte;
if (((1 << field->descriptortype) & kFixed64OkMask) == 0) {
*op = kUpb_DecodeOp_UnknownField;
}
return ptr + 8;
return upb_WireReader_ReadFixed64(ptr, &val->uint64_val);
case kUpb_WireType_Delimited:
ptr = upb_Decoder_DecodeSize(d, ptr, &val->size);
*op = _upb_Decoder_GetDelimitedOp(mt, field);

@ -281,14 +281,24 @@ UPB_INLINE const char* upb_EpsCopyInputStream_ReadStringAliased(
return ret;
}
// Skips `size` bytes of string data from the input and returns a pointer past
// the end. Returns NULL on end of stream or error.
// Skips `size` bytes of data from the input and returns a pointer past the end.
// Returns NULL on end of stream or error.
UPB_INLINE const char* upb_EpsCopyInputStream_Skip(upb_EpsCopyInputStream* e,
const char* ptr, int size) {
if (!upb_EpsCopyInputStream_CheckDataSizeAvailable(e, ptr, size)) return NULL;
return ptr + size;
}
// Copies `size` bytes of data from the input `ptr` into the buffer `to`, and
// returns a pointer past the end. Returns NULL on end of stream or error.
UPB_INLINE const char* upb_EpsCopyInputStream_Copy(upb_EpsCopyInputStream* e,
const char* ptr, void* to,
int size) {
if (!upb_EpsCopyInputStream_CheckDataSizeAvailable(e, ptr, size)) return NULL;
memcpy(to, ptr, size);
return ptr + size;
}
// Reads string data from the stream and advances the pointer accordingly.
// If aliasing was enabled when the stream was initialized, then the returned
// pointer will point into the input buffer if possible, otherwise new data
@ -309,10 +319,8 @@ UPB_INLINE const char* upb_EpsCopyInputStream_ReadString(
UPB_ASSERT(arena);
char* data = (char*)upb_Arena_Malloc(arena, size);
if (!data) return NULL;
memcpy(data, *ptr, size);
const char* ret = *ptr + size;
const char* ret = upb_EpsCopyInputStream_Copy(e, *ptr, data, size);
*ptr = data;
UPB_ASSUME(ret != NULL);
return ret;
}
}

@ -50,9 +50,9 @@ _upb_WireReader_ReadLongVarint(const char* ptr, uint64_t val) {
return ret;
}
const char* upb_WireReader_SkipGroup(const char* ptr, uint32_t tag,
int depth_limit,
upb_EpsCopyInputStream* stream) {
const char* _upb_WireReader_SkipGroup(const char* ptr, uint32_t tag,
int depth_limit,
upb_EpsCopyInputStream* stream) {
if (--depth_limit == 0) return NULL;
uint32_t end_group_tag = (tag & ~7ULL) | kUpb_WireType_EndGroup;
while (!upb_EpsCopyInputStream_IsDone(stream, &ptr)) {
@ -60,7 +60,7 @@ const char* upb_WireReader_SkipGroup(const char* ptr, uint32_t tag,
ptr = upb_WireReader_ReadTag(ptr, &tag);
if (!ptr) return NULL;
if (tag == end_group_tag) return ptr;
ptr = upb_WireReader_SkipValue(ptr, tag, depth_limit, stream);
ptr = _upb_WireReader_SkipValue(ptr, tag, depth_limit, stream);
if (!ptr) return NULL;
}
return ptr;

@ -157,26 +157,25 @@ UPB_INLINE const char* upb_WireReader_ReadFixed64(const char* ptr, void* val) {
return ptr + 8;
}
const char* _upb_WireReader_SkipGroup(const char* ptr, uint32_t tag,
int depth_limit,
upb_EpsCopyInputStream* stream);
// Skips data for a group, returning a pointer past the end of the group, or
// NULL if there was an error parsing the group. The `tag` argument should be
// the start group tag that begins the group. The `depth_limit` argument
// indicates how many levels of recursion the group is allowed to have before
// reporting a parse error (this limit exists to protect against stack
// overflow).
const char* upb_WireReader_SkipGroup(const char* ptr, uint32_t tag,
int depth_limit,
upb_EpsCopyInputStream* stream);
// Skips data for a wire value of any type, returning a pointer past the end of
// the data, or NULL if there was an error parsing the group. The `tag` argument
// should be the tag that was just parsed. The `depth_limit` argument indicates
// how many levels of recursion a group is allowed to have before reporting a
// parse error (this limit exists to protect against stack overflow).
//
// REQUIRES: there must be at least 10 bytes of data available at `ptr`.
// Bounds checks must be performed before calling this function, preferably
// by calling upb_EpsCopyInputStream_IsDone().
UPB_INLINE const char* upb_WireReader_SkipValue(
// TODO: evaluate how the depth_limit should be specified. Do users need
// control over this?
UPB_INLINE const char* upb_WireReader_SkipGroup(
const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) {
return _upb_WireReader_SkipGroup(ptr, tag, 100, stream);
}
UPB_INLINE const char* _upb_WireReader_SkipValue(
const char* ptr, uint32_t tag, int depth_limit,
upb_EpsCopyInputStream* stream) {
switch (upb_WireReader_GetWireType(tag)) {
@ -194,7 +193,7 @@ UPB_INLINE const char* upb_WireReader_SkipValue(
return ptr;
}
case kUpb_WireType_StartGroup:
return upb_WireReader_SkipGroup(ptr, tag, depth_limit, stream);
return _upb_WireReader_SkipGroup(ptr, tag, depth_limit, stream);
case kUpb_WireType_EndGroup:
return NULL; // Should be handled before now.
default:
@ -202,6 +201,23 @@ UPB_INLINE const char* upb_WireReader_SkipValue(
}
}
// Skips data for a wire value of any type, returning a pointer past the end of
// the data, or NULL if there was an error parsing the group. The `tag` argument
// should be the tag that was just parsed. The `depth_limit` argument indicates
// how many levels of recursion a group is allowed to have before reporting a
// parse error (this limit exists to protect against stack overflow).
//
// REQUIRES: there must be at least 10 bytes of data available at `ptr`.
// Bounds checks must be performed before calling this function, preferably
// by calling upb_EpsCopyInputStream_IsDone().
//
// TODO: evaluate how the depth_limit should be specified. Do users need
// control over this?
UPB_INLINE const char* upb_WireReader_SkipValue(
const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) {
return _upb_WireReader_SkipValue(ptr, tag, 100, stream);
}
#ifdef __cplusplus
} /* extern "C" */
#endif

Loading…
Cancel
Save