test

Dependencies:   Nanopb iSerial mbed BaseJpegDecode FatFileSystem SDFileSystem RingBuffer Camera_LS_Y201

Committer:
cgraham
Date:
Thu Sep 18 15:21:47 2014 +0000
Revision:
0:d69efd0ee139
test

Who changed what in which revision?

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