Tomas Johansen
/
nanopb_test
Nanopb (lightweight version of googles protobuf) test. It is not working as it should yet.
nanopb/pb_decode.c@3:fd0e1bc80f78, 2014-04-09 (annotated)
- Committer:
- Tomas
- Date:
- Wed Apr 09 11:44:14 2014 +0000
- Revision:
- 3:fd0e1bc80f78
- Parent:
- 0:bada2c7bd577
removed unnecessary libraries
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Tomas | 0:bada2c7bd577 | 1 | /* pb_decode.c -- decode a protobuf using minimal resources |
Tomas | 0:bada2c7bd577 | 2 | * |
Tomas | 0:bada2c7bd577 | 3 | * 2011 Petteri Aimonen <jpa@kapsi.fi> |
Tomas | 0:bada2c7bd577 | 4 | */ |
Tomas | 0:bada2c7bd577 | 5 | |
Tomas | 0:bada2c7bd577 | 6 | /* Use the GCC warn_unused_result attribute to check that all return values |
Tomas | 0:bada2c7bd577 | 7 | * are propagated correctly. On other compilers and gcc before 3.4.0 just |
Tomas | 0:bada2c7bd577 | 8 | * ignore the annotation. |
Tomas | 0:bada2c7bd577 | 9 | */ |
Tomas | 0:bada2c7bd577 | 10 | #if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) |
Tomas | 0:bada2c7bd577 | 11 | #define checkreturn |
Tomas | 0:bada2c7bd577 | 12 | #else |
Tomas | 0:bada2c7bd577 | 13 | #define checkreturn __attribute__((warn_unused_result)) |
Tomas | 0:bada2c7bd577 | 14 | #endif |
Tomas | 0:bada2c7bd577 | 15 | |
Tomas | 0:bada2c7bd577 | 16 | #define NANOPB_INTERNALS |
Tomas | 0:bada2c7bd577 | 17 | #include "pb.h" |
Tomas | 0:bada2c7bd577 | 18 | #include "pb_decode.h" |
Tomas | 0:bada2c7bd577 | 19 | |
Tomas | 0:bada2c7bd577 | 20 | /************************************** |
Tomas | 0:bada2c7bd577 | 21 | * Declarations internal to this file * |
Tomas | 0:bada2c7bd577 | 22 | **************************************/ |
Tomas | 0:bada2c7bd577 | 23 | |
Tomas | 0:bada2c7bd577 | 24 | /* Iterator for pb_field_t list */ |
Tomas | 0:bada2c7bd577 | 25 | typedef struct { |
Tomas | 0:bada2c7bd577 | 26 | const pb_field_t *start; /* Start of the pb_field_t array */ |
Tomas | 0:bada2c7bd577 | 27 | const pb_field_t *pos; /* Current position of the iterator */ |
Tomas | 0:bada2c7bd577 | 28 | unsigned field_index; /* Zero-based index of the field. */ |
Tomas | 0:bada2c7bd577 | 29 | unsigned required_field_index; /* Zero-based index that counts only the required fields */ |
Tomas | 0:bada2c7bd577 | 30 | void *dest_struct; /* Pointer to the destination structure to decode to */ |
Tomas | 0:bada2c7bd577 | 31 | void *pData; /* Pointer where to store current field value */ |
Tomas | 0:bada2c7bd577 | 32 | void *pSize; /* Pointer where to store the size of current array field */ |
Tomas | 0:bada2c7bd577 | 33 | } pb_field_iterator_t; |
Tomas | 0:bada2c7bd577 | 34 | |
Tomas | 0:bada2c7bd577 | 35 | typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; |
Tomas | 0:bada2c7bd577 | 36 | |
Tomas | 0:bada2c7bd577 | 37 | static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count); |
Tomas | 0:bada2c7bd577 | 38 | static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); |
Tomas | 0:bada2c7bd577 | 39 | static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, uint8_t *buf, size_t *size); |
Tomas | 0:bada2c7bd577 | 40 | static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct); |
Tomas | 0:bada2c7bd577 | 41 | static bool pb_field_next(pb_field_iterator_t *iter); |
Tomas | 0:bada2c7bd577 | 42 | static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag); |
Tomas | 0:bada2c7bd577 | 43 | static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); |
Tomas | 0:bada2c7bd577 | 44 | static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); |
Tomas | 0:bada2c7bd577 | 45 | static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); |
Tomas | 0:bada2c7bd577 | 46 | static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); |
Tomas | 0:bada2c7bd577 | 47 | static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter); |
Tomas | 0:bada2c7bd577 | 48 | static bool checkreturn find_extension_field(pb_field_iterator_t *iter); |
Tomas | 0:bada2c7bd577 | 49 | static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); |
Tomas | 0:bada2c7bd577 | 50 | static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); |
Tomas | 0:bada2c7bd577 | 51 | static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); |
Tomas | 0:bada2c7bd577 | 52 | static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest); |
Tomas | 0:bada2c7bd577 | 53 | static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest); |
Tomas | 0:bada2c7bd577 | 54 | static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest); |
Tomas | 0:bada2c7bd577 | 55 | static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); |
Tomas | 0:bada2c7bd577 | 56 | static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest); |
Tomas | 0:bada2c7bd577 | 57 | static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest); |
Tomas | 0:bada2c7bd577 | 58 | static bool checkreturn pb_skip_varint(pb_istream_t *stream); |
Tomas | 0:bada2c7bd577 | 59 | static bool checkreturn pb_skip_string(pb_istream_t *stream); |
Tomas | 0:bada2c7bd577 | 60 | |
Tomas | 0:bada2c7bd577 | 61 | /* --- Function pointers to field decoders --- |
Tomas | 0:bada2c7bd577 | 62 | * Order in the array must match pb_action_t LTYPE numbering. |
Tomas | 0:bada2c7bd577 | 63 | */ |
Tomas | 0:bada2c7bd577 | 64 | static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { |
Tomas | 0:bada2c7bd577 | 65 | &pb_dec_varint, |
Tomas | 0:bada2c7bd577 | 66 | &pb_dec_uvarint, |
Tomas | 0:bada2c7bd577 | 67 | &pb_dec_svarint, |
Tomas | 0:bada2c7bd577 | 68 | &pb_dec_fixed32, |
Tomas | 0:bada2c7bd577 | 69 | &pb_dec_fixed64, |
Tomas | 0:bada2c7bd577 | 70 | |
Tomas | 0:bada2c7bd577 | 71 | &pb_dec_bytes, |
Tomas | 0:bada2c7bd577 | 72 | &pb_dec_string, |
Tomas | 0:bada2c7bd577 | 73 | &pb_dec_submessage, |
Tomas | 0:bada2c7bd577 | 74 | NULL /* extensions */ |
Tomas | 0:bada2c7bd577 | 75 | }; |
Tomas | 0:bada2c7bd577 | 76 | |
Tomas | 0:bada2c7bd577 | 77 | /******************************* |
Tomas | 0:bada2c7bd577 | 78 | * pb_istream_t implementation * |
Tomas | 0:bada2c7bd577 | 79 | *******************************/ |
Tomas | 0:bada2c7bd577 | 80 | |
Tomas | 0:bada2c7bd577 | 81 | static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count) |
Tomas | 0:bada2c7bd577 | 82 | { |
Tomas | 0:bada2c7bd577 | 83 | uint8_t *source = (uint8_t*)stream->state; |
Tomas | 0:bada2c7bd577 | 84 | stream->state = source + count; |
Tomas | 0:bada2c7bd577 | 85 | |
Tomas | 0:bada2c7bd577 | 86 | if (buf != NULL) |
Tomas | 0:bada2c7bd577 | 87 | { |
Tomas | 0:bada2c7bd577 | 88 | while (count--) |
Tomas | 0:bada2c7bd577 | 89 | *buf++ = *source++; |
Tomas | 0:bada2c7bd577 | 90 | } |
Tomas | 0:bada2c7bd577 | 91 | |
Tomas | 0:bada2c7bd577 | 92 | return true; |
Tomas | 0:bada2c7bd577 | 93 | } |
Tomas | 0:bada2c7bd577 | 94 | |
Tomas | 0:bada2c7bd577 | 95 | bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count) |
Tomas | 0:bada2c7bd577 | 96 | { |
Tomas | 0:bada2c7bd577 | 97 | #ifndef PB_BUFFER_ONLY |
Tomas | 0:bada2c7bd577 | 98 | if (buf == NULL && stream->callback != buf_read) |
Tomas | 0:bada2c7bd577 | 99 | { |
Tomas | 0:bada2c7bd577 | 100 | /* Skip input bytes */ |
Tomas | 0:bada2c7bd577 | 101 | uint8_t tmp[16]; |
Tomas | 0:bada2c7bd577 | 102 | while (count > 16) |
Tomas | 0:bada2c7bd577 | 103 | { |
Tomas | 0:bada2c7bd577 | 104 | if (!pb_read(stream, tmp, 16)) |
Tomas | 0:bada2c7bd577 | 105 | return false; |
Tomas | 0:bada2c7bd577 | 106 | |
Tomas | 0:bada2c7bd577 | 107 | count -= 16; |
Tomas | 0:bada2c7bd577 | 108 | } |
Tomas | 0:bada2c7bd577 | 109 | |
Tomas | 0:bada2c7bd577 | 110 | return pb_read(stream, tmp, count); |
Tomas | 0:bada2c7bd577 | 111 | } |
Tomas | 0:bada2c7bd577 | 112 | #endif |
Tomas | 0:bada2c7bd577 | 113 | |
Tomas | 0:bada2c7bd577 | 114 | if (stream->bytes_left < count) |
Tomas | 0:bada2c7bd577 | 115 | PB_RETURN_ERROR(stream, "end-of-stream"); |
Tomas | 0:bada2c7bd577 | 116 | |
Tomas | 0:bada2c7bd577 | 117 | #ifndef PB_BUFFER_ONLY |
Tomas | 0:bada2c7bd577 | 118 | if (!stream->callback(stream, buf, count)) |
Tomas | 0:bada2c7bd577 | 119 | PB_RETURN_ERROR(stream, "io error"); |
Tomas | 0:bada2c7bd577 | 120 | #else |
Tomas | 0:bada2c7bd577 | 121 | if (!buf_read(stream, buf, count)) |
Tomas | 0:bada2c7bd577 | 122 | return false; |
Tomas | 0:bada2c7bd577 | 123 | #endif |
Tomas | 0:bada2c7bd577 | 124 | |
Tomas | 0:bada2c7bd577 | 125 | stream->bytes_left -= count; |
Tomas | 0:bada2c7bd577 | 126 | return true; |
Tomas | 0:bada2c7bd577 | 127 | } |
Tomas | 0:bada2c7bd577 | 128 | |
Tomas | 0:bada2c7bd577 | 129 | /* Read a single byte from input stream. buf may not be NULL. |
Tomas | 0:bada2c7bd577 | 130 | * This is an optimization for the varint decoding. */ |
Tomas | 0:bada2c7bd577 | 131 | static bool checkreturn pb_readbyte(pb_istream_t *stream, uint8_t *buf) |
Tomas | 0:bada2c7bd577 | 132 | { |
Tomas | 0:bada2c7bd577 | 133 | if (!stream->bytes_left) |
Tomas | 0:bada2c7bd577 | 134 | PB_RETURN_ERROR(stream, "end-of-stream"); |
Tomas | 0:bada2c7bd577 | 135 | |
Tomas | 0:bada2c7bd577 | 136 | #ifndef PB_BUFFER_ONLY |
Tomas | 0:bada2c7bd577 | 137 | if (!stream->callback(stream, buf, 1)) |
Tomas | 0:bada2c7bd577 | 138 | PB_RETURN_ERROR(stream, "io error"); |
Tomas | 0:bada2c7bd577 | 139 | #else |
Tomas | 0:bada2c7bd577 | 140 | *buf = *(uint8_t*)stream->state; |
Tomas | 0:bada2c7bd577 | 141 | stream->state = (uint8_t*)stream->state + 1; |
Tomas | 0:bada2c7bd577 | 142 | #endif |
Tomas | 0:bada2c7bd577 | 143 | |
Tomas | 0:bada2c7bd577 | 144 | stream->bytes_left--; |
Tomas | 0:bada2c7bd577 | 145 | |
Tomas | 0:bada2c7bd577 | 146 | return true; |
Tomas | 0:bada2c7bd577 | 147 | } |
Tomas | 0:bada2c7bd577 | 148 | |
Tomas | 0:bada2c7bd577 | 149 | pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize) |
Tomas | 0:bada2c7bd577 | 150 | { |
Tomas | 0:bada2c7bd577 | 151 | pb_istream_t stream; |
Tomas | 0:bada2c7bd577 | 152 | #ifdef PB_BUFFER_ONLY |
Tomas | 0:bada2c7bd577 | 153 | stream.callback = NULL; |
Tomas | 0:bada2c7bd577 | 154 | #else |
Tomas | 0:bada2c7bd577 | 155 | stream.callback = &buf_read; |
Tomas | 0:bada2c7bd577 | 156 | #endif |
Tomas | 0:bada2c7bd577 | 157 | stream.state = buf; |
Tomas | 0:bada2c7bd577 | 158 | stream.bytes_left = bufsize; |
Tomas | 0:bada2c7bd577 | 159 | #ifndef PB_NO_ERRMSG |
Tomas | 0:bada2c7bd577 | 160 | stream.errmsg = NULL; |
Tomas | 0:bada2c7bd577 | 161 | #endif |
Tomas | 0:bada2c7bd577 | 162 | return stream; |
Tomas | 0:bada2c7bd577 | 163 | } |
Tomas | 0:bada2c7bd577 | 164 | |
Tomas | 0:bada2c7bd577 | 165 | /******************** |
Tomas | 0:bada2c7bd577 | 166 | * Helper functions * |
Tomas | 0:bada2c7bd577 | 167 | ********************/ |
Tomas | 0:bada2c7bd577 | 168 | |
Tomas | 0:bada2c7bd577 | 169 | static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) |
Tomas | 0:bada2c7bd577 | 170 | { |
Tomas | 0:bada2c7bd577 | 171 | uint8_t byte; |
Tomas | 0:bada2c7bd577 | 172 | uint32_t result; |
Tomas | 0:bada2c7bd577 | 173 | |
Tomas | 0:bada2c7bd577 | 174 | if (!pb_readbyte(stream, &byte)) |
Tomas | 0:bada2c7bd577 | 175 | return false; |
Tomas | 0:bada2c7bd577 | 176 | |
Tomas | 0:bada2c7bd577 | 177 | if (!(byte & 0x80)) |
Tomas | 0:bada2c7bd577 | 178 | { |
Tomas | 0:bada2c7bd577 | 179 | /* Quick case, 1 byte value */ |
Tomas | 0:bada2c7bd577 | 180 | result = byte; |
Tomas | 0:bada2c7bd577 | 181 | } |
Tomas | 0:bada2c7bd577 | 182 | else |
Tomas | 0:bada2c7bd577 | 183 | { |
Tomas | 0:bada2c7bd577 | 184 | /* Multibyte case */ |
Tomas | 0:bada2c7bd577 | 185 | uint8_t bitpos = 7; |
Tomas | 0:bada2c7bd577 | 186 | result = byte & 0x7F; |
Tomas | 0:bada2c7bd577 | 187 | |
Tomas | 0:bada2c7bd577 | 188 | do |
Tomas | 0:bada2c7bd577 | 189 | { |
Tomas | 0:bada2c7bd577 | 190 | if (bitpos >= 32) |
Tomas | 0:bada2c7bd577 | 191 | PB_RETURN_ERROR(stream, "varint overflow"); |
Tomas | 0:bada2c7bd577 | 192 | |
Tomas | 0:bada2c7bd577 | 193 | if (!pb_readbyte(stream, &byte)) |
Tomas | 0:bada2c7bd577 | 194 | return false; |
Tomas | 0:bada2c7bd577 | 195 | |
Tomas | 0:bada2c7bd577 | 196 | result |= (uint32_t)(byte & 0x7F) << bitpos; |
Tomas | 0:bada2c7bd577 | 197 | bitpos = (uint8_t)(bitpos + 7); |
Tomas | 0:bada2c7bd577 | 198 | } while (byte & 0x80); |
Tomas | 0:bada2c7bd577 | 199 | } |
Tomas | 0:bada2c7bd577 | 200 | |
Tomas | 0:bada2c7bd577 | 201 | *dest = result; |
Tomas | 0:bada2c7bd577 | 202 | return true; |
Tomas | 0:bada2c7bd577 | 203 | } |
Tomas | 0:bada2c7bd577 | 204 | |
Tomas | 0:bada2c7bd577 | 205 | bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) |
Tomas | 0:bada2c7bd577 | 206 | { |
Tomas | 0:bada2c7bd577 | 207 | uint8_t byte; |
Tomas | 0:bada2c7bd577 | 208 | uint8_t bitpos = 0; |
Tomas | 0:bada2c7bd577 | 209 | uint64_t result = 0; |
Tomas | 0:bada2c7bd577 | 210 | |
Tomas | 0:bada2c7bd577 | 211 | do |
Tomas | 0:bada2c7bd577 | 212 | { |
Tomas | 0:bada2c7bd577 | 213 | if (bitpos >= 64) |
Tomas | 0:bada2c7bd577 | 214 | PB_RETURN_ERROR(stream, "varint overflow"); |
Tomas | 0:bada2c7bd577 | 215 | |
Tomas | 0:bada2c7bd577 | 216 | if (!pb_readbyte(stream, &byte)) |
Tomas | 0:bada2c7bd577 | 217 | return false; |
Tomas | 0:bada2c7bd577 | 218 | |
Tomas | 0:bada2c7bd577 | 219 | result |= (uint64_t)(byte & 0x7F) << bitpos; |
Tomas | 0:bada2c7bd577 | 220 | bitpos = (uint8_t)(bitpos + 7); |
Tomas | 0:bada2c7bd577 | 221 | } while (byte & 0x80); |
Tomas | 0:bada2c7bd577 | 222 | |
Tomas | 0:bada2c7bd577 | 223 | *dest = result; |
Tomas | 0:bada2c7bd577 | 224 | return true; |
Tomas | 0:bada2c7bd577 | 225 | } |
Tomas | 0:bada2c7bd577 | 226 | |
Tomas | 0:bada2c7bd577 | 227 | bool checkreturn pb_skip_varint(pb_istream_t *stream) |
Tomas | 0:bada2c7bd577 | 228 | { |
Tomas | 0:bada2c7bd577 | 229 | uint8_t byte; |
Tomas | 0:bada2c7bd577 | 230 | do |
Tomas | 0:bada2c7bd577 | 231 | { |
Tomas | 0:bada2c7bd577 | 232 | if (!pb_read(stream, &byte, 1)) |
Tomas | 0:bada2c7bd577 | 233 | return false; |
Tomas | 0:bada2c7bd577 | 234 | } while (byte & 0x80); |
Tomas | 0:bada2c7bd577 | 235 | return true; |
Tomas | 0:bada2c7bd577 | 236 | } |
Tomas | 0:bada2c7bd577 | 237 | |
Tomas | 0:bada2c7bd577 | 238 | bool checkreturn pb_skip_string(pb_istream_t *stream) |
Tomas | 0:bada2c7bd577 | 239 | { |
Tomas | 0:bada2c7bd577 | 240 | uint32_t length; |
Tomas | 0:bada2c7bd577 | 241 | if (!pb_decode_varint32(stream, &length)) |
Tomas | 0:bada2c7bd577 | 242 | return false; |
Tomas | 0:bada2c7bd577 | 243 | |
Tomas | 0:bada2c7bd577 | 244 | return pb_read(stream, NULL, length); |
Tomas | 0:bada2c7bd577 | 245 | } |
Tomas | 0:bada2c7bd577 | 246 | |
Tomas | 0:bada2c7bd577 | 247 | bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof) |
Tomas | 0:bada2c7bd577 | 248 | { |
Tomas | 0:bada2c7bd577 | 249 | uint32_t temp; |
Tomas | 0:bada2c7bd577 | 250 | *eof = false; |
Tomas | 0:bada2c7bd577 | 251 | *wire_type = (pb_wire_type_t) 0; |
Tomas | 0:bada2c7bd577 | 252 | *tag = 0; |
Tomas | 0:bada2c7bd577 | 253 | |
Tomas | 0:bada2c7bd577 | 254 | if (!pb_decode_varint32(stream, &temp)) |
Tomas | 0:bada2c7bd577 | 255 | { |
Tomas | 0:bada2c7bd577 | 256 | if (stream->bytes_left == 0) |
Tomas | 0:bada2c7bd577 | 257 | *eof = true; |
Tomas | 0:bada2c7bd577 | 258 | |
Tomas | 0:bada2c7bd577 | 259 | return false; |
Tomas | 0:bada2c7bd577 | 260 | } |
Tomas | 0:bada2c7bd577 | 261 | |
Tomas | 0:bada2c7bd577 | 262 | if (temp == 0) |
Tomas | 0:bada2c7bd577 | 263 | { |
Tomas | 0:bada2c7bd577 | 264 | *eof = true; /* Special feature: allow 0-terminated messages. */ |
Tomas | 0:bada2c7bd577 | 265 | return false; |
Tomas | 0:bada2c7bd577 | 266 | } |
Tomas | 0:bada2c7bd577 | 267 | |
Tomas | 0:bada2c7bd577 | 268 | *tag = temp >> 3; |
Tomas | 0:bada2c7bd577 | 269 | *wire_type = (pb_wire_type_t)(temp & 7); |
Tomas | 0:bada2c7bd577 | 270 | return true; |
Tomas | 0:bada2c7bd577 | 271 | } |
Tomas | 0:bada2c7bd577 | 272 | |
Tomas | 0:bada2c7bd577 | 273 | bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) |
Tomas | 0:bada2c7bd577 | 274 | { |
Tomas | 0:bada2c7bd577 | 275 | switch (wire_type) |
Tomas | 0:bada2c7bd577 | 276 | { |
Tomas | 0:bada2c7bd577 | 277 | case PB_WT_VARINT: return pb_skip_varint(stream); |
Tomas | 0:bada2c7bd577 | 278 | case PB_WT_64BIT: return pb_read(stream, NULL, 8); |
Tomas | 0:bada2c7bd577 | 279 | case PB_WT_STRING: return pb_skip_string(stream); |
Tomas | 0:bada2c7bd577 | 280 | case PB_WT_32BIT: return pb_read(stream, NULL, 4); |
Tomas | 0:bada2c7bd577 | 281 | default: PB_RETURN_ERROR(stream, "invalid wire_type"); |
Tomas | 0:bada2c7bd577 | 282 | } |
Tomas | 0:bada2c7bd577 | 283 | } |
Tomas | 0:bada2c7bd577 | 284 | |
Tomas | 0:bada2c7bd577 | 285 | /* Read a raw value to buffer, for the purpose of passing it to callback as |
Tomas | 0:bada2c7bd577 | 286 | * a substream. Size is maximum size on call, and actual size on return. |
Tomas | 0:bada2c7bd577 | 287 | */ |
Tomas | 0:bada2c7bd577 | 288 | static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, uint8_t *buf, size_t *size) |
Tomas | 0:bada2c7bd577 | 289 | { |
Tomas | 0:bada2c7bd577 | 290 | size_t max_size = *size; |
Tomas | 0:bada2c7bd577 | 291 | switch (wire_type) |
Tomas | 0:bada2c7bd577 | 292 | { |
Tomas | 0:bada2c7bd577 | 293 | case PB_WT_VARINT: |
Tomas | 0:bada2c7bd577 | 294 | *size = 0; |
Tomas | 0:bada2c7bd577 | 295 | do |
Tomas | 0:bada2c7bd577 | 296 | { |
Tomas | 0:bada2c7bd577 | 297 | (*size)++; |
Tomas | 0:bada2c7bd577 | 298 | if (*size > max_size) return false; |
Tomas | 0:bada2c7bd577 | 299 | if (!pb_read(stream, buf, 1)) return false; |
Tomas | 0:bada2c7bd577 | 300 | } while (*buf++ & 0x80); |
Tomas | 0:bada2c7bd577 | 301 | return true; |
Tomas | 0:bada2c7bd577 | 302 | |
Tomas | 0:bada2c7bd577 | 303 | case PB_WT_64BIT: |
Tomas | 0:bada2c7bd577 | 304 | *size = 8; |
Tomas | 0:bada2c7bd577 | 305 | return pb_read(stream, buf, 8); |
Tomas | 0:bada2c7bd577 | 306 | |
Tomas | 0:bada2c7bd577 | 307 | case PB_WT_32BIT: |
Tomas | 0:bada2c7bd577 | 308 | *size = 4; |
Tomas | 0:bada2c7bd577 | 309 | return pb_read(stream, buf, 4); |
Tomas | 0:bada2c7bd577 | 310 | |
Tomas | 0:bada2c7bd577 | 311 | default: PB_RETURN_ERROR(stream, "invalid wire_type"); |
Tomas | 0:bada2c7bd577 | 312 | } |
Tomas | 0:bada2c7bd577 | 313 | } |
Tomas | 0:bada2c7bd577 | 314 | |
Tomas | 0:bada2c7bd577 | 315 | /* Decode string length from stream and return a substream with limited length. |
Tomas | 0:bada2c7bd577 | 316 | * Remember to close the substream using pb_close_string_substream(). |
Tomas | 0:bada2c7bd577 | 317 | */ |
Tomas | 0:bada2c7bd577 | 318 | bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream) |
Tomas | 0:bada2c7bd577 | 319 | { |
Tomas | 0:bada2c7bd577 | 320 | uint32_t size; |
Tomas | 0:bada2c7bd577 | 321 | if (!pb_decode_varint32(stream, &size)) |
Tomas | 0:bada2c7bd577 | 322 | return false; |
Tomas | 0:bada2c7bd577 | 323 | |
Tomas | 0:bada2c7bd577 | 324 | *substream = *stream; |
Tomas | 0:bada2c7bd577 | 325 | if (substream->bytes_left < size) |
Tomas | 0:bada2c7bd577 | 326 | PB_RETURN_ERROR(stream, "parent stream too short"); |
Tomas | 0:bada2c7bd577 | 327 | |
Tomas | 0:bada2c7bd577 | 328 | substream->bytes_left = size; |
Tomas | 0:bada2c7bd577 | 329 | stream->bytes_left -= size; |
Tomas | 0:bada2c7bd577 | 330 | return true; |
Tomas | 0:bada2c7bd577 | 331 | } |
Tomas | 0:bada2c7bd577 | 332 | |
Tomas | 0:bada2c7bd577 | 333 | void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) |
Tomas | 0:bada2c7bd577 | 334 | { |
Tomas | 0:bada2c7bd577 | 335 | stream->state = substream->state; |
Tomas | 0:bada2c7bd577 | 336 | |
Tomas | 0:bada2c7bd577 | 337 | #ifndef PB_NO_ERRMSG |
Tomas | 0:bada2c7bd577 | 338 | stream->errmsg = substream->errmsg; |
Tomas | 0:bada2c7bd577 | 339 | #endif |
Tomas | 0:bada2c7bd577 | 340 | } |
Tomas | 0:bada2c7bd577 | 341 | |
Tomas | 0:bada2c7bd577 | 342 | static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct) |
Tomas | 0:bada2c7bd577 | 343 | { |
Tomas | 0:bada2c7bd577 | 344 | iter->start = iter->pos = fields; |
Tomas | 0:bada2c7bd577 | 345 | iter->field_index = 0; |
Tomas | 0:bada2c7bd577 | 346 | iter->required_field_index = 0; |
Tomas | 0:bada2c7bd577 | 347 | iter->pData = (char*)dest_struct + iter->pos->data_offset; |
Tomas | 0:bada2c7bd577 | 348 | iter->pSize = (char*)iter->pData + iter->pos->size_offset; |
Tomas | 0:bada2c7bd577 | 349 | iter->dest_struct = dest_struct; |
Tomas | 0:bada2c7bd577 | 350 | } |
Tomas | 0:bada2c7bd577 | 351 | |
Tomas | 0:bada2c7bd577 | 352 | static bool pb_field_next(pb_field_iterator_t *iter) |
Tomas | 0:bada2c7bd577 | 353 | { |
Tomas | 0:bada2c7bd577 | 354 | bool notwrapped = true; |
Tomas | 0:bada2c7bd577 | 355 | size_t prev_size = iter->pos->data_size; |
Tomas | 0:bada2c7bd577 | 356 | |
Tomas | 0:bada2c7bd577 | 357 | if (PB_ATYPE(iter->pos->type) == PB_ATYPE_STATIC && |
Tomas | 0:bada2c7bd577 | 358 | PB_HTYPE(iter->pos->type) == PB_HTYPE_REPEATED) |
Tomas | 0:bada2c7bd577 | 359 | { |
Tomas | 0:bada2c7bd577 | 360 | prev_size *= iter->pos->array_size; |
Tomas | 0:bada2c7bd577 | 361 | } |
Tomas | 0:bada2c7bd577 | 362 | |
Tomas | 0:bada2c7bd577 | 363 | if (iter->pos->tag == 0) |
Tomas | 0:bada2c7bd577 | 364 | return false; /* Only happens with empty message types */ |
Tomas | 0:bada2c7bd577 | 365 | |
Tomas | 0:bada2c7bd577 | 366 | if (PB_HTYPE(iter->pos->type) == PB_HTYPE_REQUIRED) |
Tomas | 0:bada2c7bd577 | 367 | iter->required_field_index++; |
Tomas | 0:bada2c7bd577 | 368 | |
Tomas | 0:bada2c7bd577 | 369 | iter->pos++; |
Tomas | 0:bada2c7bd577 | 370 | iter->field_index++; |
Tomas | 0:bada2c7bd577 | 371 | if (iter->pos->tag == 0) |
Tomas | 0:bada2c7bd577 | 372 | { |
Tomas | 0:bada2c7bd577 | 373 | iter->pos = iter->start; |
Tomas | 0:bada2c7bd577 | 374 | iter->field_index = 0; |
Tomas | 0:bada2c7bd577 | 375 | iter->required_field_index = 0; |
Tomas | 0:bada2c7bd577 | 376 | iter->pData = iter->dest_struct; |
Tomas | 0:bada2c7bd577 | 377 | prev_size = 0; |
Tomas | 0:bada2c7bd577 | 378 | notwrapped = false; |
Tomas | 0:bada2c7bd577 | 379 | } |
Tomas | 0:bada2c7bd577 | 380 | |
Tomas | 0:bada2c7bd577 | 381 | iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset; |
Tomas | 0:bada2c7bd577 | 382 | iter->pSize = (char*)iter->pData + iter->pos->size_offset; |
Tomas | 0:bada2c7bd577 | 383 | return notwrapped; |
Tomas | 0:bada2c7bd577 | 384 | } |
Tomas | 0:bada2c7bd577 | 385 | |
Tomas | 0:bada2c7bd577 | 386 | static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag) |
Tomas | 0:bada2c7bd577 | 387 | { |
Tomas | 0:bada2c7bd577 | 388 | unsigned start = iter->field_index; |
Tomas | 0:bada2c7bd577 | 389 | |
Tomas | 0:bada2c7bd577 | 390 | do { |
Tomas | 0:bada2c7bd577 | 391 | if (iter->pos->tag == tag && |
Tomas | 0:bada2c7bd577 | 392 | PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) |
Tomas | 0:bada2c7bd577 | 393 | { |
Tomas | 0:bada2c7bd577 | 394 | return true; |
Tomas | 0:bada2c7bd577 | 395 | } |
Tomas | 0:bada2c7bd577 | 396 | pb_field_next(iter); |
Tomas | 0:bada2c7bd577 | 397 | } while (iter->field_index != start); |
Tomas | 0:bada2c7bd577 | 398 | |
Tomas | 0:bada2c7bd577 | 399 | return false; |
Tomas | 0:bada2c7bd577 | 400 | } |
Tomas | 0:bada2c7bd577 | 401 | |
Tomas | 0:bada2c7bd577 | 402 | /************************* |
Tomas | 0:bada2c7bd577 | 403 | * Decode a single field * |
Tomas | 0:bada2c7bd577 | 404 | *************************/ |
Tomas | 0:bada2c7bd577 | 405 | |
Tomas | 0:bada2c7bd577 | 406 | static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) |
Tomas | 0:bada2c7bd577 | 407 | { |
Tomas | 0:bada2c7bd577 | 408 | pb_type_t type; |
Tomas | 0:bada2c7bd577 | 409 | pb_decoder_t func; |
Tomas | 0:bada2c7bd577 | 410 | |
Tomas | 0:bada2c7bd577 | 411 | type = iter->pos->type; |
Tomas | 0:bada2c7bd577 | 412 | func = PB_DECODERS[PB_LTYPE(type)]; |
Tomas | 0:bada2c7bd577 | 413 | |
Tomas | 0:bada2c7bd577 | 414 | switch (PB_HTYPE(type)) |
Tomas | 0:bada2c7bd577 | 415 | { |
Tomas | 0:bada2c7bd577 | 416 | case PB_HTYPE_REQUIRED: |
Tomas | 0:bada2c7bd577 | 417 | return func(stream, iter->pos, iter->pData); |
Tomas | 0:bada2c7bd577 | 418 | |
Tomas | 0:bada2c7bd577 | 419 | case PB_HTYPE_OPTIONAL: |
Tomas | 0:bada2c7bd577 | 420 | *(bool*)iter->pSize = true; |
Tomas | 0:bada2c7bd577 | 421 | return func(stream, iter->pos, iter->pData); |
Tomas | 0:bada2c7bd577 | 422 | |
Tomas | 0:bada2c7bd577 | 423 | case PB_HTYPE_REPEATED: |
Tomas | 0:bada2c7bd577 | 424 | if (wire_type == PB_WT_STRING |
Tomas | 0:bada2c7bd577 | 425 | && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) |
Tomas | 0:bada2c7bd577 | 426 | { |
Tomas | 0:bada2c7bd577 | 427 | /* Packed array */ |
Tomas | 0:bada2c7bd577 | 428 | bool status = true; |
Tomas | 0:bada2c7bd577 | 429 | size_t *size = (size_t*)iter->pSize; |
Tomas | 0:bada2c7bd577 | 430 | pb_istream_t substream; |
Tomas | 0:bada2c7bd577 | 431 | if (!pb_make_string_substream(stream, &substream)) |
Tomas | 0:bada2c7bd577 | 432 | return false; |
Tomas | 0:bada2c7bd577 | 433 | |
Tomas | 0:bada2c7bd577 | 434 | while (substream.bytes_left && *size < iter->pos->array_size) |
Tomas | 0:bada2c7bd577 | 435 | { |
Tomas | 0:bada2c7bd577 | 436 | void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); |
Tomas | 0:bada2c7bd577 | 437 | if (!func(&substream, iter->pos, pItem)) |
Tomas | 0:bada2c7bd577 | 438 | { |
Tomas | 0:bada2c7bd577 | 439 | status = false; |
Tomas | 0:bada2c7bd577 | 440 | break; |
Tomas | 0:bada2c7bd577 | 441 | } |
Tomas | 0:bada2c7bd577 | 442 | (*size)++; |
Tomas | 0:bada2c7bd577 | 443 | } |
Tomas | 0:bada2c7bd577 | 444 | pb_close_string_substream(stream, &substream); |
Tomas | 0:bada2c7bd577 | 445 | |
Tomas | 0:bada2c7bd577 | 446 | if (substream.bytes_left != 0) |
Tomas | 0:bada2c7bd577 | 447 | PB_RETURN_ERROR(stream, "array overflow"); |
Tomas | 0:bada2c7bd577 | 448 | |
Tomas | 0:bada2c7bd577 | 449 | return status; |
Tomas | 0:bada2c7bd577 | 450 | } |
Tomas | 0:bada2c7bd577 | 451 | else |
Tomas | 0:bada2c7bd577 | 452 | { |
Tomas | 0:bada2c7bd577 | 453 | /* Repeated field */ |
Tomas | 0:bada2c7bd577 | 454 | size_t *size = (size_t*)iter->pSize; |
Tomas | 0:bada2c7bd577 | 455 | void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); |
Tomas | 0:bada2c7bd577 | 456 | if (*size >= iter->pos->array_size) |
Tomas | 0:bada2c7bd577 | 457 | PB_RETURN_ERROR(stream, "array overflow"); |
Tomas | 0:bada2c7bd577 | 458 | |
Tomas | 0:bada2c7bd577 | 459 | (*size)++; |
Tomas | 0:bada2c7bd577 | 460 | return func(stream, iter->pos, pItem); |
Tomas | 0:bada2c7bd577 | 461 | } |
Tomas | 0:bada2c7bd577 | 462 | |
Tomas | 0:bada2c7bd577 | 463 | default: |
Tomas | 0:bada2c7bd577 | 464 | PB_RETURN_ERROR(stream, "invalid field type"); |
Tomas | 0:bada2c7bd577 | 465 | } |
Tomas | 0:bada2c7bd577 | 466 | } |
Tomas | 0:bada2c7bd577 | 467 | |
Tomas | 0:bada2c7bd577 | 468 | static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) |
Tomas | 0:bada2c7bd577 | 469 | { |
Tomas | 0:bada2c7bd577 | 470 | pb_callback_t *pCallback = (pb_callback_t*)iter->pData; |
Tomas | 0:bada2c7bd577 | 471 | |
Tomas | 0:bada2c7bd577 | 472 | #ifdef PB_OLD_CALLBACK_STYLE |
Tomas | 0:bada2c7bd577 | 473 | void *arg = pCallback->arg; |
Tomas | 0:bada2c7bd577 | 474 | #else |
Tomas | 0:bada2c7bd577 | 475 | void **arg = &(pCallback->arg); |
Tomas | 0:bada2c7bd577 | 476 | #endif |
Tomas | 0:bada2c7bd577 | 477 | |
Tomas | 0:bada2c7bd577 | 478 | if (pCallback->funcs.decode == NULL) |
Tomas | 0:bada2c7bd577 | 479 | return pb_skip_field(stream, wire_type); |
Tomas | 0:bada2c7bd577 | 480 | |
Tomas | 0:bada2c7bd577 | 481 | if (wire_type == PB_WT_STRING) |
Tomas | 0:bada2c7bd577 | 482 | { |
Tomas | 0:bada2c7bd577 | 483 | pb_istream_t substream; |
Tomas | 0:bada2c7bd577 | 484 | |
Tomas | 0:bada2c7bd577 | 485 | if (!pb_make_string_substream(stream, &substream)) |
Tomas | 0:bada2c7bd577 | 486 | return false; |
Tomas | 0:bada2c7bd577 | 487 | |
Tomas | 0:bada2c7bd577 | 488 | do |
Tomas | 0:bada2c7bd577 | 489 | { |
Tomas | 0:bada2c7bd577 | 490 | if (!pCallback->funcs.decode(&substream, iter->pos, arg)) |
Tomas | 0:bada2c7bd577 | 491 | PB_RETURN_ERROR(stream, "callback failed"); |
Tomas | 0:bada2c7bd577 | 492 | } while (substream.bytes_left); |
Tomas | 0:bada2c7bd577 | 493 | |
Tomas | 0:bada2c7bd577 | 494 | pb_close_string_substream(stream, &substream); |
Tomas | 0:bada2c7bd577 | 495 | return true; |
Tomas | 0:bada2c7bd577 | 496 | } |
Tomas | 0:bada2c7bd577 | 497 | else |
Tomas | 0:bada2c7bd577 | 498 | { |
Tomas | 0:bada2c7bd577 | 499 | /* Copy the single scalar value to stack. |
Tomas | 0:bada2c7bd577 | 500 | * This is required so that we can limit the stream length, |
Tomas | 0:bada2c7bd577 | 501 | * which in turn allows to use same callback for packed and |
Tomas | 0:bada2c7bd577 | 502 | * not-packed fields. */ |
Tomas | 0:bada2c7bd577 | 503 | pb_istream_t substream; |
Tomas | 0:bada2c7bd577 | 504 | uint8_t buffer[10]; |
Tomas | 0:bada2c7bd577 | 505 | size_t size = sizeof(buffer); |
Tomas | 0:bada2c7bd577 | 506 | |
Tomas | 0:bada2c7bd577 | 507 | if (!read_raw_value(stream, wire_type, buffer, &size)) |
Tomas | 0:bada2c7bd577 | 508 | return false; |
Tomas | 0:bada2c7bd577 | 509 | substream = pb_istream_from_buffer(buffer, size); |
Tomas | 0:bada2c7bd577 | 510 | |
Tomas | 0:bada2c7bd577 | 511 | return pCallback->funcs.decode(&substream, iter->pos, arg); |
Tomas | 0:bada2c7bd577 | 512 | } |
Tomas | 0:bada2c7bd577 | 513 | } |
Tomas | 0:bada2c7bd577 | 514 | |
Tomas | 0:bada2c7bd577 | 515 | static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) |
Tomas | 0:bada2c7bd577 | 516 | { |
Tomas | 0:bada2c7bd577 | 517 | switch (PB_ATYPE(iter->pos->type)) |
Tomas | 0:bada2c7bd577 | 518 | { |
Tomas | 0:bada2c7bd577 | 519 | case PB_ATYPE_STATIC: |
Tomas | 0:bada2c7bd577 | 520 | return decode_static_field(stream, wire_type, iter); |
Tomas | 0:bada2c7bd577 | 521 | |
Tomas | 0:bada2c7bd577 | 522 | case PB_ATYPE_CALLBACK: |
Tomas | 0:bada2c7bd577 | 523 | return decode_callback_field(stream, wire_type, iter); |
Tomas | 0:bada2c7bd577 | 524 | |
Tomas | 0:bada2c7bd577 | 525 | default: |
Tomas | 0:bada2c7bd577 | 526 | PB_RETURN_ERROR(stream, "invalid field type"); |
Tomas | 0:bada2c7bd577 | 527 | } |
Tomas | 0:bada2c7bd577 | 528 | } |
Tomas | 0:bada2c7bd577 | 529 | |
Tomas | 0:bada2c7bd577 | 530 | /* Default handler for extension fields. Expects a pb_field_t structure |
Tomas | 0:bada2c7bd577 | 531 | * in extension->type->arg. */ |
Tomas | 0:bada2c7bd577 | 532 | static bool checkreturn default_extension_decoder(pb_istream_t *stream, |
Tomas | 0:bada2c7bd577 | 533 | pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) |
Tomas | 0:bada2c7bd577 | 534 | { |
Tomas | 0:bada2c7bd577 | 535 | const pb_field_t *field = (const pb_field_t*)extension->type->arg; |
Tomas | 0:bada2c7bd577 | 536 | pb_field_iterator_t iter; |
Tomas | 0:bada2c7bd577 | 537 | bool dummy; |
Tomas | 0:bada2c7bd577 | 538 | |
Tomas | 0:bada2c7bd577 | 539 | if (field->tag != tag) |
Tomas | 0:bada2c7bd577 | 540 | return true; |
Tomas | 0:bada2c7bd577 | 541 | |
Tomas | 0:bada2c7bd577 | 542 | iter.start = field; |
Tomas | 0:bada2c7bd577 | 543 | iter.pos = field; |
Tomas | 0:bada2c7bd577 | 544 | iter.field_index = 0; |
Tomas | 0:bada2c7bd577 | 545 | iter.required_field_index = 0; |
Tomas | 0:bada2c7bd577 | 546 | iter.dest_struct = extension->dest; |
Tomas | 0:bada2c7bd577 | 547 | iter.pData = extension->dest; |
Tomas | 0:bada2c7bd577 | 548 | iter.pSize = &dummy; |
Tomas | 0:bada2c7bd577 | 549 | |
Tomas | 0:bada2c7bd577 | 550 | return decode_field(stream, wire_type, &iter); |
Tomas | 0:bada2c7bd577 | 551 | } |
Tomas | 0:bada2c7bd577 | 552 | |
Tomas | 0:bada2c7bd577 | 553 | /* Try to decode an unknown field as an extension field. Tries each extension |
Tomas | 0:bada2c7bd577 | 554 | * decoder in turn, until one of them handles the field or loop ends. */ |
Tomas | 0:bada2c7bd577 | 555 | static bool checkreturn decode_extension(pb_istream_t *stream, |
Tomas | 0:bada2c7bd577 | 556 | uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter) |
Tomas | 0:bada2c7bd577 | 557 | { |
Tomas | 0:bada2c7bd577 | 558 | pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; |
Tomas | 0:bada2c7bd577 | 559 | size_t pos = stream->bytes_left; |
Tomas | 0:bada2c7bd577 | 560 | |
Tomas | 0:bada2c7bd577 | 561 | while (extension && pos == stream->bytes_left) |
Tomas | 0:bada2c7bd577 | 562 | { |
Tomas | 0:bada2c7bd577 | 563 | bool status; |
Tomas | 0:bada2c7bd577 | 564 | if (extension->type->decode) |
Tomas | 0:bada2c7bd577 | 565 | status = extension->type->decode(stream, extension, tag, wire_type); |
Tomas | 0:bada2c7bd577 | 566 | else |
Tomas | 0:bada2c7bd577 | 567 | status = default_extension_decoder(stream, extension, tag, wire_type); |
Tomas | 0:bada2c7bd577 | 568 | |
Tomas | 0:bada2c7bd577 | 569 | if (!status) |
Tomas | 0:bada2c7bd577 | 570 | return false; |
Tomas | 0:bada2c7bd577 | 571 | |
Tomas | 0:bada2c7bd577 | 572 | extension = extension->next; |
Tomas | 0:bada2c7bd577 | 573 | } |
Tomas | 0:bada2c7bd577 | 574 | |
Tomas | 0:bada2c7bd577 | 575 | return true; |
Tomas | 0:bada2c7bd577 | 576 | } |
Tomas | 0:bada2c7bd577 | 577 | |
Tomas | 0:bada2c7bd577 | 578 | /* Step through the iterator until an extension field is found or until all |
Tomas | 0:bada2c7bd577 | 579 | * entries have been checked. There can be only one extension field per |
Tomas | 0:bada2c7bd577 | 580 | * message. Returns false if no extension field is found. */ |
Tomas | 0:bada2c7bd577 | 581 | static bool checkreturn find_extension_field(pb_field_iterator_t *iter) |
Tomas | 0:bada2c7bd577 | 582 | { |
Tomas | 0:bada2c7bd577 | 583 | unsigned start = iter->field_index; |
Tomas | 0:bada2c7bd577 | 584 | |
Tomas | 0:bada2c7bd577 | 585 | do { |
Tomas | 0:bada2c7bd577 | 586 | if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) |
Tomas | 0:bada2c7bd577 | 587 | return true; |
Tomas | 0:bada2c7bd577 | 588 | pb_field_next(iter); |
Tomas | 0:bada2c7bd577 | 589 | } while (iter->field_index != start); |
Tomas | 0:bada2c7bd577 | 590 | |
Tomas | 0:bada2c7bd577 | 591 | return false; |
Tomas | 0:bada2c7bd577 | 592 | } |
Tomas | 0:bada2c7bd577 | 593 | |
Tomas | 0:bada2c7bd577 | 594 | /* Initialize message fields to default values, recursively */ |
Tomas | 0:bada2c7bd577 | 595 | static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) |
Tomas | 0:bada2c7bd577 | 596 | { |
Tomas | 0:bada2c7bd577 | 597 | pb_field_iterator_t iter; |
Tomas | 0:bada2c7bd577 | 598 | pb_field_init(&iter, fields, dest_struct); |
Tomas | 0:bada2c7bd577 | 599 | |
Tomas | 0:bada2c7bd577 | 600 | /* Initialize size/has fields and apply default values */ |
Tomas | 0:bada2c7bd577 | 601 | do |
Tomas | 0:bada2c7bd577 | 602 | { |
Tomas | 0:bada2c7bd577 | 603 | pb_type_t type; |
Tomas | 0:bada2c7bd577 | 604 | type = iter.pos->type; |
Tomas | 0:bada2c7bd577 | 605 | |
Tomas | 0:bada2c7bd577 | 606 | if (iter.pos->tag == 0) |
Tomas | 0:bada2c7bd577 | 607 | continue; |
Tomas | 0:bada2c7bd577 | 608 | |
Tomas | 0:bada2c7bd577 | 609 | if (PB_ATYPE(type) == PB_ATYPE_STATIC) |
Tomas | 0:bada2c7bd577 | 610 | { |
Tomas | 0:bada2c7bd577 | 611 | /* Initialize the size field for optional/repeated fields to 0. */ |
Tomas | 0:bada2c7bd577 | 612 | if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL) |
Tomas | 0:bada2c7bd577 | 613 | { |
Tomas | 0:bada2c7bd577 | 614 | *(bool*)iter.pSize = false; |
Tomas | 0:bada2c7bd577 | 615 | } |
Tomas | 0:bada2c7bd577 | 616 | else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) |
Tomas | 0:bada2c7bd577 | 617 | { |
Tomas | 0:bada2c7bd577 | 618 | *(size_t*)iter.pSize = 0; |
Tomas | 0:bada2c7bd577 | 619 | continue; /* Array is empty, no need to initialize contents */ |
Tomas | 0:bada2c7bd577 | 620 | } |
Tomas | 0:bada2c7bd577 | 621 | |
Tomas | 0:bada2c7bd577 | 622 | /* Initialize field contents to default value */ |
Tomas | 0:bada2c7bd577 | 623 | if (PB_LTYPE(iter.pos->type) == PB_LTYPE_SUBMESSAGE) |
Tomas | 0:bada2c7bd577 | 624 | { |
Tomas | 0:bada2c7bd577 | 625 | pb_message_set_to_defaults((const pb_field_t *) iter.pos->ptr, iter.pData); |
Tomas | 0:bada2c7bd577 | 626 | } |
Tomas | 0:bada2c7bd577 | 627 | else if (iter.pos->ptr != NULL) |
Tomas | 0:bada2c7bd577 | 628 | { |
Tomas | 0:bada2c7bd577 | 629 | memcpy(iter.pData, iter.pos->ptr, iter.pos->data_size); |
Tomas | 0:bada2c7bd577 | 630 | } |
Tomas | 0:bada2c7bd577 | 631 | else |
Tomas | 0:bada2c7bd577 | 632 | { |
Tomas | 0:bada2c7bd577 | 633 | memset(iter.pData, 0, iter.pos->data_size); |
Tomas | 0:bada2c7bd577 | 634 | } |
Tomas | 0:bada2c7bd577 | 635 | } |
Tomas | 0:bada2c7bd577 | 636 | else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) |
Tomas | 0:bada2c7bd577 | 637 | { |
Tomas | 0:bada2c7bd577 | 638 | continue; /* Don't overwrite callback */ |
Tomas | 0:bada2c7bd577 | 639 | } |
Tomas | 0:bada2c7bd577 | 640 | } while (pb_field_next(&iter)); |
Tomas | 0:bada2c7bd577 | 641 | } |
Tomas | 0:bada2c7bd577 | 642 | |
Tomas | 0:bada2c7bd577 | 643 | /********************* |
Tomas | 0:bada2c7bd577 | 644 | * Decode all fields * |
Tomas | 0:bada2c7bd577 | 645 | *********************/ |
Tomas | 0:bada2c7bd577 | 646 | |
Tomas | 0:bada2c7bd577 | 647 | bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) |
Tomas | 0:bada2c7bd577 | 648 | { |
Tomas | 0:bada2c7bd577 | 649 | uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0}; /* Used to check for required fields */ |
Tomas | 0:bada2c7bd577 | 650 | uint32_t extension_range_start = 0; |
Tomas | 0:bada2c7bd577 | 651 | pb_field_iterator_t iter; |
Tomas | 0:bada2c7bd577 | 652 | |
Tomas | 0:bada2c7bd577 | 653 | pb_field_init(&iter, fields, dest_struct); |
Tomas | 0:bada2c7bd577 | 654 | |
Tomas | 0:bada2c7bd577 | 655 | while (stream->bytes_left) |
Tomas | 0:bada2c7bd577 | 656 | { |
Tomas | 0:bada2c7bd577 | 657 | uint32_t tag; |
Tomas | 0:bada2c7bd577 | 658 | pb_wire_type_t wire_type; |
Tomas | 0:bada2c7bd577 | 659 | bool eof; |
Tomas | 0:bada2c7bd577 | 660 | |
Tomas | 0:bada2c7bd577 | 661 | if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) |
Tomas | 0:bada2c7bd577 | 662 | { |
Tomas | 0:bada2c7bd577 | 663 | if (eof) |
Tomas | 0:bada2c7bd577 | 664 | break; |
Tomas | 0:bada2c7bd577 | 665 | else |
Tomas | 0:bada2c7bd577 | 666 | return false; |
Tomas | 0:bada2c7bd577 | 667 | } |
Tomas | 0:bada2c7bd577 | 668 | |
Tomas | 0:bada2c7bd577 | 669 | if (!pb_field_find(&iter, tag)) |
Tomas | 0:bada2c7bd577 | 670 | { |
Tomas | 0:bada2c7bd577 | 671 | /* No match found, check if it matches an extension. */ |
Tomas | 0:bada2c7bd577 | 672 | if (tag >= extension_range_start) |
Tomas | 0:bada2c7bd577 | 673 | { |
Tomas | 0:bada2c7bd577 | 674 | if (!find_extension_field(&iter)) |
Tomas | 0:bada2c7bd577 | 675 | extension_range_start = (uint32_t)-1; |
Tomas | 0:bada2c7bd577 | 676 | else |
Tomas | 0:bada2c7bd577 | 677 | extension_range_start = iter.pos->tag; |
Tomas | 0:bada2c7bd577 | 678 | |
Tomas | 0:bada2c7bd577 | 679 | if (tag >= extension_range_start) |
Tomas | 0:bada2c7bd577 | 680 | { |
Tomas | 0:bada2c7bd577 | 681 | size_t pos = stream->bytes_left; |
Tomas | 0:bada2c7bd577 | 682 | |
Tomas | 0:bada2c7bd577 | 683 | if (!decode_extension(stream, tag, wire_type, &iter)) |
Tomas | 0:bada2c7bd577 | 684 | return false; |
Tomas | 0:bada2c7bd577 | 685 | |
Tomas | 0:bada2c7bd577 | 686 | if (pos != stream->bytes_left) |
Tomas | 0:bada2c7bd577 | 687 | { |
Tomas | 0:bada2c7bd577 | 688 | /* The field was handled */ |
Tomas | 0:bada2c7bd577 | 689 | continue; |
Tomas | 0:bada2c7bd577 | 690 | } |
Tomas | 0:bada2c7bd577 | 691 | } |
Tomas | 0:bada2c7bd577 | 692 | } |
Tomas | 0:bada2c7bd577 | 693 | |
Tomas | 0:bada2c7bd577 | 694 | /* No match found, skip data */ |
Tomas | 0:bada2c7bd577 | 695 | if (!pb_skip_field(stream, wire_type)) |
Tomas | 0:bada2c7bd577 | 696 | return false; |
Tomas | 0:bada2c7bd577 | 697 | continue; |
Tomas | 0:bada2c7bd577 | 698 | } |
Tomas | 0:bada2c7bd577 | 699 | |
Tomas | 0:bada2c7bd577 | 700 | if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED |
Tomas | 0:bada2c7bd577 | 701 | && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) |
Tomas | 0:bada2c7bd577 | 702 | { |
Tomas | 0:bada2c7bd577 | 703 | fields_seen[iter.required_field_index >> 3] |= (uint8_t)(1 << (iter.required_field_index & 7)); |
Tomas | 0:bada2c7bd577 | 704 | } |
Tomas | 0:bada2c7bd577 | 705 | |
Tomas | 0:bada2c7bd577 | 706 | if (!decode_field(stream, wire_type, &iter)) |
Tomas | 0:bada2c7bd577 | 707 | return false; |
Tomas | 0:bada2c7bd577 | 708 | } |
Tomas | 0:bada2c7bd577 | 709 | |
Tomas | 0:bada2c7bd577 | 710 | /* Check that all required fields were present. */ |
Tomas | 0:bada2c7bd577 | 711 | { |
Tomas | 0:bada2c7bd577 | 712 | /* First figure out the number of required fields by |
Tomas | 0:bada2c7bd577 | 713 | * seeking to the end of the field array. Usually we |
Tomas | 0:bada2c7bd577 | 714 | * are already close to end after decoding. |
Tomas | 0:bada2c7bd577 | 715 | */ |
Tomas | 0:bada2c7bd577 | 716 | unsigned req_field_count; |
Tomas | 0:bada2c7bd577 | 717 | pb_type_t last_type; |
Tomas | 0:bada2c7bd577 | 718 | unsigned i; |
Tomas | 0:bada2c7bd577 | 719 | do { |
Tomas | 0:bada2c7bd577 | 720 | req_field_count = iter.required_field_index; |
Tomas | 0:bada2c7bd577 | 721 | last_type = iter.pos->type; |
Tomas | 0:bada2c7bd577 | 722 | } while (pb_field_next(&iter)); |
Tomas | 0:bada2c7bd577 | 723 | |
Tomas | 0:bada2c7bd577 | 724 | /* Fixup if last field was also required. */ |
Tomas | 0:bada2c7bd577 | 725 | if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag) |
Tomas | 0:bada2c7bd577 | 726 | req_field_count++; |
Tomas | 0:bada2c7bd577 | 727 | |
Tomas | 0:bada2c7bd577 | 728 | /* Check the whole bytes */ |
Tomas | 0:bada2c7bd577 | 729 | for (i = 0; i < (req_field_count >> 3); i++) |
Tomas | 0:bada2c7bd577 | 730 | { |
Tomas | 0:bada2c7bd577 | 731 | if (fields_seen[i] != 0xFF) |
Tomas | 0:bada2c7bd577 | 732 | PB_RETURN_ERROR(stream, "missing required field"); |
Tomas | 0:bada2c7bd577 | 733 | } |
Tomas | 0:bada2c7bd577 | 734 | |
Tomas | 0:bada2c7bd577 | 735 | /* Check the remaining bits */ |
Tomas | 0:bada2c7bd577 | 736 | if (fields_seen[req_field_count >> 3] != (0xFF >> (8 - (req_field_count & 7)))) |
Tomas | 0:bada2c7bd577 | 737 | PB_RETURN_ERROR(stream, "missing required field"); |
Tomas | 0:bada2c7bd577 | 738 | } |
Tomas | 0:bada2c7bd577 | 739 | |
Tomas | 0:bada2c7bd577 | 740 | return true; |
Tomas | 0:bada2c7bd577 | 741 | } |
Tomas | 0:bada2c7bd577 | 742 | |
Tomas | 0:bada2c7bd577 | 743 | bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) |
Tomas | 0:bada2c7bd577 | 744 | { |
Tomas | 0:bada2c7bd577 | 745 | pb_message_set_to_defaults(fields, dest_struct); |
Tomas | 0:bada2c7bd577 | 746 | return pb_decode_noinit(stream, fields, dest_struct); |
Tomas | 0:bada2c7bd577 | 747 | } |
Tomas | 0:bada2c7bd577 | 748 | |
Tomas | 0:bada2c7bd577 | 749 | bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) |
Tomas | 0:bada2c7bd577 | 750 | { |
Tomas | 0:bada2c7bd577 | 751 | pb_istream_t substream; |
Tomas | 0:bada2c7bd577 | 752 | bool status; |
Tomas | 0:bada2c7bd577 | 753 | |
Tomas | 0:bada2c7bd577 | 754 | if (!pb_make_string_substream(stream, &substream)) |
Tomas | 0:bada2c7bd577 | 755 | return false; |
Tomas | 0:bada2c7bd577 | 756 | |
Tomas | 0:bada2c7bd577 | 757 | status = pb_decode(&substream, fields, dest_struct); |
Tomas | 0:bada2c7bd577 | 758 | pb_close_string_substream(stream, &substream); |
Tomas | 0:bada2c7bd577 | 759 | return status; |
Tomas | 0:bada2c7bd577 | 760 | } |
Tomas | 0:bada2c7bd577 | 761 | |
Tomas | 0:bada2c7bd577 | 762 | /* Field decoders */ |
Tomas | 0:bada2c7bd577 | 763 | |
Tomas | 0:bada2c7bd577 | 764 | bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest) |
Tomas | 0:bada2c7bd577 | 765 | { |
Tomas | 0:bada2c7bd577 | 766 | uint64_t value; |
Tomas | 0:bada2c7bd577 | 767 | if (!pb_decode_varint(stream, &value)) |
Tomas | 0:bada2c7bd577 | 768 | return false; |
Tomas | 0:bada2c7bd577 | 769 | |
Tomas | 0:bada2c7bd577 | 770 | if (value & 1) |
Tomas | 0:bada2c7bd577 | 771 | *dest = (int64_t)(~(value >> 1)); |
Tomas | 0:bada2c7bd577 | 772 | else |
Tomas | 0:bada2c7bd577 | 773 | *dest = (int64_t)(value >> 1); |
Tomas | 0:bada2c7bd577 | 774 | |
Tomas | 0:bada2c7bd577 | 775 | return true; |
Tomas | 0:bada2c7bd577 | 776 | } |
Tomas | 0:bada2c7bd577 | 777 | |
Tomas | 0:bada2c7bd577 | 778 | bool pb_decode_fixed32(pb_istream_t *stream, void *dest) |
Tomas | 0:bada2c7bd577 | 779 | { |
Tomas | 0:bada2c7bd577 | 780 | #ifdef __BIG_ENDIAN__ |
Tomas | 0:bada2c7bd577 | 781 | uint8_t *bytes = (uint8_t*)dest; |
Tomas | 0:bada2c7bd577 | 782 | uint8_t lebytes[4]; |
Tomas | 0:bada2c7bd577 | 783 | |
Tomas | 0:bada2c7bd577 | 784 | if (!pb_read(stream, lebytes, 4)) |
Tomas | 0:bada2c7bd577 | 785 | return false; |
Tomas | 0:bada2c7bd577 | 786 | |
Tomas | 0:bada2c7bd577 | 787 | bytes[0] = lebytes[3]; |
Tomas | 0:bada2c7bd577 | 788 | bytes[1] = lebytes[2]; |
Tomas | 0:bada2c7bd577 | 789 | bytes[2] = lebytes[1]; |
Tomas | 0:bada2c7bd577 | 790 | bytes[3] = lebytes[0]; |
Tomas | 0:bada2c7bd577 | 791 | return true; |
Tomas | 0:bada2c7bd577 | 792 | #else |
Tomas | 0:bada2c7bd577 | 793 | return pb_read(stream, (uint8_t*)dest, 4); |
Tomas | 0:bada2c7bd577 | 794 | #endif |
Tomas | 0:bada2c7bd577 | 795 | } |
Tomas | 0:bada2c7bd577 | 796 | |
Tomas | 0:bada2c7bd577 | 797 | bool pb_decode_fixed64(pb_istream_t *stream, void *dest) |
Tomas | 0:bada2c7bd577 | 798 | { |
Tomas | 0:bada2c7bd577 | 799 | #ifdef __BIG_ENDIAN__ |
Tomas | 0:bada2c7bd577 | 800 | uint8_t *bytes = (uint8_t*)dest; |
Tomas | 0:bada2c7bd577 | 801 | uint8_t lebytes[8]; |
Tomas | 0:bada2c7bd577 | 802 | |
Tomas | 0:bada2c7bd577 | 803 | if (!pb_read(stream, lebytes, 8)) |
Tomas | 0:bada2c7bd577 | 804 | return false; |
Tomas | 0:bada2c7bd577 | 805 | |
Tomas | 0:bada2c7bd577 | 806 | bytes[0] = lebytes[7]; |
Tomas | 0:bada2c7bd577 | 807 | bytes[1] = lebytes[6]; |
Tomas | 0:bada2c7bd577 | 808 | bytes[2] = lebytes[5]; |
Tomas | 0:bada2c7bd577 | 809 | bytes[3] = lebytes[4]; |
Tomas | 0:bada2c7bd577 | 810 | bytes[4] = lebytes[3]; |
Tomas | 0:bada2c7bd577 | 811 | bytes[5] = lebytes[2]; |
Tomas | 0:bada2c7bd577 | 812 | bytes[6] = lebytes[1]; |
Tomas | 0:bada2c7bd577 | 813 | bytes[7] = lebytes[0]; |
Tomas | 0:bada2c7bd577 | 814 | return true; |
Tomas | 0:bada2c7bd577 | 815 | #else |
Tomas | 0:bada2c7bd577 | 816 | return pb_read(stream, (uint8_t*)dest, 8); |
Tomas | 0:bada2c7bd577 | 817 | #endif |
Tomas | 0:bada2c7bd577 | 818 | } |
Tomas | 0:bada2c7bd577 | 819 | |
Tomas | 0:bada2c7bd577 | 820 | bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) |
Tomas | 0:bada2c7bd577 | 821 | { |
Tomas | 0:bada2c7bd577 | 822 | uint64_t value; |
Tomas | 0:bada2c7bd577 | 823 | if (!pb_decode_varint(stream, &value)) |
Tomas | 0:bada2c7bd577 | 824 | return false; |
Tomas | 0:bada2c7bd577 | 825 | |
Tomas | 0:bada2c7bd577 | 826 | switch (field->data_size) |
Tomas | 0:bada2c7bd577 | 827 | { |
Tomas | 0:bada2c7bd577 | 828 | case 1: *(int8_t*)dest = (int8_t)value; break; |
Tomas | 0:bada2c7bd577 | 829 | case 2: *(int16_t*)dest = (int16_t)value; break; |
Tomas | 0:bada2c7bd577 | 830 | case 4: *(int32_t*)dest = (int32_t)value; break; |
Tomas | 0:bada2c7bd577 | 831 | case 8: *(int64_t*)dest = (int64_t)value; break; |
Tomas | 0:bada2c7bd577 | 832 | default: PB_RETURN_ERROR(stream, "invalid data_size"); |
Tomas | 0:bada2c7bd577 | 833 | } |
Tomas | 0:bada2c7bd577 | 834 | |
Tomas | 0:bada2c7bd577 | 835 | return true; |
Tomas | 0:bada2c7bd577 | 836 | } |
Tomas | 0:bada2c7bd577 | 837 | |
Tomas | 0:bada2c7bd577 | 838 | bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) |
Tomas | 0:bada2c7bd577 | 839 | { |
Tomas | 0:bada2c7bd577 | 840 | uint64_t value; |
Tomas | 0:bada2c7bd577 | 841 | if (!pb_decode_varint(stream, &value)) |
Tomas | 0:bada2c7bd577 | 842 | return false; |
Tomas | 0:bada2c7bd577 | 843 | |
Tomas | 0:bada2c7bd577 | 844 | switch (field->data_size) |
Tomas | 0:bada2c7bd577 | 845 | { |
Tomas | 0:bada2c7bd577 | 846 | case 4: *(uint32_t*)dest = (uint32_t)value; break; |
Tomas | 0:bada2c7bd577 | 847 | case 8: *(uint64_t*)dest = value; break; |
Tomas | 0:bada2c7bd577 | 848 | default: PB_RETURN_ERROR(stream, "invalid data_size"); |
Tomas | 0:bada2c7bd577 | 849 | } |
Tomas | 0:bada2c7bd577 | 850 | |
Tomas | 0:bada2c7bd577 | 851 | return true; |
Tomas | 0:bada2c7bd577 | 852 | } |
Tomas | 0:bada2c7bd577 | 853 | |
Tomas | 0:bada2c7bd577 | 854 | bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) |
Tomas | 0:bada2c7bd577 | 855 | { |
Tomas | 0:bada2c7bd577 | 856 | int64_t value; |
Tomas | 0:bada2c7bd577 | 857 | if (!pb_decode_svarint(stream, &value)) |
Tomas | 0:bada2c7bd577 | 858 | return false; |
Tomas | 0:bada2c7bd577 | 859 | |
Tomas | 0:bada2c7bd577 | 860 | switch (field->data_size) |
Tomas | 0:bada2c7bd577 | 861 | { |
Tomas | 0:bada2c7bd577 | 862 | case 4: *(int32_t*)dest = (int32_t)value; break; |
Tomas | 0:bada2c7bd577 | 863 | case 8: *(int64_t*)dest = value; break; |
Tomas | 0:bada2c7bd577 | 864 | default: PB_RETURN_ERROR(stream, "invalid data_size"); |
Tomas | 0:bada2c7bd577 | 865 | } |
Tomas | 0:bada2c7bd577 | 866 | |
Tomas | 0:bada2c7bd577 | 867 | return true; |
Tomas | 0:bada2c7bd577 | 868 | } |
Tomas | 0:bada2c7bd577 | 869 | |
Tomas | 0:bada2c7bd577 | 870 | bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) |
Tomas | 0:bada2c7bd577 | 871 | { |
Tomas | 0:bada2c7bd577 | 872 | UNUSED(field); |
Tomas | 0:bada2c7bd577 | 873 | return pb_decode_fixed32(stream, dest); |
Tomas | 0:bada2c7bd577 | 874 | } |
Tomas | 0:bada2c7bd577 | 875 | |
Tomas | 0:bada2c7bd577 | 876 | bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) |
Tomas | 0:bada2c7bd577 | 877 | { |
Tomas | 0:bada2c7bd577 | 878 | UNUSED(field); |
Tomas | 0:bada2c7bd577 | 879 | return pb_decode_fixed64(stream, dest); |
Tomas | 0:bada2c7bd577 | 880 | } |
Tomas | 0:bada2c7bd577 | 881 | |
Tomas | 0:bada2c7bd577 | 882 | bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) |
Tomas | 0:bada2c7bd577 | 883 | { |
Tomas | 0:bada2c7bd577 | 884 | pb_bytes_array_t *x = (pb_bytes_array_t*)dest; |
Tomas | 0:bada2c7bd577 | 885 | |
Tomas | 0:bada2c7bd577 | 886 | uint32_t temp; |
Tomas | 0:bada2c7bd577 | 887 | if (!pb_decode_varint32(stream, &temp)) |
Tomas | 0:bada2c7bd577 | 888 | return false; |
Tomas | 0:bada2c7bd577 | 889 | x->size = temp; |
Tomas | 0:bada2c7bd577 | 890 | |
Tomas | 0:bada2c7bd577 | 891 | /* Check length, noting the space taken by the size_t header. */ |
Tomas | 0:bada2c7bd577 | 892 | if (x->size > field->data_size - offsetof(pb_bytes_array_t, bytes)) |
Tomas | 0:bada2c7bd577 | 893 | PB_RETURN_ERROR(stream, "bytes overflow"); |
Tomas | 0:bada2c7bd577 | 894 | |
Tomas | 0:bada2c7bd577 | 895 | return pb_read(stream, x->bytes, x->size); |
Tomas | 0:bada2c7bd577 | 896 | } |
Tomas | 0:bada2c7bd577 | 897 | |
Tomas | 0:bada2c7bd577 | 898 | bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) |
Tomas | 0:bada2c7bd577 | 899 | { |
Tomas | 0:bada2c7bd577 | 900 | uint32_t size; |
Tomas | 0:bada2c7bd577 | 901 | bool status; |
Tomas | 0:bada2c7bd577 | 902 | if (!pb_decode_varint32(stream, &size)) |
Tomas | 0:bada2c7bd577 | 903 | return false; |
Tomas | 0:bada2c7bd577 | 904 | |
Tomas | 0:bada2c7bd577 | 905 | /* Check length, noting the null terminator */ |
Tomas | 0:bada2c7bd577 | 906 | if (size + 1 > field->data_size) |
Tomas | 0:bada2c7bd577 | 907 | PB_RETURN_ERROR(stream, "string overflow"); |
Tomas | 0:bada2c7bd577 | 908 | |
Tomas | 0:bada2c7bd577 | 909 | status = pb_read(stream, (uint8_t*)dest, size); |
Tomas | 0:bada2c7bd577 | 910 | *((uint8_t*)dest + size) = 0; |
Tomas | 0:bada2c7bd577 | 911 | return status; |
Tomas | 0:bada2c7bd577 | 912 | } |
Tomas | 0:bada2c7bd577 | 913 | |
Tomas | 0:bada2c7bd577 | 914 | bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) |
Tomas | 0:bada2c7bd577 | 915 | { |
Tomas | 0:bada2c7bd577 | 916 | bool status; |
Tomas | 0:bada2c7bd577 | 917 | pb_istream_t substream; |
Tomas | 0:bada2c7bd577 | 918 | const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr; |
Tomas | 0:bada2c7bd577 | 919 | |
Tomas | 0:bada2c7bd577 | 920 | if (!pb_make_string_substream(stream, &substream)) |
Tomas | 0:bada2c7bd577 | 921 | return false; |
Tomas | 0:bada2c7bd577 | 922 | |
Tomas | 0:bada2c7bd577 | 923 | if (field->ptr == NULL) |
Tomas | 0:bada2c7bd577 | 924 | PB_RETURN_ERROR(stream, "invalid field descriptor"); |
Tomas | 0:bada2c7bd577 | 925 | |
Tomas | 0:bada2c7bd577 | 926 | /* New array entries need to be initialized, while required and optional |
Tomas | 0:bada2c7bd577 | 927 | * submessages have already been initialized in the top-level pb_decode. */ |
Tomas | 0:bada2c7bd577 | 928 | if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED) |
Tomas | 0:bada2c7bd577 | 929 | status = pb_decode(&substream, submsg_fields, dest); |
Tomas | 0:bada2c7bd577 | 930 | else |
Tomas | 0:bada2c7bd577 | 931 | status = pb_decode_noinit(&substream, submsg_fields, dest); |
Tomas | 0:bada2c7bd577 | 932 | |
Tomas | 0:bada2c7bd577 | 933 | pb_close_string_substream(stream, &substream); |
Tomas | 0:bada2c7bd577 | 934 | return status; |
Tomas | 0:bada2c7bd577 | 935 | } |
Tomas | 0:bada2c7bd577 | 936 |