|
|
|
@ -76,7 +76,9 @@ static size_t upb_roundup_pow2(size_t bytes) { |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
UPB_NORETURN static void encode_err(upb_encstate* e) { UPB_LONGJMP(e->err, 1); } |
|
|
|
|
UPB_NORETURN static void encode_err(upb_encstate* e, upb_EncodeStatus s) { |
|
|
|
|
UPB_LONGJMP(e->err, s); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
UPB_NOINLINE |
|
|
|
|
static void encode_growbuffer(upb_encstate* e, size_t bytes) { |
|
|
|
@ -84,7 +86,7 @@ static void encode_growbuffer(upb_encstate* e, size_t bytes) { |
|
|
|
|
size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); |
|
|
|
|
char* new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size); |
|
|
|
|
|
|
|
|
|
if (!new_buf) encode_err(e); |
|
|
|
|
if (!new_buf) encode_err(e, kUpb_EncodeStatus_OutOfMemory); |
|
|
|
|
|
|
|
|
|
/* We want previous data at the end, realloc() put it at the beginning. */ |
|
|
|
|
if (old_size > 0) { |
|
|
|
@ -255,7 +257,7 @@ static void encode_scalar(upb_encstate* e, const void* _field_mem, |
|
|
|
|
if (submsg == NULL) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (--e->depth == 0) encode_err(e); |
|
|
|
|
if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); |
|
|
|
|
encode_tag(e, f->number, kUpb_WireType_EndGroup); |
|
|
|
|
encode_message(e, submsg, subm, &size); |
|
|
|
|
wire_type = kUpb_WireType_StartGroup; |
|
|
|
@ -269,7 +271,7 @@ static void encode_scalar(upb_encstate* e, const void* _field_mem, |
|
|
|
|
if (submsg == NULL) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (--e->depth == 0) encode_err(e); |
|
|
|
|
if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); |
|
|
|
|
encode_message(e, submsg, subm, &size); |
|
|
|
|
encode_varint(e, size); |
|
|
|
|
wire_type = kUpb_WireType_Delimited; |
|
|
|
@ -355,7 +357,7 @@ static void encode_array(upb_encstate* e, const upb_Message* msg, |
|
|
|
|
const void* const* start = _upb_array_constptr(arr); |
|
|
|
|
const void* const* ptr = start + arr->len; |
|
|
|
|
const upb_MiniTable* subm = subs[f->submsg_index].submsg; |
|
|
|
|
if (--e->depth == 0) encode_err(e); |
|
|
|
|
if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); |
|
|
|
|
do { |
|
|
|
|
size_t size; |
|
|
|
|
ptr--; |
|
|
|
@ -370,7 +372,7 @@ static void encode_array(upb_encstate* e, const upb_Message* msg, |
|
|
|
|
const void* const* start = _upb_array_constptr(arr); |
|
|
|
|
const void* const* ptr = start + arr->len; |
|
|
|
|
const upb_MiniTable* subm = subs[f->submsg_index].submsg; |
|
|
|
|
if (--e->depth == 0) encode_err(e); |
|
|
|
|
if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); |
|
|
|
|
do { |
|
|
|
|
size_t size; |
|
|
|
|
ptr--; |
|
|
|
@ -413,7 +415,7 @@ static void encode_map(upb_encstate* e, const upb_Message* msg, |
|
|
|
|
|
|
|
|
|
if (map == NULL) return; |
|
|
|
|
|
|
|
|
|
if (e->options & kUpb_Encode_Deterministic) { |
|
|
|
|
if (e->options & kUpb_EncodeOption_Deterministic) { |
|
|
|
|
_upb_sortedmap sorted; |
|
|
|
|
_upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map, |
|
|
|
|
&sorted); |
|
|
|
@ -520,16 +522,16 @@ static void encode_message(upb_encstate* e, const upb_Message* msg, |
|
|
|
|
const upb_MiniTable* m, size_t* size) { |
|
|
|
|
size_t pre_len = e->limit - e->ptr; |
|
|
|
|
|
|
|
|
|
if ((e->options & kUpb_Encode_CheckRequired) && m->required_count) { |
|
|
|
|
if ((e->options & kUpb_EncodeOption_CheckRequired) && m->required_count) { |
|
|
|
|
uint64_t msg_head; |
|
|
|
|
memcpy(&msg_head, msg, 8); |
|
|
|
|
msg_head = _upb_BigEndian_Swap64(msg_head); |
|
|
|
|
if (upb_MiniTable_requiredmask(m) & ~msg_head) { |
|
|
|
|
encode_err(e); |
|
|
|
|
encode_err(e, kUpb_EncodeStatus_MissingRequired); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ((e->options & kUpb_Encode_SkipUnknown) == 0) { |
|
|
|
|
if ((e->options & kUpb_EncodeOption_SkipUnknown) == 0) { |
|
|
|
|
size_t unknown_size; |
|
|
|
|
const char* unknown = upb_Message_GetUnknown(msg, &unknown_size); |
|
|
|
|
|
|
|
|
@ -570,8 +572,9 @@ static void encode_message(upb_encstate* e, const upb_Message* msg, |
|
|
|
|
*size = (e->limit - e->ptr) - pre_len; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, |
|
|
|
|
upb_Arena* arena, size_t* size) { |
|
|
|
|
upb_EncodeStatus upb_Encode(const void* msg, const upb_MiniTable* l, |
|
|
|
|
int options, upb_Arena* arena, char** buf, |
|
|
|
|
size_t* size) { |
|
|
|
|
upb_encstate e; |
|
|
|
|
unsigned depth = (unsigned)options >> 16; |
|
|
|
|
|
|
|
|
@ -582,23 +585,28 @@ char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, |
|
|
|
|
e.depth = depth ? depth : 64; |
|
|
|
|
e.options = options; |
|
|
|
|
_upb_mapsorter_init(&e.sorter); |
|
|
|
|
char* ret = NULL; |
|
|
|
|
|
|
|
|
|
if (UPB_SETJMP(e.err)) { |
|
|
|
|
*size = 0; |
|
|
|
|
ret = NULL; |
|
|
|
|
} else { |
|
|
|
|
upb_EncodeStatus status = UPB_SETJMP(e.err); |
|
|
|
|
|
|
|
|
|
// Unfortunately we must continue to perform hackery here because there are
|
|
|
|
|
// code paths which blindly copy the returned pointer without bothering to
|
|
|
|
|
// check for errors until much later (b/235839510). So we still set *buf to
|
|
|
|
|
// NULL on error and we still set it to non-NULL on a successful empty result.
|
|
|
|
|
if (status == kUpb_EncodeStatus_Ok) { |
|
|
|
|
encode_message(&e, msg, l, size); |
|
|
|
|
*size = e.limit - e.ptr; |
|
|
|
|
if (*size == 0) { |
|
|
|
|
static char ch; |
|
|
|
|
ret = &ch; |
|
|
|
|
*buf = &ch; |
|
|
|
|
} else { |
|
|
|
|
UPB_ASSERT(e.ptr); |
|
|
|
|
ret = e.ptr; |
|
|
|
|
*buf = e.ptr; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
*buf = NULL; |
|
|
|
|
*size = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_upb_mapsorter_destroy(&e.sorter); |
|
|
|
|
return ret; |
|
|
|
|
return status; |
|
|
|
|
} |
|
|
|
|