Nanopb is a plain-C implementation of Google's Protocol Buffers data format. It is targeted at 32 bit microcontrollers, but is also fit for other embedded systems with tight (2-10 kB ROM, <1 kB RAM) memory constraints.

Dependents:   FBRLogger Dumb_box_rev2

Uploaded from http://koti.kapsi.fi/~jpa/nanopb/ Original licence included below.

Copyright (c) 2011 Petteri Aimonen <jpa at nanopb.mail.kapsi.fi>

This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.

  1. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
  2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. This notice may not be removed or altered from any source distribution.
Committer:
intrinseca
Date:
Fri Mar 01 12:41:26 2013 +0000
Revision:
1:e08406101222
Parent:
0:c7beea49fc91
fix bugs

Who changed what in which revision?

UserRevisionLine numberNew contents of line
intrinseca 0:c7beea49fc91 1 /* pb_encode.c -- encode a protobuf using minimal resources
intrinseca 0:c7beea49fc91 2 *
intrinseca 0:c7beea49fc91 3 * 2011 Petteri Aimonen <jpa@kapsi.fi>
intrinseca 0:c7beea49fc91 4 */
intrinseca 0:c7beea49fc91 5
intrinseca 0:c7beea49fc91 6 #define NANOPB_INTERNALS
intrinseca 0:c7beea49fc91 7 #include "pb.h"
intrinseca 0:c7beea49fc91 8 #include "pb_encode.h"
intrinseca 0:c7beea49fc91 9 #include <string.h>
intrinseca 1:e08406101222 10 #include <stdio.h>
intrinseca 0:c7beea49fc91 11
intrinseca 0:c7beea49fc91 12 /* The warn_unused_result attribute appeared first in gcc-3.4.0 */
intrinseca 0:c7beea49fc91 13 #if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
intrinseca 0:c7beea49fc91 14 #define checkreturn
intrinseca 0:c7beea49fc91 15 #else
intrinseca 0:c7beea49fc91 16 /* Verify that we remember to check all return values for proper error propagation */
intrinseca 0:c7beea49fc91 17 #define checkreturn __attribute__((warn_unused_result))
intrinseca 0:c7beea49fc91 18 #endif
intrinseca 0:c7beea49fc91 19
intrinseca 0:c7beea49fc91 20 typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn;
intrinseca 0:c7beea49fc91 21
intrinseca 0:c7beea49fc91 22 /* --- Function pointers to field encoders ---
intrinseca 0:c7beea49fc91 23 * Order in the array must match pb_action_t LTYPE numbering.
intrinseca 0:c7beea49fc91 24 */
intrinseca 0:c7beea49fc91 25 static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = {
intrinseca 0:c7beea49fc91 26 &pb_enc_varint,
intrinseca 0:c7beea49fc91 27 &pb_enc_svarint,
intrinseca 0:c7beea49fc91 28 &pb_enc_fixed32,
intrinseca 0:c7beea49fc91 29 &pb_enc_fixed64,
intrinseca 0:c7beea49fc91 30
intrinseca 0:c7beea49fc91 31 &pb_enc_bytes,
intrinseca 0:c7beea49fc91 32 &pb_enc_string,
intrinseca 0:c7beea49fc91 33 &pb_enc_submessage
intrinseca 0:c7beea49fc91 34 };
intrinseca 0:c7beea49fc91 35
intrinseca 0:c7beea49fc91 36 /* pb_ostream_t implementation */
intrinseca 0:c7beea49fc91 37
intrinseca 0:c7beea49fc91 38 static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
intrinseca 0:c7beea49fc91 39 {
intrinseca 0:c7beea49fc91 40 uint8_t *dest = (uint8_t*)stream->state;
intrinseca 0:c7beea49fc91 41 stream->state = dest + count;
intrinseca 0:c7beea49fc91 42
intrinseca 0:c7beea49fc91 43 while (count--)
intrinseca 0:c7beea49fc91 44 *dest++ = *buf++;
intrinseca 0:c7beea49fc91 45
intrinseca 0:c7beea49fc91 46 return true;
intrinseca 0:c7beea49fc91 47 }
intrinseca 0:c7beea49fc91 48
intrinseca 0:c7beea49fc91 49 pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize)
intrinseca 0:c7beea49fc91 50 {
intrinseca 0:c7beea49fc91 51 pb_ostream_t stream;
intrinseca 0:c7beea49fc91 52 #ifdef PB_BUFFER_ONLY
intrinseca 0:c7beea49fc91 53 stream.callback = (void*)1; /* Just some marker value */
intrinseca 0:c7beea49fc91 54 #else
intrinseca 0:c7beea49fc91 55 stream.callback = &buf_write;
intrinseca 0:c7beea49fc91 56 #endif
intrinseca 0:c7beea49fc91 57 stream.state = buf;
intrinseca 0:c7beea49fc91 58 stream.max_size = bufsize;
intrinseca 0:c7beea49fc91 59 stream.bytes_written = 0;
intrinseca 0:c7beea49fc91 60 return stream;
intrinseca 0:c7beea49fc91 61 }
intrinseca 0:c7beea49fc91 62
intrinseca 0:c7beea49fc91 63 bool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
intrinseca 0:c7beea49fc91 64 {
intrinseca 0:c7beea49fc91 65 if (stream->callback != NULL)
intrinseca 0:c7beea49fc91 66 {
intrinseca 0:c7beea49fc91 67 if (stream->bytes_written + count > stream->max_size)
intrinseca 0:c7beea49fc91 68 return false;
intrinseca 0:c7beea49fc91 69
intrinseca 0:c7beea49fc91 70 #ifdef PB_BUFFER_ONLY
intrinseca 0:c7beea49fc91 71 if (!buf_write(stream, buf, count))
intrinseca 0:c7beea49fc91 72 return false;
intrinseca 0:c7beea49fc91 73 #else
intrinseca 0:c7beea49fc91 74 if (!stream->callback(stream, buf, count))
intrinseca 0:c7beea49fc91 75 return false;
intrinseca 0:c7beea49fc91 76 #endif
intrinseca 0:c7beea49fc91 77 }
intrinseca 0:c7beea49fc91 78
intrinseca 0:c7beea49fc91 79 stream->bytes_written += count;
intrinseca 0:c7beea49fc91 80 return true;
intrinseca 0:c7beea49fc91 81 }
intrinseca 0:c7beea49fc91 82
intrinseca 0:c7beea49fc91 83 /* Main encoding stuff */
intrinseca 0:c7beea49fc91 84
intrinseca 0:c7beea49fc91 85 /* Callbacks don't need this function because they usually know the data type
intrinseca 0:c7beea49fc91 86 * without examining the field structure.
intrinseca 0:c7beea49fc91 87 * Therefore it is static for now.
intrinseca 0:c7beea49fc91 88 */
intrinseca 0:c7beea49fc91 89 static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field,
intrinseca 0:c7beea49fc91 90 const void *pData, size_t count, pb_encoder_t func)
intrinseca 0:c7beea49fc91 91 {
intrinseca 0:c7beea49fc91 92 size_t i;
intrinseca 0:c7beea49fc91 93 const void *p;
intrinseca 0:c7beea49fc91 94 size_t size;
intrinseca 0:c7beea49fc91 95
intrinseca 0:c7beea49fc91 96 if (count == 0)
intrinseca 0:c7beea49fc91 97 return true;
intrinseca 0:c7beea49fc91 98
intrinseca 0:c7beea49fc91 99 if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
intrinseca 0:c7beea49fc91 100 {
intrinseca 0:c7beea49fc91 101 if (!pb_encode_tag(stream, PB_WT_STRING, field->tag))
intrinseca 0:c7beea49fc91 102 return false;
intrinseca 0:c7beea49fc91 103
intrinseca 0:c7beea49fc91 104 /* Determine the total size of packed array. */
intrinseca 0:c7beea49fc91 105 if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32)
intrinseca 0:c7beea49fc91 106 {
intrinseca 0:c7beea49fc91 107 size = 4 * count;
intrinseca 0:c7beea49fc91 108 }
intrinseca 0:c7beea49fc91 109 else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
intrinseca 0:c7beea49fc91 110 {
intrinseca 0:c7beea49fc91 111 size = 8 * count;
intrinseca 0:c7beea49fc91 112 }
intrinseca 0:c7beea49fc91 113 else
intrinseca 0:c7beea49fc91 114 {
intrinseca 0:c7beea49fc91 115 pb_ostream_t sizestream = {0,0,0,0};
intrinseca 0:c7beea49fc91 116 p = pData;
intrinseca 0:c7beea49fc91 117 for (i = 0; i < count; i++)
intrinseca 0:c7beea49fc91 118 {
intrinseca 0:c7beea49fc91 119 if (!func(&sizestream, field, p))
intrinseca 0:c7beea49fc91 120 return false;
intrinseca 0:c7beea49fc91 121 p = (const char*)p + field->data_size;
intrinseca 0:c7beea49fc91 122 }
intrinseca 0:c7beea49fc91 123 size = sizestream.bytes_written;
intrinseca 0:c7beea49fc91 124 }
intrinseca 0:c7beea49fc91 125
intrinseca 0:c7beea49fc91 126 if (!pb_encode_varint(stream, (uint64_t)size))
intrinseca 0:c7beea49fc91 127 return false;
intrinseca 0:c7beea49fc91 128
intrinseca 0:c7beea49fc91 129 if (stream->callback == NULL)
intrinseca 0:c7beea49fc91 130 return pb_write(stream, NULL, size); /* Just sizing.. */
intrinseca 0:c7beea49fc91 131
intrinseca 0:c7beea49fc91 132 /* Write the data */
intrinseca 0:c7beea49fc91 133 p = pData;
intrinseca 0:c7beea49fc91 134 for (i = 0; i < count; i++)
intrinseca 0:c7beea49fc91 135 {
intrinseca 0:c7beea49fc91 136 if (!func(stream, field, p))
intrinseca 0:c7beea49fc91 137 return false;
intrinseca 0:c7beea49fc91 138 p = (const char*)p + field->data_size;
intrinseca 0:c7beea49fc91 139 }
intrinseca 0:c7beea49fc91 140 }
intrinseca 0:c7beea49fc91 141 else
intrinseca 0:c7beea49fc91 142 {
intrinseca 0:c7beea49fc91 143 p = pData;
intrinseca 0:c7beea49fc91 144 for (i = 0; i < count; i++)
intrinseca 0:c7beea49fc91 145 {
intrinseca 0:c7beea49fc91 146 if (!pb_encode_tag_for_field(stream, field))
intrinseca 0:c7beea49fc91 147 return false;
intrinseca 0:c7beea49fc91 148 if (!func(stream, field, p))
intrinseca 0:c7beea49fc91 149 return false;
intrinseca 0:c7beea49fc91 150 p = (const char*)p + field->data_size;
intrinseca 0:c7beea49fc91 151 }
intrinseca 0:c7beea49fc91 152 }
intrinseca 0:c7beea49fc91 153
intrinseca 0:c7beea49fc91 154 return true;
intrinseca 0:c7beea49fc91 155 }
intrinseca 0:c7beea49fc91 156
intrinseca 0:c7beea49fc91 157 bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
intrinseca 0:c7beea49fc91 158 {
intrinseca 0:c7beea49fc91 159 const pb_field_t *field = fields;
intrinseca 0:c7beea49fc91 160 const void *pData = src_struct;
intrinseca 0:c7beea49fc91 161 const void *pSize;
intrinseca 0:c7beea49fc91 162 size_t prev_size = 0;
intrinseca 0:c7beea49fc91 163
intrinseca 0:c7beea49fc91 164 while (field->tag != 0)
intrinseca 0:c7beea49fc91 165 {
intrinseca 0:c7beea49fc91 166 pb_encoder_t func = PB_ENCODERS[PB_LTYPE(field->type)];
intrinseca 0:c7beea49fc91 167 pData = (const char*)pData + prev_size + field->data_offset;
intrinseca 0:c7beea49fc91 168 pSize = (const char*)pData + field->size_offset;
intrinseca 0:c7beea49fc91 169
intrinseca 0:c7beea49fc91 170 prev_size = field->data_size;
intrinseca 0:c7beea49fc91 171 if (PB_HTYPE(field->type) == PB_HTYPE_ARRAY)
intrinseca 0:c7beea49fc91 172 prev_size *= field->array_size;
intrinseca 0:c7beea49fc91 173
intrinseca 0:c7beea49fc91 174 switch (PB_HTYPE(field->type))
intrinseca 0:c7beea49fc91 175 {
intrinseca 0:c7beea49fc91 176 case PB_HTYPE_REQUIRED:
intrinseca 0:c7beea49fc91 177 if (!pb_encode_tag_for_field(stream, field))
intrinseca 0:c7beea49fc91 178 return false;
intrinseca 0:c7beea49fc91 179 if (!func(stream, field, pData))
intrinseca 0:c7beea49fc91 180 return false;
intrinseca 0:c7beea49fc91 181 break;
intrinseca 0:c7beea49fc91 182
intrinseca 0:c7beea49fc91 183 case PB_HTYPE_OPTIONAL:
intrinseca 0:c7beea49fc91 184 if (*(const bool*)pSize)
intrinseca 0:c7beea49fc91 185 {
intrinseca 0:c7beea49fc91 186 if (!pb_encode_tag_for_field(stream, field))
intrinseca 0:c7beea49fc91 187 return false;
intrinseca 0:c7beea49fc91 188
intrinseca 0:c7beea49fc91 189 if (!func(stream, field, pData))
intrinseca 0:c7beea49fc91 190 return false;
intrinseca 0:c7beea49fc91 191 }
intrinseca 0:c7beea49fc91 192 break;
intrinseca 0:c7beea49fc91 193
intrinseca 0:c7beea49fc91 194 case PB_HTYPE_ARRAY:
intrinseca 0:c7beea49fc91 195 if (!encode_array(stream, field, pData, *(const size_t*)pSize, func))
intrinseca 0:c7beea49fc91 196 return false;
intrinseca 0:c7beea49fc91 197 break;
intrinseca 0:c7beea49fc91 198
intrinseca 0:c7beea49fc91 199 case PB_HTYPE_CALLBACK:
intrinseca 0:c7beea49fc91 200 {
intrinseca 0:c7beea49fc91 201 const pb_callback_t *callback = (const pb_callback_t*)pData;
intrinseca 0:c7beea49fc91 202 if (callback->funcs.encode != NULL)
intrinseca 0:c7beea49fc91 203 {
intrinseca 0:c7beea49fc91 204 if (!callback->funcs.encode(stream, field, callback->arg))
intrinseca 0:c7beea49fc91 205 return false;
intrinseca 0:c7beea49fc91 206 }
intrinseca 0:c7beea49fc91 207 break;
intrinseca 0:c7beea49fc91 208 }
intrinseca 0:c7beea49fc91 209 }
intrinseca 0:c7beea49fc91 210
intrinseca 0:c7beea49fc91 211 field++;
intrinseca 0:c7beea49fc91 212 }
intrinseca 0:c7beea49fc91 213
intrinseca 0:c7beea49fc91 214 return true;
intrinseca 0:c7beea49fc91 215 }
intrinseca 0:c7beea49fc91 216
intrinseca 0:c7beea49fc91 217 /* Helper functions */
intrinseca 0:c7beea49fc91 218 bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value)
intrinseca 0:c7beea49fc91 219 {
intrinseca 0:c7beea49fc91 220 uint8_t buffer[10];
intrinseca 0:c7beea49fc91 221 size_t i = 0;
intrinseca 0:c7beea49fc91 222
intrinseca 0:c7beea49fc91 223 if (value == 0)
intrinseca 0:c7beea49fc91 224 return pb_write(stream, (uint8_t*)&value, 1);
intrinseca 0:c7beea49fc91 225
intrinseca 0:c7beea49fc91 226 while (value)
intrinseca 0:c7beea49fc91 227 {
intrinseca 0:c7beea49fc91 228 buffer[i] = (uint8_t)((value & 0x7F) | 0x80);
intrinseca 0:c7beea49fc91 229 value >>= 7;
intrinseca 0:c7beea49fc91 230 i++;
intrinseca 0:c7beea49fc91 231 }
intrinseca 0:c7beea49fc91 232 buffer[i-1] &= 0x7F; /* Unset top bit on last byte */
intrinseca 0:c7beea49fc91 233
intrinseca 0:c7beea49fc91 234 return pb_write(stream, buffer, i);
intrinseca 0:c7beea49fc91 235 }
intrinseca 0:c7beea49fc91 236
intrinseca 0:c7beea49fc91 237 bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value)
intrinseca 0:c7beea49fc91 238 {
intrinseca 0:c7beea49fc91 239 uint64_t zigzagged;
intrinseca 0:c7beea49fc91 240 if (value < 0)
intrinseca 0:c7beea49fc91 241 zigzagged = (uint64_t)(~(value << 1));
intrinseca 0:c7beea49fc91 242 else
intrinseca 0:c7beea49fc91 243 zigzagged = (uint64_t)(value << 1);
intrinseca 0:c7beea49fc91 244
intrinseca 0:c7beea49fc91 245 return pb_encode_varint(stream, zigzagged);
intrinseca 0:c7beea49fc91 246 }
intrinseca 0:c7beea49fc91 247
intrinseca 0:c7beea49fc91 248 bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value)
intrinseca 0:c7beea49fc91 249 {
intrinseca 0:c7beea49fc91 250 #ifdef __BIG_ENDIAN__
intrinseca 0:c7beea49fc91 251 const uint8_t *bytes = value;
intrinseca 0:c7beea49fc91 252 uint8_t lebytes[4];
intrinseca 0:c7beea49fc91 253 lebytes[0] = bytes[3];
intrinseca 0:c7beea49fc91 254 lebytes[1] = bytes[2];
intrinseca 0:c7beea49fc91 255 lebytes[2] = bytes[1];
intrinseca 0:c7beea49fc91 256 lebytes[3] = bytes[0];
intrinseca 0:c7beea49fc91 257 return pb_write(stream, lebytes, 4);
intrinseca 0:c7beea49fc91 258 #else
intrinseca 0:c7beea49fc91 259 return pb_write(stream, (const uint8_t*)value, 4);
intrinseca 0:c7beea49fc91 260 #endif
intrinseca 0:c7beea49fc91 261 }
intrinseca 0:c7beea49fc91 262
intrinseca 0:c7beea49fc91 263 bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
intrinseca 0:c7beea49fc91 264 {
intrinseca 0:c7beea49fc91 265 #ifdef __BIG_ENDIAN__
intrinseca 0:c7beea49fc91 266 const uint8_t *bytes = value;
intrinseca 0:c7beea49fc91 267 uint8_t lebytes[8];
intrinseca 0:c7beea49fc91 268 lebytes[0] = bytes[7];
intrinseca 0:c7beea49fc91 269 lebytes[1] = bytes[6];
intrinseca 0:c7beea49fc91 270 lebytes[2] = bytes[5];
intrinseca 0:c7beea49fc91 271 lebytes[3] = bytes[4];
intrinseca 0:c7beea49fc91 272 lebytes[4] = bytes[3];
intrinseca 0:c7beea49fc91 273 lebytes[5] = bytes[2];
intrinseca 0:c7beea49fc91 274 lebytes[6] = bytes[1];
intrinseca 0:c7beea49fc91 275 lebytes[7] = bytes[0];
intrinseca 0:c7beea49fc91 276 return pb_write(stream, lebytes, 8);
intrinseca 0:c7beea49fc91 277 #else
intrinseca 0:c7beea49fc91 278 return pb_write(stream, (const uint8_t*)value, 8);
intrinseca 0:c7beea49fc91 279 #endif
intrinseca 0:c7beea49fc91 280 }
intrinseca 0:c7beea49fc91 281
intrinseca 0:c7beea49fc91 282 bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
intrinseca 0:c7beea49fc91 283 {
intrinseca 0:c7beea49fc91 284 uint64_t tag = wiretype | (field_number << 3);
intrinseca 0:c7beea49fc91 285 return pb_encode_varint(stream, tag);
intrinseca 0:c7beea49fc91 286 }
intrinseca 0:c7beea49fc91 287
intrinseca 0:c7beea49fc91 288 bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field)
intrinseca 0:c7beea49fc91 289 {
intrinseca 0:c7beea49fc91 290 pb_wire_type_t wiretype;
intrinseca 0:c7beea49fc91 291 switch (PB_LTYPE(field->type))
intrinseca 0:c7beea49fc91 292 {
intrinseca 0:c7beea49fc91 293 case PB_LTYPE_VARINT:
intrinseca 0:c7beea49fc91 294 case PB_LTYPE_SVARINT:
intrinseca 0:c7beea49fc91 295 wiretype = PB_WT_VARINT;
intrinseca 0:c7beea49fc91 296 break;
intrinseca 0:c7beea49fc91 297
intrinseca 0:c7beea49fc91 298 case PB_LTYPE_FIXED32:
intrinseca 0:c7beea49fc91 299 wiretype = PB_WT_32BIT;
intrinseca 0:c7beea49fc91 300 break;
intrinseca 0:c7beea49fc91 301
intrinseca 0:c7beea49fc91 302 case PB_LTYPE_FIXED64:
intrinseca 0:c7beea49fc91 303 wiretype = PB_WT_64BIT;
intrinseca 0:c7beea49fc91 304 break;
intrinseca 0:c7beea49fc91 305
intrinseca 0:c7beea49fc91 306 case PB_LTYPE_BYTES:
intrinseca 0:c7beea49fc91 307 case PB_LTYPE_STRING:
intrinseca 0:c7beea49fc91 308 case PB_LTYPE_SUBMESSAGE:
intrinseca 0:c7beea49fc91 309 wiretype = PB_WT_STRING;
intrinseca 0:c7beea49fc91 310 break;
intrinseca 0:c7beea49fc91 311
intrinseca 0:c7beea49fc91 312 default:
intrinseca 0:c7beea49fc91 313 return false;
intrinseca 0:c7beea49fc91 314 }
intrinseca 0:c7beea49fc91 315
intrinseca 0:c7beea49fc91 316 return pb_encode_tag(stream, wiretype, field->tag);
intrinseca 0:c7beea49fc91 317 }
intrinseca 0:c7beea49fc91 318
intrinseca 0:c7beea49fc91 319 bool checkreturn pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size)
intrinseca 0:c7beea49fc91 320 {
intrinseca 0:c7beea49fc91 321 if (!pb_encode_varint(stream, (uint64_t)size))
intrinseca 0:c7beea49fc91 322 return false;
intrinseca 0:c7beea49fc91 323
intrinseca 0:c7beea49fc91 324 return pb_write(stream, buffer, size);
intrinseca 0:c7beea49fc91 325 }
intrinseca 0:c7beea49fc91 326
intrinseca 0:c7beea49fc91 327 bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
intrinseca 0:c7beea49fc91 328 {
intrinseca 0:c7beea49fc91 329 /* First calculate the message size using a non-writing substream. */
intrinseca 0:c7beea49fc91 330 pb_ostream_t substream = {0,0,0,0};
intrinseca 0:c7beea49fc91 331 size_t size;
intrinseca 0:c7beea49fc91 332 bool status;
intrinseca 0:c7beea49fc91 333
intrinseca 0:c7beea49fc91 334 if (!pb_encode(&substream, fields, src_struct))
intrinseca 0:c7beea49fc91 335 return false;
intrinseca 0:c7beea49fc91 336
intrinseca 0:c7beea49fc91 337 size = substream.bytes_written;
intrinseca 0:c7beea49fc91 338
intrinseca 0:c7beea49fc91 339 if (!pb_encode_varint(stream, (uint64_t)size))
intrinseca 0:c7beea49fc91 340 return false;
intrinseca 0:c7beea49fc91 341
intrinseca 0:c7beea49fc91 342 if (stream->callback == NULL)
intrinseca 0:c7beea49fc91 343 return pb_write(stream, NULL, size); /* Just sizing */
intrinseca 0:c7beea49fc91 344
intrinseca 0:c7beea49fc91 345 if (stream->bytes_written + size > stream->max_size)
intrinseca 0:c7beea49fc91 346 return false;
intrinseca 0:c7beea49fc91 347
intrinseca 0:c7beea49fc91 348 /* Use a substream to verify that a callback doesn't write more than
intrinseca 0:c7beea49fc91 349 * what it did the first time. */
intrinseca 0:c7beea49fc91 350 substream.callback = stream->callback;
intrinseca 0:c7beea49fc91 351 substream.state = stream->state;
intrinseca 0:c7beea49fc91 352 substream.max_size = size;
intrinseca 0:c7beea49fc91 353 substream.bytes_written = 0;
intrinseca 0:c7beea49fc91 354
intrinseca 0:c7beea49fc91 355 status = pb_encode(&substream, fields, src_struct);
intrinseca 0:c7beea49fc91 356
intrinseca 0:c7beea49fc91 357 stream->bytes_written += substream.bytes_written;
intrinseca 0:c7beea49fc91 358 stream->state = substream.state;
intrinseca 0:c7beea49fc91 359
intrinseca 0:c7beea49fc91 360 if (substream.bytes_written != size)
intrinseca 0:c7beea49fc91 361 return false;
intrinseca 0:c7beea49fc91 362
intrinseca 0:c7beea49fc91 363 return status;
intrinseca 0:c7beea49fc91 364 }
intrinseca 0:c7beea49fc91 365
intrinseca 0:c7beea49fc91 366 /* Field encoders */
intrinseca 0:c7beea49fc91 367
intrinseca 0:c7beea49fc91 368 bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
intrinseca 0:c7beea49fc91 369 {
intrinseca 0:c7beea49fc91 370 uint64_t value = 0;
intrinseca 0:c7beea49fc91 371
intrinseca 0:c7beea49fc91 372 switch (field->data_size)
intrinseca 0:c7beea49fc91 373 {
intrinseca 0:c7beea49fc91 374 case 1: value = *(const uint8_t*)src; break;
intrinseca 0:c7beea49fc91 375 case 2: value = *(const uint16_t*)src; break;
intrinseca 0:c7beea49fc91 376 case 4: value = *(const uint32_t*)src; break;
intrinseca 0:c7beea49fc91 377 case 8: value = *(const uint64_t*)src; break;
intrinseca 0:c7beea49fc91 378 default: return false;
intrinseca 0:c7beea49fc91 379 }
intrinseca 0:c7beea49fc91 380
intrinseca 0:c7beea49fc91 381 return pb_encode_varint(stream, value);
intrinseca 0:c7beea49fc91 382 }
intrinseca 0:c7beea49fc91 383
intrinseca 0:c7beea49fc91 384 bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
intrinseca 0:c7beea49fc91 385 {
intrinseca 0:c7beea49fc91 386 int64_t value = 0;
intrinseca 0:c7beea49fc91 387
intrinseca 0:c7beea49fc91 388 switch (field->data_size)
intrinseca 0:c7beea49fc91 389 {
intrinseca 0:c7beea49fc91 390 case 4: value = *(const int32_t*)src; break;
intrinseca 0:c7beea49fc91 391 case 8: value = *(const int64_t*)src; break;
intrinseca 0:c7beea49fc91 392 default: return false;
intrinseca 0:c7beea49fc91 393 }
intrinseca 0:c7beea49fc91 394
intrinseca 0:c7beea49fc91 395 return pb_encode_svarint(stream, value);
intrinseca 0:c7beea49fc91 396 }
intrinseca 0:c7beea49fc91 397
intrinseca 0:c7beea49fc91 398 bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src)
intrinseca 0:c7beea49fc91 399 {
intrinseca 0:c7beea49fc91 400 UNUSED(field);
intrinseca 0:c7beea49fc91 401 return pb_encode_fixed64(stream, src);
intrinseca 0:c7beea49fc91 402 }
intrinseca 0:c7beea49fc91 403
intrinseca 0:c7beea49fc91 404 bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src)
intrinseca 0:c7beea49fc91 405 {
intrinseca 0:c7beea49fc91 406 UNUSED(field);
intrinseca 0:c7beea49fc91 407 return pb_encode_fixed32(stream, src);
intrinseca 0:c7beea49fc91 408 }
intrinseca 0:c7beea49fc91 409
intrinseca 0:c7beea49fc91 410 bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
intrinseca 0:c7beea49fc91 411 {
intrinseca 0:c7beea49fc91 412 const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src;
intrinseca 0:c7beea49fc91 413 UNUSED(field);
intrinseca 0:c7beea49fc91 414 return pb_encode_string(stream, bytes->bytes, bytes->size);
intrinseca 0:c7beea49fc91 415 }
intrinseca 0:c7beea49fc91 416
intrinseca 0:c7beea49fc91 417 bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src)
intrinseca 0:c7beea49fc91 418 {
intrinseca 0:c7beea49fc91 419 UNUSED(field);
intrinseca 0:c7beea49fc91 420 return pb_encode_string(stream, (const uint8_t*)src, strlen((const char*)src));
intrinseca 0:c7beea49fc91 421 }
intrinseca 0:c7beea49fc91 422
intrinseca 0:c7beea49fc91 423 bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src)
intrinseca 0:c7beea49fc91 424 {
intrinseca 0:c7beea49fc91 425 if (field->ptr == NULL)
intrinseca 0:c7beea49fc91 426 return false;
intrinseca 0:c7beea49fc91 427
intrinseca 0:c7beea49fc91 428 return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src);
intrinseca 0:c7beea49fc91 429 }
intrinseca 0:c7beea49fc91 430