intel/tinycbor

Can not leave or re-enter the container when parsing the SENML-CBOR array

Opened this issue · 2 comments

Hello, I am dealing with a such SENML-CBOR array:

[{0: "/3/0/10", 2: 55}]
It has one item and 2 maps as you can see.

Also this aray may be bigger, for example:
[{0: "/3/0/10", 2: 55}, {0: "/3/0/12", 3: "ResetErrors"}, {0: "/3/0/13", 6: 2889055551}, {0: "/3/0/4", 3: "Reboot"}, {0: "/3/0/9", 2: 100}].

I am trying to run through this array once, check the every first map of every item of the array and then I need to get back to the begining of this array and parse it to the end.
But I have an issue with getting back to the array's begining/start.

Here is my code with yours library've been implemented:

    err = cbor_parser_init(buffer, bufferLen, 0, &parser, &array);    
    if (err != CborNoError)
    {
        LOG_ARG("cbor_parser_init FAILED with error %d", err);
        return -1;
    }

    CborType type = cbor_value_get_type(&array);
    LOG_ARG("type = %x(%d)", type, type);
    if (type == CborArrayType) 
    {
        err = cbor_value_get_array_length(&array, &arrLen);
        if (err != CborNoError)
        {
            LOG_ARG("cbor_value_get_array_length FAILED with error %d", err);
            return -1;
        }
        LOG_ARG("array length = %d", arrLen);
        if (arrLen <= 0) {
            LOG("wrong array length FAILED");
            return -1;
        }
        if (arrLen > 0) 
        {
            sCount = prv_count_s_in_array(&array);
            LOG_ARG("s quantity = %d", sCount);
            LOG_ARG("array remaining = %d", array.remaining);
            /// Here I need to get back to the array.start and parse it "once again"
        }                                    
        
  /*  prv_count_s_in_array brief*/      
 size_t prv_count_s_in_array(CborValue* array) {
    CborValue map;
    CborError err;
    CborValue arrayStart;
    int sCount = 0;

    // Enter the CBOR array
    err = cbor_value_enter_container(array, array);
    if (err != CborNoError)
    {
        LOG_ARG("cbor_value_enter_container array FAILED with error %d", err);
        return -1;
    }

    // Save the starting position of the array
    cbor_value_get_next_byte(&arrayStart);
    arrayStart.parser = array->parser;

    // Iterate through each map in the array
    while (!cbor_value_at_end(array)) 
    {
        LOG("CHECKPOINT 1 -------------------------------------------");
        err = cbor_value_enter_container(array, &map); // Enter each map
        if (err != CborNoError)
        {
            LOG_ARG("cbor_value_enter_container map FAILED with error %d", err);
            return -1;
        }

        while (!cbor_value_at_end(&map)) 
        {
            LOG("CHECKPOINT 2 -------------------------------------------");
                
            // Skip the key
            err = cbor_value_advance(&map);
            if (err != CborNoError) {
                printf("Error advancing to value\n");
                return -1;
            }  
            // Get the value
            CborType typeMap = cbor_value_get_type(&map);
            if (typeMap == CborTextStringType) 
            {
            // If the value is a text string, count the backslashes
            // if (cbor_value_is_text_string(&map)) {
                size_t len;
                char *text;
                
                cbor_value_dup_text_string(&map, &text, &len, NULL);
                // Count *** in the string
                int sCount = countS(text);
                // Check if the count is equal to 3 (indicating a resource)
                if (sCount == 2) {
                    sCount++;
                }
            }/// MAP_NAME
            // Move to the next key-value pair
            err = cbor_value_advance(&map);
            if (err != CborNoError) {
                LOG_ARG("cbor_value_advance map FAILED with error %d", err);
                return -1;
            }
        }///!while not end map
        LOG("CHECKPOINT 4 -------------------------------------------");
        err = cbor_value_leave_container(array, &map); /// leave the map
        if (err != CborNoError)
        {
            LOG_ARG("cbor_value_leave_container array FAILED with error %d", err);
            return -1;
        }
        LOG("CHECKPOINT 5 -------------------------------------------");
        LOG_ARG("array->remaining %d", array->remaining);
        /// Move to the next map
        if (array->remaining > 1){
            err = cbor_value_advance(array);
            if (err != CborNoError) {
                LOG_ARG("cbor_value_advance array FAILED with error %d", err);
                return -1;
            }
        }
    }///!while not end of array
    /// Here I have tried to leave the array-array-container or/and enter the array-array-container once more but FAILED
    /// err = cbor_value_leave_container(array, array); /// leave the array
    ///    if (err != CborNoError)
    ///    {
    ///        LOG_ARG("cbor_value_leave_container array FAILED with error %d", err);
    ///        return -1;
    ///    }
    LOG("CHECKPOINT 6 -------------------------------------------");
    /// err = cbor_value_enter_container(array, array); /// re-enter the array
    ///    if (err != CborNoError)
    ///    {
    ///        LOG_ARG("cbor_value_leave_container array FAILED with error %d", err);
    ///        return -1;
    ///    }

    // Reset the array pointer to the starting position
    *array = arrayStart;

    return resourceCount;
} 
        

So, is the entering of the same container possible? Or, maybe, there is some other method to switch back the CborValue to the start of the cbor-buffer?
I guess that leave-container() may not work, cause there may be NO next array - we have only one array and leave_container seems to need the next value to switch to.
But, why the enter-container does not work? I have checked the array.remaining and it was 0 in the end of my function.
Now I am using a workaround - I am saving the starting point and re-setting it when I finish my checking function.
Also I want to admit that leave_container(array,map) works fine. So, question is about re-entering the array mainly.
Maybe there is something I have missed. Will be glad and grateful for any advice.

In any way, thanks for your library! Have a nice day, cheers!

[{0: "/3/0/10", 2: 55}]
It has one item and 2 maps as you can see.

That's one array with one map, and the map has two entries. That's different from:

[{0: "/3/0/10", 2: 55}, {0: "/3/0/12", 3: "ResetErrors"}, {0: "/3/0/13", 6: 2889055551}, {0: "/3/0/4", 3: "Reboot"}, {0: "/3/0/9", 2: 100}]

That's an array with multiple maps, each of which has two entries.

   // Save the starting position of the array
   cbor_value_get_next_byte(&arrayStart);
   arrayStart.parser = array->parser;
...
   // Reset the array pointer to the starting position
   *array = arrayStart;

Don't do that. Just save the CborValue object at that state. Those objects are copyable and, if you're just reading from a buffer, you can do it all over again.

        LOG("CHECKPOINT 4 -------------------------------------------");
        err = cbor_value_leave_container(array, &map); /// leave the map
        if (err != CborNoError)
        {
            LOG_ARG("cbor_value_leave_container array FAILED with error %d", err);
            return -1;
        }
        LOG("CHECKPOINT 5 -------------------------------------------");
        LOG_ARG("array->remaining %d", array->remaining);
        /// Move to the next map
        if (array->remaining > 1){
            err = cbor_value_advance(array);
            if (err != CborNoError) {
                LOG_ARG("cbor_value_advance array FAILED with error %d", err);
                return -1;
            }
        }

You shouldn't do that advance. The cbor_value_leave_container repositions the array iterator to the next element. I think you can just delete the block starting from CHECKPOINT 5 to the end of the loop.