45 lines
1.3 KiB
C
45 lines
1.3 KiB
C
/*
|
|
* pb_decode_string — protobuf-like string decoder.
|
|
* Pre-fix; internal RPC layer.
|
|
*
|
|
* Wire format: <varint length> <length bytes of data>
|
|
* Caller passes a buffer; this writes the decoded length-prefixed string
|
|
* into a heap buffer allocated based on the wire-supplied length.
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static int read_varint(const uint8_t **p, const uint8_t *end, uint64_t *out) {
|
|
uint64_t v = 0; int shift = 0;
|
|
while (*p < end) {
|
|
uint8_t b = *(*p)++;
|
|
v |= ((uint64_t)(b & 0x7f)) << shift;
|
|
if ((b & 0x80) == 0) { *out = v; return 0; }
|
|
shift += 7;
|
|
if (shift > 63) return -1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/* Returns a newly malloc'd copy of the decoded string. *out_len gets length. */
|
|
char *pb_decode_string(const uint8_t *buf, size_t buf_len, size_t *out_len) {
|
|
const uint8_t *p = buf, *end = buf + buf_len;
|
|
|
|
uint64_t declared_len = 0;
|
|
if (read_varint(&p, end, &declared_len) != 0) return NULL;
|
|
|
|
/* allocate +1 for nul terminator */
|
|
char *s = (char *)malloc((size_t)declared_len + 1);
|
|
if (s == NULL) return NULL;
|
|
|
|
/* copy declared_len bytes from the wire */
|
|
memcpy(s, p, (size_t)declared_len);
|
|
s[declared_len] = '\0';
|
|
|
|
*out_len = (size_t)declared_len;
|
|
return s;
|
|
}
|