test code 123
Fork of LinkNode-Test by
nRF51822_Science_Journal/pb_decode.c@1:b0d4fbbdb244, 2016-10-28 (annotated)
- Committer:
- youkee
- Date:
- Fri Oct 28 13:04:10 2016 +0000
- Revision:
- 1:b0d4fbbdb244
- Parent:
- 0:1ad0e04b1bc5
ghhbfdd
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
youkee | 0:1ad0e04b1bc5 | 1 | /* pb_decode.c -- decode a protobuf using minimal resources |
youkee | 0:1ad0e04b1bc5 | 2 | * |
youkee | 0:1ad0e04b1bc5 | 3 | * 2011 Petteri Aimonen <jpa@kapsi.fi> |
youkee | 0:1ad0e04b1bc5 | 4 | */ |
youkee | 0:1ad0e04b1bc5 | 5 | |
youkee | 0:1ad0e04b1bc5 | 6 | /* Use the GCC warn_unused_result attribute to check that all return values |
youkee | 0:1ad0e04b1bc5 | 7 | * are propagated correctly. On other compilers and gcc before 3.4.0 just |
youkee | 0:1ad0e04b1bc5 | 8 | * ignore the annotation. |
youkee | 0:1ad0e04b1bc5 | 9 | */ |
youkee | 0:1ad0e04b1bc5 | 10 | #if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) |
youkee | 0:1ad0e04b1bc5 | 11 | #define checkreturn |
youkee | 0:1ad0e04b1bc5 | 12 | #else |
youkee | 0:1ad0e04b1bc5 | 13 | #define checkreturn __attribute__((warn_unused_result)) |
youkee | 0:1ad0e04b1bc5 | 14 | #endif |
youkee | 0:1ad0e04b1bc5 | 15 | |
youkee | 0:1ad0e04b1bc5 | 16 | #include "pb.h" |
youkee | 0:1ad0e04b1bc5 | 17 | #include "pb_decode.h" |
youkee | 0:1ad0e04b1bc5 | 18 | #include "pb_common.h" |
youkee | 0:1ad0e04b1bc5 | 19 | |
youkee | 0:1ad0e04b1bc5 | 20 | /************************************** |
youkee | 0:1ad0e04b1bc5 | 21 | * Declarations internal to this file * |
youkee | 0:1ad0e04b1bc5 | 22 | **************************************/ |
youkee | 0:1ad0e04b1bc5 | 23 | |
youkee | 0:1ad0e04b1bc5 | 24 | typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; |
youkee | 0:1ad0e04b1bc5 | 25 | |
youkee | 0:1ad0e04b1bc5 | 26 | static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); |
youkee | 0:1ad0e04b1bc5 | 27 | static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); |
youkee | 0:1ad0e04b1bc5 | 28 | static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size); |
youkee | 0:1ad0e04b1bc5 | 29 | static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); |
youkee | 0:1ad0e04b1bc5 | 30 | static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); |
youkee | 0:1ad0e04b1bc5 | 31 | static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); |
youkee | 0:1ad0e04b1bc5 | 32 | static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension); |
youkee | 0:1ad0e04b1bc5 | 33 | static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); |
youkee | 0:1ad0e04b1bc5 | 34 | static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter); |
youkee | 0:1ad0e04b1bc5 | 35 | static bool checkreturn find_extension_field(pb_field_iter_t *iter); |
youkee | 0:1ad0e04b1bc5 | 36 | static void pb_field_set_to_default(pb_field_iter_t *iter); |
youkee | 0:1ad0e04b1bc5 | 37 | static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); |
youkee | 0:1ad0e04b1bc5 | 38 | static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); |
youkee | 0:1ad0e04b1bc5 | 39 | static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); |
youkee | 0:1ad0e04b1bc5 | 40 | static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest); |
youkee | 0:1ad0e04b1bc5 | 41 | static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest); |
youkee | 0:1ad0e04b1bc5 | 42 | static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest); |
youkee | 0:1ad0e04b1bc5 | 43 | static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); |
youkee | 0:1ad0e04b1bc5 | 44 | static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest); |
youkee | 0:1ad0e04b1bc5 | 45 | static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest); |
youkee | 0:1ad0e04b1bc5 | 46 | static bool checkreturn pb_skip_varint(pb_istream_t *stream); |
youkee | 0:1ad0e04b1bc5 | 47 | static bool checkreturn pb_skip_string(pb_istream_t *stream); |
youkee | 0:1ad0e04b1bc5 | 48 | |
youkee | 0:1ad0e04b1bc5 | 49 | #ifdef PB_ENABLE_MALLOC |
youkee | 0:1ad0e04b1bc5 | 50 | static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size); |
youkee | 0:1ad0e04b1bc5 | 51 | static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter); |
youkee | 0:1ad0e04b1bc5 | 52 | static void pb_release_single_field(const pb_field_iter_t *iter); |
youkee | 0:1ad0e04b1bc5 | 53 | #endif |
youkee | 0:1ad0e04b1bc5 | 54 | |
youkee | 0:1ad0e04b1bc5 | 55 | /* --- Function pointers to field decoders --- |
youkee | 0:1ad0e04b1bc5 | 56 | * Order in the array must match pb_action_t LTYPE numbering. |
youkee | 0:1ad0e04b1bc5 | 57 | */ |
youkee | 0:1ad0e04b1bc5 | 58 | static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { |
youkee | 0:1ad0e04b1bc5 | 59 | &pb_dec_varint, |
youkee | 0:1ad0e04b1bc5 | 60 | &pb_dec_uvarint, |
youkee | 0:1ad0e04b1bc5 | 61 | &pb_dec_svarint, |
youkee | 0:1ad0e04b1bc5 | 62 | &pb_dec_fixed32, |
youkee | 0:1ad0e04b1bc5 | 63 | &pb_dec_fixed64, |
youkee | 0:1ad0e04b1bc5 | 64 | |
youkee | 0:1ad0e04b1bc5 | 65 | &pb_dec_bytes, |
youkee | 0:1ad0e04b1bc5 | 66 | &pb_dec_string, |
youkee | 0:1ad0e04b1bc5 | 67 | &pb_dec_submessage, |
youkee | 0:1ad0e04b1bc5 | 68 | NULL /* extensions */ |
youkee | 0:1ad0e04b1bc5 | 69 | }; |
youkee | 0:1ad0e04b1bc5 | 70 | |
youkee | 0:1ad0e04b1bc5 | 71 | /******************************* |
youkee | 0:1ad0e04b1bc5 | 72 | * pb_istream_t implementation * |
youkee | 0:1ad0e04b1bc5 | 73 | *******************************/ |
youkee | 0:1ad0e04b1bc5 | 74 | |
youkee | 0:1ad0e04b1bc5 | 75 | static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) |
youkee | 0:1ad0e04b1bc5 | 76 | { |
youkee | 0:1ad0e04b1bc5 | 77 | const pb_byte_t *source = (const pb_byte_t*)stream->state; |
youkee | 0:1ad0e04b1bc5 | 78 | stream->state = (pb_byte_t*)stream->state + count; |
youkee | 0:1ad0e04b1bc5 | 79 | |
youkee | 0:1ad0e04b1bc5 | 80 | if (buf != NULL) |
youkee | 0:1ad0e04b1bc5 | 81 | { |
youkee | 0:1ad0e04b1bc5 | 82 | while (count--) |
youkee | 0:1ad0e04b1bc5 | 83 | *buf++ = *source++; |
youkee | 0:1ad0e04b1bc5 | 84 | } |
youkee | 0:1ad0e04b1bc5 | 85 | |
youkee | 0:1ad0e04b1bc5 | 86 | return true; |
youkee | 0:1ad0e04b1bc5 | 87 | } |
youkee | 0:1ad0e04b1bc5 | 88 | |
youkee | 0:1ad0e04b1bc5 | 89 | bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) |
youkee | 0:1ad0e04b1bc5 | 90 | { |
youkee | 0:1ad0e04b1bc5 | 91 | #ifndef PB_BUFFER_ONLY |
youkee | 0:1ad0e04b1bc5 | 92 | if (buf == NULL && stream->callback != buf_read) |
youkee | 0:1ad0e04b1bc5 | 93 | { |
youkee | 0:1ad0e04b1bc5 | 94 | /* Skip input bytes */ |
youkee | 0:1ad0e04b1bc5 | 95 | pb_byte_t tmp[16]; |
youkee | 0:1ad0e04b1bc5 | 96 | while (count > 16) |
youkee | 0:1ad0e04b1bc5 | 97 | { |
youkee | 0:1ad0e04b1bc5 | 98 | if (!pb_read(stream, tmp, 16)) |
youkee | 0:1ad0e04b1bc5 | 99 | return false; |
youkee | 0:1ad0e04b1bc5 | 100 | |
youkee | 0:1ad0e04b1bc5 | 101 | count -= 16; |
youkee | 0:1ad0e04b1bc5 | 102 | } |
youkee | 0:1ad0e04b1bc5 | 103 | |
youkee | 0:1ad0e04b1bc5 | 104 | return pb_read(stream, tmp, count); |
youkee | 0:1ad0e04b1bc5 | 105 | } |
youkee | 0:1ad0e04b1bc5 | 106 | #endif |
youkee | 0:1ad0e04b1bc5 | 107 | |
youkee | 0:1ad0e04b1bc5 | 108 | if (stream->bytes_left < count) |
youkee | 0:1ad0e04b1bc5 | 109 | PB_RETURN_ERROR(stream, "end-of-stream"); |
youkee | 0:1ad0e04b1bc5 | 110 | |
youkee | 0:1ad0e04b1bc5 | 111 | #ifndef PB_BUFFER_ONLY |
youkee | 0:1ad0e04b1bc5 | 112 | if (!stream->callback(stream, buf, count)) |
youkee | 0:1ad0e04b1bc5 | 113 | PB_RETURN_ERROR(stream, "io error"); |
youkee | 0:1ad0e04b1bc5 | 114 | #else |
youkee | 0:1ad0e04b1bc5 | 115 | if (!buf_read(stream, buf, count)) |
youkee | 0:1ad0e04b1bc5 | 116 | return false; |
youkee | 0:1ad0e04b1bc5 | 117 | #endif |
youkee | 0:1ad0e04b1bc5 | 118 | |
youkee | 0:1ad0e04b1bc5 | 119 | stream->bytes_left -= count; |
youkee | 0:1ad0e04b1bc5 | 120 | return true; |
youkee | 0:1ad0e04b1bc5 | 121 | } |
youkee | 0:1ad0e04b1bc5 | 122 | |
youkee | 0:1ad0e04b1bc5 | 123 | /* Read a single byte from input stream. buf may not be NULL. |
youkee | 0:1ad0e04b1bc5 | 124 | * This is an optimization for the varint decoding. */ |
youkee | 0:1ad0e04b1bc5 | 125 | static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf) |
youkee | 0:1ad0e04b1bc5 | 126 | { |
youkee | 0:1ad0e04b1bc5 | 127 | if (stream->bytes_left == 0) |
youkee | 0:1ad0e04b1bc5 | 128 | PB_RETURN_ERROR(stream, "end-of-stream"); |
youkee | 0:1ad0e04b1bc5 | 129 | |
youkee | 0:1ad0e04b1bc5 | 130 | #ifndef PB_BUFFER_ONLY |
youkee | 0:1ad0e04b1bc5 | 131 | if (!stream->callback(stream, buf, 1)) |
youkee | 0:1ad0e04b1bc5 | 132 | PB_RETURN_ERROR(stream, "io error"); |
youkee | 0:1ad0e04b1bc5 | 133 | #else |
youkee | 0:1ad0e04b1bc5 | 134 | *buf = *(const pb_byte_t*)stream->state; |
youkee | 0:1ad0e04b1bc5 | 135 | stream->state = (pb_byte_t*)stream->state + 1; |
youkee | 0:1ad0e04b1bc5 | 136 | #endif |
youkee | 0:1ad0e04b1bc5 | 137 | |
youkee | 0:1ad0e04b1bc5 | 138 | stream->bytes_left--; |
youkee | 0:1ad0e04b1bc5 | 139 | |
youkee | 0:1ad0e04b1bc5 | 140 | return true; |
youkee | 0:1ad0e04b1bc5 | 141 | } |
youkee | 0:1ad0e04b1bc5 | 142 | |
youkee | 0:1ad0e04b1bc5 | 143 | pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize) |
youkee | 0:1ad0e04b1bc5 | 144 | { |
youkee | 0:1ad0e04b1bc5 | 145 | pb_istream_t stream; |
youkee | 0:1ad0e04b1bc5 | 146 | /* Cast away the const from buf without a compiler error. We are |
youkee | 0:1ad0e04b1bc5 | 147 | * careful to use it only in a const manner in the callbacks. |
youkee | 0:1ad0e04b1bc5 | 148 | */ |
youkee | 0:1ad0e04b1bc5 | 149 | union { |
youkee | 0:1ad0e04b1bc5 | 150 | void *state; |
youkee | 0:1ad0e04b1bc5 | 151 | const void *c_state; |
youkee | 0:1ad0e04b1bc5 | 152 | } state; |
youkee | 0:1ad0e04b1bc5 | 153 | #ifdef PB_BUFFER_ONLY |
youkee | 0:1ad0e04b1bc5 | 154 | stream.callback = NULL; |
youkee | 0:1ad0e04b1bc5 | 155 | #else |
youkee | 0:1ad0e04b1bc5 | 156 | stream.callback = &buf_read; |
youkee | 0:1ad0e04b1bc5 | 157 | #endif |
youkee | 0:1ad0e04b1bc5 | 158 | state.c_state = buf; |
youkee | 0:1ad0e04b1bc5 | 159 | stream.state = state.state; |
youkee | 0:1ad0e04b1bc5 | 160 | stream.bytes_left = bufsize; |
youkee | 0:1ad0e04b1bc5 | 161 | #ifndef PB_NO_ERRMSG |
youkee | 0:1ad0e04b1bc5 | 162 | stream.errmsg = NULL; |
youkee | 0:1ad0e04b1bc5 | 163 | #endif |
youkee | 0:1ad0e04b1bc5 | 164 | return stream; |
youkee | 0:1ad0e04b1bc5 | 165 | } |
youkee | 0:1ad0e04b1bc5 | 166 | |
youkee | 0:1ad0e04b1bc5 | 167 | /******************** |
youkee | 0:1ad0e04b1bc5 | 168 | * Helper functions * |
youkee | 0:1ad0e04b1bc5 | 169 | ********************/ |
youkee | 0:1ad0e04b1bc5 | 170 | |
youkee | 0:1ad0e04b1bc5 | 171 | static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) |
youkee | 0:1ad0e04b1bc5 | 172 | { |
youkee | 0:1ad0e04b1bc5 | 173 | pb_byte_t byte; |
youkee | 0:1ad0e04b1bc5 | 174 | uint32_t result; |
youkee | 0:1ad0e04b1bc5 | 175 | |
youkee | 0:1ad0e04b1bc5 | 176 | if (!pb_readbyte(stream, &byte)) |
youkee | 0:1ad0e04b1bc5 | 177 | return false; |
youkee | 0:1ad0e04b1bc5 | 178 | |
youkee | 0:1ad0e04b1bc5 | 179 | if ((byte & 0x80) == 0) |
youkee | 0:1ad0e04b1bc5 | 180 | { |
youkee | 0:1ad0e04b1bc5 | 181 | /* Quick case, 1 byte value */ |
youkee | 0:1ad0e04b1bc5 | 182 | result = byte; |
youkee | 0:1ad0e04b1bc5 | 183 | } |
youkee | 0:1ad0e04b1bc5 | 184 | else |
youkee | 0:1ad0e04b1bc5 | 185 | { |
youkee | 0:1ad0e04b1bc5 | 186 | /* Multibyte case */ |
youkee | 0:1ad0e04b1bc5 | 187 | uint_fast8_t bitpos = 7; |
youkee | 0:1ad0e04b1bc5 | 188 | result = byte & 0x7F; |
youkee | 0:1ad0e04b1bc5 | 189 | |
youkee | 0:1ad0e04b1bc5 | 190 | do |
youkee | 0:1ad0e04b1bc5 | 191 | { |
youkee | 0:1ad0e04b1bc5 | 192 | if (bitpos >= 32) |
youkee | 0:1ad0e04b1bc5 | 193 | PB_RETURN_ERROR(stream, "varint overflow"); |
youkee | 0:1ad0e04b1bc5 | 194 | |
youkee | 0:1ad0e04b1bc5 | 195 | if (!pb_readbyte(stream, &byte)) |
youkee | 0:1ad0e04b1bc5 | 196 | return false; |
youkee | 0:1ad0e04b1bc5 | 197 | |
youkee | 0:1ad0e04b1bc5 | 198 | result |= (uint32_t)(byte & 0x7F) << bitpos; |
youkee | 0:1ad0e04b1bc5 | 199 | bitpos = (uint_fast8_t)(bitpos + 7); |
youkee | 0:1ad0e04b1bc5 | 200 | } while (byte & 0x80); |
youkee | 0:1ad0e04b1bc5 | 201 | } |
youkee | 0:1ad0e04b1bc5 | 202 | |
youkee | 0:1ad0e04b1bc5 | 203 | *dest = result; |
youkee | 0:1ad0e04b1bc5 | 204 | return true; |
youkee | 0:1ad0e04b1bc5 | 205 | } |
youkee | 0:1ad0e04b1bc5 | 206 | |
youkee | 0:1ad0e04b1bc5 | 207 | bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) |
youkee | 0:1ad0e04b1bc5 | 208 | { |
youkee | 0:1ad0e04b1bc5 | 209 | pb_byte_t byte; |
youkee | 0:1ad0e04b1bc5 | 210 | uint_fast8_t bitpos = 0; |
youkee | 0:1ad0e04b1bc5 | 211 | uint64_t result = 0; |
youkee | 0:1ad0e04b1bc5 | 212 | |
youkee | 0:1ad0e04b1bc5 | 213 | do |
youkee | 0:1ad0e04b1bc5 | 214 | { |
youkee | 0:1ad0e04b1bc5 | 215 | if (bitpos >= 64) |
youkee | 0:1ad0e04b1bc5 | 216 | PB_RETURN_ERROR(stream, "varint overflow"); |
youkee | 0:1ad0e04b1bc5 | 217 | |
youkee | 0:1ad0e04b1bc5 | 218 | if (!pb_readbyte(stream, &byte)) |
youkee | 0:1ad0e04b1bc5 | 219 | return false; |
youkee | 0:1ad0e04b1bc5 | 220 | |
youkee | 0:1ad0e04b1bc5 | 221 | result |= (uint64_t)(byte & 0x7F) << bitpos; |
youkee | 0:1ad0e04b1bc5 | 222 | bitpos = (uint_fast8_t)(bitpos + 7); |
youkee | 0:1ad0e04b1bc5 | 223 | } while (byte & 0x80); |
youkee | 0:1ad0e04b1bc5 | 224 | |
youkee | 0:1ad0e04b1bc5 | 225 | *dest = result; |
youkee | 0:1ad0e04b1bc5 | 226 | return true; |
youkee | 0:1ad0e04b1bc5 | 227 | } |
youkee | 0:1ad0e04b1bc5 | 228 | |
youkee | 0:1ad0e04b1bc5 | 229 | bool checkreturn pb_skip_varint(pb_istream_t *stream) |
youkee | 0:1ad0e04b1bc5 | 230 | { |
youkee | 0:1ad0e04b1bc5 | 231 | pb_byte_t byte; |
youkee | 0:1ad0e04b1bc5 | 232 | do |
youkee | 0:1ad0e04b1bc5 | 233 | { |
youkee | 0:1ad0e04b1bc5 | 234 | if (!pb_read(stream, &byte, 1)) |
youkee | 0:1ad0e04b1bc5 | 235 | return false; |
youkee | 0:1ad0e04b1bc5 | 236 | } while (byte & 0x80); |
youkee | 0:1ad0e04b1bc5 | 237 | return true; |
youkee | 0:1ad0e04b1bc5 | 238 | } |
youkee | 0:1ad0e04b1bc5 | 239 | |
youkee | 0:1ad0e04b1bc5 | 240 | bool checkreturn pb_skip_string(pb_istream_t *stream) |
youkee | 0:1ad0e04b1bc5 | 241 | { |
youkee | 0:1ad0e04b1bc5 | 242 | uint32_t length; |
youkee | 0:1ad0e04b1bc5 | 243 | if (!pb_decode_varint32(stream, &length)) |
youkee | 0:1ad0e04b1bc5 | 244 | return false; |
youkee | 0:1ad0e04b1bc5 | 245 | |
youkee | 0:1ad0e04b1bc5 | 246 | return pb_read(stream, NULL, length); |
youkee | 0:1ad0e04b1bc5 | 247 | } |
youkee | 0:1ad0e04b1bc5 | 248 | |
youkee | 0:1ad0e04b1bc5 | 249 | bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof) |
youkee | 0:1ad0e04b1bc5 | 250 | { |
youkee | 0:1ad0e04b1bc5 | 251 | uint32_t temp; |
youkee | 0:1ad0e04b1bc5 | 252 | *eof = false; |
youkee | 0:1ad0e04b1bc5 | 253 | *wire_type = (pb_wire_type_t) 0; |
youkee | 0:1ad0e04b1bc5 | 254 | *tag = 0; |
youkee | 0:1ad0e04b1bc5 | 255 | |
youkee | 0:1ad0e04b1bc5 | 256 | if (!pb_decode_varint32(stream, &temp)) |
youkee | 0:1ad0e04b1bc5 | 257 | { |
youkee | 0:1ad0e04b1bc5 | 258 | if (stream->bytes_left == 0) |
youkee | 0:1ad0e04b1bc5 | 259 | *eof = true; |
youkee | 0:1ad0e04b1bc5 | 260 | |
youkee | 0:1ad0e04b1bc5 | 261 | return false; |
youkee | 0:1ad0e04b1bc5 | 262 | } |
youkee | 0:1ad0e04b1bc5 | 263 | |
youkee | 0:1ad0e04b1bc5 | 264 | if (temp == 0) |
youkee | 0:1ad0e04b1bc5 | 265 | { |
youkee | 0:1ad0e04b1bc5 | 266 | *eof = true; /* Special feature: allow 0-terminated messages. */ |
youkee | 0:1ad0e04b1bc5 | 267 | return false; |
youkee | 0:1ad0e04b1bc5 | 268 | } |
youkee | 0:1ad0e04b1bc5 | 269 | |
youkee | 0:1ad0e04b1bc5 | 270 | *tag = temp >> 3; |
youkee | 0:1ad0e04b1bc5 | 271 | *wire_type = (pb_wire_type_t)(temp & 7); |
youkee | 0:1ad0e04b1bc5 | 272 | return true; |
youkee | 0:1ad0e04b1bc5 | 273 | } |
youkee | 0:1ad0e04b1bc5 | 274 | |
youkee | 0:1ad0e04b1bc5 | 275 | bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) |
youkee | 0:1ad0e04b1bc5 | 276 | { |
youkee | 0:1ad0e04b1bc5 | 277 | switch (wire_type) |
youkee | 0:1ad0e04b1bc5 | 278 | { |
youkee | 0:1ad0e04b1bc5 | 279 | case PB_WT_VARINT: return pb_skip_varint(stream); |
youkee | 0:1ad0e04b1bc5 | 280 | case PB_WT_64BIT: return pb_read(stream, NULL, 8); |
youkee | 0:1ad0e04b1bc5 | 281 | case PB_WT_STRING: return pb_skip_string(stream); |
youkee | 0:1ad0e04b1bc5 | 282 | case PB_WT_32BIT: return pb_read(stream, NULL, 4); |
youkee | 0:1ad0e04b1bc5 | 283 | default: PB_RETURN_ERROR(stream, "invalid wire_type"); |
youkee | 0:1ad0e04b1bc5 | 284 | } |
youkee | 0:1ad0e04b1bc5 | 285 | } |
youkee | 0:1ad0e04b1bc5 | 286 | |
youkee | 0:1ad0e04b1bc5 | 287 | /* Read a raw value to buffer, for the purpose of passing it to callback as |
youkee | 0:1ad0e04b1bc5 | 288 | * a substream. Size is maximum size on call, and actual size on return. |
youkee | 0:1ad0e04b1bc5 | 289 | */ |
youkee | 0:1ad0e04b1bc5 | 290 | static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size) |
youkee | 0:1ad0e04b1bc5 | 291 | { |
youkee | 0:1ad0e04b1bc5 | 292 | size_t max_size = *size; |
youkee | 0:1ad0e04b1bc5 | 293 | switch (wire_type) |
youkee | 0:1ad0e04b1bc5 | 294 | { |
youkee | 0:1ad0e04b1bc5 | 295 | case PB_WT_VARINT: |
youkee | 0:1ad0e04b1bc5 | 296 | *size = 0; |
youkee | 0:1ad0e04b1bc5 | 297 | do |
youkee | 0:1ad0e04b1bc5 | 298 | { |
youkee | 0:1ad0e04b1bc5 | 299 | (*size)++; |
youkee | 0:1ad0e04b1bc5 | 300 | if (*size > max_size) return false; |
youkee | 0:1ad0e04b1bc5 | 301 | if (!pb_read(stream, buf, 1)) return false; |
youkee | 0:1ad0e04b1bc5 | 302 | } while (*buf++ & 0x80); |
youkee | 0:1ad0e04b1bc5 | 303 | return true; |
youkee | 0:1ad0e04b1bc5 | 304 | |
youkee | 0:1ad0e04b1bc5 | 305 | case PB_WT_64BIT: |
youkee | 0:1ad0e04b1bc5 | 306 | *size = 8; |
youkee | 0:1ad0e04b1bc5 | 307 | return pb_read(stream, buf, 8); |
youkee | 0:1ad0e04b1bc5 | 308 | |
youkee | 0:1ad0e04b1bc5 | 309 | case PB_WT_32BIT: |
youkee | 0:1ad0e04b1bc5 | 310 | *size = 4; |
youkee | 0:1ad0e04b1bc5 | 311 | return pb_read(stream, buf, 4); |
youkee | 0:1ad0e04b1bc5 | 312 | |
youkee | 0:1ad0e04b1bc5 | 313 | default: PB_RETURN_ERROR(stream, "invalid wire_type"); |
youkee | 0:1ad0e04b1bc5 | 314 | } |
youkee | 0:1ad0e04b1bc5 | 315 | } |
youkee | 0:1ad0e04b1bc5 | 316 | |
youkee | 0:1ad0e04b1bc5 | 317 | /* Decode string length from stream and return a substream with limited length. |
youkee | 0:1ad0e04b1bc5 | 318 | * Remember to close the substream using pb_close_string_substream(). |
youkee | 0:1ad0e04b1bc5 | 319 | */ |
youkee | 0:1ad0e04b1bc5 | 320 | bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream) |
youkee | 0:1ad0e04b1bc5 | 321 | { |
youkee | 0:1ad0e04b1bc5 | 322 | uint32_t size; |
youkee | 0:1ad0e04b1bc5 | 323 | if (!pb_decode_varint32(stream, &size)) |
youkee | 0:1ad0e04b1bc5 | 324 | return false; |
youkee | 0:1ad0e04b1bc5 | 325 | |
youkee | 0:1ad0e04b1bc5 | 326 | *substream = *stream; |
youkee | 0:1ad0e04b1bc5 | 327 | if (substream->bytes_left < size) |
youkee | 0:1ad0e04b1bc5 | 328 | PB_RETURN_ERROR(stream, "parent stream too short"); |
youkee | 0:1ad0e04b1bc5 | 329 | |
youkee | 0:1ad0e04b1bc5 | 330 | substream->bytes_left = size; |
youkee | 0:1ad0e04b1bc5 | 331 | stream->bytes_left -= size; |
youkee | 0:1ad0e04b1bc5 | 332 | return true; |
youkee | 0:1ad0e04b1bc5 | 333 | } |
youkee | 0:1ad0e04b1bc5 | 334 | |
youkee | 0:1ad0e04b1bc5 | 335 | void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) |
youkee | 0:1ad0e04b1bc5 | 336 | { |
youkee | 0:1ad0e04b1bc5 | 337 | stream->state = substream->state; |
youkee | 0:1ad0e04b1bc5 | 338 | |
youkee | 0:1ad0e04b1bc5 | 339 | #ifndef PB_NO_ERRMSG |
youkee | 0:1ad0e04b1bc5 | 340 | stream->errmsg = substream->errmsg; |
youkee | 0:1ad0e04b1bc5 | 341 | #endif |
youkee | 0:1ad0e04b1bc5 | 342 | } |
youkee | 0:1ad0e04b1bc5 | 343 | |
youkee | 0:1ad0e04b1bc5 | 344 | /************************* |
youkee | 0:1ad0e04b1bc5 | 345 | * Decode a single field * |
youkee | 0:1ad0e04b1bc5 | 346 | *************************/ |
youkee | 0:1ad0e04b1bc5 | 347 | |
youkee | 0:1ad0e04b1bc5 | 348 | static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) |
youkee | 0:1ad0e04b1bc5 | 349 | { |
youkee | 0:1ad0e04b1bc5 | 350 | pb_type_t type; |
youkee | 0:1ad0e04b1bc5 | 351 | pb_decoder_t func; |
youkee | 0:1ad0e04b1bc5 | 352 | |
youkee | 0:1ad0e04b1bc5 | 353 | type = iter->pos->type; |
youkee | 0:1ad0e04b1bc5 | 354 | func = PB_DECODERS[PB_LTYPE(type)]; |
youkee | 0:1ad0e04b1bc5 | 355 | |
youkee | 0:1ad0e04b1bc5 | 356 | switch (PB_HTYPE(type)) |
youkee | 0:1ad0e04b1bc5 | 357 | { |
youkee | 0:1ad0e04b1bc5 | 358 | case PB_HTYPE_REQUIRED: |
youkee | 0:1ad0e04b1bc5 | 359 | return func(stream, iter->pos, iter->pData); |
youkee | 0:1ad0e04b1bc5 | 360 | |
youkee | 0:1ad0e04b1bc5 | 361 | case PB_HTYPE_OPTIONAL: |
youkee | 0:1ad0e04b1bc5 | 362 | *(bool*)iter->pSize = true; |
youkee | 0:1ad0e04b1bc5 | 363 | return func(stream, iter->pos, iter->pData); |
youkee | 0:1ad0e04b1bc5 | 364 | |
youkee | 0:1ad0e04b1bc5 | 365 | case PB_HTYPE_REPEATED: |
youkee | 0:1ad0e04b1bc5 | 366 | if (wire_type == PB_WT_STRING |
youkee | 0:1ad0e04b1bc5 | 367 | && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) |
youkee | 0:1ad0e04b1bc5 | 368 | { |
youkee | 0:1ad0e04b1bc5 | 369 | /* Packed array */ |
youkee | 0:1ad0e04b1bc5 | 370 | bool status = true; |
youkee | 0:1ad0e04b1bc5 | 371 | pb_size_t *size = (pb_size_t*)iter->pSize; |
youkee | 0:1ad0e04b1bc5 | 372 | pb_istream_t substream; |
youkee | 0:1ad0e04b1bc5 | 373 | if (!pb_make_string_substream(stream, &substream)) |
youkee | 0:1ad0e04b1bc5 | 374 | return false; |
youkee | 0:1ad0e04b1bc5 | 375 | |
youkee | 0:1ad0e04b1bc5 | 376 | while (substream.bytes_left > 0 && *size < iter->pos->array_size) |
youkee | 0:1ad0e04b1bc5 | 377 | { |
youkee | 0:1ad0e04b1bc5 | 378 | void *pItem = (char*)iter->pData + iter->pos->data_size * (*size); |
youkee | 0:1ad0e04b1bc5 | 379 | if (!func(&substream, iter->pos, pItem)) |
youkee | 0:1ad0e04b1bc5 | 380 | { |
youkee | 0:1ad0e04b1bc5 | 381 | status = false; |
youkee | 0:1ad0e04b1bc5 | 382 | break; |
youkee | 0:1ad0e04b1bc5 | 383 | } |
youkee | 0:1ad0e04b1bc5 | 384 | (*size)++; |
youkee | 0:1ad0e04b1bc5 | 385 | } |
youkee | 0:1ad0e04b1bc5 | 386 | pb_close_string_substream(stream, &substream); |
youkee | 0:1ad0e04b1bc5 | 387 | |
youkee | 0:1ad0e04b1bc5 | 388 | if (substream.bytes_left != 0) |
youkee | 0:1ad0e04b1bc5 | 389 | PB_RETURN_ERROR(stream, "array overflow"); |
youkee | 0:1ad0e04b1bc5 | 390 | |
youkee | 0:1ad0e04b1bc5 | 391 | return status; |
youkee | 0:1ad0e04b1bc5 | 392 | } |
youkee | 0:1ad0e04b1bc5 | 393 | else |
youkee | 0:1ad0e04b1bc5 | 394 | { |
youkee | 0:1ad0e04b1bc5 | 395 | /* Repeated field */ |
youkee | 0:1ad0e04b1bc5 | 396 | pb_size_t *size = (pb_size_t*)iter->pSize; |
youkee | 0:1ad0e04b1bc5 | 397 | void *pItem = (char*)iter->pData + iter->pos->data_size * (*size); |
youkee | 0:1ad0e04b1bc5 | 398 | if (*size >= iter->pos->array_size) |
youkee | 0:1ad0e04b1bc5 | 399 | PB_RETURN_ERROR(stream, "array overflow"); |
youkee | 0:1ad0e04b1bc5 | 400 | |
youkee | 0:1ad0e04b1bc5 | 401 | (*size)++; |
youkee | 0:1ad0e04b1bc5 | 402 | return func(stream, iter->pos, pItem); |
youkee | 0:1ad0e04b1bc5 | 403 | } |
youkee | 0:1ad0e04b1bc5 | 404 | |
youkee | 0:1ad0e04b1bc5 | 405 | case PB_HTYPE_ONEOF: |
youkee | 0:1ad0e04b1bc5 | 406 | *(pb_size_t*)iter->pSize = iter->pos->tag; |
youkee | 0:1ad0e04b1bc5 | 407 | if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) |
youkee | 0:1ad0e04b1bc5 | 408 | { |
youkee | 0:1ad0e04b1bc5 | 409 | /* We memset to zero so that any callbacks are set to NULL. |
youkee | 0:1ad0e04b1bc5 | 410 | * Then set any default values. */ |
youkee | 0:1ad0e04b1bc5 | 411 | memset(iter->pData, 0, iter->pos->data_size); |
youkee | 0:1ad0e04b1bc5 | 412 | pb_message_set_to_defaults((const pb_field_t*)iter->pos->ptr, iter->pData); |
youkee | 0:1ad0e04b1bc5 | 413 | } |
youkee | 0:1ad0e04b1bc5 | 414 | return func(stream, iter->pos, iter->pData); |
youkee | 0:1ad0e04b1bc5 | 415 | |
youkee | 0:1ad0e04b1bc5 | 416 | default: |
youkee | 0:1ad0e04b1bc5 | 417 | PB_RETURN_ERROR(stream, "invalid field type"); |
youkee | 0:1ad0e04b1bc5 | 418 | } |
youkee | 0:1ad0e04b1bc5 | 419 | } |
youkee | 0:1ad0e04b1bc5 | 420 | |
youkee | 0:1ad0e04b1bc5 | 421 | #ifdef PB_ENABLE_MALLOC |
youkee | 0:1ad0e04b1bc5 | 422 | /* Allocate storage for the field and store the pointer at iter->pData. |
youkee | 0:1ad0e04b1bc5 | 423 | * array_size is the number of entries to reserve in an array. |
youkee | 0:1ad0e04b1bc5 | 424 | * Zero size is not allowed, use pb_free() for releasing. |
youkee | 0:1ad0e04b1bc5 | 425 | */ |
youkee | 0:1ad0e04b1bc5 | 426 | static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size) |
youkee | 0:1ad0e04b1bc5 | 427 | { |
youkee | 0:1ad0e04b1bc5 | 428 | void *ptr = *(void**)pData; |
youkee | 0:1ad0e04b1bc5 | 429 | |
youkee | 0:1ad0e04b1bc5 | 430 | if (data_size == 0 || array_size == 0) |
youkee | 0:1ad0e04b1bc5 | 431 | PB_RETURN_ERROR(stream, "invalid size"); |
youkee | 0:1ad0e04b1bc5 | 432 | |
youkee | 0:1ad0e04b1bc5 | 433 | /* Check for multiplication overflows. |
youkee | 0:1ad0e04b1bc5 | 434 | * This code avoids the costly division if the sizes are small enough. |
youkee | 0:1ad0e04b1bc5 | 435 | * Multiplication is safe as long as only half of bits are set |
youkee | 0:1ad0e04b1bc5 | 436 | * in either multiplicand. |
youkee | 0:1ad0e04b1bc5 | 437 | */ |
youkee | 0:1ad0e04b1bc5 | 438 | { |
youkee | 0:1ad0e04b1bc5 | 439 | const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4); |
youkee | 0:1ad0e04b1bc5 | 440 | if (data_size >= check_limit || array_size >= check_limit) |
youkee | 0:1ad0e04b1bc5 | 441 | { |
youkee | 0:1ad0e04b1bc5 | 442 | const size_t size_max = (size_t)-1; |
youkee | 0:1ad0e04b1bc5 | 443 | if (size_max / array_size < data_size) |
youkee | 0:1ad0e04b1bc5 | 444 | { |
youkee | 0:1ad0e04b1bc5 | 445 | PB_RETURN_ERROR(stream, "size too large"); |
youkee | 0:1ad0e04b1bc5 | 446 | } |
youkee | 0:1ad0e04b1bc5 | 447 | } |
youkee | 0:1ad0e04b1bc5 | 448 | } |
youkee | 0:1ad0e04b1bc5 | 449 | |
youkee | 0:1ad0e04b1bc5 | 450 | /* Allocate new or expand previous allocation */ |
youkee | 0:1ad0e04b1bc5 | 451 | /* Note: on failure the old pointer will remain in the structure, |
youkee | 0:1ad0e04b1bc5 | 452 | * the message must be freed by caller also on error return. */ |
youkee | 0:1ad0e04b1bc5 | 453 | ptr = pb_realloc(ptr, array_size * data_size); |
youkee | 0:1ad0e04b1bc5 | 454 | if (ptr == NULL) |
youkee | 0:1ad0e04b1bc5 | 455 | PB_RETURN_ERROR(stream, "realloc failed"); |
youkee | 0:1ad0e04b1bc5 | 456 | |
youkee | 0:1ad0e04b1bc5 | 457 | *(void**)pData = ptr; |
youkee | 0:1ad0e04b1bc5 | 458 | return true; |
youkee | 0:1ad0e04b1bc5 | 459 | } |
youkee | 0:1ad0e04b1bc5 | 460 | |
youkee | 0:1ad0e04b1bc5 | 461 | /* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ |
youkee | 0:1ad0e04b1bc5 | 462 | static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter) |
youkee | 0:1ad0e04b1bc5 | 463 | { |
youkee | 0:1ad0e04b1bc5 | 464 | if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || |
youkee | 0:1ad0e04b1bc5 | 465 | PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) |
youkee | 0:1ad0e04b1bc5 | 466 | { |
youkee | 0:1ad0e04b1bc5 | 467 | *(void**)pItem = NULL; |
youkee | 0:1ad0e04b1bc5 | 468 | } |
youkee | 0:1ad0e04b1bc5 | 469 | else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) |
youkee | 0:1ad0e04b1bc5 | 470 | { |
youkee | 0:1ad0e04b1bc5 | 471 | pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem); |
youkee | 0:1ad0e04b1bc5 | 472 | } |
youkee | 0:1ad0e04b1bc5 | 473 | } |
youkee | 0:1ad0e04b1bc5 | 474 | #endif |
youkee | 0:1ad0e04b1bc5 | 475 | |
youkee | 0:1ad0e04b1bc5 | 476 | static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) |
youkee | 0:1ad0e04b1bc5 | 477 | { |
youkee | 0:1ad0e04b1bc5 | 478 | #ifndef PB_ENABLE_MALLOC |
youkee | 0:1ad0e04b1bc5 | 479 | PB_UNUSED(wire_type); |
youkee | 0:1ad0e04b1bc5 | 480 | PB_UNUSED(iter); |
youkee | 0:1ad0e04b1bc5 | 481 | PB_RETURN_ERROR(stream, "no malloc support"); |
youkee | 0:1ad0e04b1bc5 | 482 | #else |
youkee | 0:1ad0e04b1bc5 | 483 | pb_type_t type; |
youkee | 0:1ad0e04b1bc5 | 484 | pb_decoder_t func; |
youkee | 0:1ad0e04b1bc5 | 485 | |
youkee | 0:1ad0e04b1bc5 | 486 | type = iter->pos->type; |
youkee | 0:1ad0e04b1bc5 | 487 | func = PB_DECODERS[PB_LTYPE(type)]; |
youkee | 0:1ad0e04b1bc5 | 488 | |
youkee | 0:1ad0e04b1bc5 | 489 | switch (PB_HTYPE(type)) |
youkee | 0:1ad0e04b1bc5 | 490 | { |
youkee | 0:1ad0e04b1bc5 | 491 | case PB_HTYPE_REQUIRED: |
youkee | 0:1ad0e04b1bc5 | 492 | case PB_HTYPE_OPTIONAL: |
youkee | 0:1ad0e04b1bc5 | 493 | case PB_HTYPE_ONEOF: |
youkee | 0:1ad0e04b1bc5 | 494 | if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && |
youkee | 0:1ad0e04b1bc5 | 495 | *(void**)iter->pData != NULL) |
youkee | 0:1ad0e04b1bc5 | 496 | { |
youkee | 0:1ad0e04b1bc5 | 497 | /* Duplicate field, have to release the old allocation first. */ |
youkee | 0:1ad0e04b1bc5 | 498 | pb_release_single_field(iter); |
youkee | 0:1ad0e04b1bc5 | 499 | } |
youkee | 0:1ad0e04b1bc5 | 500 | |
youkee | 0:1ad0e04b1bc5 | 501 | if (PB_HTYPE(type) == PB_HTYPE_ONEOF) |
youkee | 0:1ad0e04b1bc5 | 502 | { |
youkee | 0:1ad0e04b1bc5 | 503 | *(pb_size_t*)iter->pSize = iter->pos->tag; |
youkee | 0:1ad0e04b1bc5 | 504 | } |
youkee | 0:1ad0e04b1bc5 | 505 | |
youkee | 0:1ad0e04b1bc5 | 506 | if (PB_LTYPE(type) == PB_LTYPE_STRING || |
youkee | 0:1ad0e04b1bc5 | 507 | PB_LTYPE(type) == PB_LTYPE_BYTES) |
youkee | 0:1ad0e04b1bc5 | 508 | { |
youkee | 0:1ad0e04b1bc5 | 509 | return func(stream, iter->pos, iter->pData); |
youkee | 0:1ad0e04b1bc5 | 510 | } |
youkee | 0:1ad0e04b1bc5 | 511 | else |
youkee | 0:1ad0e04b1bc5 | 512 | { |
youkee | 0:1ad0e04b1bc5 | 513 | if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1)) |
youkee | 0:1ad0e04b1bc5 | 514 | return false; |
youkee | 0:1ad0e04b1bc5 | 515 | |
youkee | 0:1ad0e04b1bc5 | 516 | initialize_pointer_field(*(void**)iter->pData, iter); |
youkee | 0:1ad0e04b1bc5 | 517 | return func(stream, iter->pos, *(void**)iter->pData); |
youkee | 0:1ad0e04b1bc5 | 518 | } |
youkee | 0:1ad0e04b1bc5 | 519 | |
youkee | 0:1ad0e04b1bc5 | 520 | case PB_HTYPE_REPEATED: |
youkee | 0:1ad0e04b1bc5 | 521 | if (wire_type == PB_WT_STRING |
youkee | 0:1ad0e04b1bc5 | 522 | && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) |
youkee | 0:1ad0e04b1bc5 | 523 | { |
youkee | 0:1ad0e04b1bc5 | 524 | /* Packed array, multiple items come in at once. */ |
youkee | 0:1ad0e04b1bc5 | 525 | bool status = true; |
youkee | 0:1ad0e04b1bc5 | 526 | pb_size_t *size = (pb_size_t*)iter->pSize; |
youkee | 0:1ad0e04b1bc5 | 527 | size_t allocated_size = *size; |
youkee | 0:1ad0e04b1bc5 | 528 | void *pItem; |
youkee | 0:1ad0e04b1bc5 | 529 | pb_istream_t substream; |
youkee | 0:1ad0e04b1bc5 | 530 | |
youkee | 0:1ad0e04b1bc5 | 531 | if (!pb_make_string_substream(stream, &substream)) |
youkee | 0:1ad0e04b1bc5 | 532 | return false; |
youkee | 0:1ad0e04b1bc5 | 533 | |
youkee | 0:1ad0e04b1bc5 | 534 | while (substream.bytes_left) |
youkee | 0:1ad0e04b1bc5 | 535 | { |
youkee | 0:1ad0e04b1bc5 | 536 | if ((size_t)*size + 1 > allocated_size) |
youkee | 0:1ad0e04b1bc5 | 537 | { |
youkee | 0:1ad0e04b1bc5 | 538 | /* Allocate more storage. This tries to guess the |
youkee | 0:1ad0e04b1bc5 | 539 | * number of remaining entries. Round the division |
youkee | 0:1ad0e04b1bc5 | 540 | * upwards. */ |
youkee | 0:1ad0e04b1bc5 | 541 | allocated_size += (substream.bytes_left - 1) / iter->pos->data_size + 1; |
youkee | 0:1ad0e04b1bc5 | 542 | |
youkee | 0:1ad0e04b1bc5 | 543 | if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size)) |
youkee | 0:1ad0e04b1bc5 | 544 | { |
youkee | 0:1ad0e04b1bc5 | 545 | status = false; |
youkee | 0:1ad0e04b1bc5 | 546 | break; |
youkee | 0:1ad0e04b1bc5 | 547 | } |
youkee | 0:1ad0e04b1bc5 | 548 | } |
youkee | 0:1ad0e04b1bc5 | 549 | |
youkee | 0:1ad0e04b1bc5 | 550 | /* Decode the array entry */ |
youkee | 0:1ad0e04b1bc5 | 551 | pItem = *(char**)iter->pData + iter->pos->data_size * (*size); |
youkee | 0:1ad0e04b1bc5 | 552 | initialize_pointer_field(pItem, iter); |
youkee | 0:1ad0e04b1bc5 | 553 | if (!func(&substream, iter->pos, pItem)) |
youkee | 0:1ad0e04b1bc5 | 554 | { |
youkee | 0:1ad0e04b1bc5 | 555 | status = false; |
youkee | 0:1ad0e04b1bc5 | 556 | break; |
youkee | 0:1ad0e04b1bc5 | 557 | } |
youkee | 0:1ad0e04b1bc5 | 558 | |
youkee | 0:1ad0e04b1bc5 | 559 | if (*size == PB_SIZE_MAX) |
youkee | 0:1ad0e04b1bc5 | 560 | { |
youkee | 0:1ad0e04b1bc5 | 561 | #ifndef PB_NO_ERRMSG |
youkee | 0:1ad0e04b1bc5 | 562 | stream->errmsg = "too many array entries"; |
youkee | 0:1ad0e04b1bc5 | 563 | #endif |
youkee | 0:1ad0e04b1bc5 | 564 | status = false; |
youkee | 0:1ad0e04b1bc5 | 565 | break; |
youkee | 0:1ad0e04b1bc5 | 566 | } |
youkee | 0:1ad0e04b1bc5 | 567 | |
youkee | 0:1ad0e04b1bc5 | 568 | (*size)++; |
youkee | 0:1ad0e04b1bc5 | 569 | } |
youkee | 0:1ad0e04b1bc5 | 570 | pb_close_string_substream(stream, &substream); |
youkee | 0:1ad0e04b1bc5 | 571 | |
youkee | 0:1ad0e04b1bc5 | 572 | return status; |
youkee | 0:1ad0e04b1bc5 | 573 | } |
youkee | 0:1ad0e04b1bc5 | 574 | else |
youkee | 0:1ad0e04b1bc5 | 575 | { |
youkee | 0:1ad0e04b1bc5 | 576 | /* Normal repeated field, i.e. only one item at a time. */ |
youkee | 0:1ad0e04b1bc5 | 577 | pb_size_t *size = (pb_size_t*)iter->pSize; |
youkee | 0:1ad0e04b1bc5 | 578 | void *pItem; |
youkee | 0:1ad0e04b1bc5 | 579 | |
youkee | 0:1ad0e04b1bc5 | 580 | if (*size == PB_SIZE_MAX) |
youkee | 0:1ad0e04b1bc5 | 581 | PB_RETURN_ERROR(stream, "too many array entries"); |
youkee | 0:1ad0e04b1bc5 | 582 | |
youkee | 0:1ad0e04b1bc5 | 583 | (*size)++; |
youkee | 0:1ad0e04b1bc5 | 584 | if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size)) |
youkee | 0:1ad0e04b1bc5 | 585 | return false; |
youkee | 0:1ad0e04b1bc5 | 586 | |
youkee | 0:1ad0e04b1bc5 | 587 | pItem = *(char**)iter->pData + iter->pos->data_size * (*size - 1); |
youkee | 0:1ad0e04b1bc5 | 588 | initialize_pointer_field(pItem, iter); |
youkee | 0:1ad0e04b1bc5 | 589 | return func(stream, iter->pos, pItem); |
youkee | 0:1ad0e04b1bc5 | 590 | } |
youkee | 0:1ad0e04b1bc5 | 591 | |
youkee | 0:1ad0e04b1bc5 | 592 | default: |
youkee | 0:1ad0e04b1bc5 | 593 | PB_RETURN_ERROR(stream, "invalid field type"); |
youkee | 0:1ad0e04b1bc5 | 594 | } |
youkee | 0:1ad0e04b1bc5 | 595 | #endif |
youkee | 0:1ad0e04b1bc5 | 596 | } |
youkee | 0:1ad0e04b1bc5 | 597 | |
youkee | 0:1ad0e04b1bc5 | 598 | static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) |
youkee | 0:1ad0e04b1bc5 | 599 | { |
youkee | 0:1ad0e04b1bc5 | 600 | pb_callback_t *pCallback = (pb_callback_t*)iter->pData; |
youkee | 0:1ad0e04b1bc5 | 601 | |
youkee | 0:1ad0e04b1bc5 | 602 | #ifdef PB_OLD_CALLBACK_STYLE |
youkee | 0:1ad0e04b1bc5 | 603 | void *arg = pCallback->arg; |
youkee | 0:1ad0e04b1bc5 | 604 | #else |
youkee | 0:1ad0e04b1bc5 | 605 | void **arg = &(pCallback->arg); |
youkee | 0:1ad0e04b1bc5 | 606 | #endif |
youkee | 0:1ad0e04b1bc5 | 607 | |
youkee | 0:1ad0e04b1bc5 | 608 | if (pCallback->funcs.decode == NULL) |
youkee | 0:1ad0e04b1bc5 | 609 | return pb_skip_field(stream, wire_type); |
youkee | 0:1ad0e04b1bc5 | 610 | |
youkee | 0:1ad0e04b1bc5 | 611 | if (wire_type == PB_WT_STRING) |
youkee | 0:1ad0e04b1bc5 | 612 | { |
youkee | 0:1ad0e04b1bc5 | 613 | pb_istream_t substream; |
youkee | 0:1ad0e04b1bc5 | 614 | |
youkee | 0:1ad0e04b1bc5 | 615 | if (!pb_make_string_substream(stream, &substream)) |
youkee | 0:1ad0e04b1bc5 | 616 | return false; |
youkee | 0:1ad0e04b1bc5 | 617 | |
youkee | 0:1ad0e04b1bc5 | 618 | do |
youkee | 0:1ad0e04b1bc5 | 619 | { |
youkee | 0:1ad0e04b1bc5 | 620 | if (!pCallback->funcs.decode(&substream, iter->pos, arg)) |
youkee | 0:1ad0e04b1bc5 | 621 | PB_RETURN_ERROR(stream, "callback failed"); |
youkee | 0:1ad0e04b1bc5 | 622 | } while (substream.bytes_left); |
youkee | 0:1ad0e04b1bc5 | 623 | |
youkee | 0:1ad0e04b1bc5 | 624 | pb_close_string_substream(stream, &substream); |
youkee | 0:1ad0e04b1bc5 | 625 | return true; |
youkee | 0:1ad0e04b1bc5 | 626 | } |
youkee | 0:1ad0e04b1bc5 | 627 | else |
youkee | 0:1ad0e04b1bc5 | 628 | { |
youkee | 0:1ad0e04b1bc5 | 629 | /* Copy the single scalar value to stack. |
youkee | 0:1ad0e04b1bc5 | 630 | * This is required so that we can limit the stream length, |
youkee | 0:1ad0e04b1bc5 | 631 | * which in turn allows to use same callback for packed and |
youkee | 0:1ad0e04b1bc5 | 632 | * not-packed fields. */ |
youkee | 0:1ad0e04b1bc5 | 633 | pb_istream_t substream; |
youkee | 0:1ad0e04b1bc5 | 634 | pb_byte_t buffer[10]; |
youkee | 0:1ad0e04b1bc5 | 635 | size_t size = sizeof(buffer); |
youkee | 0:1ad0e04b1bc5 | 636 | |
youkee | 0:1ad0e04b1bc5 | 637 | if (!read_raw_value(stream, wire_type, buffer, &size)) |
youkee | 0:1ad0e04b1bc5 | 638 | return false; |
youkee | 0:1ad0e04b1bc5 | 639 | substream = pb_istream_from_buffer(buffer, size); |
youkee | 0:1ad0e04b1bc5 | 640 | |
youkee | 0:1ad0e04b1bc5 | 641 | return pCallback->funcs.decode(&substream, iter->pos, arg); |
youkee | 0:1ad0e04b1bc5 | 642 | } |
youkee | 0:1ad0e04b1bc5 | 643 | } |
youkee | 0:1ad0e04b1bc5 | 644 | |
youkee | 0:1ad0e04b1bc5 | 645 | static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) |
youkee | 0:1ad0e04b1bc5 | 646 | { |
youkee | 0:1ad0e04b1bc5 | 647 | #ifdef PB_ENABLE_MALLOC |
youkee | 0:1ad0e04b1bc5 | 648 | /* When decoding an oneof field, check if there is old data that must be |
youkee | 0:1ad0e04b1bc5 | 649 | * released first. */ |
youkee | 0:1ad0e04b1bc5 | 650 | if (PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF) |
youkee | 0:1ad0e04b1bc5 | 651 | { |
youkee | 0:1ad0e04b1bc5 | 652 | if (!pb_release_union_field(stream, iter)) |
youkee | 0:1ad0e04b1bc5 | 653 | return false; |
youkee | 0:1ad0e04b1bc5 | 654 | } |
youkee | 0:1ad0e04b1bc5 | 655 | #endif |
youkee | 0:1ad0e04b1bc5 | 656 | |
youkee | 0:1ad0e04b1bc5 | 657 | switch (PB_ATYPE(iter->pos->type)) |
youkee | 0:1ad0e04b1bc5 | 658 | { |
youkee | 0:1ad0e04b1bc5 | 659 | case PB_ATYPE_STATIC: |
youkee | 0:1ad0e04b1bc5 | 660 | return decode_static_field(stream, wire_type, iter); |
youkee | 0:1ad0e04b1bc5 | 661 | |
youkee | 0:1ad0e04b1bc5 | 662 | case PB_ATYPE_POINTER: |
youkee | 0:1ad0e04b1bc5 | 663 | return decode_pointer_field(stream, wire_type, iter); |
youkee | 0:1ad0e04b1bc5 | 664 | |
youkee | 0:1ad0e04b1bc5 | 665 | case PB_ATYPE_CALLBACK: |
youkee | 0:1ad0e04b1bc5 | 666 | return decode_callback_field(stream, wire_type, iter); |
youkee | 0:1ad0e04b1bc5 | 667 | |
youkee | 0:1ad0e04b1bc5 | 668 | default: |
youkee | 0:1ad0e04b1bc5 | 669 | PB_RETURN_ERROR(stream, "invalid field type"); |
youkee | 0:1ad0e04b1bc5 | 670 | } |
youkee | 0:1ad0e04b1bc5 | 671 | } |
youkee | 0:1ad0e04b1bc5 | 672 | |
youkee | 0:1ad0e04b1bc5 | 673 | static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension) |
youkee | 0:1ad0e04b1bc5 | 674 | { |
youkee | 0:1ad0e04b1bc5 | 675 | /* Fake a field iterator for the extension field. |
youkee | 0:1ad0e04b1bc5 | 676 | * It is not actually safe to advance this iterator, but decode_field |
youkee | 0:1ad0e04b1bc5 | 677 | * will not even try to. */ |
youkee | 0:1ad0e04b1bc5 | 678 | const pb_field_t *field = (const pb_field_t*)extension->type->arg; |
youkee | 0:1ad0e04b1bc5 | 679 | (void)pb_field_iter_begin(iter, field, extension->dest); |
youkee | 0:1ad0e04b1bc5 | 680 | iter->pData = extension->dest; |
youkee | 0:1ad0e04b1bc5 | 681 | iter->pSize = &extension->found; |
youkee | 0:1ad0e04b1bc5 | 682 | |
youkee | 0:1ad0e04b1bc5 | 683 | if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) |
youkee | 0:1ad0e04b1bc5 | 684 | { |
youkee | 0:1ad0e04b1bc5 | 685 | /* For pointer extensions, the pointer is stored directly |
youkee | 0:1ad0e04b1bc5 | 686 | * in the extension structure. This avoids having an extra |
youkee | 0:1ad0e04b1bc5 | 687 | * indirection. */ |
youkee | 0:1ad0e04b1bc5 | 688 | iter->pData = &extension->dest; |
youkee | 0:1ad0e04b1bc5 | 689 | } |
youkee | 0:1ad0e04b1bc5 | 690 | } |
youkee | 0:1ad0e04b1bc5 | 691 | |
youkee | 0:1ad0e04b1bc5 | 692 | /* Default handler for extension fields. Expects a pb_field_t structure |
youkee | 0:1ad0e04b1bc5 | 693 | * in extension->type->arg. */ |
youkee | 0:1ad0e04b1bc5 | 694 | static bool checkreturn default_extension_decoder(pb_istream_t *stream, |
youkee | 0:1ad0e04b1bc5 | 695 | pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) |
youkee | 0:1ad0e04b1bc5 | 696 | { |
youkee | 0:1ad0e04b1bc5 | 697 | const pb_field_t *field = (const pb_field_t*)extension->type->arg; |
youkee | 0:1ad0e04b1bc5 | 698 | pb_field_iter_t iter; |
youkee | 0:1ad0e04b1bc5 | 699 | |
youkee | 0:1ad0e04b1bc5 | 700 | if (field->tag != tag) |
youkee | 0:1ad0e04b1bc5 | 701 | return true; |
youkee | 0:1ad0e04b1bc5 | 702 | |
youkee | 0:1ad0e04b1bc5 | 703 | iter_from_extension(&iter, extension); |
youkee | 0:1ad0e04b1bc5 | 704 | extension->found = true; |
youkee | 0:1ad0e04b1bc5 | 705 | return decode_field(stream, wire_type, &iter); |
youkee | 0:1ad0e04b1bc5 | 706 | } |
youkee | 0:1ad0e04b1bc5 | 707 | |
youkee | 0:1ad0e04b1bc5 | 708 | /* Try to decode an unknown field as an extension field. Tries each extension |
youkee | 0:1ad0e04b1bc5 | 709 | * decoder in turn, until one of them handles the field or loop ends. */ |
youkee | 0:1ad0e04b1bc5 | 710 | static bool checkreturn decode_extension(pb_istream_t *stream, |
youkee | 0:1ad0e04b1bc5 | 711 | uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter) |
youkee | 0:1ad0e04b1bc5 | 712 | { |
youkee | 0:1ad0e04b1bc5 | 713 | pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; |
youkee | 0:1ad0e04b1bc5 | 714 | size_t pos = stream->bytes_left; |
youkee | 0:1ad0e04b1bc5 | 715 | |
youkee | 0:1ad0e04b1bc5 | 716 | while (extension != NULL && pos == stream->bytes_left) |
youkee | 0:1ad0e04b1bc5 | 717 | { |
youkee | 0:1ad0e04b1bc5 | 718 | bool status; |
youkee | 0:1ad0e04b1bc5 | 719 | if (extension->type->decode) |
youkee | 0:1ad0e04b1bc5 | 720 | status = extension->type->decode(stream, extension, tag, wire_type); |
youkee | 0:1ad0e04b1bc5 | 721 | else |
youkee | 0:1ad0e04b1bc5 | 722 | status = default_extension_decoder(stream, extension, tag, wire_type); |
youkee | 0:1ad0e04b1bc5 | 723 | |
youkee | 0:1ad0e04b1bc5 | 724 | if (!status) |
youkee | 0:1ad0e04b1bc5 | 725 | return false; |
youkee | 0:1ad0e04b1bc5 | 726 | |
youkee | 0:1ad0e04b1bc5 | 727 | extension = extension->next; |
youkee | 0:1ad0e04b1bc5 | 728 | } |
youkee | 0:1ad0e04b1bc5 | 729 | |
youkee | 0:1ad0e04b1bc5 | 730 | return true; |
youkee | 0:1ad0e04b1bc5 | 731 | } |
youkee | 0:1ad0e04b1bc5 | 732 | |
youkee | 0:1ad0e04b1bc5 | 733 | /* Step through the iterator until an extension field is found or until all |
youkee | 0:1ad0e04b1bc5 | 734 | * entries have been checked. There can be only one extension field per |
youkee | 0:1ad0e04b1bc5 | 735 | * message. Returns false if no extension field is found. */ |
youkee | 0:1ad0e04b1bc5 | 736 | static bool checkreturn find_extension_field(pb_field_iter_t *iter) |
youkee | 0:1ad0e04b1bc5 | 737 | { |
youkee | 0:1ad0e04b1bc5 | 738 | const pb_field_t *start = iter->pos; |
youkee | 0:1ad0e04b1bc5 | 739 | |
youkee | 0:1ad0e04b1bc5 | 740 | do { |
youkee | 0:1ad0e04b1bc5 | 741 | if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) |
youkee | 0:1ad0e04b1bc5 | 742 | return true; |
youkee | 0:1ad0e04b1bc5 | 743 | (void)pb_field_iter_next(iter); |
youkee | 0:1ad0e04b1bc5 | 744 | } while (iter->pos != start); |
youkee | 0:1ad0e04b1bc5 | 745 | |
youkee | 0:1ad0e04b1bc5 | 746 | return false; |
youkee | 0:1ad0e04b1bc5 | 747 | } |
youkee | 0:1ad0e04b1bc5 | 748 | |
youkee | 0:1ad0e04b1bc5 | 749 | /* Initialize message fields to default values, recursively */ |
youkee | 0:1ad0e04b1bc5 | 750 | static void pb_field_set_to_default(pb_field_iter_t *iter) |
youkee | 0:1ad0e04b1bc5 | 751 | { |
youkee | 0:1ad0e04b1bc5 | 752 | pb_type_t type; |
youkee | 0:1ad0e04b1bc5 | 753 | type = iter->pos->type; |
youkee | 0:1ad0e04b1bc5 | 754 | |
youkee | 0:1ad0e04b1bc5 | 755 | if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) |
youkee | 0:1ad0e04b1bc5 | 756 | { |
youkee | 0:1ad0e04b1bc5 | 757 | pb_extension_t *ext = *(pb_extension_t* const *)iter->pData; |
youkee | 0:1ad0e04b1bc5 | 758 | while (ext != NULL) |
youkee | 0:1ad0e04b1bc5 | 759 | { |
youkee | 0:1ad0e04b1bc5 | 760 | pb_field_iter_t ext_iter; |
youkee | 0:1ad0e04b1bc5 | 761 | ext->found = false; |
youkee | 0:1ad0e04b1bc5 | 762 | iter_from_extension(&ext_iter, ext); |
youkee | 0:1ad0e04b1bc5 | 763 | pb_field_set_to_default(&ext_iter); |
youkee | 0:1ad0e04b1bc5 | 764 | ext = ext->next; |
youkee | 0:1ad0e04b1bc5 | 765 | } |
youkee | 0:1ad0e04b1bc5 | 766 | } |
youkee | 0:1ad0e04b1bc5 | 767 | else if (PB_ATYPE(type) == PB_ATYPE_STATIC) |
youkee | 0:1ad0e04b1bc5 | 768 | { |
youkee | 0:1ad0e04b1bc5 | 769 | bool init_data = true; |
youkee | 0:1ad0e04b1bc5 | 770 | if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL) |
youkee | 0:1ad0e04b1bc5 | 771 | { |
youkee | 0:1ad0e04b1bc5 | 772 | /* Set has_field to false. Still initialize the optional field |
youkee | 0:1ad0e04b1bc5 | 773 | * itself also. */ |
youkee | 0:1ad0e04b1bc5 | 774 | *(bool*)iter->pSize = false; |
youkee | 0:1ad0e04b1bc5 | 775 | } |
youkee | 0:1ad0e04b1bc5 | 776 | else if (PB_HTYPE(type) == PB_HTYPE_REPEATED || |
youkee | 0:1ad0e04b1bc5 | 777 | PB_HTYPE(type) == PB_HTYPE_ONEOF) |
youkee | 0:1ad0e04b1bc5 | 778 | { |
youkee | 0:1ad0e04b1bc5 | 779 | /* REPEATED: Set array count to 0, no need to initialize contents. |
youkee | 0:1ad0e04b1bc5 | 780 | ONEOF: Set which_field to 0. */ |
youkee | 0:1ad0e04b1bc5 | 781 | *(pb_size_t*)iter->pSize = 0; |
youkee | 0:1ad0e04b1bc5 | 782 | init_data = false; |
youkee | 0:1ad0e04b1bc5 | 783 | } |
youkee | 0:1ad0e04b1bc5 | 784 | |
youkee | 0:1ad0e04b1bc5 | 785 | if (init_data) |
youkee | 0:1ad0e04b1bc5 | 786 | { |
youkee | 0:1ad0e04b1bc5 | 787 | if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) |
youkee | 0:1ad0e04b1bc5 | 788 | { |
youkee | 0:1ad0e04b1bc5 | 789 | /* Initialize submessage to defaults */ |
youkee | 0:1ad0e04b1bc5 | 790 | pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, iter->pData); |
youkee | 0:1ad0e04b1bc5 | 791 | } |
youkee | 0:1ad0e04b1bc5 | 792 | else if (iter->pos->ptr != NULL) |
youkee | 0:1ad0e04b1bc5 | 793 | { |
youkee | 0:1ad0e04b1bc5 | 794 | /* Initialize to default value */ |
youkee | 0:1ad0e04b1bc5 | 795 | memcpy(iter->pData, iter->pos->ptr, iter->pos->data_size); |
youkee | 0:1ad0e04b1bc5 | 796 | } |
youkee | 0:1ad0e04b1bc5 | 797 | else |
youkee | 0:1ad0e04b1bc5 | 798 | { |
youkee | 0:1ad0e04b1bc5 | 799 | /* Initialize to zeros */ |
youkee | 0:1ad0e04b1bc5 | 800 | memset(iter->pData, 0, iter->pos->data_size); |
youkee | 0:1ad0e04b1bc5 | 801 | } |
youkee | 0:1ad0e04b1bc5 | 802 | } |
youkee | 0:1ad0e04b1bc5 | 803 | } |
youkee | 0:1ad0e04b1bc5 | 804 | else if (PB_ATYPE(type) == PB_ATYPE_POINTER) |
youkee | 0:1ad0e04b1bc5 | 805 | { |
youkee | 0:1ad0e04b1bc5 | 806 | /* Initialize the pointer to NULL. */ |
youkee | 0:1ad0e04b1bc5 | 807 | *(void**)iter->pData = NULL; |
youkee | 0:1ad0e04b1bc5 | 808 | |
youkee | 0:1ad0e04b1bc5 | 809 | /* Initialize array count to 0. */ |
youkee | 0:1ad0e04b1bc5 | 810 | if (PB_HTYPE(type) == PB_HTYPE_REPEATED || |
youkee | 0:1ad0e04b1bc5 | 811 | PB_HTYPE(type) == PB_HTYPE_ONEOF) |
youkee | 0:1ad0e04b1bc5 | 812 | { |
youkee | 0:1ad0e04b1bc5 | 813 | *(pb_size_t*)iter->pSize = 0; |
youkee | 0:1ad0e04b1bc5 | 814 | } |
youkee | 0:1ad0e04b1bc5 | 815 | } |
youkee | 0:1ad0e04b1bc5 | 816 | else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) |
youkee | 0:1ad0e04b1bc5 | 817 | { |
youkee | 0:1ad0e04b1bc5 | 818 | /* Don't overwrite callback */ |
youkee | 0:1ad0e04b1bc5 | 819 | } |
youkee | 0:1ad0e04b1bc5 | 820 | } |
youkee | 0:1ad0e04b1bc5 | 821 | |
youkee | 0:1ad0e04b1bc5 | 822 | static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) |
youkee | 0:1ad0e04b1bc5 | 823 | { |
youkee | 0:1ad0e04b1bc5 | 824 | pb_field_iter_t iter; |
youkee | 0:1ad0e04b1bc5 | 825 | |
youkee | 0:1ad0e04b1bc5 | 826 | if (!pb_field_iter_begin(&iter, fields, dest_struct)) |
youkee | 0:1ad0e04b1bc5 | 827 | return; /* Empty message type */ |
youkee | 0:1ad0e04b1bc5 | 828 | |
youkee | 0:1ad0e04b1bc5 | 829 | do |
youkee | 0:1ad0e04b1bc5 | 830 | { |
youkee | 0:1ad0e04b1bc5 | 831 | pb_field_set_to_default(&iter); |
youkee | 0:1ad0e04b1bc5 | 832 | } while (pb_field_iter_next(&iter)); |
youkee | 0:1ad0e04b1bc5 | 833 | } |
youkee | 0:1ad0e04b1bc5 | 834 | |
youkee | 0:1ad0e04b1bc5 | 835 | /********************* |
youkee | 0:1ad0e04b1bc5 | 836 | * Decode all fields * |
youkee | 0:1ad0e04b1bc5 | 837 | *********************/ |
youkee | 0:1ad0e04b1bc5 | 838 | |
youkee | 0:1ad0e04b1bc5 | 839 | bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) |
youkee | 0:1ad0e04b1bc5 | 840 | { |
youkee | 0:1ad0e04b1bc5 | 841 | uint32_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 31) / 32] = {0, 0}; |
youkee | 0:1ad0e04b1bc5 | 842 | const uint32_t allbits = ~(uint32_t)0; |
youkee | 0:1ad0e04b1bc5 | 843 | uint32_t extension_range_start = 0; |
youkee | 0:1ad0e04b1bc5 | 844 | pb_field_iter_t iter; |
youkee | 0:1ad0e04b1bc5 | 845 | |
youkee | 0:1ad0e04b1bc5 | 846 | /* Return value ignored, as empty message types will be correctly handled by |
youkee | 0:1ad0e04b1bc5 | 847 | * pb_field_iter_find() anyway. */ |
youkee | 0:1ad0e04b1bc5 | 848 | (void)pb_field_iter_begin(&iter, fields, dest_struct); |
youkee | 0:1ad0e04b1bc5 | 849 | |
youkee | 0:1ad0e04b1bc5 | 850 | while (stream->bytes_left) |
youkee | 0:1ad0e04b1bc5 | 851 | { |
youkee | 0:1ad0e04b1bc5 | 852 | uint32_t tag; |
youkee | 0:1ad0e04b1bc5 | 853 | pb_wire_type_t wire_type; |
youkee | 0:1ad0e04b1bc5 | 854 | bool eof; |
youkee | 0:1ad0e04b1bc5 | 855 | |
youkee | 0:1ad0e04b1bc5 | 856 | if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) |
youkee | 0:1ad0e04b1bc5 | 857 | { |
youkee | 0:1ad0e04b1bc5 | 858 | if (eof) |
youkee | 0:1ad0e04b1bc5 | 859 | break; |
youkee | 0:1ad0e04b1bc5 | 860 | else |
youkee | 0:1ad0e04b1bc5 | 861 | return false; |
youkee | 0:1ad0e04b1bc5 | 862 | } |
youkee | 0:1ad0e04b1bc5 | 863 | |
youkee | 0:1ad0e04b1bc5 | 864 | if (!pb_field_iter_find(&iter, tag)) |
youkee | 0:1ad0e04b1bc5 | 865 | { |
youkee | 0:1ad0e04b1bc5 | 866 | /* No match found, check if it matches an extension. */ |
youkee | 0:1ad0e04b1bc5 | 867 | if (tag >= extension_range_start) |
youkee | 0:1ad0e04b1bc5 | 868 | { |
youkee | 0:1ad0e04b1bc5 | 869 | if (!find_extension_field(&iter)) |
youkee | 0:1ad0e04b1bc5 | 870 | extension_range_start = (uint32_t)-1; |
youkee | 0:1ad0e04b1bc5 | 871 | else |
youkee | 0:1ad0e04b1bc5 | 872 | extension_range_start = iter.pos->tag; |
youkee | 0:1ad0e04b1bc5 | 873 | |
youkee | 0:1ad0e04b1bc5 | 874 | if (tag >= extension_range_start) |
youkee | 0:1ad0e04b1bc5 | 875 | { |
youkee | 0:1ad0e04b1bc5 | 876 | size_t pos = stream->bytes_left; |
youkee | 0:1ad0e04b1bc5 | 877 | |
youkee | 0:1ad0e04b1bc5 | 878 | if (!decode_extension(stream, tag, wire_type, &iter)) |
youkee | 0:1ad0e04b1bc5 | 879 | return false; |
youkee | 0:1ad0e04b1bc5 | 880 | |
youkee | 0:1ad0e04b1bc5 | 881 | if (pos != stream->bytes_left) |
youkee | 0:1ad0e04b1bc5 | 882 | { |
youkee | 0:1ad0e04b1bc5 | 883 | /* The field was handled */ |
youkee | 0:1ad0e04b1bc5 | 884 | continue; |
youkee | 0:1ad0e04b1bc5 | 885 | } |
youkee | 0:1ad0e04b1bc5 | 886 | } |
youkee | 0:1ad0e04b1bc5 | 887 | } |
youkee | 0:1ad0e04b1bc5 | 888 | |
youkee | 0:1ad0e04b1bc5 | 889 | /* No match found, skip data */ |
youkee | 0:1ad0e04b1bc5 | 890 | if (!pb_skip_field(stream, wire_type)) |
youkee | 0:1ad0e04b1bc5 | 891 | return false; |
youkee | 0:1ad0e04b1bc5 | 892 | continue; |
youkee | 0:1ad0e04b1bc5 | 893 | } |
youkee | 0:1ad0e04b1bc5 | 894 | |
youkee | 0:1ad0e04b1bc5 | 895 | if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED |
youkee | 0:1ad0e04b1bc5 | 896 | && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) |
youkee | 0:1ad0e04b1bc5 | 897 | { |
youkee | 0:1ad0e04b1bc5 | 898 | uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31)); |
youkee | 0:1ad0e04b1bc5 | 899 | fields_seen[iter.required_field_index >> 5] |= tmp; |
youkee | 0:1ad0e04b1bc5 | 900 | } |
youkee | 0:1ad0e04b1bc5 | 901 | |
youkee | 0:1ad0e04b1bc5 | 902 | if (!decode_field(stream, wire_type, &iter)) |
youkee | 0:1ad0e04b1bc5 | 903 | return false; |
youkee | 0:1ad0e04b1bc5 | 904 | } |
youkee | 0:1ad0e04b1bc5 | 905 | |
youkee | 0:1ad0e04b1bc5 | 906 | /* Check that all required fields were present. */ |
youkee | 0:1ad0e04b1bc5 | 907 | { |
youkee | 0:1ad0e04b1bc5 | 908 | /* First figure out the number of required fields by |
youkee | 0:1ad0e04b1bc5 | 909 | * seeking to the end of the field array. Usually we |
youkee | 0:1ad0e04b1bc5 | 910 | * are already close to end after decoding. |
youkee | 0:1ad0e04b1bc5 | 911 | */ |
youkee | 0:1ad0e04b1bc5 | 912 | unsigned req_field_count; |
youkee | 0:1ad0e04b1bc5 | 913 | pb_type_t last_type; |
youkee | 0:1ad0e04b1bc5 | 914 | unsigned i; |
youkee | 0:1ad0e04b1bc5 | 915 | do { |
youkee | 0:1ad0e04b1bc5 | 916 | req_field_count = iter.required_field_index; |
youkee | 0:1ad0e04b1bc5 | 917 | last_type = iter.pos->type; |
youkee | 0:1ad0e04b1bc5 | 918 | } while (pb_field_iter_next(&iter)); |
youkee | 0:1ad0e04b1bc5 | 919 | |
youkee | 0:1ad0e04b1bc5 | 920 | /* Fixup if last field was also required. */ |
youkee | 0:1ad0e04b1bc5 | 921 | if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) |
youkee | 0:1ad0e04b1bc5 | 922 | req_field_count++; |
youkee | 0:1ad0e04b1bc5 | 923 | |
youkee | 0:1ad0e04b1bc5 | 924 | if (req_field_count > 0) |
youkee | 0:1ad0e04b1bc5 | 925 | { |
youkee | 0:1ad0e04b1bc5 | 926 | /* Check the whole words */ |
youkee | 0:1ad0e04b1bc5 | 927 | for (i = 0; i < (req_field_count >> 5); i++) |
youkee | 0:1ad0e04b1bc5 | 928 | { |
youkee | 0:1ad0e04b1bc5 | 929 | if (fields_seen[i] != allbits) |
youkee | 0:1ad0e04b1bc5 | 930 | PB_RETURN_ERROR(stream, "missing required field"); |
youkee | 0:1ad0e04b1bc5 | 931 | } |
youkee | 0:1ad0e04b1bc5 | 932 | |
youkee | 0:1ad0e04b1bc5 | 933 | /* Check the remaining bits */ |
youkee | 0:1ad0e04b1bc5 | 934 | if (fields_seen[req_field_count >> 5] != (allbits >> (32 - (req_field_count & 31)))) |
youkee | 0:1ad0e04b1bc5 | 935 | PB_RETURN_ERROR(stream, "missing required field"); |
youkee | 0:1ad0e04b1bc5 | 936 | } |
youkee | 0:1ad0e04b1bc5 | 937 | } |
youkee | 0:1ad0e04b1bc5 | 938 | |
youkee | 0:1ad0e04b1bc5 | 939 | return true; |
youkee | 0:1ad0e04b1bc5 | 940 | } |
youkee | 0:1ad0e04b1bc5 | 941 | |
youkee | 0:1ad0e04b1bc5 | 942 | bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) |
youkee | 0:1ad0e04b1bc5 | 943 | { |
youkee | 0:1ad0e04b1bc5 | 944 | bool status; |
youkee | 0:1ad0e04b1bc5 | 945 | pb_message_set_to_defaults(fields, dest_struct); |
youkee | 0:1ad0e04b1bc5 | 946 | status = pb_decode_noinit(stream, fields, dest_struct); |
youkee | 0:1ad0e04b1bc5 | 947 | |
youkee | 0:1ad0e04b1bc5 | 948 | #ifdef PB_ENABLE_MALLOC |
youkee | 0:1ad0e04b1bc5 | 949 | if (!status) |
youkee | 0:1ad0e04b1bc5 | 950 | pb_release(fields, dest_struct); |
youkee | 0:1ad0e04b1bc5 | 951 | #endif |
youkee | 0:1ad0e04b1bc5 | 952 | |
youkee | 0:1ad0e04b1bc5 | 953 | return status; |
youkee | 0:1ad0e04b1bc5 | 954 | } |
youkee | 0:1ad0e04b1bc5 | 955 | |
youkee | 0:1ad0e04b1bc5 | 956 | bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) |
youkee | 0:1ad0e04b1bc5 | 957 | { |
youkee | 0:1ad0e04b1bc5 | 958 | pb_istream_t substream; |
youkee | 0:1ad0e04b1bc5 | 959 | bool status; |
youkee | 0:1ad0e04b1bc5 | 960 | |
youkee | 0:1ad0e04b1bc5 | 961 | if (!pb_make_string_substream(stream, &substream)) |
youkee | 0:1ad0e04b1bc5 | 962 | return false; |
youkee | 0:1ad0e04b1bc5 | 963 | |
youkee | 0:1ad0e04b1bc5 | 964 | status = pb_decode(&substream, fields, dest_struct); |
youkee | 0:1ad0e04b1bc5 | 965 | pb_close_string_substream(stream, &substream); |
youkee | 0:1ad0e04b1bc5 | 966 | return status; |
youkee | 0:1ad0e04b1bc5 | 967 | } |
youkee | 0:1ad0e04b1bc5 | 968 | |
youkee | 0:1ad0e04b1bc5 | 969 | #ifdef PB_ENABLE_MALLOC |
youkee | 0:1ad0e04b1bc5 | 970 | /* Given an oneof field, if there has already been a field inside this oneof, |
youkee | 0:1ad0e04b1bc5 | 971 | * release it before overwriting with a different one. */ |
youkee | 0:1ad0e04b1bc5 | 972 | static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter) |
youkee | 0:1ad0e04b1bc5 | 973 | { |
youkee | 0:1ad0e04b1bc5 | 974 | pb_size_t old_tag = *(pb_size_t*)iter->pSize; /* Previous which_ value */ |
youkee | 0:1ad0e04b1bc5 | 975 | pb_size_t new_tag = iter->pos->tag; /* New which_ value */ |
youkee | 0:1ad0e04b1bc5 | 976 | |
youkee | 0:1ad0e04b1bc5 | 977 | if (old_tag == 0) |
youkee | 0:1ad0e04b1bc5 | 978 | return true; /* Ok, no old data in union */ |
youkee | 0:1ad0e04b1bc5 | 979 | |
youkee | 0:1ad0e04b1bc5 | 980 | if (old_tag == new_tag) |
youkee | 0:1ad0e04b1bc5 | 981 | return true; /* Ok, old data is of same type => merge */ |
youkee | 0:1ad0e04b1bc5 | 982 | |
youkee | 0:1ad0e04b1bc5 | 983 | /* Release old data. The find can fail if the message struct contains |
youkee | 0:1ad0e04b1bc5 | 984 | * invalid data. */ |
youkee | 0:1ad0e04b1bc5 | 985 | if (!pb_field_iter_find(iter, old_tag)) |
youkee | 0:1ad0e04b1bc5 | 986 | PB_RETURN_ERROR(stream, "invalid union tag"); |
youkee | 0:1ad0e04b1bc5 | 987 | |
youkee | 0:1ad0e04b1bc5 | 988 | pb_release_single_field(iter); |
youkee | 0:1ad0e04b1bc5 | 989 | |
youkee | 0:1ad0e04b1bc5 | 990 | /* Restore iterator to where it should be. |
youkee | 0:1ad0e04b1bc5 | 991 | * This shouldn't fail unless the pb_field_t structure is corrupted. */ |
youkee | 0:1ad0e04b1bc5 | 992 | if (!pb_field_iter_find(iter, new_tag)) |
youkee | 0:1ad0e04b1bc5 | 993 | PB_RETURN_ERROR(stream, "iterator error"); |
youkee | 0:1ad0e04b1bc5 | 994 | |
youkee | 0:1ad0e04b1bc5 | 995 | return true; |
youkee | 0:1ad0e04b1bc5 | 996 | } |
youkee | 0:1ad0e04b1bc5 | 997 | |
youkee | 0:1ad0e04b1bc5 | 998 | static void pb_release_single_field(const pb_field_iter_t *iter) |
youkee | 0:1ad0e04b1bc5 | 999 | { |
youkee | 0:1ad0e04b1bc5 | 1000 | pb_type_t type; |
youkee | 0:1ad0e04b1bc5 | 1001 | type = iter->pos->type; |
youkee | 0:1ad0e04b1bc5 | 1002 | |
youkee | 0:1ad0e04b1bc5 | 1003 | if (PB_HTYPE(type) == PB_HTYPE_ONEOF) |
youkee | 0:1ad0e04b1bc5 | 1004 | { |
youkee | 0:1ad0e04b1bc5 | 1005 | if (*(pb_size_t*)iter->pSize != iter->pos->tag) |
youkee | 0:1ad0e04b1bc5 | 1006 | return; /* This is not the current field in the union */ |
youkee | 0:1ad0e04b1bc5 | 1007 | } |
youkee | 0:1ad0e04b1bc5 | 1008 | |
youkee | 0:1ad0e04b1bc5 | 1009 | /* Release anything contained inside an extension or submsg. |
youkee | 0:1ad0e04b1bc5 | 1010 | * This has to be done even if the submsg itself is statically |
youkee | 0:1ad0e04b1bc5 | 1011 | * allocated. */ |
youkee | 0:1ad0e04b1bc5 | 1012 | if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) |
youkee | 0:1ad0e04b1bc5 | 1013 | { |
youkee | 0:1ad0e04b1bc5 | 1014 | /* Release fields from all extensions in the linked list */ |
youkee | 0:1ad0e04b1bc5 | 1015 | pb_extension_t *ext = *(pb_extension_t**)iter->pData; |
youkee | 0:1ad0e04b1bc5 | 1016 | while (ext != NULL) |
youkee | 0:1ad0e04b1bc5 | 1017 | { |
youkee | 0:1ad0e04b1bc5 | 1018 | pb_field_iter_t ext_iter; |
youkee | 0:1ad0e04b1bc5 | 1019 | iter_from_extension(&ext_iter, ext); |
youkee | 0:1ad0e04b1bc5 | 1020 | pb_release_single_field(&ext_iter); |
youkee | 0:1ad0e04b1bc5 | 1021 | ext = ext->next; |
youkee | 0:1ad0e04b1bc5 | 1022 | } |
youkee | 0:1ad0e04b1bc5 | 1023 | } |
youkee | 0:1ad0e04b1bc5 | 1024 | else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) |
youkee | 0:1ad0e04b1bc5 | 1025 | { |
youkee | 0:1ad0e04b1bc5 | 1026 | /* Release fields in submessage or submsg array */ |
youkee | 0:1ad0e04b1bc5 | 1027 | void *pItem = iter->pData; |
youkee | 0:1ad0e04b1bc5 | 1028 | pb_size_t count = 1; |
youkee | 0:1ad0e04b1bc5 | 1029 | |
youkee | 0:1ad0e04b1bc5 | 1030 | if (PB_ATYPE(type) == PB_ATYPE_POINTER) |
youkee | 0:1ad0e04b1bc5 | 1031 | { |
youkee | 0:1ad0e04b1bc5 | 1032 | pItem = *(void**)iter->pData; |
youkee | 0:1ad0e04b1bc5 | 1033 | } |
youkee | 0:1ad0e04b1bc5 | 1034 | |
youkee | 0:1ad0e04b1bc5 | 1035 | if (PB_HTYPE(type) == PB_HTYPE_REPEATED) |
youkee | 0:1ad0e04b1bc5 | 1036 | { |
youkee | 0:1ad0e04b1bc5 | 1037 | count = *(pb_size_t*)iter->pSize; |
youkee | 0:1ad0e04b1bc5 | 1038 | |
youkee | 0:1ad0e04b1bc5 | 1039 | if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size) |
youkee | 0:1ad0e04b1bc5 | 1040 | { |
youkee | 0:1ad0e04b1bc5 | 1041 | /* Protect against corrupted _count fields */ |
youkee | 0:1ad0e04b1bc5 | 1042 | count = iter->pos->array_size; |
youkee | 0:1ad0e04b1bc5 | 1043 | } |
youkee | 0:1ad0e04b1bc5 | 1044 | } |
youkee | 0:1ad0e04b1bc5 | 1045 | |
youkee | 0:1ad0e04b1bc5 | 1046 | if (pItem) |
youkee | 0:1ad0e04b1bc5 | 1047 | { |
youkee | 0:1ad0e04b1bc5 | 1048 | while (count--) |
youkee | 0:1ad0e04b1bc5 | 1049 | { |
youkee | 0:1ad0e04b1bc5 | 1050 | pb_release((const pb_field_t*)iter->pos->ptr, pItem); |
youkee | 0:1ad0e04b1bc5 | 1051 | pItem = (char*)pItem + iter->pos->data_size; |
youkee | 0:1ad0e04b1bc5 | 1052 | } |
youkee | 0:1ad0e04b1bc5 | 1053 | } |
youkee | 0:1ad0e04b1bc5 | 1054 | } |
youkee | 0:1ad0e04b1bc5 | 1055 | |
youkee | 0:1ad0e04b1bc5 | 1056 | if (PB_ATYPE(type) == PB_ATYPE_POINTER) |
youkee | 0:1ad0e04b1bc5 | 1057 | { |
youkee | 0:1ad0e04b1bc5 | 1058 | if (PB_HTYPE(type) == PB_HTYPE_REPEATED && |
youkee | 0:1ad0e04b1bc5 | 1059 | (PB_LTYPE(type) == PB_LTYPE_STRING || |
youkee | 0:1ad0e04b1bc5 | 1060 | PB_LTYPE(type) == PB_LTYPE_BYTES)) |
youkee | 0:1ad0e04b1bc5 | 1061 | { |
youkee | 0:1ad0e04b1bc5 | 1062 | /* Release entries in repeated string or bytes array */ |
youkee | 0:1ad0e04b1bc5 | 1063 | void **pItem = *(void***)iter->pData; |
youkee | 0:1ad0e04b1bc5 | 1064 | pb_size_t count = *(pb_size_t*)iter->pSize; |
youkee | 0:1ad0e04b1bc5 | 1065 | while (count--) |
youkee | 0:1ad0e04b1bc5 | 1066 | { |
youkee | 0:1ad0e04b1bc5 | 1067 | pb_free(*pItem); |
youkee | 0:1ad0e04b1bc5 | 1068 | *pItem++ = NULL; |
youkee | 0:1ad0e04b1bc5 | 1069 | } |
youkee | 0:1ad0e04b1bc5 | 1070 | } |
youkee | 0:1ad0e04b1bc5 | 1071 | |
youkee | 0:1ad0e04b1bc5 | 1072 | if (PB_HTYPE(type) == PB_HTYPE_REPEATED) |
youkee | 0:1ad0e04b1bc5 | 1073 | { |
youkee | 0:1ad0e04b1bc5 | 1074 | /* We are going to release the array, so set the size to 0 */ |
youkee | 0:1ad0e04b1bc5 | 1075 | *(pb_size_t*)iter->pSize = 0; |
youkee | 0:1ad0e04b1bc5 | 1076 | } |
youkee | 0:1ad0e04b1bc5 | 1077 | |
youkee | 0:1ad0e04b1bc5 | 1078 | /* Release main item */ |
youkee | 0:1ad0e04b1bc5 | 1079 | pb_free(*(void**)iter->pData); |
youkee | 0:1ad0e04b1bc5 | 1080 | *(void**)iter->pData = NULL; |
youkee | 0:1ad0e04b1bc5 | 1081 | } |
youkee | 0:1ad0e04b1bc5 | 1082 | } |
youkee | 0:1ad0e04b1bc5 | 1083 | |
youkee | 0:1ad0e04b1bc5 | 1084 | void pb_release(const pb_field_t fields[], void *dest_struct) |
youkee | 0:1ad0e04b1bc5 | 1085 | { |
youkee | 0:1ad0e04b1bc5 | 1086 | pb_field_iter_t iter; |
youkee | 0:1ad0e04b1bc5 | 1087 | |
youkee | 0:1ad0e04b1bc5 | 1088 | if (!dest_struct) |
youkee | 0:1ad0e04b1bc5 | 1089 | return; /* Ignore NULL pointers, similar to free() */ |
youkee | 0:1ad0e04b1bc5 | 1090 | |
youkee | 0:1ad0e04b1bc5 | 1091 | if (!pb_field_iter_begin(&iter, fields, dest_struct)) |
youkee | 0:1ad0e04b1bc5 | 1092 | return; /* Empty message type */ |
youkee | 0:1ad0e04b1bc5 | 1093 | |
youkee | 0:1ad0e04b1bc5 | 1094 | do |
youkee | 0:1ad0e04b1bc5 | 1095 | { |
youkee | 0:1ad0e04b1bc5 | 1096 | pb_release_single_field(&iter); |
youkee | 0:1ad0e04b1bc5 | 1097 | } while (pb_field_iter_next(&iter)); |
youkee | 0:1ad0e04b1bc5 | 1098 | } |
youkee | 0:1ad0e04b1bc5 | 1099 | #endif |
youkee | 0:1ad0e04b1bc5 | 1100 | |
youkee | 0:1ad0e04b1bc5 | 1101 | /* Field decoders */ |
youkee | 0:1ad0e04b1bc5 | 1102 | |
youkee | 0:1ad0e04b1bc5 | 1103 | bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest) |
youkee | 0:1ad0e04b1bc5 | 1104 | { |
youkee | 0:1ad0e04b1bc5 | 1105 | uint64_t value; |
youkee | 0:1ad0e04b1bc5 | 1106 | if (!pb_decode_varint(stream, &value)) |
youkee | 0:1ad0e04b1bc5 | 1107 | return false; |
youkee | 0:1ad0e04b1bc5 | 1108 | |
youkee | 0:1ad0e04b1bc5 | 1109 | if (value & 1) |
youkee | 0:1ad0e04b1bc5 | 1110 | *dest = (int64_t)(~(value >> 1)); |
youkee | 0:1ad0e04b1bc5 | 1111 | else |
youkee | 0:1ad0e04b1bc5 | 1112 | *dest = (int64_t)(value >> 1); |
youkee | 0:1ad0e04b1bc5 | 1113 | |
youkee | 0:1ad0e04b1bc5 | 1114 | return true; |
youkee | 0:1ad0e04b1bc5 | 1115 | } |
youkee | 0:1ad0e04b1bc5 | 1116 | |
youkee | 0:1ad0e04b1bc5 | 1117 | bool pb_decode_fixed32(pb_istream_t *stream, void *dest) |
youkee | 0:1ad0e04b1bc5 | 1118 | { |
youkee | 0:1ad0e04b1bc5 | 1119 | pb_byte_t bytes[4]; |
youkee | 0:1ad0e04b1bc5 | 1120 | |
youkee | 0:1ad0e04b1bc5 | 1121 | if (!pb_read(stream, bytes, 4)) |
youkee | 0:1ad0e04b1bc5 | 1122 | return false; |
youkee | 0:1ad0e04b1bc5 | 1123 | |
youkee | 0:1ad0e04b1bc5 | 1124 | *(uint32_t*)dest = ((uint32_t)bytes[0] << 0) | |
youkee | 0:1ad0e04b1bc5 | 1125 | ((uint32_t)bytes[1] << 8) | |
youkee | 0:1ad0e04b1bc5 | 1126 | ((uint32_t)bytes[2] << 16) | |
youkee | 0:1ad0e04b1bc5 | 1127 | ((uint32_t)bytes[3] << 24); |
youkee | 0:1ad0e04b1bc5 | 1128 | return true; |
youkee | 0:1ad0e04b1bc5 | 1129 | } |
youkee | 0:1ad0e04b1bc5 | 1130 | |
youkee | 0:1ad0e04b1bc5 | 1131 | bool pb_decode_fixed64(pb_istream_t *stream, void *dest) |
youkee | 0:1ad0e04b1bc5 | 1132 | { |
youkee | 0:1ad0e04b1bc5 | 1133 | pb_byte_t bytes[8]; |
youkee | 0:1ad0e04b1bc5 | 1134 | |
youkee | 0:1ad0e04b1bc5 | 1135 | if (!pb_read(stream, bytes, 8)) |
youkee | 0:1ad0e04b1bc5 | 1136 | return false; |
youkee | 0:1ad0e04b1bc5 | 1137 | |
youkee | 0:1ad0e04b1bc5 | 1138 | *(uint64_t*)dest = ((uint64_t)bytes[0] << 0) | |
youkee | 0:1ad0e04b1bc5 | 1139 | ((uint64_t)bytes[1] << 8) | |
youkee | 0:1ad0e04b1bc5 | 1140 | ((uint64_t)bytes[2] << 16) | |
youkee | 0:1ad0e04b1bc5 | 1141 | ((uint64_t)bytes[3] << 24) | |
youkee | 0:1ad0e04b1bc5 | 1142 | ((uint64_t)bytes[4] << 32) | |
youkee | 0:1ad0e04b1bc5 | 1143 | ((uint64_t)bytes[5] << 40) | |
youkee | 0:1ad0e04b1bc5 | 1144 | ((uint64_t)bytes[6] << 48) | |
youkee | 0:1ad0e04b1bc5 | 1145 | ((uint64_t)bytes[7] << 56); |
youkee | 0:1ad0e04b1bc5 | 1146 | |
youkee | 0:1ad0e04b1bc5 | 1147 | return true; |
youkee | 0:1ad0e04b1bc5 | 1148 | } |
youkee | 0:1ad0e04b1bc5 | 1149 | |
youkee | 0:1ad0e04b1bc5 | 1150 | static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) |
youkee | 0:1ad0e04b1bc5 | 1151 | { |
youkee | 0:1ad0e04b1bc5 | 1152 | uint64_t value; |
youkee | 0:1ad0e04b1bc5 | 1153 | int64_t svalue; |
youkee | 0:1ad0e04b1bc5 | 1154 | int64_t clamped; |
youkee | 0:1ad0e04b1bc5 | 1155 | if (!pb_decode_varint(stream, &value)) |
youkee | 0:1ad0e04b1bc5 | 1156 | return false; |
youkee | 0:1ad0e04b1bc5 | 1157 | |
youkee | 0:1ad0e04b1bc5 | 1158 | /* See issue 97: Google's C++ protobuf allows negative varint values to |
youkee | 0:1ad0e04b1bc5 | 1159 | * be cast as int32_t, instead of the int64_t that should be used when |
youkee | 0:1ad0e04b1bc5 | 1160 | * encoding. Previous nanopb versions had a bug in encoding. In order to |
youkee | 0:1ad0e04b1bc5 | 1161 | * not break decoding of such messages, we cast <=32 bit fields to |
youkee | 0:1ad0e04b1bc5 | 1162 | * int32_t first to get the sign correct. |
youkee | 0:1ad0e04b1bc5 | 1163 | */ |
youkee | 0:1ad0e04b1bc5 | 1164 | if (field->data_size == sizeof(int64_t)) |
youkee | 0:1ad0e04b1bc5 | 1165 | svalue = (int64_t)value; |
youkee | 0:1ad0e04b1bc5 | 1166 | else |
youkee | 0:1ad0e04b1bc5 | 1167 | svalue = (int32_t)value; |
youkee | 0:1ad0e04b1bc5 | 1168 | |
youkee | 0:1ad0e04b1bc5 | 1169 | /* Cast to the proper field size, while checking for overflows */ |
youkee | 0:1ad0e04b1bc5 | 1170 | if (field->data_size == sizeof(int64_t)) |
youkee | 0:1ad0e04b1bc5 | 1171 | clamped = *(int64_t*)dest = svalue; |
youkee | 0:1ad0e04b1bc5 | 1172 | else if (field->data_size == sizeof(int32_t)) |
youkee | 0:1ad0e04b1bc5 | 1173 | clamped = *(int32_t*)dest = (int32_t)svalue; |
youkee | 0:1ad0e04b1bc5 | 1174 | else if (field->data_size == sizeof(int_least16_t)) |
youkee | 0:1ad0e04b1bc5 | 1175 | clamped = *(int_least16_t*)dest = (int_least16_t)svalue; |
youkee | 0:1ad0e04b1bc5 | 1176 | else if (field->data_size == sizeof(int_least8_t)) |
youkee | 0:1ad0e04b1bc5 | 1177 | clamped = *(int_least8_t*)dest = (int_least8_t)svalue; |
youkee | 0:1ad0e04b1bc5 | 1178 | else |
youkee | 0:1ad0e04b1bc5 | 1179 | PB_RETURN_ERROR(stream, "invalid data_size"); |
youkee | 0:1ad0e04b1bc5 | 1180 | |
youkee | 0:1ad0e04b1bc5 | 1181 | if (clamped != svalue) |
youkee | 0:1ad0e04b1bc5 | 1182 | PB_RETURN_ERROR(stream, "integer too large"); |
youkee | 0:1ad0e04b1bc5 | 1183 | |
youkee | 0:1ad0e04b1bc5 | 1184 | return true; |
youkee | 0:1ad0e04b1bc5 | 1185 | } |
youkee | 0:1ad0e04b1bc5 | 1186 | |
youkee | 0:1ad0e04b1bc5 | 1187 | static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) |
youkee | 0:1ad0e04b1bc5 | 1188 | { |
youkee | 0:1ad0e04b1bc5 | 1189 | uint64_t value, clamped; |
youkee | 0:1ad0e04b1bc5 | 1190 | if (!pb_decode_varint(stream, &value)) |
youkee | 0:1ad0e04b1bc5 | 1191 | return false; |
youkee | 0:1ad0e04b1bc5 | 1192 | |
youkee | 0:1ad0e04b1bc5 | 1193 | /* Cast to the proper field size, while checking for overflows */ |
youkee | 0:1ad0e04b1bc5 | 1194 | if (field->data_size == sizeof(uint64_t)) |
youkee | 0:1ad0e04b1bc5 | 1195 | clamped = *(uint64_t*)dest = value; |
youkee | 0:1ad0e04b1bc5 | 1196 | else if (field->data_size == sizeof(uint32_t)) |
youkee | 0:1ad0e04b1bc5 | 1197 | clamped = *(uint32_t*)dest = (uint32_t)value; |
youkee | 0:1ad0e04b1bc5 | 1198 | else if (field->data_size == sizeof(uint_least16_t)) |
youkee | 0:1ad0e04b1bc5 | 1199 | clamped = *(uint_least16_t*)dest = (uint_least16_t)value; |
youkee | 0:1ad0e04b1bc5 | 1200 | else if (field->data_size == sizeof(uint_least8_t)) |
youkee | 0:1ad0e04b1bc5 | 1201 | clamped = *(uint_least8_t*)dest = (uint_least8_t)value; |
youkee | 0:1ad0e04b1bc5 | 1202 | else |
youkee | 0:1ad0e04b1bc5 | 1203 | PB_RETURN_ERROR(stream, "invalid data_size"); |
youkee | 0:1ad0e04b1bc5 | 1204 | |
youkee | 0:1ad0e04b1bc5 | 1205 | if (clamped != value) |
youkee | 0:1ad0e04b1bc5 | 1206 | PB_RETURN_ERROR(stream, "integer too large"); |
youkee | 0:1ad0e04b1bc5 | 1207 | |
youkee | 0:1ad0e04b1bc5 | 1208 | return true; |
youkee | 0:1ad0e04b1bc5 | 1209 | } |
youkee | 0:1ad0e04b1bc5 | 1210 | |
youkee | 0:1ad0e04b1bc5 | 1211 | static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) |
youkee | 0:1ad0e04b1bc5 | 1212 | { |
youkee | 0:1ad0e04b1bc5 | 1213 | int64_t value, clamped; |
youkee | 0:1ad0e04b1bc5 | 1214 | if (!pb_decode_svarint(stream, &value)) |
youkee | 0:1ad0e04b1bc5 | 1215 | return false; |
youkee | 0:1ad0e04b1bc5 | 1216 | |
youkee | 0:1ad0e04b1bc5 | 1217 | /* Cast to the proper field size, while checking for overflows */ |
youkee | 0:1ad0e04b1bc5 | 1218 | if (field->data_size == sizeof(int64_t)) |
youkee | 0:1ad0e04b1bc5 | 1219 | clamped = *(int64_t*)dest = value; |
youkee | 0:1ad0e04b1bc5 | 1220 | else if (field->data_size == sizeof(int32_t)) |
youkee | 0:1ad0e04b1bc5 | 1221 | clamped = *(int32_t*)dest = (int32_t)value; |
youkee | 0:1ad0e04b1bc5 | 1222 | else if (field->data_size == sizeof(int_least16_t)) |
youkee | 0:1ad0e04b1bc5 | 1223 | clamped = *(int_least16_t*)dest = (int_least16_t)value; |
youkee | 0:1ad0e04b1bc5 | 1224 | else if (field->data_size == sizeof(int_least8_t)) |
youkee | 0:1ad0e04b1bc5 | 1225 | clamped = *(int_least8_t*)dest = (int_least8_t)value; |
youkee | 0:1ad0e04b1bc5 | 1226 | else |
youkee | 0:1ad0e04b1bc5 | 1227 | PB_RETURN_ERROR(stream, "invalid data_size"); |
youkee | 0:1ad0e04b1bc5 | 1228 | |
youkee | 0:1ad0e04b1bc5 | 1229 | if (clamped != value) |
youkee | 0:1ad0e04b1bc5 | 1230 | PB_RETURN_ERROR(stream, "integer too large"); |
youkee | 0:1ad0e04b1bc5 | 1231 | |
youkee | 0:1ad0e04b1bc5 | 1232 | return true; |
youkee | 0:1ad0e04b1bc5 | 1233 | } |
youkee | 0:1ad0e04b1bc5 | 1234 | |
youkee | 0:1ad0e04b1bc5 | 1235 | static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) |
youkee | 0:1ad0e04b1bc5 | 1236 | { |
youkee | 0:1ad0e04b1bc5 | 1237 | PB_UNUSED(field); |
youkee | 0:1ad0e04b1bc5 | 1238 | return pb_decode_fixed32(stream, dest); |
youkee | 0:1ad0e04b1bc5 | 1239 | } |
youkee | 0:1ad0e04b1bc5 | 1240 | |
youkee | 0:1ad0e04b1bc5 | 1241 | static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) |
youkee | 0:1ad0e04b1bc5 | 1242 | { |
youkee | 0:1ad0e04b1bc5 | 1243 | PB_UNUSED(field); |
youkee | 0:1ad0e04b1bc5 | 1244 | return pb_decode_fixed64(stream, dest); |
youkee | 0:1ad0e04b1bc5 | 1245 | } |
youkee | 0:1ad0e04b1bc5 | 1246 | |
youkee | 0:1ad0e04b1bc5 | 1247 | static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) |
youkee | 0:1ad0e04b1bc5 | 1248 | { |
youkee | 0:1ad0e04b1bc5 | 1249 | uint32_t size; |
youkee | 0:1ad0e04b1bc5 | 1250 | size_t alloc_size; |
youkee | 0:1ad0e04b1bc5 | 1251 | pb_bytes_array_t *bdest; |
youkee | 0:1ad0e04b1bc5 | 1252 | |
youkee | 0:1ad0e04b1bc5 | 1253 | if (!pb_decode_varint32(stream, &size)) |
youkee | 0:1ad0e04b1bc5 | 1254 | return false; |
youkee | 0:1ad0e04b1bc5 | 1255 | |
youkee | 0:1ad0e04b1bc5 | 1256 | if (size > PB_SIZE_MAX) |
youkee | 0:1ad0e04b1bc5 | 1257 | PB_RETURN_ERROR(stream, "bytes overflow"); |
youkee | 0:1ad0e04b1bc5 | 1258 | |
youkee | 0:1ad0e04b1bc5 | 1259 | alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size); |
youkee | 0:1ad0e04b1bc5 | 1260 | if (size > alloc_size) |
youkee | 0:1ad0e04b1bc5 | 1261 | PB_RETURN_ERROR(stream, "size too large"); |
youkee | 0:1ad0e04b1bc5 | 1262 | |
youkee | 0:1ad0e04b1bc5 | 1263 | if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) |
youkee | 0:1ad0e04b1bc5 | 1264 | { |
youkee | 0:1ad0e04b1bc5 | 1265 | #ifndef PB_ENABLE_MALLOC |
youkee | 0:1ad0e04b1bc5 | 1266 | PB_RETURN_ERROR(stream, "no malloc support"); |
youkee | 0:1ad0e04b1bc5 | 1267 | #else |
youkee | 0:1ad0e04b1bc5 | 1268 | if (!allocate_field(stream, dest, alloc_size, 1)) |
youkee | 0:1ad0e04b1bc5 | 1269 | return false; |
youkee | 0:1ad0e04b1bc5 | 1270 | bdest = *(pb_bytes_array_t**)dest; |
youkee | 0:1ad0e04b1bc5 | 1271 | #endif |
youkee | 0:1ad0e04b1bc5 | 1272 | } |
youkee | 0:1ad0e04b1bc5 | 1273 | else |
youkee | 0:1ad0e04b1bc5 | 1274 | { |
youkee | 0:1ad0e04b1bc5 | 1275 | if (alloc_size > field->data_size) |
youkee | 0:1ad0e04b1bc5 | 1276 | PB_RETURN_ERROR(stream, "bytes overflow"); |
youkee | 0:1ad0e04b1bc5 | 1277 | bdest = (pb_bytes_array_t*)dest; |
youkee | 0:1ad0e04b1bc5 | 1278 | } |
youkee | 0:1ad0e04b1bc5 | 1279 | |
youkee | 0:1ad0e04b1bc5 | 1280 | bdest->size = (pb_size_t)size; |
youkee | 0:1ad0e04b1bc5 | 1281 | return pb_read(stream, bdest->bytes, size); |
youkee | 0:1ad0e04b1bc5 | 1282 | } |
youkee | 0:1ad0e04b1bc5 | 1283 | |
youkee | 0:1ad0e04b1bc5 | 1284 | static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) |
youkee | 0:1ad0e04b1bc5 | 1285 | { |
youkee | 0:1ad0e04b1bc5 | 1286 | uint32_t size; |
youkee | 0:1ad0e04b1bc5 | 1287 | size_t alloc_size; |
youkee | 0:1ad0e04b1bc5 | 1288 | bool status; |
youkee | 0:1ad0e04b1bc5 | 1289 | if (!pb_decode_varint32(stream, &size)) |
youkee | 0:1ad0e04b1bc5 | 1290 | return false; |
youkee | 0:1ad0e04b1bc5 | 1291 | |
youkee | 0:1ad0e04b1bc5 | 1292 | /* Space for null terminator */ |
youkee | 0:1ad0e04b1bc5 | 1293 | alloc_size = size + 1; |
youkee | 0:1ad0e04b1bc5 | 1294 | |
youkee | 0:1ad0e04b1bc5 | 1295 | if (alloc_size < size) |
youkee | 0:1ad0e04b1bc5 | 1296 | PB_RETURN_ERROR(stream, "size too large"); |
youkee | 0:1ad0e04b1bc5 | 1297 | |
youkee | 0:1ad0e04b1bc5 | 1298 | if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) |
youkee | 0:1ad0e04b1bc5 | 1299 | { |
youkee | 0:1ad0e04b1bc5 | 1300 | #ifndef PB_ENABLE_MALLOC |
youkee | 0:1ad0e04b1bc5 | 1301 | PB_RETURN_ERROR(stream, "no malloc support"); |
youkee | 0:1ad0e04b1bc5 | 1302 | #else |
youkee | 0:1ad0e04b1bc5 | 1303 | if (!allocate_field(stream, dest, alloc_size, 1)) |
youkee | 0:1ad0e04b1bc5 | 1304 | return false; |
youkee | 0:1ad0e04b1bc5 | 1305 | dest = *(void**)dest; |
youkee | 0:1ad0e04b1bc5 | 1306 | #endif |
youkee | 0:1ad0e04b1bc5 | 1307 | } |
youkee | 0:1ad0e04b1bc5 | 1308 | else |
youkee | 0:1ad0e04b1bc5 | 1309 | { |
youkee | 0:1ad0e04b1bc5 | 1310 | if (alloc_size > field->data_size) |
youkee | 0:1ad0e04b1bc5 | 1311 | PB_RETURN_ERROR(stream, "string overflow"); |
youkee | 0:1ad0e04b1bc5 | 1312 | } |
youkee | 0:1ad0e04b1bc5 | 1313 | |
youkee | 0:1ad0e04b1bc5 | 1314 | status = pb_read(stream, (pb_byte_t*)dest, size); |
youkee | 0:1ad0e04b1bc5 | 1315 | *((pb_byte_t*)dest + size) = 0; |
youkee | 0:1ad0e04b1bc5 | 1316 | return status; |
youkee | 0:1ad0e04b1bc5 | 1317 | } |
youkee | 0:1ad0e04b1bc5 | 1318 | |
youkee | 0:1ad0e04b1bc5 | 1319 | static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) |
youkee | 0:1ad0e04b1bc5 | 1320 | { |
youkee | 0:1ad0e04b1bc5 | 1321 | bool status; |
youkee | 0:1ad0e04b1bc5 | 1322 | pb_istream_t substream; |
youkee | 0:1ad0e04b1bc5 | 1323 | const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr; |
youkee | 0:1ad0e04b1bc5 | 1324 | |
youkee | 0:1ad0e04b1bc5 | 1325 | if (!pb_make_string_substream(stream, &substream)) |
youkee | 0:1ad0e04b1bc5 | 1326 | return false; |
youkee | 0:1ad0e04b1bc5 | 1327 | |
youkee | 0:1ad0e04b1bc5 | 1328 | if (field->ptr == NULL) |
youkee | 0:1ad0e04b1bc5 | 1329 | PB_RETURN_ERROR(stream, "invalid field descriptor"); |
youkee | 0:1ad0e04b1bc5 | 1330 | |
youkee | 0:1ad0e04b1bc5 | 1331 | /* New array entries need to be initialized, while required and optional |
youkee | 0:1ad0e04b1bc5 | 1332 | * submessages have already been initialized in the top-level pb_decode. */ |
youkee | 0:1ad0e04b1bc5 | 1333 | if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED) |
youkee | 0:1ad0e04b1bc5 | 1334 | status = pb_decode(&substream, submsg_fields, dest); |
youkee | 0:1ad0e04b1bc5 | 1335 | else |
youkee | 0:1ad0e04b1bc5 | 1336 | status = pb_decode_noinit(&substream, submsg_fields, dest); |
youkee | 0:1ad0e04b1bc5 | 1337 | |
youkee | 0:1ad0e04b1bc5 | 1338 | pb_close_string_substream(stream, &substream); |
youkee | 0:1ad0e04b1bc5 | 1339 | return status; |
youkee | 0:1ad0e04b1bc5 | 1340 | } |