intel / tinycbor

Concise Binary Object Representation (CBOR) Library
MIT License
492 stars 187 forks source link

Add cbor_encode_cbor #162

Open mkm85 opened 5 years ago

mkm85 commented 5 years ago

I propose adding a function which can encode encoded cbor into a CborEncoder.

Lets assume you have a system where chunks of data is encoded as cbor. If you are going to merge these chunks into a new cbor map they have to be decoded and then encoded again into the map. If instead one can just make a map and insert the binary cbor directly into this map then a decoding and reencoding is unneccessary.

CborError cbor_encode_cbor(CborEncoder encoder, uint8_t cbor, size_t size);

Regards, Michael

thiagomacieira commented 5 years ago

The problem will be that we still need to decode and re-encode in order to keep the state in CborEncoder: it tries to keep the count of elements added, so it can tell you if you made a mistake.

Copying without decoding would be only possible if the array or map has unknown length. Would that be acceptable?

mkm85 commented 5 years ago

I was thinking about adding the cbor as a single value e.g.

uint8_t example1[5] = { 0x82, 0x01, 0x82, 0x02, 0x03 };
uint8_t example2[8] = { 0x82, 0x61, 0x61, 0xa1, 0x61, 0x62, 60x1, 0x63 };

CborEncoder encoder;
cbor_encoder_init(&encoder, ....)
CborEncoder map;
cbor_encoder_create_map(&encoder, &map, CborIndefiniteLength);
cbor_encode_text_stringz(&map, "foo");
cbor_encode_cbor(&map, example1, 5);
cbor_encode_text_stringz(&map, "bar");
cbor_encode_cbor(&map, example2, 8);
cbor_encoder_close_container(...)
...

I see that it will give some problems if the encoded cbor is containing multiple values. And it would indeed be dangerous if an odd number of elements is added to a map. Maybe I is too dangerous to add such a functionality to the api.

thiagomacieira commented 5 years ago

That we could easily do, yes.

georgen117 commented 5 years ago

There is a tag for a Cbor byte string.
(from RFC 7049) 2.4.4.1. Encoded CBOR Data Item

Sometimes it is beneficial to carry an embedded CBOR data item that is not meant to be decoded immediately at the time the enclosing data item is being parsed. Tag 24 (CBOR data item) can be used to tag the embedded byte string as a data item encoded in CBOR format.

If we do use cbor encode cbor that tag should be used.

mkm85 commented 5 years ago

Using a tag and a byte string is possible with the current api, but it was not the intended semantics with this request. So the name is probably not the best.

thiagomacieira commented 5 years ago

Right, something like cbor_encode_encoded_item.

sijohans commented 4 years ago

I'll like to vote for this feature. I have two use cases where i have a hard coded cbor map or array that i would like to put into a high level map. E.g., i have a framework that receives a request to query for capabilities. An application on top of this layers defines the capabilities array.

/*
 * capabilities = {"modes": ["fly", "walk", "run"], "other": { ... }}
 * User defined function for getting capabilities.
 */
void get_capabilities(const uint8_t **ptr, size_t *size)
{
    /* Could be hard coded or created at startup for instance. */
    static uint8_t capabilities[] = { ... };
}

/* On a framework level. */
write_capabilities_response(CborEncoder *response)
{
   /* Here some other information are written to response that the framework requires. */
   .....

    /* Write user specified capabilities. */
    const uint8_t *capabilities = NULL;
    size_t size = 0;
    get_capabilities(&capabilities, &size);
    verify(capabilities != NULL and size > 0)
    cbor_encode_text_stringz(&response, "capabilities");
    cbor_encode_cbor(&response, capabilities, size);
}

I realize this was quite a bad example. But i have maps and arrays defined elsewhere and want to write them into the encoder.

ayechanpyaesonework commented 4 years ago

Hello. I tried to use TSonono solution and it gave me an error. What I am trying to do is. I want to add cbor tagged data into array. Please see my below code. It gave me an error when i try to close the container.

else if ([object isKindOfClass:NSData.class]) {
        NSData *dataObject = (NSData *)object;

        CborParser parser;
        CborValue value;
        const int flags = 0;

        uint8_t *inBuffer = (uint8_t *)dataObject.bytes;
        size_t inBufferLen = dataObject.length;

        CborError err = cbor_parser_init(inBuffer, inBufferLen, 0, &parser, &value);
        CborType i = cbor_value_get_type(&value);

        if(i == CborTagType) {
            return [self ds_performSafeEncodingIntoBuffer:buffer bufferSize:bufferSize encoder:encoder encodingBlock:^CborError {
                return cbor_encode_raw(encoder,  inBuffer, inBufferLen);
            }];
        }

    }

This is the code for cbor_encode_raw CborError cbor_encode_raw(CborEncoder *encoder, const uint8_t *raw, size_t length) { return append_to_buffer(encoder, raw, length); }

thiagomacieira commented 4 years ago

Your code is not correct, unless you're certain that the buffer you got contains exactly one item. What error did you get?