Parser: merge the break-handling code in enter_container()
There was a section of code that was mostly the same, dealing with the
possibility of reading a Break (0xFF) as the next element in a map or
array. The only difference was that preparse_next_value() also
decremented the item count for the current list.
We could have used that, but that would have meant a +1 on the list,
which in turn lowers the number of possible elements from UINT32_MAX-1
to UINT32_MAX-2. Not a big deal, but we can avoid it by just splitting
to a new function and retaining tail-call optimisations.
Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
diff --git a/src/cborparser.c b/src/cborparser.c
index 6410faf..099cdc8 100644
--- a/src/cborparser.c
+++ b/src/cborparser.c
@@ -297,15 +297,9 @@
return CborNoError;
}
-static CborError preparse_next_value(CborValue *it)
+static CborError preparse_next_value_nodecrement(CborValue *it)
{
- if (it->remaining != UINT32_MAX) {
- /* don't decrement the item count if the current item is tag: they don't count */
- if (it->type != CborTagType && !--it->remaining) {
- it->type = CborInvalidType;
- return CborNoError;
- }
- } else if (it->remaining == UINT32_MAX && it->ptr != it->parser->end && *it->ptr == (uint8_t)BreakByte) {
+ if (it->remaining == UINT32_MAX && it->ptr != it->parser->end && *it->ptr == (uint8_t)BreakByte) {
/* end of map or array */
++it->ptr;
it->type = CborInvalidType;
@@ -316,6 +310,18 @@
return preparse_value(it);
}
+static CborError preparse_next_value(CborValue *it)
+{
+ if (it->remaining != UINT32_MAX) {
+ /* don't decrement the item count if the current item is tag: they don't count */
+ if (it->type != CborTagType && --it->remaining == 0) {
+ it->type = CborInvalidType;
+ return CborNoError;
+ }
+ }
+ return preparse_next_value_nodecrement(it);
+}
+
static CborError advance_internal(CborValue *it)
{
uint64_t length;
@@ -578,22 +584,15 @@
*/
CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed)
{
- CborError err;
cbor_assert(cbor_value_is_container(it));
*recursed = *it;
if (it->flags & CborIteratorFlag_UnknownLength) {
recursed->remaining = UINT32_MAX;
++recursed->ptr;
- err = preparse_value(recursed);
- if (err != CborErrorUnexpectedBreak)
- return err;
- /* actually, break was expected here
- * it's just an empty container */
- ++recursed->ptr;
} else {
uint64_t len;
- err = _cbor_value_extract_number(&recursed->ptr, recursed->parser->end, &len);
+ CborError err = _cbor_value_extract_number(&recursed->ptr, recursed->parser->end, &len);
cbor_assert(err == CborNoError);
recursed->remaining = (uint32_t)len;
@@ -611,14 +610,13 @@
}
recursed->remaining *= 2;
}
- if (len != 0)
- return preparse_value(recursed);
+ if (len == 0) {
+ /* the case of the empty container */
+ recursed->type = CborInvalidType;
+ return CborNoError;
+ }
}
-
- /* the case of the empty container */
- recursed->type = CborInvalidType;
- recursed->remaining = 0;
- return CborNoError;
+ return preparse_next_value_nodecrement(recursed);
}
/**