Nanopb files
Dependents: nanopb_V2 Message_generator LEX_Threaded_Programming_V3
pb_encode.c@3:67ee10c4ae98, 2019-08-19 (annotated)
- 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?
User | Revision | Line number | New 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 | } |