MINOR: tools: add cbor encode helpers

Add cbor helpers to encode strings (bytes/text) and integers according to
RFC8949, also add cbor_encode_ctx struct to pass encoding options such as
how to encode a single byte.
This commit is contained in:
Aurelien DARRAGON 2024-04-22 17:38:44 +02:00
parent 3f7c8387c0
commit 810303e3e6
3 changed files with 193 additions and 0 deletions

View File

@ -165,4 +165,20 @@ struct net_addr_type {
int xprt_type; // transport layer
};
/* To easily pass context to cbor encode functions
*/
struct cbor_encode_ctx {
/* function pointer that cbor encode functions will use to encode a
* single byte.
*
* The function needs to return the position of the last written byte
* on success and NULL on failure. The function cannot write past <stop>
*/
char *(*e_byte_fct)(struct cbor_encode_ctx *ctx,
char *start, char *stop, uint8_t byte);
/* to pass some context to the encode_byte fct */
void *e_byte_fct_ctx;
};
#endif /* _HAPROXY_TOOLS_T_H */

View File

@ -432,6 +432,25 @@ char *escape_string(char *start, char *stop,
const char escape, const long *map,
const char *string, const char *string_stop);
/* Below are RFC8949 compliant cbor encode helper functions, see source
* file for functions descriptions
*/
char *cbor_encode_uint64_prefix(struct cbor_encode_ctx *ctx,
char *start, char *stop,
uint64_t value, uint8_t prefix);
char *cbor_encode_int64(struct cbor_encode_ctx *ctx,
char *start, char *stop, int64_t value);
char *cbor_encode_bytes_prefix(struct cbor_encode_ctx *ctx,
char *start, char *stop,
const char *bytes, size_t len,
uint8_t prefix);
char *cbor_encode_bytes(struct cbor_encode_ctx *ctx,
char *start, char *stop,
const char *bytes, size_t len);
char *cbor_encode_text(struct cbor_encode_ctx *ctx,
char *start, char *stop,
const char *text, size_t len);
/* Check a string for using it in a CSV output format. If the string contains
* one of the following four char <">, <,>, CR or LF, the string is
* encapsulated between <"> and the <"> are escaped by a <""> sequence.

View File

@ -2064,6 +2064,164 @@ char *escape_string(char *start, char *stop,
return NULL;
}
/* CBOR helper to encode an uint64 value with prefix (3bits MAJOR type)
* according to RFC8949
*
* CBOR encode ctx is provided in <ctx>
*
* Returns the position of the last written byte on success and NULL on
* error. The function cannot write past <stop>
*/
char *cbor_encode_uint64_prefix(struct cbor_encode_ctx *ctx,
char *start, char *stop, uint64_t value,
uint8_t prefix)
{
int nb_bytes = 0;
/*
* For encoding logic, see:
* https://www.rfc-editor.org/rfc/rfc8949.html#name-specification-of-the-cbor-e
*/
if (value < 24) {
/* argument is the value itself */
prefix |= value;
}
else {
if (value <= 0xFFU) {
/* 1-byte */
nb_bytes = 1;
prefix |= 24; // 0x18
}
else if (value <= 0xFFFFU) {
/* 2 bytes */
nb_bytes = 2;
prefix |= 25; // 0x19
}
else if (value <= 0xFFFFFFFFU) {
/* 4 bytes */
nb_bytes = 4;
prefix |= 26; // 0x1A
}
else {
/* 8 bytes */
nb_bytes = 8;
prefix |= 27; // 0x1B
}
}
start = ctx->e_byte_fct(ctx, start, stop, prefix);
if (start == NULL)
return NULL;
/* encode 1 byte at a time from higher bits to lower bits */
while (nb_bytes) {
uint8_t cur_byte = (value >> ((nb_bytes - 1) * 8)) & 0xFFU;
start = ctx->e_byte_fct(ctx, start, stop, cur_byte);
if (start == NULL)
return NULL;
nb_bytes--;
}
return start;
}
/* CBOR helper to encode an int64 value according to RFC8949
*
* CBOR encode ctx is provided in <ctx>
*
* Returns the position of the last written byte on success and NULL on
* error. The function cannot write past <stop>
*/
char *cbor_encode_int64(struct cbor_encode_ctx *ctx,
char *start, char *stop, int64_t value)
{
uint64_t absolute_value = llabs(value);
int cbor_prefix;
/*
* For encoding logic, see:
* https://www.rfc-editor.org/rfc/rfc8949.html#name-specification-of-the-cbor-e
*/
if (value >= 0)
cbor_prefix = 0x00; // unsigned int
else {
cbor_prefix = 0x20; // negative int
/* N-1 for negative int */
absolute_value -= 1;
}
return cbor_encode_uint64_prefix(ctx, start, stop,
absolute_value, cbor_prefix);
}
/* CBOR helper to encode a <prefix> string chunk according to RFC8949
*
* if <bytes> is NULL, then only the <prefix> (with length) will be
* emitted
*
* CBOR encode ctx is provided in <ctx>
*
* Returns the position of the last written byte on success and NULL on
* error. The function cannot write past <stop>
*/
char *cbor_encode_bytes_prefix(struct cbor_encode_ctx *ctx,
char *start, char *stop,
const char *bytes, size_t len,
uint8_t prefix)
{
size_t it = 0;
/* write prefix (with text length as argument) */
start = cbor_encode_uint64_prefix(ctx, start, stop,
len, prefix);
if (start == NULL)
return NULL;
/* write actual bytes if provided */
while (bytes && it < len) {
start = ctx->e_byte_fct(ctx, start, stop, bytes[it]);
if (start == NULL)
return NULL;
it++;
}
return start;
}
/* CBOR helper to encode a text chunk according to RFC8949
*
* if <text> is NULL, then only the text prefix (with length) will be emitted
*
* CBOR encode ctx is provided in <ctx>
*
* Returns the position of the last written byte on success and NULL on
* error. The function cannot write past <stop>
*/
char *cbor_encode_text(struct cbor_encode_ctx *ctx,
char *start, char *stop,
const char *text, size_t len)
{
return cbor_encode_bytes_prefix(ctx, start, stop, text, len, 0x60);
}
/* CBOR helper to encode a byte string chunk according to RFC8949
*
* if <bytes> is NULL, then only the byte string prefix (with length) will be
* emitted
*
* CBOR encode ctx is provided in <ctx>
*
* Returns the position of the last written byte on success and NULL on
* error. The function cannot write past <stop>
*/
char *cbor_encode_bytes(struct cbor_encode_ctx *ctx,
char *start, char *stop,
const char *bytes, size_t len)
{
return cbor_encode_bytes_prefix(ctx, start, stop, bytes, len, 0x40);
}
/* Check a string for using it in a CSV output format. If the string contains
* one of the following four char <">, <,>, CR or LF, the string is
* encapsulated between <"> and the <"> are escaped by a <""> sequence.