1 /* pb_encode.c -- encode a protobuf using minimal resources
3 * 2011 Petteri Aimonen <jpa@kapsi.fi>
6 #define NANOPB_INTERNALS
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.
14 #if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
17 #define checkreturn __attribute__((warn_unused_result))
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;
25 static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_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);
32 /* --- Function pointers to field encoders ---
33 * Order in the array must match pb_action_t LTYPE numbering.
35 static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = {
47 /*******************************
48 * pb_ostream_t implementation *
49 *******************************/
51 static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
53 uint8_t *dest = (uint8_t*)stream->state;
54 stream->state = dest + count;
62 pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize)
66 stream.callback = (void*)1; /* Just a marker value */
68 stream.callback = &buf_write;
71 stream.max_size = bufsize;
72 stream.bytes_written = 0;
79 bool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
81 if (stream->callback != NULL)
83 if (stream->bytes_written + count > stream->max_size)
84 PB_RETURN_ERROR(stream, "stream full");
87 if (!buf_write(stream, buf, count))
88 PB_RETURN_ERROR(stream, "io error");
90 if (!stream->callback(stream, buf, count))
91 PB_RETURN_ERROR(stream, "io error");
95 stream->bytes_written += count;
99 /*************************
100 * Encode a single field *
101 *************************/
103 /* Encode a static array. Handles the size calculations and possible packing. */
104 static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field,
105 const void *pData, size_t count, pb_encoder_t func)
114 if (count > field->array_size)
115 PB_RETURN_ERROR(stream, "array max size exceeded");
117 /* We always pack arrays if the datatype allows it. */
118 if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
120 if (!pb_encode_tag(stream, PB_WT_STRING, field->tag))
123 /* Determine the total size of packed array. */
124 if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32)
128 else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
134 pb_ostream_t sizestream = PB_OSTREAM_SIZING;
136 for (i = 0; i < count; i++)
138 if (!func(&sizestream, field, p))
140 p = (const char*)p + field->data_size;
142 size = sizestream.bytes_written;
145 if (!pb_encode_varint(stream, (uint64_t)size))
148 if (stream->callback == NULL)
149 return pb_write(stream, NULL, size); /* Just sizing.. */
153 for (i = 0; i < count; i++)
155 if (!func(stream, field, p))
157 p = (const char*)p + field->data_size;
163 for (i = 0; i < count; i++)
165 if (!pb_encode_tag_for_field(stream, field))
167 if (!func(stream, field, p))
169 p = (const char*)p + field->data_size;
176 /* Encode a field with static allocation, i.e. one whose data is stored
177 * in the structure itself. */
178 static bool checkreturn encode_static_field(pb_ostream_t *stream,
179 const pb_field_t *field, const void *pData)
185 func = PB_ENCODERS[PB_LTYPE(field->type)];
187 if (field->size_offset)
188 pSize = (const char*)pData + field->size_offset;
192 switch (PB_HTYPE(field->type))
194 case PB_HTYPE_REQUIRED:
195 if (!pb_encode_tag_for_field(stream, field))
197 if (!func(stream, field, pData))
201 case PB_HTYPE_OPTIONAL:
202 if (*(const bool*)pSize)
204 if (!pb_encode_tag_for_field(stream, field))
207 if (!func(stream, field, pData))
212 case PB_HTYPE_REPEATED:
213 if (!encode_array(stream, field, pData, *(const size_t*)pSize, func))
218 PB_RETURN_ERROR(stream, "invalid field type");
224 /* Encode a field with callback semantics. This means that a user function is
225 * called to provide and encode the actual data. */
226 static bool checkreturn encode_callback_field(pb_ostream_t *stream,
227 const pb_field_t *field, const void *pData)
229 const pb_callback_t *callback = (const pb_callback_t*)pData;
231 #ifdef PB_OLD_CALLBACK_STYLE
232 const void *arg = callback->arg;
234 void * const *arg = &(callback->arg);
237 if (callback->funcs.encode != NULL)
239 if (!callback->funcs.encode(stream, field, arg))
240 PB_RETURN_ERROR(stream, "callback error");
245 /* Encode a single field of any callback or static type. */
246 static bool checkreturn encode_field(pb_ostream_t *stream,
247 const pb_field_t *field, const void *pData)
249 switch (PB_ATYPE(field->type))
251 case PB_ATYPE_STATIC:
252 return encode_static_field(stream, field, pData);
254 case PB_ATYPE_CALLBACK:
255 return encode_callback_field(stream, field, pData);
258 PB_RETURN_ERROR(stream, "invalid field type");
262 /* Default handler for extension fields. Expects to have a pb_field_t
263 * pointer in the extension->type->arg field. */
264 static bool checkreturn default_extension_encoder(pb_ostream_t *stream,
265 const pb_extension_t *extension)
267 const pb_field_t *field = (const pb_field_t*)extension->type->arg;
268 return encode_field(stream, field, extension->dest);
271 /* Walk through all the registered extensions and give them a chance
272 * to encode themselves. */
273 static bool checkreturn encode_extension_field(pb_ostream_t *stream,
274 const pb_field_t *field, const void *pData)
276 const pb_extension_t *extension = *(const pb_extension_t* const *)pData;
282 if (extension->type->encode)
283 status = extension->type->encode(stream, extension);
285 status = default_extension_encoder(stream, extension);
290 extension = extension->next;
296 /*********************
297 * Encode all fields *
298 *********************/
300 bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
302 const pb_field_t *field = fields;
303 const void *pData = src_struct;
304 size_t prev_size = 0;
306 while (field->tag != 0)
308 pData = (const char*)pData + prev_size + field->data_offset;
309 prev_size = field->data_size;
311 /* Special case for static arrays */
312 if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
313 PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
315 prev_size *= field->array_size;
318 if (PB_LTYPE(field->type) == PB_LTYPE_EXTENSION)
320 /* Special case for the extension field placeholder */
321 if (!encode_extension_field(stream, field, pData))
327 if (!encode_field(stream, field, pData))
337 bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
339 return pb_encode_submessage(stream, fields, src_struct);
342 /********************
344 ********************/
345 bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value)
351 return pb_write(stream, (uint8_t*)&value, 1);
355 buffer[i] = (uint8_t)((value & 0x7F) | 0x80);
359 buffer[i-1] &= 0x7F; /* Unset top bit on last byte */
361 return pb_write(stream, buffer, i);
364 bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value)
368 zigzagged = (uint64_t)(~(value << 1));
370 zigzagged = (uint64_t)(value << 1);
372 return pb_encode_varint(stream, zigzagged);
375 bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value)
377 #ifdef __BIG_ENDIAN__
378 const uint8_t *bytes = value;
380 lebytes[0] = bytes[3];
381 lebytes[1] = bytes[2];
382 lebytes[2] = bytes[1];
383 lebytes[3] = bytes[0];
384 return pb_write(stream, lebytes, 4);
386 return pb_write(stream, (const uint8_t*)value, 4);
390 bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
392 #ifdef __BIG_ENDIAN__
393 const uint8_t *bytes = value;
395 lebytes[0] = bytes[7];
396 lebytes[1] = bytes[6];
397 lebytes[2] = bytes[5];
398 lebytes[3] = bytes[4];
399 lebytes[4] = bytes[3];
400 lebytes[5] = bytes[2];
401 lebytes[6] = bytes[1];
402 lebytes[7] = bytes[0];
403 return pb_write(stream, lebytes, 8);
405 return pb_write(stream, (const uint8_t*)value, 8);
409 bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
411 uint64_t tag = wiretype | (field_number << 3);
412 return pb_encode_varint(stream, tag);
415 bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field)
417 pb_wire_type_t wiretype;
418 switch (PB_LTYPE(field->type))
420 case PB_LTYPE_VARINT:
421 case PB_LTYPE_SVARINT:
422 wiretype = PB_WT_VARINT;
425 case PB_LTYPE_FIXED32:
426 wiretype = PB_WT_32BIT;
429 case PB_LTYPE_FIXED64:
430 wiretype = PB_WT_64BIT;
434 case PB_LTYPE_STRING:
435 case PB_LTYPE_SUBMESSAGE:
436 wiretype = PB_WT_STRING;
440 PB_RETURN_ERROR(stream, "invalid field type");
443 return pb_encode_tag(stream, wiretype, field->tag);
446 bool checkreturn pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size)
448 if (!pb_encode_varint(stream, (uint64_t)size))
451 return pb_write(stream, buffer, size);
454 bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
456 /* First calculate the message size using a non-writing substream. */
457 pb_ostream_t substream = PB_OSTREAM_SIZING;
461 if (!pb_encode(&substream, fields, src_struct))
464 size = substream.bytes_written;
466 if (!pb_encode_varint(stream, (uint64_t)size))
469 if (stream->callback == NULL)
470 return pb_write(stream, NULL, size); /* Just sizing */
472 if (stream->bytes_written + size > stream->max_size)
473 PB_RETURN_ERROR(stream, "stream full");
475 /* Use a substream to verify that a callback doesn't write more than
476 * what it did the first time. */
477 substream.callback = stream->callback;
478 substream.state = stream->state;
479 substream.max_size = size;
480 substream.bytes_written = 0;
482 substream.errmsg = NULL;
485 status = pb_encode(&substream, fields, src_struct);
487 stream->bytes_written += substream.bytes_written;
488 stream->state = substream.state;
490 stream->errmsg = substream.errmsg;
493 if (substream.bytes_written != size)
494 PB_RETURN_ERROR(stream, "submsg size changed");
501 bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
505 switch (field->data_size)
507 case 1: value = *(const uint8_t*)src; break;
508 case 2: value = *(const uint16_t*)src; break;
509 case 4: value = *(const uint32_t*)src; break;
510 case 8: value = *(const uint64_t*)src; break;
511 default: PB_RETURN_ERROR(stream, "invalid data_size");
514 return pb_encode_varint(stream, value);
517 bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
521 switch (field->data_size)
523 case 4: value = *(const int32_t*)src; break;
524 case 8: value = *(const int64_t*)src; break;
525 default: PB_RETURN_ERROR(stream, "invalid data_size");
528 return pb_encode_svarint(stream, value);
531 bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src)
534 return pb_encode_fixed64(stream, src);
537 bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src)
540 return pb_encode_fixed32(stream, src);
543 bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
545 const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src;
547 if (bytes->size + offsetof(pb_bytes_array_t, bytes) > field->data_size)
548 PB_RETURN_ERROR(stream, "bytes size exceeded");
550 return pb_encode_string(stream, bytes->bytes, bytes->size);
553 bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src)
555 /* strnlen() is not always available, so just use a for-loop */
557 const char *p = (const char*)src;
558 while (size < field->data_size && *p != '\0')
564 return pb_encode_string(stream, (const uint8_t*)src, size);
567 bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src)
569 if (field->ptr == NULL)
570 PB_RETURN_ERROR(stream, "invalid field descriptor");
572 return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src);