1 /* pb_encode.c -- encode a protobuf using minimal resources
2 *
3 * 2011 Petteri Aimonen <jpa@kapsi.fi>
4 */
5
6 #include "pb.h"
7 #include "pb_encode.h"
8 #include "pb_common.h"
9
10 /* Use the GCC warn_unused_result attribute to check that all return values
11 * are propagated correctly. On other compilers and gcc before 3.4.0 just
12 * ignore the annotation.
13 */
14 #if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
15 #define checkreturn
16 #else
17 #define checkreturn __attribute__((warn_unused_result))
18 #endif
19
20 /**************************************
21 * Declarations internal to this file *
22 **************************************/
23 typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn;
24
25 static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
26 static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func);
27 static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
28 static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension);
29 static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
30 static void *pb_const_cast(const void *p);
31 static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
32 static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
33 static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
34 static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src);
35 static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src);
36 static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src);
37 static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src);
38 static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src);
39 static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src);
40
41 #ifdef PB_WITHOUT_64BIT
42 #define pb_int64_t int32_t
43 #define pb_uint64_t uint32_t
44
45 static bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t value);
46 #else
47 #define pb_int64_t int64_t
48 #define pb_uint64_t uint64_t
49 #endif
50
51 /* --- Function pointers to field encoders ---
52 * Order in the array must match pb_action_t LTYPE numbering.
53 */
54 static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = {
55 &pb_enc_varint,
56 &pb_enc_uvarint,
57 &pb_enc_svarint,
58 &pb_enc_fixed32,
59 &pb_enc_fixed64,
60
61 &pb_enc_bytes,
62 &pb_enc_string,
63 &pb_enc_submessage,
64 NULL, /* extensions */
65 &pb_enc_fixed_length_bytes
66 };
67
68 /*******************************
69 * pb_ostream_t implementation *
70 *******************************/
71
buf_write(pb_ostream_t * stream,const pb_byte_t * buf,size_t count)72 static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
73 {
74 size_t i;
75 pb_byte_t *dest = (pb_byte_t*)stream->state;
76 stream->state = dest + count;
77
78 for (i = 0; i < count; i++)
79 dest[i] = buf[i];
80
81 return true;
82 }
83
pb_ostream_from_buffer(pb_byte_t * buf,size_t bufsize)84 pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize)
85 {
86 pb_ostream_t stream;
87 #ifdef PB_BUFFER_ONLY
88 stream.callback = (void*)1; /* Just a marker value */
89 #else
90 stream.callback = &buf_write;
91 #endif
92 stream.state = buf;
93 stream.max_size = bufsize;
94 stream.bytes_written = 0;
95 #ifndef PB_NO_ERRMSG
96 stream.errmsg = NULL;
97 #endif
98 return stream;
99 }
100
pb_write(pb_ostream_t * stream,const pb_byte_t * buf,size_t count)101 bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
102 {
103 if (stream->callback != NULL)
104 {
105 if (stream->bytes_written + count > stream->max_size)
106 PB_RETURN_ERROR(stream, "stream full");
107
108 #ifdef PB_BUFFER_ONLY
109 if (!buf_write(stream, buf, count))
110 PB_RETURN_ERROR(stream, "io error");
111 #else
112 if (!stream->callback(stream, buf, count))
113 PB_RETURN_ERROR(stream, "io error");
114 #endif
115 }
116
117 stream->bytes_written += count;
118 return true;
119 }
120
121 /*************************
122 * Encode a single field *
123 *************************/
124
125 /* Encode a static array. Handles the size calculations and possible packing. */
encode_array(pb_ostream_t * stream,const pb_field_t * field,const void * pData,size_t count,pb_encoder_t func)126 static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field,
127 const void *pData, size_t count, pb_encoder_t func)
128 {
129 size_t i;
130 const void *p;
131 size_t size;
132
133 if (count == 0)
134 return true;
135
136 if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size)
137 PB_RETURN_ERROR(stream, "array max size exceeded");
138
139 /* We always pack arrays if the datatype allows it. */
140 if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
141 {
142 if (!pb_encode_tag(stream, PB_WT_STRING, field->tag))
143 return false;
144
145 /* Determine the total size of packed array. */
146 if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32)
147 {
148 size = 4 * count;
149 }
150 else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
151 {
152 size = 8 * count;
153 }
154 else
155 {
156 pb_ostream_t sizestream = PB_OSTREAM_SIZING;
157 p = pData;
158 for (i = 0; i < count; i++)
159 {
160 if (!func(&sizestream, field, p))
161 return false;
162 p = (const char*)p + field->data_size;
163 }
164 size = sizestream.bytes_written;
165 }
166
167 if (!pb_encode_varint(stream, (pb_uint64_t)size))
168 return false;
169
170 if (stream->callback == NULL)
171 return pb_write(stream, NULL, size); /* Just sizing.. */
172
173 /* Write the data */
174 p = pData;
175 for (i = 0; i < count; i++)
176 {
177 if (!func(stream, field, p))
178 return false;
179 p = (const char*)p + field->data_size;
180 }
181 }
182 else
183 {
184 p = pData;
185 for (i = 0; i < count; i++)
186 {
187 if (!pb_encode_tag_for_field(stream, field))
188 return false;
189
190 /* Normally the data is stored directly in the array entries, but
191 * for pointer-type string and bytes fields, the array entries are
192 * actually pointers themselves also. So we have to dereference once
193 * more to get to the actual data. */
194 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER &&
195 (PB_LTYPE(field->type) == PB_LTYPE_STRING ||
196 PB_LTYPE(field->type) == PB_LTYPE_BYTES))
197 {
198 if (!func(stream, field, *(const void* const*)p))
199 return false;
200 }
201 else
202 {
203 if (!func(stream, field, p))
204 return false;
205 }
206 p = (const char*)p + field->data_size;
207 }
208 }
209
210 return true;
211 }
212
213 /* In proto3, all fields are optional and are only encoded if their value is "non-zero".
214 * This function implements the check for the zero value. */
pb_check_proto3_default_value(const pb_field_t * field,const void * pData)215 static bool pb_check_proto3_default_value(const pb_field_t *field, const void *pData)
216 {
217 pb_type_t type = field->type;
218 const void *pSize = (const char*)pData + field->size_offset;
219
220 if (PB_HTYPE(type) == PB_HTYPE_REQUIRED)
221 {
222 /* Required proto2 fields inside proto3 submessage, pretty rare case */
223 return false;
224 }
225 else if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
226 {
227 /* Repeated fields inside proto3 submessage: present if count != 0 */
228 return *(const pb_size_t*)pSize == 0;
229 }
230 else if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
231 {
232 /* Oneof fields */
233 return *(const pb_size_t*)pSize == 0;
234 }
235 else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->size_offset)
236 {
237 /* Proto2 optional fields inside proto3 submessage */
238 return *(const bool*)pSize == false;
239 }
240
241 /* Rest is proto3 singular fields */
242
243 if (PB_ATYPE(type) == PB_ATYPE_STATIC)
244 {
245 if (PB_LTYPE(type) == PB_LTYPE_BYTES)
246 {
247 const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)pData;
248 return bytes->size == 0;
249 }
250 else if (PB_LTYPE(type) == PB_LTYPE_STRING)
251 {
252 return *(const char*)pData == '\0';
253 }
254 else if (PB_LTYPE(type) == PB_LTYPE_FIXED_LENGTH_BYTES)
255 {
256 /* Fixed length bytes is only empty if its length is fixed
257 * as 0. Which would be pretty strange, but we can check
258 * it anyway. */
259 return field->data_size == 0;
260 }
261 else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE)
262 {
263 /* Check all fields in the submessage to find if any of them
264 * are non-zero. The comparison cannot be done byte-per-byte
265 * because the C struct may contain padding bytes that must
266 * be skipped.
267 */
268 pb_field_iter_t iter;
269 if (pb_field_iter_begin(&iter, (const pb_field_t*)field->ptr, pb_const_cast(pData)))
270 {
271 do
272 {
273 if (!pb_check_proto3_default_value(iter.pos, iter.pData))
274 {
275 return false;
276 }
277 } while (pb_field_iter_next(&iter));
278 }
279 return true;
280 }
281 }
282
283 {
284 /* Catch-all branch that does byte-per-byte comparison for zero value.
285 *
286 * This is for all pointer fields, and for static PB_LTYPE_VARINT,
287 * UVARINT, SVARINT, FIXED32, FIXED64, EXTENSION fields, and also
288 * callback fields. These all have integer or pointer value which
289 * can be compared with 0.
290 */
291 pb_size_t i;
292 const char *p = (const char*)pData;
293 for (i = 0; i < field->data_size; i++)
294 {
295 if (p[i] != 0)
296 {
297 return false;
298 }
299 }
300
301 return true;
302 }
303 }
304
305 /* Encode a field with static or pointer allocation, i.e. one whose data
306 * is available to the encoder directly. */
encode_basic_field(pb_ostream_t * stream,const pb_field_t * field,const void * pData)307 static bool checkreturn encode_basic_field(pb_ostream_t *stream,
308 const pb_field_t *field, const void *pData)
309 {
310 pb_encoder_t func;
311 bool implicit_has;
312 const void *pSize = &implicit_has;
313
314 func = PB_ENCODERS[PB_LTYPE(field->type)];
315
316 if (field->size_offset)
317 {
318 /* Static optional, repeated or oneof field */
319 pSize = (const char*)pData + field->size_offset;
320 }
321 else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL)
322 {
323 /* Proto3 style field, optional but without explicit has_ field. */
324 implicit_has = !pb_check_proto3_default_value(field, pData);
325 }
326 else
327 {
328 /* Required field, always present */
329 implicit_has = true;
330 }
331
332 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
333 {
334 /* pData is a pointer to the field, which contains pointer to
335 * the data. If the 2nd pointer is NULL, it is interpreted as if
336 * the has_field was false.
337 */
338 pData = *(const void* const*)pData;
339 implicit_has = (pData != NULL);
340 }
341
342 switch (PB_HTYPE(field->type))
343 {
344 case PB_HTYPE_REQUIRED:
345 if (!pData)
346 PB_RETURN_ERROR(stream, "missing required field");
347 if (!pb_encode_tag_for_field(stream, field))
348 return false;
349 if (!func(stream, field, pData))
350 return false;
351 break;
352
353 case PB_HTYPE_OPTIONAL:
354 if (*(const bool*)pSize)
355 {
356 if (!pb_encode_tag_for_field(stream, field))
357 return false;
358
359 if (!func(stream, field, pData))
360 return false;
361 }
362 break;
363
364 case PB_HTYPE_REPEATED: {
365 pb_size_t count;
366 if (field->size_offset != 0) {
367 count = *(const pb_size_t*)pSize;
368 } else {
369 count = field->array_size;
370 }
371 if (!encode_array(stream, field, pData, count, func))
372 return false;
373 break;
374 }
375
376 case PB_HTYPE_ONEOF:
377 if (*(const pb_size_t*)pSize == field->tag)
378 {
379 if (!pb_encode_tag_for_field(stream, field))
380 return false;
381
382 if (!func(stream, field, pData))
383 return false;
384 }
385 break;
386
387 default:
388 PB_RETURN_ERROR(stream, "invalid field type");
389 }
390
391 return true;
392 }
393
394 /* Encode a field with callback semantics. This means that a user function is
395 * called to provide and encode the actual data. */
encode_callback_field(pb_ostream_t * stream,const pb_field_t * field,const void * pData)396 static bool checkreturn encode_callback_field(pb_ostream_t *stream,
397 const pb_field_t *field, const void *pData)
398 {
399 const pb_callback_t *callback = (const pb_callback_t*)pData;
400
401 #ifdef PB_OLD_CALLBACK_STYLE
402 const void *arg = callback->arg;
403 #else
404 void * const *arg = &(callback->arg);
405 #endif
406
407 if (callback->funcs.encode != NULL)
408 {
409 if (!callback->funcs.encode(stream, field, arg))
410 PB_RETURN_ERROR(stream, "callback error");
411 }
412 return true;
413 }
414
415 /* Encode a single field of any callback or static type. */
encode_field(pb_ostream_t * stream,const pb_field_t * field,const void * pData)416 static bool checkreturn encode_field(pb_ostream_t *stream,
417 const pb_field_t *field, const void *pData)
418 {
419 switch (PB_ATYPE(field->type))
420 {
421 case PB_ATYPE_STATIC:
422 case PB_ATYPE_POINTER:
423 return encode_basic_field(stream, field, pData);
424
425 case PB_ATYPE_CALLBACK:
426 return encode_callback_field(stream, field, pData);
427
428 default:
429 PB_RETURN_ERROR(stream, "invalid field type");
430 }
431 }
432
433 /* Default handler for extension fields. Expects to have a pb_field_t
434 * pointer in the extension->type->arg field. */
default_extension_encoder(pb_ostream_t * stream,const pb_extension_t * extension)435 static bool checkreturn default_extension_encoder(pb_ostream_t *stream,
436 const pb_extension_t *extension)
437 {
438 const pb_field_t *field = (const pb_field_t*)extension->type->arg;
439
440 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
441 {
442 /* For pointer extensions, the pointer is stored directly
443 * in the extension structure. This avoids having an extra
444 * indirection. */
445 return encode_field(stream, field, &extension->dest);
446 }
447 else
448 {
449 return encode_field(stream, field, extension->dest);
450 }
451 }
452
453 /* Walk through all the registered extensions and give them a chance
454 * to encode themselves. */
encode_extension_field(pb_ostream_t * stream,const pb_field_t * field,const void * pData)455 static bool checkreturn encode_extension_field(pb_ostream_t *stream,
456 const pb_field_t *field, const void *pData)
457 {
458 const pb_extension_t *extension = *(const pb_extension_t* const *)pData;
459 PB_UNUSED(field);
460
461 while (extension)
462 {
463 bool status;
464 if (extension->type->encode)
465 status = extension->type->encode(stream, extension);
466 else
467 status = default_extension_encoder(stream, extension);
468
469 if (!status)
470 return false;
471
472 extension = extension->next;
473 }
474
475 return true;
476 }
477
478 /*********************
479 * Encode all fields *
480 *********************/
481
pb_const_cast(const void * p)482 static void *pb_const_cast(const void *p)
483 {
484 /* Note: this casts away const, in order to use the common field iterator
485 * logic for both encoding and decoding. */
486 union {
487 void *p1;
488 const void *p2;
489 } t;
490 t.p2 = p;
491 return t.p1;
492 }
493
pb_encode(pb_ostream_t * stream,const pb_field_t fields[],const void * src_struct)494 bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
495 {
496 pb_field_iter_t iter;
497 if (!pb_field_iter_begin(&iter, fields, pb_const_cast(src_struct)))
498 return true; /* Empty message type */
499
500 do {
501 if (PB_LTYPE(iter.pos->type) == PB_LTYPE_EXTENSION)
502 {
503 /* Special case for the extension field placeholder */
504 if (!encode_extension_field(stream, iter.pos, iter.pData))
505 return false;
506 }
507 else
508 {
509 /* Regular field */
510 if (!encode_field(stream, iter.pos, iter.pData))
511 return false;
512 }
513 } while (pb_field_iter_next(&iter));
514
515 return true;
516 }
517
pb_encode_delimited(pb_ostream_t * stream,const pb_field_t fields[],const void * src_struct)518 bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
519 {
520 return pb_encode_submessage(stream, fields, src_struct);
521 }
522
pb_encode_nullterminated(pb_ostream_t * stream,const pb_field_t fields[],const void * src_struct)523 bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
524 {
525 const pb_byte_t zero = 0;
526
527 if (!pb_encode(stream, fields, src_struct))
528 return false;
529
530 return pb_write(stream, &zero, 1);
531 }
532
pb_get_encoded_size(size_t * size,const pb_field_t fields[],const void * src_struct)533 bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct)
534 {
535 pb_ostream_t stream = PB_OSTREAM_SIZING;
536
537 if (!pb_encode(&stream, fields, src_struct))
538 return false;
539
540 *size = stream.bytes_written;
541 return true;
542 }
543
544 /********************
545 * Helper functions *
546 ********************/
547
548 #ifdef PB_WITHOUT_64BIT
pb_encode_negative_varint(pb_ostream_t * stream,pb_uint64_t value)549 bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t value)
550 {
551 pb_byte_t buffer[10];
552 size_t i = 0;
553 size_t compensation = 32;/* we need to compensate 32 bits all set to 1 */
554
555 while (value)
556 {
557 buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80);
558 value >>= 7;
559 if (compensation)
560 {
561 /* re-set all the compensation bits we can or need */
562 size_t bits = compensation > 7 ? 7 : compensation;
563 value ^= (pb_uint64_t)((0xFFu >> (8 - bits)) << 25); /* set the number of bits needed on the lowest of the most significant 7 bits */
564 compensation -= bits;
565 }
566 i++;
567 }
568 buffer[i - 1] &= 0x7F; /* Unset top bit on last byte */
569
570 return pb_write(stream, buffer, i);
571 }
572 #endif
573
pb_encode_varint(pb_ostream_t * stream,pb_uint64_t value)574 bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value)
575 {
576 pb_byte_t buffer[10];
577 size_t i = 0;
578
579 if (value <= 0x7F)
580 {
581 pb_byte_t v = (pb_byte_t)value;
582 return pb_write(stream, &v, 1);
583 }
584
585 while (value)
586 {
587 buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80);
588 value >>= 7;
589 i++;
590 }
591 buffer[i-1] &= 0x7F; /* Unset top bit on last byte */
592
593 return pb_write(stream, buffer, i);
594 }
595
pb_encode_svarint(pb_ostream_t * stream,pb_int64_t value)596 bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value)
597 {
598 pb_uint64_t zigzagged;
599 if (value < 0)
600 zigzagged = ~((pb_uint64_t)value << 1);
601 else
602 zigzagged = (pb_uint64_t)value << 1;
603
604 return pb_encode_varint(stream, zigzagged);
605 }
606
pb_encode_fixed32(pb_ostream_t * stream,const void * value)607 bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value)
608 {
609 uint32_t val = *(const uint32_t*)value;
610 pb_byte_t bytes[4];
611 bytes[0] = (pb_byte_t)(val & 0xFF);
612 bytes[1] = (pb_byte_t)((val >> 8) & 0xFF);
613 bytes[2] = (pb_byte_t)((val >> 16) & 0xFF);
614 bytes[3] = (pb_byte_t)((val >> 24) & 0xFF);
615 return pb_write(stream, bytes, 4);
616 }
617
618 #ifndef PB_WITHOUT_64BIT
pb_encode_fixed64(pb_ostream_t * stream,const void * value)619 bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
620 {
621 uint64_t val = *(const uint64_t*)value;
622 pb_byte_t bytes[8];
623 bytes[0] = (pb_byte_t)(val & 0xFF);
624 bytes[1] = (pb_byte_t)((val >> 8) & 0xFF);
625 bytes[2] = (pb_byte_t)((val >> 16) & 0xFF);
626 bytes[3] = (pb_byte_t)((val >> 24) & 0xFF);
627 bytes[4] = (pb_byte_t)((val >> 32) & 0xFF);
628 bytes[5] = (pb_byte_t)((val >> 40) & 0xFF);
629 bytes[6] = (pb_byte_t)((val >> 48) & 0xFF);
630 bytes[7] = (pb_byte_t)((val >> 56) & 0xFF);
631 return pb_write(stream, bytes, 8);
632 }
633 #endif
634
pb_encode_tag(pb_ostream_t * stream,pb_wire_type_t wiretype,uint32_t field_number)635 bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
636 {
637 pb_uint64_t tag = ((pb_uint64_t)field_number << 3) | wiretype;
638 return pb_encode_varint(stream, tag);
639 }
640
pb_encode_tag_for_field(pb_ostream_t * stream,const pb_field_t * field)641 bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field)
642 {
643 pb_wire_type_t wiretype;
644 switch (PB_LTYPE(field->type))
645 {
646 case PB_LTYPE_VARINT:
647 case PB_LTYPE_UVARINT:
648 case PB_LTYPE_SVARINT:
649 wiretype = PB_WT_VARINT;
650 break;
651
652 case PB_LTYPE_FIXED32:
653 wiretype = PB_WT_32BIT;
654 break;
655
656 case PB_LTYPE_FIXED64:
657 wiretype = PB_WT_64BIT;
658 break;
659
660 case PB_LTYPE_BYTES:
661 case PB_LTYPE_STRING:
662 case PB_LTYPE_SUBMESSAGE:
663 case PB_LTYPE_FIXED_LENGTH_BYTES:
664 wiretype = PB_WT_STRING;
665 break;
666
667 default:
668 PB_RETURN_ERROR(stream, "invalid field type");
669 }
670
671 return pb_encode_tag(stream, wiretype, field->tag);
672 }
673
pb_encode_string(pb_ostream_t * stream,const pb_byte_t * buffer,size_t size)674 bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size)
675 {
676 if (!pb_encode_varint(stream, (pb_uint64_t)size))
677 return false;
678
679 return pb_write(stream, buffer, size);
680 }
681
pb_encode_submessage(pb_ostream_t * stream,const pb_field_t fields[],const void * src_struct)682 bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
683 {
684 /* First calculate the message size using a non-writing substream. */
685 pb_ostream_t substream = PB_OSTREAM_SIZING;
686 size_t size;
687 bool status;
688
689 if (!pb_encode(&substream, fields, src_struct))
690 {
691 #ifndef PB_NO_ERRMSG
692 stream->errmsg = substream.errmsg;
693 #endif
694 return false;
695 }
696
697 size = substream.bytes_written;
698
699 if (!pb_encode_varint(stream, (pb_uint64_t)size))
700 return false;
701
702 if (stream->callback == NULL)
703 return pb_write(stream, NULL, size); /* Just sizing */
704
705 if (stream->bytes_written + size > stream->max_size)
706 PB_RETURN_ERROR(stream, "stream full");
707
708 /* Use a substream to verify that a callback doesn't write more than
709 * what it did the first time. */
710 substream.callback = stream->callback;
711 substream.state = stream->state;
712 substream.max_size = size;
713 substream.bytes_written = 0;
714 #ifndef PB_NO_ERRMSG
715 substream.errmsg = NULL;
716 #endif
717
718 status = pb_encode(&substream, fields, src_struct);
719
720 stream->bytes_written += substream.bytes_written;
721 stream->state = substream.state;
722 #ifndef PB_NO_ERRMSG
723 stream->errmsg = substream.errmsg;
724 #endif
725
726 if (substream.bytes_written != size)
727 PB_RETURN_ERROR(stream, "submsg size changed");
728
729 return status;
730 }
731
732 /* Field encoders */
733
pb_enc_varint(pb_ostream_t * stream,const pb_field_t * field,const void * src)734 static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
735 {
736 pb_int64_t value = 0;
737
738 if (field->data_size == sizeof(int_least8_t))
739 value = *(const int_least8_t*)src;
740 else if (field->data_size == sizeof(int_least16_t))
741 value = *(const int_least16_t*)src;
742 else if (field->data_size == sizeof(int32_t))
743 value = *(const int32_t*)src;
744 else if (field->data_size == sizeof(pb_int64_t))
745 value = *(const pb_int64_t*)src;
746 else
747 PB_RETURN_ERROR(stream, "invalid data_size");
748
749 #ifdef PB_WITHOUT_64BIT
750 if (value < 0)
751 return pb_encode_negative_varint(stream, (pb_uint64_t)value);
752 else
753 #endif
754 return pb_encode_varint(stream, (pb_uint64_t)value);
755 }
756
pb_enc_uvarint(pb_ostream_t * stream,const pb_field_t * field,const void * src)757 static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
758 {
759 pb_uint64_t value = 0;
760
761 if (field->data_size == sizeof(uint_least8_t))
762 value = *(const uint_least8_t*)src;
763 else if (field->data_size == sizeof(uint_least16_t))
764 value = *(const uint_least16_t*)src;
765 else if (field->data_size == sizeof(uint32_t))
766 value = *(const uint32_t*)src;
767 else if (field->data_size == sizeof(pb_uint64_t))
768 value = *(const pb_uint64_t*)src;
769 else
770 PB_RETURN_ERROR(stream, "invalid data_size");
771
772 return pb_encode_varint(stream, value);
773 }
774
pb_enc_svarint(pb_ostream_t * stream,const pb_field_t * field,const void * src)775 static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
776 {
777 pb_int64_t value = 0;
778
779 if (field->data_size == sizeof(int_least8_t))
780 value = *(const int_least8_t*)src;
781 else if (field->data_size == sizeof(int_least16_t))
782 value = *(const int_least16_t*)src;
783 else if (field->data_size == sizeof(int32_t))
784 value = *(const int32_t*)src;
785 else if (field->data_size == sizeof(pb_int64_t))
786 value = *(const pb_int64_t*)src;
787 else
788 PB_RETURN_ERROR(stream, "invalid data_size");
789
790 return pb_encode_svarint(stream, value);
791 }
792
pb_enc_fixed64(pb_ostream_t * stream,const pb_field_t * field,const void * src)793 static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src)
794 {
795 PB_UNUSED(field);
796 #ifndef PB_WITHOUT_64BIT
797 return pb_encode_fixed64(stream, src);
798 #else
799 PB_UNUSED(src);
800 PB_RETURN_ERROR(stream, "no 64bit support");
801 #endif
802 }
803
pb_enc_fixed32(pb_ostream_t * stream,const pb_field_t * field,const void * src)804 static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src)
805 {
806 PB_UNUSED(field);
807 return pb_encode_fixed32(stream, src);
808 }
809
pb_enc_bytes(pb_ostream_t * stream,const pb_field_t * field,const void * src)810 static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
811 {
812 const pb_bytes_array_t *bytes = NULL;
813
814 bytes = (const pb_bytes_array_t*)src;
815
816 if (src == NULL)
817 {
818 /* Treat null pointer as an empty bytes field */
819 return pb_encode_string(stream, NULL, 0);
820 }
821
822 if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
823 PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size)
824 {
825 PB_RETURN_ERROR(stream, "bytes size exceeded");
826 }
827
828 return pb_encode_string(stream, bytes->bytes, bytes->size);
829 }
830
pb_enc_string(pb_ostream_t * stream,const pb_field_t * field,const void * src)831 static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src)
832 {
833 size_t size = 0;
834 size_t max_size = field->data_size;
835 const char *p = (const char*)src;
836
837 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
838 max_size = (size_t)-1;
839
840 if (src == NULL)
841 {
842 size = 0; /* Treat null pointer as an empty string */
843 }
844 else
845 {
846 /* strnlen() is not always available, so just use a loop */
847 while (size < max_size && *p != '\0')
848 {
849 size++;
850 p++;
851 }
852 }
853
854 return pb_encode_string(stream, (const pb_byte_t*)src, size);
855 }
856
pb_enc_submessage(pb_ostream_t * stream,const pb_field_t * field,const void * src)857 static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src)
858 {
859 if (field->ptr == NULL)
860 PB_RETURN_ERROR(stream, "invalid field descriptor");
861
862 return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src);
863 }
864
pb_enc_fixed_length_bytes(pb_ostream_t * stream,const pb_field_t * field,const void * src)865 static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
866 {
867 return pb_encode_string(stream, (const pb_byte_t*)src, field->data_size);
868 }
869
870