laurencelundblade / QCBOR

Comprehensive, powerful, commercial-quality CBOR encoder/ decoder that is still suited for small devices.
Other
187 stars 47 forks source link

[feature request] Convenience decode functions for tagged data #120

Open Anrock opened 3 years ago

Anrock commented 3 years ago

I'm not sure why QCBOR API was designed to treat tags as if they're attached to an enclosed items instead of the other way around but this makes decoders for protocols where major type of an item depend on a tag that wraps it quite inconvinient.

For example, imagine a protocol where one of the fields may contain some complex structure of useful payload or an error code integer. To distinguish, protocol wraps payload in 0x30 tag and error code in 0x31.

In order to decode that, one would have to QCBORDecode_VPeekNext (since it's unknown what major type of the next item) next item into some one-shot QCBORItem variable (since QCBOR attaches tags to an item) and then use QCBORDecode_GetNthTag (since VPeekNext was used) to get the tag, then switch-case on the tag, handle unknown tag values and proceed with spiffy decode functions deeper into the structure. It gets worse if there are multiple nested tags.

I believe that a couple of new functions would ease the situation. One basic decode function, say QCBORDecode_GetTag(uint64_t* tag), that consumes next tag and fills out argument. And one function for spiffy decode, say QCBORDecode_EnsureTag(uint64_t tag) that consumes next tag and checks that it's equal to an argument.

If those functions are present one could write more linear code, something like:

QCBORDecode_EnsureTag(&ctx, TAG_SUCCESS);
QCBORDecode_EnterArray(&ctx);
// decode payload
if (QCBORDecode_GetError(&ctx) != QCBOR_SUCCESS) {
  QCBORDecode_Rewind(&ctx);
  // decode error
}

Instead of multiple nested switch-cases or ifs and a bunch of temp variables.

laurencelundblade commented 3 years ago

I agree that improvements can be made and I intend to do this work.

It will take me a little while to get to it and may be a lot of work to do a good job of it.

Thank you for the comment.

laurencelundblade commented 2 years ago

Still working on it... Want to do a thorough job. If you have examples of protocols you want to decode, I'm interested. The most complex case I'm looking at is CWT + COSE which has variants and rules for how the tags nest.

Want to be able to cleanly handle branches in decoder flow when a tag is encountered or not encountered.

Anrock commented 2 years ago

It's a custom proprietary protocol, so I'm not sure if I can share it here, sorry. But scheme is basically a tree where each node is an array with statically known "envelope"-fields and last field is some tagged array/map structure and it's scheme determined by a tag.

laurencelundblade commented 2 years ago

It's just one level of tag, right? No nesting of one tag in another (like CWT/COSE), right?

Anrock commented 2 years ago

@laurencelundblade up to 2 tags nesting. As I've mentioned in opening post there is at least (Success)(PayloadType)[fields] and (Failure)(ErrorType)[fields] now.