Nanopb files

Dependents:   nanopb_V2 Message_generator LEX_Threaded_Programming_V3

Committer:
omatthews
Date:
Mon Aug 19 15:23:39 2019 +0000
Revision:
3:67ee10c4ae98
Parent:
2:d2c61a9be078
It works

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