File syn_protobuf.c¶
File List > src > syntropic > util > syn_protobuf.c
Go to the documentation of this file
#include "syn_protobuf.h"
#include <string.h>
SYN_Status syn_pb_encoder_init(SYN_PB_Encoder *enc, uint8_t *buf, size_t capacity)
{
if ((enc == NULL) || (buf == NULL) || (capacity == 0U)) {
return SYN_INVALID_PARAM;
}
enc->buf = buf;
enc->capacity = capacity;
enc->offset = 0U;
return SYN_OK;
}
SYN_Status syn_pb_encode_varint(SYN_PB_Encoder *enc, uint64_t value)
{
if (enc == NULL) {
return SYN_INVALID_PARAM;
}
while (value >= 0x80U) {
if (enc->offset >= enc->capacity) {
return SYN_ERROR; /* LCOV_EXCL_LINE: Defensive capacity guard */
}
enc->buf[enc->offset++] = (uint8_t)((value & 0x7FU) | 0x80U);
value >>= 7;
}
if (enc->offset >= enc->capacity) {
return SYN_ERROR;
}
enc->buf[enc->offset++] = (uint8_t)(value & 0x7FU);
return SYN_OK;
}
SYN_Status syn_pb_encode_tag(SYN_PB_Encoder *enc, uint32_t field_number, uint8_t wire_type)
{
if ((enc == NULL) || (field_number == 0U)) {
return SYN_INVALID_PARAM;
}
uint32_t key = (field_number << 3) | (wire_type & 0x07U);
return syn_pb_encode_varint(enc, key);
}
SYN_Status syn_pb_encode_int32(SYN_PB_Encoder *enc, uint32_t field_number, int32_t value)
{
if (enc == NULL) {
return SYN_INVALID_PARAM;
}
if (syn_pb_encode_tag(enc, field_number, SYN_PB_WIRE_VARINT) != SYN_OK) {
return SYN_ERROR;
}
return syn_pb_encode_varint(enc, (uint64_t)(int64_t)value);
}
SYN_Status syn_pb_encode_uint32(SYN_PB_Encoder *enc, uint32_t field_number, uint32_t value)
{
if (enc == NULL) {
return SYN_INVALID_PARAM;
}
if (syn_pb_encode_tag(enc, field_number, SYN_PB_WIRE_VARINT) != SYN_OK) {
return SYN_ERROR;
}
return syn_pb_encode_varint(enc, value);
}
SYN_Status syn_pb_encode_bool(SYN_PB_Encoder *enc, uint32_t field_number, bool value)
{
return syn_pb_encode_uint32(enc, field_number, value ? 1U : 0U);
}
SYN_Status syn_pb_encode_fixed32(SYN_PB_Encoder *enc, uint32_t field_number, uint32_t value)
{
if (enc == NULL) {
return SYN_INVALID_PARAM;
}
if (syn_pb_encode_tag(enc, field_number, SYN_PB_WIRE_FIXED32) != SYN_OK) {
return SYN_ERROR;
}
if (enc->offset + 4U > enc->capacity) {
return SYN_ERROR; /* LCOV_EXCL_LINE: Defensive capacity guard */
}
enc->buf[enc->offset++] = (uint8_t)(value & 0xFFU);
enc->buf[enc->offset++] = (uint8_t)((value >> 8) & 0xFFU);
enc->buf[enc->offset++] = (uint8_t)((value >> 16) & 0xFFU);
enc->buf[enc->offset++] = (uint8_t)((value >> 24) & 0xFFU);
return SYN_OK;
}
SYN_Status syn_pb_encode_bytes(SYN_PB_Encoder *enc, uint32_t field_number, const uint8_t *bytes,
size_t len)
{
if ((enc == NULL) || (bytes == NULL)) {
return SYN_INVALID_PARAM;
}
if (syn_pb_encode_tag(enc, field_number, SYN_PB_WIRE_LENGTH_DELIMITED) != SYN_OK) {
return SYN_ERROR;
}
if (syn_pb_encode_varint(enc, len) != SYN_OK) {
return SYN_ERROR; /* LCOV_EXCL_LINE: Defensive varint guard */
}
if (len > enc->capacity - enc->offset) {
return SYN_ERROR; /* LCOV_EXCL_LINE: Defensive capacity guard */
}
memcpy(&enc->buf[enc->offset], bytes, len);
enc->offset += len;
return SYN_OK;
}
SYN_Status syn_pb_encode_string(SYN_PB_Encoder *enc, uint32_t field_number, const char *str)
{
if (str == NULL) {
return SYN_INVALID_PARAM;
}
return syn_pb_encode_bytes(enc, field_number, (const uint8_t *)str, strlen(str));
}
SYN_Status syn_pb_decoder_init(SYN_PB_Decoder *dec, const uint8_t *buf, size_t size)
{
if ((dec == NULL) || (buf == NULL)) {
return SYN_INVALID_PARAM;
}
dec->buf = buf;
dec->size = size;
dec->offset = 0U;
return SYN_OK;
}
SYN_Status syn_pb_decode_varint(SYN_PB_Decoder *dec, uint64_t *value)
{
if ((dec == NULL) || (value == NULL)) {
return SYN_INVALID_PARAM;
}
uint64_t val = 0;
uint32_t shift = 0;
while (dec->offset < dec->size) {
uint8_t b = dec->buf[dec->offset++];
val |= ((uint64_t)(b & 0x7FU)) << shift;
if ((b & 0x80U) == 0U) {
*value = val;
return SYN_OK;
}
shift += 7U;
if (shift >= 64U) {
return SYN_ERROR; /* Overflow */
}
}
return SYN_ERROR;
}
SYN_Status syn_pb_decode_tag(SYN_PB_Decoder *dec, SYN_PB_Tag *tag)
{
if ((dec == NULL) || (tag == NULL)) {
return SYN_INVALID_PARAM;
}
if (dec->offset >= dec->size) {
return SYN_ERROR; /* End of stream */
}
uint64_t key = 0;
if (syn_pb_decode_varint(dec, &key) != SYN_OK) {
return SYN_ERROR;
}
tag->field_number = (uint32_t)(key >> 3);
tag->wire_type = (uint8_t)(key & 0x07U);
return SYN_OK;
}
SYN_Status syn_pb_decode_fixed32(SYN_PB_Decoder *dec, uint32_t *value)
{
if ((dec == NULL) || (value == NULL)) {
return SYN_INVALID_PARAM;
}
if (dec->offset + 4U > dec->size) {
return SYN_ERROR;
}
uint32_t val = ((uint32_t)dec->buf[dec->offset]) |
(((uint32_t)dec->buf[dec->offset + 1U]) << 8) |
(((uint32_t)dec->buf[dec->offset + 2U]) << 16) |
(((uint32_t)dec->buf[dec->offset + 3U]) << 24);
dec->offset += 4U;
*value = val;
return SYN_OK;
}
SYN_Status syn_pb_decode_bytes(SYN_PB_Decoder *dec, const uint8_t **bytes, size_t *len)
{
if ((dec == NULL) || (bytes == NULL) || (len == NULL)) {
return SYN_INVALID_PARAM;
}
uint64_t l = 0;
if (syn_pb_decode_varint(dec, &l) != SYN_OK) {
return SYN_ERROR;
}
if ((size_t)l > dec->size - dec->offset) {
return SYN_ERROR;
}
*bytes = &dec->buf[dec->offset];
*len = (size_t)l;
dec->offset += (size_t)l;
return SYN_OK;
}
SYN_Status syn_pb_skip_field(SYN_PB_Decoder *dec, uint8_t wire_type)
{
if (dec == NULL) {
return SYN_INVALID_PARAM;
}
uint64_t dummy_v;
uint32_t dummy_f;
const uint8_t *dummy_b;
size_t dummy_l;
switch (wire_type) {
/* LCOV_EXCL_START */
case SYN_PB_WIRE_VARINT:
return syn_pb_decode_varint(dec, &dummy_v);
/* LCOV_EXCL_STOP */
case SYN_PB_WIRE_FIXED32:
return syn_pb_decode_fixed32(dec, &dummy_f);
case SYN_PB_WIRE_LENGTH_DELIMITED:
return syn_pb_decode_bytes(dec, &dummy_b, &dummy_l);
case SYN_PB_WIRE_FIXED64:
if (dec->offset + 8U > dec->size) {
return SYN_ERROR;
}
dec->offset += 8U;
return SYN_OK;
default:
return SYN_ERROR;
}
}