NordicSemiconductor / zcbor

Low footprint C/C++ CBOR library and Python tool providing code generation from CDDL descriptions.
Apache License 2.0
105 stars 34 forks source link

Can not use .size n on bytestrings #349

Closed jnz86 closed 6 months ago

jnz86 commented 11 months ago

I know that a couple of my bytestrings will be of specific size. So I used .size n on them which should be allowed, but there is an error with the generated code getting the structure members wrong.

CDDL:

test = {
    some_label,
}
some_label = ("s" : bstr .size 12)

Generated types file:

struct some_label_s {

    struct zcbor_string s;

};

struct test {

    struct some_label_s some_label_m;

};

Generated decode:

static bool encode_test(zcbor_state_t *state, const struct test *input)
{
    zcbor_print("%s\r\n", __func__);

    bool tmp_result = (((zcbor_map_start_encode(state, 1) && (((((((((*input).some_label_m.len >= 12)
    && ((*input).some_label_m.len <= 12)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false))) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false))
    && (encode_some_label_s(state, (&(*input).some_label_m))))) || (zcbor_list_map_end_force_encode(state), false)) && zcbor_map_end_encode(state, 1))));

    if (!tmp_result)
        zcbor_trace();

    return tmp_result;
}

Result:

error: 'const struct some_label_s' has no member named 'len' [build]   449 

It's not wrong. some_label_m is of some_label_s type and not struct zcbor_string type directly, so it does not have a len member. It's like it was supposed to be some_label_m.s.len

jnz86 commented 6 months ago

Is it ever going to be possible to use .size on byte strings? It's been some time since 0.7.0 came out... Any movement towards 0.8.0?

oyvindronningstad commented 6 months ago

Thanks for the report, apologies for the delay. This is a bug, and should be fixed in #375. Feel free to test and leave a review.

jnz86 commented 5 months ago

Confirmed working.

However... for CDDL:

    nonce : "n" => bstr .size 12,

I think this is could be slightly better optimized to not be two conditionals that oddly check the size.

...
    && (((zcbor_tstr_expect(state, ((tmp_str.value = (uint8_t *)"n", tmp_str.len = sizeof("n") - 1, &tmp_str)))))
    && (zcbor_bstr_decode(state, (&(*result).nonce)))
    && ((((*result).nonce.len >= 12)
    && ((*result).nonce.len <= 12)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false)))) || (zcbor_list_map_end_force_decode(state), false)) && zcbor_map_end_decode(state))));
...

This does get to len == 12 but with steps.