All in one solution demonstrating how to use nanopb Protocol Buffers library from within mbed environment. Test case is very simple. It works.

Dependencies:   nanopb protocol

Original import was an all-in-one solution that only depends on mbed.

Current implementation extracted 2 librarires:

1) nanopb contains code required to use nanopb and Timestamp dependency. 2) protocol is a specific research protocol used by LCE at Itron at the moment of commit.

The application decodes Protocol Buffers message generated with GO application using the same 'protocol'. This test level application decodes message and validates that it matches expected.

It is simply a proof that nanopb library can be used.

Committer:
sgnezdov
Date:
Wed Jul 12 22:40:29 2017 +0000
Revision:
0:fbdd0d307c19
initial import demonstrates how to decode Sample protocol buffers message.

Who changed what in which revision?

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