17ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* pb_encode.c -- encode a protobuf using minimal resources
27ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *
37ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * 2011 Petteri Aimonen <jpa@kapsi.fi>
47ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen */
57ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
67ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include "pb.h"
77ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include "pb_encode.h"
87ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
97ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Use the GCC warn_unused_result attribute to check that all return values
107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * are propagated correctly. On other compilers and gcc before 3.4.0 just
117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * ignore the annotation.
127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen */
137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    #define checkreturn
157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#else
167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    #define checkreturn __attribute__((warn_unused_result))
177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif
187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/**************************************
207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * Declarations internal to this file *
217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen **************************************/
227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohentypedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn;
237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count);
257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func);
267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension);
287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src);
337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src);
347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src);
357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src);
367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src);
377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* --- Function pointers to field encoders ---
397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * Order in the array must match pb_action_t LTYPE numbering.
407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen */
417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = {
427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    &pb_enc_varint,
437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    &pb_enc_uvarint,
447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    &pb_enc_svarint,
457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    &pb_enc_fixed32,
467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    &pb_enc_fixed64,
477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    &pb_enc_bytes,
497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    &pb_enc_string,
507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    &pb_enc_submessage,
517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    NULL /* extensions */
527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen};
537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/*******************************
557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * pb_ostream_t implementation *
567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *******************************/
577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    uint8_t *dest = (uint8_t*)stream->state;
617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    stream->state = dest + count;
627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    while (count--)
647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        *dest++ = *buf++;
657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return true;
677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenpb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize)
707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    pb_ostream_t stream;
727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifdef PB_BUFFER_ONLY
737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    stream.callback = (void*)1; /* Just a marker value */
747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#else
757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    stream.callback = &buf_write;
767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif
777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    stream.state = buf;
787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    stream.max_size = bufsize;
797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    stream.bytes_written = 0;
807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifndef PB_NO_ERRMSG
817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    stream.errmsg = NULL;
827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif
837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return stream;
847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (stream->callback != NULL)
897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (stream->bytes_written + count > stream->max_size)
917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            PB_RETURN_ERROR(stream, "stream full");
927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifdef PB_BUFFER_ONLY
947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (!buf_write(stream, buf, count))
957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            PB_RETURN_ERROR(stream, "io error");
967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#else
977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (!stream->callback(stream, buf, count))
987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            PB_RETURN_ERROR(stream, "io error");
997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif
1007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
1017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    stream->bytes_written += count;
1037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return true;
1047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
1057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/*************************
1077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * Encode a single field *
1087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *************************/
1097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Encode a static array. Handles the size calculations and possible packing. */
1117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field,
1127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                         const void *pData, size_t count, pb_encoder_t func)
1137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
1147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    size_t i;
1157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const void *p;
1167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    size_t size;
1177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (count == 0)
1197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return true;
1207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size)
1227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        PB_RETURN_ERROR(stream, "array max size exceeded");
1237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    /* We always pack arrays if the datatype allows it. */
1257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
1267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
1277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (!pb_encode_tag(stream, PB_WT_STRING, field->tag))
1287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            return false;
1297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        /* Determine the total size of packed array. */
1317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32)
1327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        {
1337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            size = 4 * count;
1347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        }
1357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
1367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        {
1377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            size = 8 * count;
1387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        }
1397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        else
1407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        {
1417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            pb_ostream_t sizestream = PB_OSTREAM_SIZING;
1427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            p = pData;
1437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            for (i = 0; i < count; i++)
1447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            {
1457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                if (!func(&sizestream, field, p))
1467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                    return false;
1477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                p = (const char*)p + field->data_size;
1487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            }
1497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            size = sizestream.bytes_written;
1507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        }
1517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (!pb_encode_varint(stream, (uint64_t)size))
1537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            return false;
1547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (stream->callback == NULL)
1567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            return pb_write(stream, NULL, size); /* Just sizing.. */
1577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        /* Write the data */
1597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        p = pData;
1607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        for (i = 0; i < count; i++)
1617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        {
1627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            if (!func(stream, field, p))
1637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                return false;
1647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            p = (const char*)p + field->data_size;
1657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        }
1667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
1677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    else
1687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
1697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        p = pData;
1707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        for (i = 0; i < count; i++)
1717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        {
1727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            if (!pb_encode_tag_for_field(stream, field))
1737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                return false;
1747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            /* Normally the data is stored directly in the array entries, but
1767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen             * for pointer-type string and bytes fields, the array entries are
1777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen             * actually pointers themselves also. So we have to dereference once
1787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen             * more to get to the actual data. */
1797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            if (PB_ATYPE(field->type) == PB_ATYPE_POINTER &&
1807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                (PB_LTYPE(field->type) == PB_LTYPE_STRING ||
1817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                 PB_LTYPE(field->type) == PB_LTYPE_BYTES))
1827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            {
1837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                if (!func(stream, field, *(const void* const*)p))
1847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                    return false;
1857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            }
1867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            else
1877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            {
1887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                if (!func(stream, field, p))
1897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                    return false;
1907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            }
1917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            p = (const char*)p + field->data_size;
1927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        }
1937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
1947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return true;
1967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
1977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Encode a field with static or pointer allocation, i.e. one whose data
1997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * is available to the encoder directly. */
2007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn encode_basic_field(pb_ostream_t *stream,
2017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const pb_field_t *field, const void *pData)
2027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
2037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    pb_encoder_t func;
2047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const void *pSize;
2057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    bool implicit_has = true;
2067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    func = PB_ENCODERS[PB_LTYPE(field->type)];
2087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (field->size_offset)
2107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        pSize = (const char*)pData + field->size_offset;
2117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    else
2127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        pSize = &implicit_has;
2137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
2157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
2167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        /* pData is a pointer to the field, which contains pointer to
2177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen         * the data. If the 2nd pointer is NULL, it is interpreted as if
2187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen         * the has_field was false.
2197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen         */
2207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        pData = *(const void* const*)pData;
2227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        implicit_has = (pData != NULL);
2237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
2247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    switch (PB_HTYPE(field->type))
2267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
2277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case PB_HTYPE_REQUIRED:
2287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            if (!pData)
2297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                PB_RETURN_ERROR(stream, "missing required field");
2307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            if (!pb_encode_tag_for_field(stream, field))
2317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                return false;
2327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            if (!func(stream, field, pData))
2337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                return false;
2347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            break;
2357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case PB_HTYPE_OPTIONAL:
2377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            if (*(const bool*)pSize)
2387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            {
2397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                if (!pb_encode_tag_for_field(stream, field))
2407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                    return false;
2417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                if (!func(stream, field, pData))
2437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                    return false;
2447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            }
2457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            break;
2467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case PB_HTYPE_REPEATED:
2487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            if (!encode_array(stream, field, pData, *(const size_t*)pSize, func))
2497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                return false;
2507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            break;
2517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        default:
2537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            PB_RETURN_ERROR(stream, "invalid field type");
2547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
2557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return true;
2577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
2587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Encode a field with callback semantics. This means that a user function is
2607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * called to provide and encode the actual data. */
2617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn encode_callback_field(pb_ostream_t *stream,
2627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const pb_field_t *field, const void *pData)
2637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
2647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const pb_callback_t *callback = (const pb_callback_t*)pData;
2657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifdef PB_OLD_CALLBACK_STYLE
2677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const void *arg = callback->arg;
2687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#else
2697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    void * const *arg = &(callback->arg);
2707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif
2717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (callback->funcs.encode != NULL)
2737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
2747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (!callback->funcs.encode(stream, field, arg))
2757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            PB_RETURN_ERROR(stream, "callback error");
2767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
2777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return true;
2787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
2797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Encode a single field of any callback or static type. */
2817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn encode_field(pb_ostream_t *stream,
2827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const pb_field_t *field, const void *pData)
2837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
2847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    switch (PB_ATYPE(field->type))
2857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
2867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case PB_ATYPE_STATIC:
2877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case PB_ATYPE_POINTER:
2887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            return encode_basic_field(stream, field, pData);
2897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case PB_ATYPE_CALLBACK:
2917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            return encode_callback_field(stream, field, pData);
2927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        default:
2947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            PB_RETURN_ERROR(stream, "invalid field type");
2957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
2967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
2977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
2987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Default handler for extension fields. Expects to have a pb_field_t
2997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * pointer in the extension->type->arg field. */
3007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn default_extension_encoder(pb_ostream_t *stream,
3017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const pb_extension_t *extension)
3027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
3037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const pb_field_t *field = (const pb_field_t*)extension->type->arg;
3047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return encode_field(stream, field, extension->dest);
3057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
3067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Walk through all the registered extensions and give them a chance
3087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * to encode themselves. */
3097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn encode_extension_field(pb_ostream_t *stream,
3107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const pb_field_t *field, const void *pData)
3117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
3127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const pb_extension_t *extension = *(const pb_extension_t* const *)pData;
3137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    UNUSED(field);
3147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    while (extension)
3167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
3177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        bool status;
3187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (extension->type->encode)
3197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            status = extension->type->encode(stream, extension);
3207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        else
3217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            status = default_extension_encoder(stream, extension);
3227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (!status)
3247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            return false;
3257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        extension = extension->next;
3277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
3287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return true;
3307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
3317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/*********************
3337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * Encode all fields *
3347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *********************/
3357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
3377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
3387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const pb_field_t *field = fields;
3397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const void *pData = src_struct;
3407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    size_t prev_size = 0;
3417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    while (field->tag != 0)
3437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
3447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        pData = (const char*)pData + prev_size + field->data_offset;
3457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
3467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            prev_size = sizeof(const void*);
3477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        else
3487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            prev_size = field->data_size;
3497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        /* Special case for static arrays */
3517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
3527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
3537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        {
3547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            prev_size *= field->array_size;
3557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        }
3567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (PB_LTYPE(field->type) == PB_LTYPE_EXTENSION)
3587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        {
3597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            /* Special case for the extension field placeholder */
3607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            if (!encode_extension_field(stream, field, pData))
3617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                return false;
3627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        }
3637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        else
3647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        {
3657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            /* Regular field */
3667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            if (!encode_field(stream, field, pData))
3677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen                return false;
3687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        }
3697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        field++;
3717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
3727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return true;
3747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
3757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
3777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
3787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_encode_submessage(stream, fields, src_struct);
3797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
3807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct)
3827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
3837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    pb_ostream_t stream = PB_OSTREAM_SIZING;
3847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (!pb_encode(&stream, fields, src_struct))
3867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return false;
3877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    *size = stream.bytes_written;
3897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return true;
3907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
3917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
3927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/********************
3937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * Helper functions *
3947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ********************/
3957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value)
3967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
3977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    uint8_t buffer[10];
3987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    size_t i = 0;
3997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (value == 0)
4017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return pb_write(stream, (uint8_t*)&value, 1);
4027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    while (value)
4047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
4057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        buffer[i] = (uint8_t)((value & 0x7F) | 0x80);
4067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        value >>= 7;
4077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        i++;
4087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
4097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    buffer[i-1] &= 0x7F; /* Unset top bit on last byte */
4107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_write(stream, buffer, i);
4127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
4137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value)
4157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
4167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    uint64_t zigzagged;
4177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (value < 0)
4187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        zigzagged = ~((uint64_t)value << 1);
4197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    else
4207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        zigzagged = (uint64_t)value << 1;
4217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_encode_varint(stream, zigzagged);
4237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
4247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value)
4267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
4277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    #ifdef __BIG_ENDIAN__
4287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const uint8_t *bytes = value;
4297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    uint8_t lebytes[4];
4307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    lebytes[0] = bytes[3];
4317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    lebytes[1] = bytes[2];
4327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    lebytes[2] = bytes[1];
4337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    lebytes[3] = bytes[0];
4347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_write(stream, lebytes, 4);
4357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    #else
4367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_write(stream, (const uint8_t*)value, 4);
4377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    #endif
4387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
4397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
4417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
4427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    #ifdef __BIG_ENDIAN__
4437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const uint8_t *bytes = value;
4447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    uint8_t lebytes[8];
4457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    lebytes[0] = bytes[7];
4467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    lebytes[1] = bytes[6];
4477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    lebytes[2] = bytes[5];
4487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    lebytes[3] = bytes[4];
4497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    lebytes[4] = bytes[3];
4507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    lebytes[5] = bytes[2];
4517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    lebytes[6] = bytes[1];
4527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    lebytes[7] = bytes[0];
4537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_write(stream, lebytes, 8);
4547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    #else
4557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_write(stream, (const uint8_t*)value, 8);
4567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    #endif
4577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
4587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
4607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
4617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    uint64_t tag = ((uint64_t)field_number << 3) | wiretype;
4627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_encode_varint(stream, tag);
4637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
4647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field)
4667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
4677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    pb_wire_type_t wiretype;
4687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    switch (PB_LTYPE(field->type))
4697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
4707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case PB_LTYPE_VARINT:
4717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case PB_LTYPE_UVARINT:
4727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case PB_LTYPE_SVARINT:
4737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            wiretype = PB_WT_VARINT;
4747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            break;
4757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case PB_LTYPE_FIXED32:
4777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            wiretype = PB_WT_32BIT;
4787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            break;
4797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case PB_LTYPE_FIXED64:
4817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            wiretype = PB_WT_64BIT;
4827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            break;
4837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case PB_LTYPE_BYTES:
4857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case PB_LTYPE_STRING:
4867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case PB_LTYPE_SUBMESSAGE:
4877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            wiretype = PB_WT_STRING;
4887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            break;
4897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        default:
4917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            PB_RETURN_ERROR(stream, "invalid field type");
4927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
4937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_encode_tag(stream, wiretype, field->tag);
4957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
4967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
4977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size)
4987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
4997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (!pb_encode_varint(stream, (uint64_t)size))
5007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return false;
5017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_write(stream, buffer, size);
5037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
5047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
5067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
5077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    /* First calculate the message size using a non-writing substream. */
5087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    pb_ostream_t substream = PB_OSTREAM_SIZING;
5097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    size_t size;
5107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    bool status;
5117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (!pb_encode(&substream, fields, src_struct))
5137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
5147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifndef PB_NO_ERRMSG
5157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        stream->errmsg = substream.errmsg;
5167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif
5177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return false;
5187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
5197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    size = substream.bytes_written;
5217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (!pb_encode_varint(stream, (uint64_t)size))
5237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return false;
5247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (stream->callback == NULL)
5267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return pb_write(stream, NULL, size); /* Just sizing */
5277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (stream->bytes_written + size > stream->max_size)
5297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        PB_RETURN_ERROR(stream, "stream full");
5307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    /* Use a substream to verify that a callback doesn't write more than
5327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen     * what it did the first time. */
5337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    substream.callback = stream->callback;
5347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    substream.state = stream->state;
5357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    substream.max_size = size;
5367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    substream.bytes_written = 0;
5377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifndef PB_NO_ERRMSG
5387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    substream.errmsg = NULL;
5397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif
5407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    status = pb_encode(&substream, fields, src_struct);
5427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    stream->bytes_written += substream.bytes_written;
5447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    stream->state = substream.state;
5457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifndef PB_NO_ERRMSG
5467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    stream->errmsg = substream.errmsg;
5477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif
5487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (substream.bytes_written != size)
5507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        PB_RETURN_ERROR(stream, "submsg size changed");
5517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return status;
5537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
5547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Field encoders */
5567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
5587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
5597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    int64_t value = 0;
5607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    /* Cases 1 and 2 are for compilers that have smaller types for bool
5627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen     * or enums. */
5637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    switch (field->data_size)
5647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
5657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case 1: value = *(const int8_t*)src; break;
5667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case 2: value = *(const int16_t*)src; break;
5677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case 4: value = *(const int32_t*)src; break;
5687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case 8: value = *(const int64_t*)src; break;
5697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        default: PB_RETURN_ERROR(stream, "invalid data_size");
5707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
5717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_encode_varint(stream, (uint64_t)value);
5737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
5747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
5767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
5777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    uint64_t value = 0;
5787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    switch (field->data_size)
5807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
5817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case 4: value = *(const uint32_t*)src; break;
5827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case 8: value = *(const uint64_t*)src; break;
5837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        default: PB_RETURN_ERROR(stream, "invalid data_size");
5847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
5857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_encode_varint(stream, value);
5877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
5887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
5907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
5917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    int64_t value = 0;
5927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
5937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    switch (field->data_size)
5947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
5957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case 4: value = *(const int32_t*)src; break;
5967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        case 8: value = *(const int64_t*)src; break;
5977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        default: PB_RETURN_ERROR(stream, "invalid data_size");
5987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
5997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
6007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_encode_svarint(stream, value);
6017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
6027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
6037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src)
6047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
6057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    UNUSED(field);
6067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_encode_fixed64(stream, src);
6077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
6087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
6097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src)
6107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
6117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    UNUSED(field);
6127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_encode_fixed32(stream, src);
6137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
6147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
6157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
6167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
6177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src;
6187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
6197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (src == NULL)
6207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
6217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        /* Threat null pointer as an empty bytes field */
6227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return pb_encode_string(stream, NULL, 0);
6237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
6247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
6257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
6267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size)
6277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
6287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        PB_RETURN_ERROR(stream, "bytes size exceeded");
6297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
6307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
6317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_encode_string(stream, bytes->bytes, bytes->size);
6327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
6337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
6347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src)
6357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
6367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    /* strnlen() is not always available, so just use a loop */
6377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    size_t size = 0;
6387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    size_t max_size = field->data_size;
6397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    const char *p = (const char*)src;
6407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
6417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
6427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        max_size = (size_t)-1;
6437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
6447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (src == NULL)
6457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
6467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        size = 0; /* Threat null pointer as an empty string */
6477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
6487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    else
6497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
6507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        while (size < max_size && *p != '\0')
6517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        {
6527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            size++;
6537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            p++;
6547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        }
6557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
6567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
6577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_encode_string(stream, (const uint8_t*)src, size);
6587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
6597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
6607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src)
6617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
6627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (field->ptr == NULL)
6637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        PB_RETURN_ERROR(stream, "invalid field descriptor");
6647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
6657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src);
6667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
6677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
668