this is a sample for mbed(LPC1768)

Committer:
1
Date:
Thu Nov 19 10:17:55 2015 +0800
Revision:
0:3163adfd2cf1
????????????????????????
1.callback
2.thread
3.auto-connect,time-up

Who changed what in which revision?

UserRevisionLine numberNew contents of line
1 0:3163adfd2cf1 1 /* pb_encode.c -- encode a protobuf using minimal resources
1 0:3163adfd2cf1 2 *
1 0:3163adfd2cf1 3 * 2011 Petteri Aimonen <jpa@kapsi.fi>
1 0:3163adfd2cf1 4 */
1 0:3163adfd2cf1 5
1 0:3163adfd2cf1 6 #define NANOPB_INTERNALS
1 0:3163adfd2cf1 7 #include "pb.h"
1 0:3163adfd2cf1 8 #include "pb_encode.h"
1 0:3163adfd2cf1 9
1 0:3163adfd2cf1 10 /* Use the GCC warn_unused_result attribute to check that all return values
1 0:3163adfd2cf1 11 * are propagated correctly. On other compilers and gcc before 3.4.0 just
1 0:3163adfd2cf1 12 * ignore the annotation.
1 0:3163adfd2cf1 13 */
1 0:3163adfd2cf1 14 #if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
1 0:3163adfd2cf1 15 #define checkreturn
1 0:3163adfd2cf1 16 #else
1 0:3163adfd2cf1 17 #define checkreturn __attribute__((warn_unused_result))
1 0:3163adfd2cf1 18 #endif
1 0:3163adfd2cf1 19
1 0:3163adfd2cf1 20 /**************************************
1 0:3163adfd2cf1 21 * Declarations internal to this file *
1 0:3163adfd2cf1 22 **************************************/
1 0:3163adfd2cf1 23 typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn;
1 0:3163adfd2cf1 24
1 0:3163adfd2cf1 25 static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count);
1 0:3163adfd2cf1 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);
1 0:3163adfd2cf1 27 static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
1 0:3163adfd2cf1 28 static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension);
1 0:3163adfd2cf1 29 static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
1 0:3163adfd2cf1 30 static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
1 0:3163adfd2cf1 31 static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
1 0:3163adfd2cf1 32 static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
1 0:3163adfd2cf1 33 static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src);
1 0:3163adfd2cf1 34 static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src);
1 0:3163adfd2cf1 35 static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src);
1 0:3163adfd2cf1 36 static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src);
1 0:3163adfd2cf1 37 static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src);
1 0:3163adfd2cf1 38
1 0:3163adfd2cf1 39 /* --- Function pointers to field encoders ---
1 0:3163adfd2cf1 40 * Order in the array must match pb_action_t LTYPE numbering.
1 0:3163adfd2cf1 41 */
1 0:3163adfd2cf1 42 static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = {
1 0:3163adfd2cf1 43 &pb_enc_varint,
1 0:3163adfd2cf1 44 &pb_enc_uvarint,
1 0:3163adfd2cf1 45 &pb_enc_svarint,
1 0:3163adfd2cf1 46 &pb_enc_fixed32,
1 0:3163adfd2cf1 47 &pb_enc_fixed64,
1 0:3163adfd2cf1 48
1 0:3163adfd2cf1 49 &pb_enc_bytes,
1 0:3163adfd2cf1 50 &pb_enc_string,
1 0:3163adfd2cf1 51 &pb_enc_submessage,
1 0:3163adfd2cf1 52 NULL /* extensions */
1 0:3163adfd2cf1 53 };
1 0:3163adfd2cf1 54
1 0:3163adfd2cf1 55 /*******************************
1 0:3163adfd2cf1 56 * pb_ostream_t implementation *
1 0:3163adfd2cf1 57 *******************************/
1 0:3163adfd2cf1 58
1 0:3163adfd2cf1 59 static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
1 0:3163adfd2cf1 60 {
1 0:3163adfd2cf1 61 uint8_t *dest = (uint8_t*)stream->state;
1 0:3163adfd2cf1 62 stream->state = dest + count;
1 0:3163adfd2cf1 63
1 0:3163adfd2cf1 64 while (count--)
1 0:3163adfd2cf1 65 *dest++ = *buf++;
1 0:3163adfd2cf1 66
1 0:3163adfd2cf1 67 return true;
1 0:3163adfd2cf1 68 }
1 0:3163adfd2cf1 69
1 0:3163adfd2cf1 70 pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize)
1 0:3163adfd2cf1 71 {
1 0:3163adfd2cf1 72 pb_ostream_t stream;
1 0:3163adfd2cf1 73 #ifdef PB_BUFFER_ONLY
1 0:3163adfd2cf1 74 stream.callback = (void*)1; /* Just a marker value */
1 0:3163adfd2cf1 75 #else
1 0:3163adfd2cf1 76 stream.callback = &buf_write;
1 0:3163adfd2cf1 77 #endif
1 0:3163adfd2cf1 78 stream.state = buf;
1 0:3163adfd2cf1 79 stream.max_size = bufsize;
1 0:3163adfd2cf1 80 stream.bytes_written = 0;
1 0:3163adfd2cf1 81 #ifndef PB_NO_ERRMSG
1 0:3163adfd2cf1 82 stream.errmsg = NULL;
1 0:3163adfd2cf1 83 #endif
1 0:3163adfd2cf1 84 return stream;
1 0:3163adfd2cf1 85 }
1 0:3163adfd2cf1 86
1 0:3163adfd2cf1 87 bool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
1 0:3163adfd2cf1 88 {
1 0:3163adfd2cf1 89 if (stream->callback != NULL)
1 0:3163adfd2cf1 90 {
1 0:3163adfd2cf1 91 if (stream->bytes_written + count > stream->max_size)
1 0:3163adfd2cf1 92 PB_RETURN_ERROR(stream, "stream full");
1 0:3163adfd2cf1 93
1 0:3163adfd2cf1 94 #ifdef PB_BUFFER_ONLY
1 0:3163adfd2cf1 95 if (!buf_write(stream, buf, count))
1 0:3163adfd2cf1 96 PB_RETURN_ERROR(stream, "io error");
1 0:3163adfd2cf1 97 #else
1 0:3163adfd2cf1 98 if (!stream->callback(stream, buf, count))
1 0:3163adfd2cf1 99 PB_RETURN_ERROR(stream, "io error");
1 0:3163adfd2cf1 100 #endif
1 0:3163adfd2cf1 101 }
1 0:3163adfd2cf1 102
1 0:3163adfd2cf1 103 stream->bytes_written += count;
1 0:3163adfd2cf1 104 return true;
1 0:3163adfd2cf1 105 }
1 0:3163adfd2cf1 106
1 0:3163adfd2cf1 107 /*************************
1 0:3163adfd2cf1 108 * Encode a single field *
1 0:3163adfd2cf1 109 *************************/
1 0:3163adfd2cf1 110
1 0:3163adfd2cf1 111 /* Encode a static array. Handles the size calculations and possible packing. */
1 0:3163adfd2cf1 112 static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field,
1 0:3163adfd2cf1 113 const void *pData, size_t count, pb_encoder_t func)
1 0:3163adfd2cf1 114 {
1 0:3163adfd2cf1 115 size_t i;
1 0:3163adfd2cf1 116 const void *p;
1 0:3163adfd2cf1 117 size_t size;
1 0:3163adfd2cf1 118
1 0:3163adfd2cf1 119 if (count == 0)
1 0:3163adfd2cf1 120 return true;
1 0:3163adfd2cf1 121
1 0:3163adfd2cf1 122 if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size)
1 0:3163adfd2cf1 123 PB_RETURN_ERROR(stream, "array max size exceeded");
1 0:3163adfd2cf1 124
1 0:3163adfd2cf1 125 /* We always pack arrays if the datatype allows it. */
1 0:3163adfd2cf1 126 if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
1 0:3163adfd2cf1 127 {
1 0:3163adfd2cf1 128 if (!pb_encode_tag(stream, PB_WT_STRING, field->tag))
1 0:3163adfd2cf1 129 return false;
1 0:3163adfd2cf1 130
1 0:3163adfd2cf1 131 /* Determine the total size of packed array. */
1 0:3163adfd2cf1 132 if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32)
1 0:3163adfd2cf1 133 {
1 0:3163adfd2cf1 134 size = 4 * count;
1 0:3163adfd2cf1 135 }
1 0:3163adfd2cf1 136 else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
1 0:3163adfd2cf1 137 {
1 0:3163adfd2cf1 138 size = 8 * count;
1 0:3163adfd2cf1 139 }
1 0:3163adfd2cf1 140 else
1 0:3163adfd2cf1 141 {
1 0:3163adfd2cf1 142 pb_ostream_t sizestream = PB_OSTREAM_SIZING;
1 0:3163adfd2cf1 143 p = pData;
1 0:3163adfd2cf1 144 for (i = 0; i < count; i++)
1 0:3163adfd2cf1 145 {
1 0:3163adfd2cf1 146 if (!func(&sizestream, field, p))
1 0:3163adfd2cf1 147 return false;
1 0:3163adfd2cf1 148 p = (const char*)p + field->data_size;
1 0:3163adfd2cf1 149 }
1 0:3163adfd2cf1 150 size = sizestream.bytes_written;
1 0:3163adfd2cf1 151 }
1 0:3163adfd2cf1 152
1 0:3163adfd2cf1 153 if (!pb_encode_varint(stream, (uint64_t)size))
1 0:3163adfd2cf1 154 return false;
1 0:3163adfd2cf1 155
1 0:3163adfd2cf1 156 if (stream->callback == NULL)
1 0:3163adfd2cf1 157 return pb_write(stream, NULL, size); /* Just sizing.. */
1 0:3163adfd2cf1 158
1 0:3163adfd2cf1 159 /* Write the data */
1 0:3163adfd2cf1 160 p = pData;
1 0:3163adfd2cf1 161 for (i = 0; i < count; i++)
1 0:3163adfd2cf1 162 {
1 0:3163adfd2cf1 163 if (!func(stream, field, p))
1 0:3163adfd2cf1 164 return false;
1 0:3163adfd2cf1 165 p = (const char*)p + field->data_size;
1 0:3163adfd2cf1 166 }
1 0:3163adfd2cf1 167 }
1 0:3163adfd2cf1 168 else
1 0:3163adfd2cf1 169 {
1 0:3163adfd2cf1 170 p = pData;
1 0:3163adfd2cf1 171 for (i = 0; i < count; i++)
1 0:3163adfd2cf1 172 {
1 0:3163adfd2cf1 173 if (!pb_encode_tag_for_field(stream, field))
1 0:3163adfd2cf1 174 return false;
1 0:3163adfd2cf1 175
1 0:3163adfd2cf1 176 /* Normally the data is stored directly in the array entries, but
1 0:3163adfd2cf1 177 * for pointer-type string fields, the array entries are actually
1 0:3163adfd2cf1 178 * string pointers. So we have to dereference once more to get to
1 0:3163adfd2cf1 179 * the character data. */
1 0:3163adfd2cf1 180 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER &&
1 0:3163adfd2cf1 181 PB_LTYPE(field->type) == PB_LTYPE_STRING)
1 0:3163adfd2cf1 182 {
1 0:3163adfd2cf1 183 if (!func(stream, field, *(const void* const*)p))
1 0:3163adfd2cf1 184 return false;
1 0:3163adfd2cf1 185 }
1 0:3163adfd2cf1 186 else
1 0:3163adfd2cf1 187 {
1 0:3163adfd2cf1 188 if (!func(stream, field, p))
1 0:3163adfd2cf1 189 return false;
1 0:3163adfd2cf1 190 }
1 0:3163adfd2cf1 191 p = (const char*)p + field->data_size;
1 0:3163adfd2cf1 192 }
1 0:3163adfd2cf1 193 }
1 0:3163adfd2cf1 194
1 0:3163adfd2cf1 195 return true;
1 0:3163adfd2cf1 196 }
1 0:3163adfd2cf1 197
1 0:3163adfd2cf1 198 /* Encode a field with static or pointer allocation, i.e. one whose data
1 0:3163adfd2cf1 199 * is available to the encoder directly. */
1 0:3163adfd2cf1 200 static bool checkreturn encode_basic_field(pb_ostream_t *stream,
1 0:3163adfd2cf1 201 const pb_field_t *field, const void *pData)
1 0:3163adfd2cf1 202 {
1 0:3163adfd2cf1 203 pb_encoder_t func;
1 0:3163adfd2cf1 204 const void *pSize;
1 0:3163adfd2cf1 205 bool implicit_has = true;
1 0:3163adfd2cf1 206
1 0:3163adfd2cf1 207 func = PB_ENCODERS[PB_LTYPE(field->type)];
1 0:3163adfd2cf1 208
1 0:3163adfd2cf1 209 if (field->size_offset)
1 0:3163adfd2cf1 210 pSize = (const char*)pData + field->size_offset;
1 0:3163adfd2cf1 211 else
1 0:3163adfd2cf1 212 pSize = &implicit_has;
1 0:3163adfd2cf1 213
1 0:3163adfd2cf1 214 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
1 0:3163adfd2cf1 215 {
1 0:3163adfd2cf1 216 /* pData is a pointer to the field, which contains pointer to
1 0:3163adfd2cf1 217 * the data. If the 2nd pointer is NULL, it is interpreted as if
1 0:3163adfd2cf1 218 * the has_field was false.
1 0:3163adfd2cf1 219 */
1 0:3163adfd2cf1 220
1 0:3163adfd2cf1 221 pData = *(const void* const*)pData;
1 0:3163adfd2cf1 222 implicit_has = (pData != NULL);
1 0:3163adfd2cf1 223 }
1 0:3163adfd2cf1 224
1 0:3163adfd2cf1 225 switch (PB_HTYPE(field->type))
1 0:3163adfd2cf1 226 {
1 0:3163adfd2cf1 227 case PB_HTYPE_REQUIRED:
1 0:3163adfd2cf1 228 if (!pData)
1 0:3163adfd2cf1 229 PB_RETURN_ERROR(stream, "missing required field");
1 0:3163adfd2cf1 230 if (!pb_encode_tag_for_field(stream, field))
1 0:3163adfd2cf1 231 return false;
1 0:3163adfd2cf1 232 if (!func(stream, field, pData))
1 0:3163adfd2cf1 233 return false;
1 0:3163adfd2cf1 234 break;
1 0:3163adfd2cf1 235
1 0:3163adfd2cf1 236 case PB_HTYPE_OPTIONAL:
1 0:3163adfd2cf1 237 if (*(const bool*)pSize)
1 0:3163adfd2cf1 238 {
1 0:3163adfd2cf1 239 if (!pb_encode_tag_for_field(stream, field))
1 0:3163adfd2cf1 240 return false;
1 0:3163adfd2cf1 241
1 0:3163adfd2cf1 242 if (!func(stream, field, pData))
1 0:3163adfd2cf1 243 return false;
1 0:3163adfd2cf1 244 }
1 0:3163adfd2cf1 245 break;
1 0:3163adfd2cf1 246
1 0:3163adfd2cf1 247 case PB_HTYPE_REPEATED:
1 0:3163adfd2cf1 248 if (!encode_array(stream, field, pData, *(const size_t*)pSize, func))
1 0:3163adfd2cf1 249 return false;
1 0:3163adfd2cf1 250 break;
1 0:3163adfd2cf1 251
1 0:3163adfd2cf1 252 default:
1 0:3163adfd2cf1 253 PB_RETURN_ERROR(stream, "invalid field type");
1 0:3163adfd2cf1 254 }
1 0:3163adfd2cf1 255
1 0:3163adfd2cf1 256 return true;
1 0:3163adfd2cf1 257 }
1 0:3163adfd2cf1 258
1 0:3163adfd2cf1 259 /* Encode a field with callback semantics. This means that a user function is
1 0:3163adfd2cf1 260 * called to provide and encode the actual data. */
1 0:3163adfd2cf1 261 static bool checkreturn encode_callback_field(pb_ostream_t *stream,
1 0:3163adfd2cf1 262 const pb_field_t *field, const void *pData)
1 0:3163adfd2cf1 263 {
1 0:3163adfd2cf1 264 const pb_callback_t *callback = (const pb_callback_t*)pData;
1 0:3163adfd2cf1 265
1 0:3163adfd2cf1 266 #ifdef PB_OLD_CALLBACK_STYLE
1 0:3163adfd2cf1 267 const void *arg = callback->arg;
1 0:3163adfd2cf1 268 #else
1 0:3163adfd2cf1 269 void * const *arg = &(callback->arg);
1 0:3163adfd2cf1 270 #endif
1 0:3163adfd2cf1 271
1 0:3163adfd2cf1 272 if (callback->funcs.encode != NULL)
1 0:3163adfd2cf1 273 {
1 0:3163adfd2cf1 274 if (!callback->funcs.encode(stream, field, arg))
1 0:3163adfd2cf1 275 PB_RETURN_ERROR(stream, "callback error");
1 0:3163adfd2cf1 276 }
1 0:3163adfd2cf1 277 return true;
1 0:3163adfd2cf1 278 }
1 0:3163adfd2cf1 279
1 0:3163adfd2cf1 280 /* Encode a single field of any callback or static type. */
1 0:3163adfd2cf1 281 static bool checkreturn encode_field(pb_ostream_t *stream,
1 0:3163adfd2cf1 282 const pb_field_t *field, const void *pData)
1 0:3163adfd2cf1 283 {
1 0:3163adfd2cf1 284 switch (PB_ATYPE(field->type))
1 0:3163adfd2cf1 285 {
1 0:3163adfd2cf1 286 case PB_ATYPE_STATIC:
1 0:3163adfd2cf1 287 case PB_ATYPE_POINTER:
1 0:3163adfd2cf1 288 return encode_basic_field(stream, field, pData);
1 0:3163adfd2cf1 289
1 0:3163adfd2cf1 290 case PB_ATYPE_CALLBACK:
1 0:3163adfd2cf1 291 return encode_callback_field(stream, field, pData);
1 0:3163adfd2cf1 292
1 0:3163adfd2cf1 293 default:
1 0:3163adfd2cf1 294 PB_RETURN_ERROR(stream, "invalid field type");
1 0:3163adfd2cf1 295 }
1 0:3163adfd2cf1 296 }
1 0:3163adfd2cf1 297
1 0:3163adfd2cf1 298 /* Default handler for extension fields. Expects to have a pb_field_t
1 0:3163adfd2cf1 299 * pointer in the extension->type->arg field. */
1 0:3163adfd2cf1 300 static bool checkreturn default_extension_encoder(pb_ostream_t *stream,
1 0:3163adfd2cf1 301 const pb_extension_t *extension)
1 0:3163adfd2cf1 302 {
1 0:3163adfd2cf1 303 const pb_field_t *field = (const pb_field_t*)extension->type->arg;
1 0:3163adfd2cf1 304 return encode_field(stream, field, extension->dest);
1 0:3163adfd2cf1 305 }
1 0:3163adfd2cf1 306
1 0:3163adfd2cf1 307 /* Walk through all the registered extensions and give them a chance
1 0:3163adfd2cf1 308 * to encode themselves. */
1 0:3163adfd2cf1 309 static bool checkreturn encode_extension_field(pb_ostream_t *stream,
1 0:3163adfd2cf1 310 const pb_field_t *field, const void *pData)
1 0:3163adfd2cf1 311 {
1 0:3163adfd2cf1 312 const pb_extension_t *extension = *(const pb_extension_t* const *)pData;
1 0:3163adfd2cf1 313 UNUSED(field);
1 0:3163adfd2cf1 314
1 0:3163adfd2cf1 315 while (extension)
1 0:3163adfd2cf1 316 {
1 0:3163adfd2cf1 317 bool status;
1 0:3163adfd2cf1 318 if (extension->type->encode)
1 0:3163adfd2cf1 319 status = extension->type->encode(stream, extension);
1 0:3163adfd2cf1 320 else
1 0:3163adfd2cf1 321 status = default_extension_encoder(stream, extension);
1 0:3163adfd2cf1 322
1 0:3163adfd2cf1 323 if (!status)
1 0:3163adfd2cf1 324 return false;
1 0:3163adfd2cf1 325
1 0:3163adfd2cf1 326 extension = extension->next;
1 0:3163adfd2cf1 327 }
1 0:3163adfd2cf1 328
1 0:3163adfd2cf1 329 return true;
1 0:3163adfd2cf1 330 }
1 0:3163adfd2cf1 331
1 0:3163adfd2cf1 332 /*********************
1 0:3163adfd2cf1 333 * Encode all fields *
1 0:3163adfd2cf1 334 *********************/
1 0:3163adfd2cf1 335
1 0:3163adfd2cf1 336 bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
1 0:3163adfd2cf1 337 {
1 0:3163adfd2cf1 338 const pb_field_t *field = fields;
1 0:3163adfd2cf1 339 const void *pData = src_struct;
1 0:3163adfd2cf1 340 size_t prev_size = 0;
1 0:3163adfd2cf1 341
1 0:3163adfd2cf1 342 while (field->tag != 0)
1 0:3163adfd2cf1 343 {
1 0:3163adfd2cf1 344 pData = (const char*)pData + prev_size + field->data_offset;
1 0:3163adfd2cf1 345 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
1 0:3163adfd2cf1 346 prev_size = sizeof(const void*);
1 0:3163adfd2cf1 347 else
1 0:3163adfd2cf1 348 prev_size = field->data_size;
1 0:3163adfd2cf1 349
1 0:3163adfd2cf1 350 /* Special case for static arrays */
1 0:3163adfd2cf1 351 if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
1 0:3163adfd2cf1 352 PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
1 0:3163adfd2cf1 353 {
1 0:3163adfd2cf1 354 prev_size *= field->array_size;
1 0:3163adfd2cf1 355 }
1 0:3163adfd2cf1 356
1 0:3163adfd2cf1 357 if (PB_LTYPE(field->type) == PB_LTYPE_EXTENSION)
1 0:3163adfd2cf1 358 {
1 0:3163adfd2cf1 359 /* Special case for the extension field placeholder */
1 0:3163adfd2cf1 360 if (!encode_extension_field(stream, field, pData))
1 0:3163adfd2cf1 361 return false;
1 0:3163adfd2cf1 362 }
1 0:3163adfd2cf1 363 else
1 0:3163adfd2cf1 364 {
1 0:3163adfd2cf1 365 /* Regular field */
1 0:3163adfd2cf1 366 if (!encode_field(stream, field, pData))
1 0:3163adfd2cf1 367 return false;
1 0:3163adfd2cf1 368 }
1 0:3163adfd2cf1 369
1 0:3163adfd2cf1 370 field++;
1 0:3163adfd2cf1 371 }
1 0:3163adfd2cf1 372
1 0:3163adfd2cf1 373 return true;
1 0:3163adfd2cf1 374 }
1 0:3163adfd2cf1 375
1 0:3163adfd2cf1 376 bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
1 0:3163adfd2cf1 377 {
1 0:3163adfd2cf1 378 return pb_encode_submessage(stream, fields, src_struct);
1 0:3163adfd2cf1 379 }
1 0:3163adfd2cf1 380
1 0:3163adfd2cf1 381 /********************
1 0:3163adfd2cf1 382 * Helper functions *
1 0:3163adfd2cf1 383 ********************/
1 0:3163adfd2cf1 384 bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value)
1 0:3163adfd2cf1 385 {
1 0:3163adfd2cf1 386 uint8_t buffer[10];
1 0:3163adfd2cf1 387 size_t i = 0;
1 0:3163adfd2cf1 388
1 0:3163adfd2cf1 389 if (value == 0)
1 0:3163adfd2cf1 390 return pb_write(stream, (uint8_t*)&value, 1);
1 0:3163adfd2cf1 391
1 0:3163adfd2cf1 392 while (value)
1 0:3163adfd2cf1 393 {
1 0:3163adfd2cf1 394 buffer[i] = (uint8_t)((value & 0x7F) | 0x80);
1 0:3163adfd2cf1 395 value >>= 7;
1 0:3163adfd2cf1 396 i++;
1 0:3163adfd2cf1 397 }
1 0:3163adfd2cf1 398 buffer[i-1] &= 0x7F; /* Unset top bit on last byte */
1 0:3163adfd2cf1 399
1 0:3163adfd2cf1 400 return pb_write(stream, buffer, i);
1 0:3163adfd2cf1 401 }
1 0:3163adfd2cf1 402
1 0:3163adfd2cf1 403 bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value)
1 0:3163adfd2cf1 404 {
1 0:3163adfd2cf1 405 uint64_t zigzagged;
1 0:3163adfd2cf1 406 if (value < 0)
1 0:3163adfd2cf1 407 zigzagged = (uint64_t)(~(value << 1));
1 0:3163adfd2cf1 408 else
1 0:3163adfd2cf1 409 zigzagged = (uint64_t)(value << 1);
1 0:3163adfd2cf1 410
1 0:3163adfd2cf1 411 return pb_encode_varint(stream, zigzagged);
1 0:3163adfd2cf1 412 }
1 0:3163adfd2cf1 413
1 0:3163adfd2cf1 414 bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value)
1 0:3163adfd2cf1 415 {
1 0:3163adfd2cf1 416 #ifdef __BIG_ENDIAN__
1 0:3163adfd2cf1 417 const uint8_t *bytes = value;
1 0:3163adfd2cf1 418 uint8_t lebytes[4];
1 0:3163adfd2cf1 419 lebytes[0] = bytes[3];
1 0:3163adfd2cf1 420 lebytes[1] = bytes[2];
1 0:3163adfd2cf1 421 lebytes[2] = bytes[1];
1 0:3163adfd2cf1 422 lebytes[3] = bytes[0];
1 0:3163adfd2cf1 423 return pb_write(stream, lebytes, 4);
1 0:3163adfd2cf1 424 #else
1 0:3163adfd2cf1 425 return pb_write(stream, (const uint8_t*)value, 4);
1 0:3163adfd2cf1 426 #endif
1 0:3163adfd2cf1 427 }
1 0:3163adfd2cf1 428
1 0:3163adfd2cf1 429 bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
1 0:3163adfd2cf1 430 {
1 0:3163adfd2cf1 431 #ifdef __BIG_ENDIAN__
1 0:3163adfd2cf1 432 const uint8_t *bytes = value;
1 0:3163adfd2cf1 433 uint8_t lebytes[8];
1 0:3163adfd2cf1 434 lebytes[0] = bytes[7];
1 0:3163adfd2cf1 435 lebytes[1] = bytes[6];
1 0:3163adfd2cf1 436 lebytes[2] = bytes[5];
1 0:3163adfd2cf1 437 lebytes[3] = bytes[4];
1 0:3163adfd2cf1 438 lebytes[4] = bytes[3];
1 0:3163adfd2cf1 439 lebytes[5] = bytes[2];
1 0:3163adfd2cf1 440 lebytes[6] = bytes[1];
1 0:3163adfd2cf1 441 lebytes[7] = bytes[0];
1 0:3163adfd2cf1 442 return pb_write(stream, lebytes, 8);
1 0:3163adfd2cf1 443 #else
1 0:3163adfd2cf1 444 return pb_write(stream, (const uint8_t*)value, 8);
1 0:3163adfd2cf1 445 #endif
1 0:3163adfd2cf1 446 }
1 0:3163adfd2cf1 447
1 0:3163adfd2cf1 448 bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
1 0:3163adfd2cf1 449 {
1 0:3163adfd2cf1 450 uint64_t tag = wiretype | (field_number << 3);
1 0:3163adfd2cf1 451 return pb_encode_varint(stream, tag);
1 0:3163adfd2cf1 452 }
1 0:3163adfd2cf1 453
1 0:3163adfd2cf1 454 bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field)
1 0:3163adfd2cf1 455 {
1 0:3163adfd2cf1 456 pb_wire_type_t wiretype;
1 0:3163adfd2cf1 457 switch (PB_LTYPE(field->type))
1 0:3163adfd2cf1 458 {
1 0:3163adfd2cf1 459 case PB_LTYPE_VARINT:
1 0:3163adfd2cf1 460 case PB_LTYPE_UVARINT:
1 0:3163adfd2cf1 461 case PB_LTYPE_SVARINT:
1 0:3163adfd2cf1 462 wiretype = PB_WT_VARINT;
1 0:3163adfd2cf1 463 break;
1 0:3163adfd2cf1 464
1 0:3163adfd2cf1 465 case PB_LTYPE_FIXED32:
1 0:3163adfd2cf1 466 wiretype = PB_WT_32BIT;
1 0:3163adfd2cf1 467 break;
1 0:3163adfd2cf1 468
1 0:3163adfd2cf1 469 case PB_LTYPE_FIXED64:
1 0:3163adfd2cf1 470 wiretype = PB_WT_64BIT;
1 0:3163adfd2cf1 471 break;
1 0:3163adfd2cf1 472
1 0:3163adfd2cf1 473 case PB_LTYPE_BYTES:
1 0:3163adfd2cf1 474 case PB_LTYPE_STRING:
1 0:3163adfd2cf1 475 case PB_LTYPE_SUBMESSAGE:
1 0:3163adfd2cf1 476 wiretype = PB_WT_STRING;
1 0:3163adfd2cf1 477 break;
1 0:3163adfd2cf1 478
1 0:3163adfd2cf1 479 default:
1 0:3163adfd2cf1 480 PB_RETURN_ERROR(stream, "invalid field type");
1 0:3163adfd2cf1 481 }
1 0:3163adfd2cf1 482
1 0:3163adfd2cf1 483 return pb_encode_tag(stream, wiretype, field->tag);
1 0:3163adfd2cf1 484 }
1 0:3163adfd2cf1 485
1 0:3163adfd2cf1 486 bool checkreturn pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size)
1 0:3163adfd2cf1 487 {
1 0:3163adfd2cf1 488 if (!pb_encode_varint(stream, (uint64_t)size))
1 0:3163adfd2cf1 489 return false;
1 0:3163adfd2cf1 490
1 0:3163adfd2cf1 491 return pb_write(stream, buffer, size);
1 0:3163adfd2cf1 492 }
1 0:3163adfd2cf1 493
1 0:3163adfd2cf1 494 bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
1 0:3163adfd2cf1 495 {
1 0:3163adfd2cf1 496 /* First calculate the message size using a non-writing substream. */
1 0:3163adfd2cf1 497 pb_ostream_t substream = PB_OSTREAM_SIZING;
1 0:3163adfd2cf1 498 size_t size;
1 0:3163adfd2cf1 499 bool status;
1 0:3163adfd2cf1 500
1 0:3163adfd2cf1 501 if (!pb_encode(&substream, fields, src_struct))
1 0:3163adfd2cf1 502 {
1 0:3163adfd2cf1 503 #ifndef PB_NO_ERRMSG
1 0:3163adfd2cf1 504 stream->errmsg = substream.errmsg;
1 0:3163adfd2cf1 505 #endif
1 0:3163adfd2cf1 506 return false;
1 0:3163adfd2cf1 507 }
1 0:3163adfd2cf1 508
1 0:3163adfd2cf1 509 size = substream.bytes_written;
1 0:3163adfd2cf1 510
1 0:3163adfd2cf1 511 if (!pb_encode_varint(stream, (uint64_t)size))
1 0:3163adfd2cf1 512 return false;
1 0:3163adfd2cf1 513
1 0:3163adfd2cf1 514 if (stream->callback == NULL)
1 0:3163adfd2cf1 515 return pb_write(stream, NULL, size); /* Just sizing */
1 0:3163adfd2cf1 516
1 0:3163adfd2cf1 517 if (stream->bytes_written + size > stream->max_size)
1 0:3163adfd2cf1 518 PB_RETURN_ERROR(stream, "stream full");
1 0:3163adfd2cf1 519
1 0:3163adfd2cf1 520 /* Use a substream to verify that a callback doesn't write more than
1 0:3163adfd2cf1 521 * what it did the first time. */
1 0:3163adfd2cf1 522 substream.callback = stream->callback;
1 0:3163adfd2cf1 523 substream.state = stream->state;
1 0:3163adfd2cf1 524 substream.max_size = size;
1 0:3163adfd2cf1 525 substream.bytes_written = 0;
1 0:3163adfd2cf1 526 #ifndef PB_NO_ERRMSG
1 0:3163adfd2cf1 527 substream.errmsg = NULL;
1 0:3163adfd2cf1 528 #endif
1 0:3163adfd2cf1 529
1 0:3163adfd2cf1 530 status = pb_encode(&substream, fields, src_struct);
1 0:3163adfd2cf1 531
1 0:3163adfd2cf1 532 stream->bytes_written += substream.bytes_written;
1 0:3163adfd2cf1 533 stream->state = substream.state;
1 0:3163adfd2cf1 534 #ifndef PB_NO_ERRMSG
1 0:3163adfd2cf1 535 stream->errmsg = substream.errmsg;
1 0:3163adfd2cf1 536 #endif
1 0:3163adfd2cf1 537
1 0:3163adfd2cf1 538 if (substream.bytes_written != size)
1 0:3163adfd2cf1 539 PB_RETURN_ERROR(stream, "submsg size changed");
1 0:3163adfd2cf1 540
1 0:3163adfd2cf1 541 return status;
1 0:3163adfd2cf1 542 }
1 0:3163adfd2cf1 543
1 0:3163adfd2cf1 544 /* Field encoders */
1 0:3163adfd2cf1 545
1 0:3163adfd2cf1 546 bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
1 0:3163adfd2cf1 547 {
1 0:3163adfd2cf1 548 int64_t value = 0;
1 0:3163adfd2cf1 549
1 0:3163adfd2cf1 550 /* Cases 1 and 2 are for compilers that have smaller types for bool
1 0:3163adfd2cf1 551 * or enums. */
1 0:3163adfd2cf1 552 switch (field->data_size)
1 0:3163adfd2cf1 553 {
1 0:3163adfd2cf1 554 case 1: value = *(const int8_t*)src; break;
1 0:3163adfd2cf1 555 case 2: value = *(const int16_t*)src; break;
1 0:3163adfd2cf1 556 case 4: value = *(const int32_t*)src; break;
1 0:3163adfd2cf1 557 case 8: value = *(const int64_t*)src; break;
1 0:3163adfd2cf1 558 default: PB_RETURN_ERROR(stream, "invalid data_size");
1 0:3163adfd2cf1 559 }
1 0:3163adfd2cf1 560
1 0:3163adfd2cf1 561 return pb_encode_varint(stream, (uint64_t)value);
1 0:3163adfd2cf1 562 }
1 0:3163adfd2cf1 563
1 0:3163adfd2cf1 564 bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
1 0:3163adfd2cf1 565 {
1 0:3163adfd2cf1 566 uint64_t value = 0;
1 0:3163adfd2cf1 567
1 0:3163adfd2cf1 568 switch (field->data_size)
1 0:3163adfd2cf1 569 {
1 0:3163adfd2cf1 570 case 4: value = *(const uint32_t*)src; break;
1 0:3163adfd2cf1 571 case 8: value = *(const uint64_t*)src; break;
1 0:3163adfd2cf1 572 default: PB_RETURN_ERROR(stream, "invalid data_size");
1 0:3163adfd2cf1 573 }
1 0:3163adfd2cf1 574
1 0:3163adfd2cf1 575 return pb_encode_varint(stream, value);
1 0:3163adfd2cf1 576 }
1 0:3163adfd2cf1 577
1 0:3163adfd2cf1 578 bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
1 0:3163adfd2cf1 579 {
1 0:3163adfd2cf1 580 int64_t value = 0;
1 0:3163adfd2cf1 581
1 0:3163adfd2cf1 582 switch (field->data_size)
1 0:3163adfd2cf1 583 {
1 0:3163adfd2cf1 584 case 4: value = *(const int32_t*)src; break;
1 0:3163adfd2cf1 585 case 8: value = *(const int64_t*)src; break;
1 0:3163adfd2cf1 586 default: PB_RETURN_ERROR(stream, "invalid data_size");
1 0:3163adfd2cf1 587 }
1 0:3163adfd2cf1 588
1 0:3163adfd2cf1 589 return pb_encode_svarint(stream, value);
1 0:3163adfd2cf1 590 }
1 0:3163adfd2cf1 591
1 0:3163adfd2cf1 592 bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src)
1 0:3163adfd2cf1 593 {
1 0:3163adfd2cf1 594 UNUSED(field);
1 0:3163adfd2cf1 595 return pb_encode_fixed64(stream, src);
1 0:3163adfd2cf1 596 }
1 0:3163adfd2cf1 597
1 0:3163adfd2cf1 598 bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src)
1 0:3163adfd2cf1 599 {
1 0:3163adfd2cf1 600 UNUSED(field);
1 0:3163adfd2cf1 601 return pb_encode_fixed32(stream, src);
1 0:3163adfd2cf1 602 }
1 0:3163adfd2cf1 603
1 0:3163adfd2cf1 604 bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
1 0:3163adfd2cf1 605 {
1 0:3163adfd2cf1 606 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
1 0:3163adfd2cf1 607 {
1 0:3163adfd2cf1 608 const pb_bytes_ptr_t *bytes = (const pb_bytes_ptr_t*)src;
1 0:3163adfd2cf1 609 return pb_encode_string(stream, bytes->bytes, bytes->size);
1 0:3163adfd2cf1 610 }
1 0:3163adfd2cf1 611 else
1 0:3163adfd2cf1 612 {
1 0:3163adfd2cf1 613 const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src;
1 0:3163adfd2cf1 614 if (bytes->size + offsetof(pb_bytes_array_t, bytes) > field->data_size)
1 0:3163adfd2cf1 615 PB_RETURN_ERROR(stream, "bytes size exceeded");
1 0:3163adfd2cf1 616
1 0:3163adfd2cf1 617 return pb_encode_string(stream, bytes->bytes, bytes->size);
1 0:3163adfd2cf1 618 }
1 0:3163adfd2cf1 619 }
1 0:3163adfd2cf1 620
1 0:3163adfd2cf1 621 bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src)
1 0:3163adfd2cf1 622 {
1 0:3163adfd2cf1 623 /* strnlen() is not always available, so just use a loop */
1 0:3163adfd2cf1 624 size_t size = 0;
1 0:3163adfd2cf1 625 size_t max_size = field->data_size;
1 0:3163adfd2cf1 626 const char *p = (const char*)src;
1 0:3163adfd2cf1 627
1 0:3163adfd2cf1 628 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
1 0:3163adfd2cf1 629 max_size = (size_t)-1;
1 0:3163adfd2cf1 630
1 0:3163adfd2cf1 631 while (size < max_size && *p != '\0')
1 0:3163adfd2cf1 632 {
1 0:3163adfd2cf1 633 size++;
1 0:3163adfd2cf1 634 p++;
1 0:3163adfd2cf1 635 }
1 0:3163adfd2cf1 636
1 0:3163adfd2cf1 637 return pb_encode_string(stream, (const uint8_t*)src, size);
1 0:3163adfd2cf1 638 }
1 0:3163adfd2cf1 639
1 0:3163adfd2cf1 640 bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src)
1 0:3163adfd2cf1 641 {
1 0:3163adfd2cf1 642 if (field->ptr == NULL)
1 0:3163adfd2cf1 643 PB_RETURN_ERROR(stream, "invalid field descriptor");
1 0:3163adfd2cf1 644
1 0:3163adfd2cf1 645 return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src);
1 0:3163adfd2cf1 646 }
1 0:3163adfd2cf1 647