cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
protobuf.c
Go to the documentation of this file.
1
8#include <limits.h>
9#include <stdint.h>
10#include <stdlib.h>
11#include <string.h>
12
18 if (!w) return;
19 w->data = NULL;
20 w->len = 0;
21 w->cap = 0;
22}
23
29 if (!w) return;
30 cwist_free(w->data);
31 w->data = NULL;
32 w->len = 0;
33 w->cap = 0;
34}
35
43 if (!w) return -1;
44 if (extra > SIZE_MAX - w->len) return -1;
45 size_t need = w->len + extra;
46 if (need <= w->cap) return 0;
47
48 size_t cap = w->cap ? w->cap : 64;
49 while (cap < need) {
50 if (cap > SIZE_MAX / 2) {
51 cap = need;
52 break;
53 }
54 cap *= 2;
55 }
56 uint8_t *next = (uint8_t *)cwist_realloc(w->data, cap);
57 if (!next) return -1;
58 w->data = next;
59 w->cap = cap;
60 return 0;
61}
62
70 if (!w) return -1;
71 if (cwist_pb_writer_reserve(w, 10) != 0) return -1;
72 while (value >= 0x80) {
73 w->data[w->len++] = (uint8_t)(value | 0x80);
74 value >>= 7;
75 }
76 w->data[w->len++] = (uint8_t)value;
77 return 0;
78}
79
88 if (!w || field_number == 0 || field_number > CWIST_PB_MAX_FIELD_NUMBER) return -1;
89 if (wire_type != CWIST_PB_VARINT && wire_type != CWIST_PB_64BIT && wire_type != CWIST_PB_LEN &&
90 wire_type != CWIST_PB_32BIT) {
91 return -1;
92 }
93 uint64_t key = ((uint64_t)field_number << 3) | (uint64_t)wire_type;
94 return cwist_pb_write_varint(w, key);
95}
96
108
119
130
138 if (!w) return -1;
139 if (cwist_pb_writer_reserve(w, 4) != 0) return -1;
140 w->data[w->len++] = (uint8_t)value;
141 w->data[w->len++] = (uint8_t)(value >> 8);
142 w->data[w->len++] = (uint8_t)(value >> 16);
143 w->data[w->len++] = (uint8_t)(value >> 24);
144 return 0;
145}
146
154 if (!w) return -1;
155 if (cwist_pb_writer_reserve(w, 8) != 0) return -1;
156 for (unsigned i = 0; i < 8; i++) w->data[w->len++] = (uint8_t)(value >> (i * 8));
157 return 0;
158}
159
171
183
192 return cwist_pb_write_fixed32_field(w, field_number, cwist_pb_float_bits(value));
193}
194
203 return cwist_pb_write_fixed64_field(w, field_number, cwist_pb_double_bits(value));
204}
205
216 size_t len) {
217 if (!w || (len > 0 && !data)) return -1;
218 if (cwist_pb_write_key(w, field_number, CWIST_PB_LEN) != 0) return -1;
219 if (cwist_pb_write_varint(w, (uint64_t)len) != 0) return -1;
220 if (cwist_pb_writer_reserve(w, len) != 0) return -1;
221 if (len > 0) memcpy(w->data + w->len, data, len);
222 w->len += len;
223 return 0;
224}
225
234 if (!value) return -1;
235 return cwist_pb_write_bytes_field(w, field_number, value, strlen(value));
236}
237
244void cwist_pb_reader_init(cwist_pb_reader *r, const void *data, size_t len) {
245 if (!r) return;
246 r->data = (const uint8_t *)data;
247 r->len = len;
248 r->pos = 0;
249}
250
259 if (!r || !out) return -1;
260 uint64_t value = 0;
261 unsigned shift = 0;
262 while (r->pos < r->len && shift <= 63) {
263 uint8_t byte = r->data[r->pos++];
264 value |= ((uint64_t)(byte & 0x7f)) << shift;
265 if ((byte & 0x80) == 0) {
266 *out = value;
267 return 0;
268 }
269 shift += 7;
270 }
271 return -1;
272}
273
285 if (!r || !field || r->pos >= r->len) return 0;
286 memset(field, 0, sizeof(*field));
287
288 uint64_t key = 0;
289 if (cwist_pb_read_varint(r, &key) != 0) return -1;
290 /* Check before the cast: a key above the field-number range would
291 * otherwise truncate to a different, valid-looking field number. */
292 if ((key >> 3) == 0 || (key >> 3) > CWIST_PB_MAX_FIELD_NUMBER) return -1;
293 field->number = (uint32_t)(key >> 3);
294 field->wire_type = (cwist_pb_wire_type_t)(key & 0x07);
295
296 switch (field->wire_type) {
297 case CWIST_PB_VARINT:
298 if (cwist_pb_read_varint(r, &field->varint) != 0) return -1;
299 return 1;
300 case CWIST_PB_LEN: {
301 uint64_t len = 0;
302 if (cwist_pb_read_varint(r, &len) != 0) return -1;
303 if (len > SIZE_MAX || (size_t)len > r->len - r->pos) return -1;
304 field->bytes = r->data + r->pos;
305 field->len = (size_t)len;
306 r->pos += field->len;
307 return 1;
308 }
309 case CWIST_PB_32BIT:
310 if (r->len - r->pos < 4) return -1;
311 field->bytes = r->data + r->pos;
312 field->len = 4;
313 r->pos += 4;
314 return 1;
315 case CWIST_PB_64BIT:
316 if (r->len - r->pos < 8) return -1;
317 field->bytes = r->data + r->pos;
318 field->len = 8;
319 r->pos += 8;
320 return 1;
321 default: return -1;
322 }
323}
324
334 (void)r;
335 return field ? 0 : -1;
336}
337
345 /* All ones for a negative value, zero otherwise, without the
346 * implementation-defined right shift of a negative signed value. */
347 return ((uint64_t)value << 1) ^ ((uint64_t)0 - ((uint64_t)value >> 63));
348}
349
356 return (int64_t)((value >> 1) ^ (uint64_t)-((int64_t)value & 1));
357}
Memory allocation wrappers backed by libttak.
void cwist_free(void *ptr)
Free memory obtained via cwist_alloc/cwist_strdup/etc.
Definition alloc.c:52
void * cwist_realloc(void *ptr, size_t new_size)
Resize an existing allocation (libttak tracked).
Definition alloc.c:27
size_t cap
Definition otel.c:56
int cwist_pb_write_fixed64_field(cwist_pb_writer *w, uint32_t field_number, uint64_t value)
Write a fixed64 field (key plus 8 little-endian bytes).
Definition protobuf.c:179
uint64_t cwist_pb_zigzag_encode(int64_t value)
ZigZag-encode a signed 64-bit value for sint fields.
Definition protobuf.c:344
int cwist_pb_write_double_field(cwist_pb_writer *w, uint32_t field_number, double value)
Write a double field by reinterpreting it as fixed64 bits.
Definition protobuf.c:202
void cwist_pb_reader_init(cwist_pb_reader *r, const void *data, size_t len)
Initialize a reader over a caller-owned buffer.
Definition protobuf.c:244
int cwist_pb_write_raw64(cwist_pb_writer *w, uint64_t value)
Append a 64-bit value in little-endian order (no key written).
Definition protobuf.c:153
int cwist_pb_write_uint64_field(cwist_pb_writer *w, uint32_t field_number, uint64_t value)
Write a uint64 field as a varint.
Definition protobuf.c:104
int cwist_pb_write_float_field(cwist_pb_writer *w, uint32_t field_number, float value)
Write a float field by reinterpreting it as fixed32 bits.
Definition protobuf.c:191
int cwist_pb_writer_reserve(cwist_pb_writer *w, size_t extra)
Ensure the writer buffer has room for extra more bytes.
Definition protobuf.c:42
void cwist_pb_writer_free(cwist_pb_writer *w)
Release the buffer owned by a Protobuf writer.
Definition protobuf.c:28
int cwist_pb_read_varint(cwist_pb_reader *r, uint64_t *out)
Read a base-128 varint, advancing the reader position.
Definition protobuf.c:258
void cwist_pb_writer_init(cwist_pb_writer *w)
Initialize a Protobuf writer to an empty buffer.
Definition protobuf.c:17
int cwist_pb_write_int64_field(cwist_pb_writer *w, uint32_t field_number, int64_t value)
Write an int64 field; negative values are encoded as ten-byte varints.
Definition protobuf.c:116
int cwist_pb_write_fixed32_field(cwist_pb_writer *w, uint32_t field_number, uint32_t value)
Write a fixed32 field (key plus 4 little-endian bytes).
Definition protobuf.c:167
int cwist_pb_read_field(cwist_pb_reader *r, cwist_pb_field *field)
Read the next field key and payload from the reader.
Definition protobuf.c:284
int cwist_pb_write_raw32(cwist_pb_writer *w, uint32_t value)
Append a 32-bit value in little-endian order (no key written).
Definition protobuf.c:137
int cwist_pb_skip_field(cwist_pb_reader *r, const cwist_pb_field *field)
Validate a parsed field descriptor.
Definition protobuf.c:333
int cwist_pb_write_bytes_field(cwist_pb_writer *w, uint32_t field_number, const void *data, size_t len)
Write a length-delimited bytes field (key, length varint, raw bytes).
Definition protobuf.c:215
int cwist_pb_write_bool_field(cwist_pb_writer *w, uint32_t field_number, int value)
Write a bool field as a 0/1 varint.
Definition protobuf.c:127
int cwist_pb_write_varint(cwist_pb_writer *w, uint64_t value)
Append a base-128 varint to the writer buffer.
Definition protobuf.c:69
int cwist_pb_write_string_field(cwist_pb_writer *w, uint32_t field_number, const char *value)
Write a string field (length-delimited, excluding the NUL terminator).
Definition protobuf.c:233
int cwist_pb_write_key(cwist_pb_writer *w, uint32_t field_number, cwist_pb_wire_type_t wire_type)
Write a field key (field number and wire type) as a varint.
Definition protobuf.c:87
int64_t cwist_pb_zigzag_decode(uint64_t value)
ZigZag-decode an unsigned 64-bit value back to a signed value.
Definition protobuf.c:355
Small Protobuf wire-format reader/writer helpers.
enum cwist_pb_wire_type cwist_pb_wire_type_t
@ CWIST_PB_VARINT
Definition protobuf.h:18
@ CWIST_PB_LEN
Definition protobuf.h:20
@ CWIST_PB_64BIT
Definition protobuf.h:19
@ CWIST_PB_32BIT
Definition protobuf.h:21
#define CWIST_PB_MAX_FIELD_NUMBER
Definition protobuf.h:25
uint32_t number
Definition protobuf.h:40
const uint8_t * bytes
Definition protobuf.h:43
uint64_t varint
Definition protobuf.h:42
cwist_pb_wire_type_t wire_type
Definition protobuf.h:41
const uint8_t * data
Definition protobuf.h:34