Nanopb files

Dependents:   nanopb_V2 Message_generator LEX_Threaded_Programming_V3

Committer:
omatthews
Date:
Fri Aug 16 16:41:33 2019 +0000
Revision:
2:d2c61a9be078
Parent:
1:e08406101222
Child:
3:67ee10c4ae98
Output message

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