Nanopb files
Dependents: nanopb_V2 Message_generator LEX_Threaded_Programming_V3
pb_decode.c@0:c7beea49fc91, 2013-02-19 (annotated)
- Committer:
- intrinseca
- Date:
- Tue Feb 19 20:03:29 2013 +0000
- Revision:
- 0:c7beea49fc91
- Child:
- 2:d2c61a9be078
Initial Uploaded Version 0.1.9
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
intrinseca | 0:c7beea49fc91 | 1 | /* pb_decode.c -- decode a protobuf using minimal resources |
intrinseca | 0:c7beea49fc91 | 2 | * |
intrinseca | 0:c7beea49fc91 | 3 | * 2011 Petteri Aimonen <jpa@kapsi.fi> |
intrinseca | 0:c7beea49fc91 | 4 | */ |
intrinseca | 0:c7beea49fc91 | 5 | |
intrinseca | 0:c7beea49fc91 | 6 | /* The warn_unused_result attribute appeared first in gcc-3.4.0 */ |
intrinseca | 0:c7beea49fc91 | 7 | #if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) |
intrinseca | 0:c7beea49fc91 | 8 | #define checkreturn |
intrinseca | 0:c7beea49fc91 | 9 | #else |
intrinseca | 0:c7beea49fc91 | 10 | /* Verify that we remember to check all return values for proper error propagation */ |
intrinseca | 0:c7beea49fc91 | 11 | #define checkreturn __attribute__((warn_unused_result)) |
intrinseca | 0:c7beea49fc91 | 12 | #endif |
intrinseca | 0:c7beea49fc91 | 13 | |
intrinseca | 0:c7beea49fc91 | 14 | #define NANOPB_INTERNALS |
intrinseca | 0:c7beea49fc91 | 15 | #include "pb.h" |
intrinseca | 0:c7beea49fc91 | 16 | #include "pb_decode.h" |
intrinseca | 0:c7beea49fc91 | 17 | #include <string.h> |
intrinseca | 0:c7beea49fc91 | 18 | |
intrinseca | 0:c7beea49fc91 | 19 | typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; |
intrinseca | 0:c7beea49fc91 | 20 | |
intrinseca | 0:c7beea49fc91 | 21 | /* --- Function pointers to field decoders --- |
intrinseca | 0:c7beea49fc91 | 22 | * Order in the array must match pb_action_t LTYPE numbering. |
intrinseca | 0:c7beea49fc91 | 23 | */ |
intrinseca | 0:c7beea49fc91 | 24 | static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { |
intrinseca | 0:c7beea49fc91 | 25 | &pb_dec_varint, |
intrinseca | 0:c7beea49fc91 | 26 | &pb_dec_svarint, |
intrinseca | 0:c7beea49fc91 | 27 | &pb_dec_fixed32, |
intrinseca | 0:c7beea49fc91 | 28 | &pb_dec_fixed64, |
intrinseca | 0:c7beea49fc91 | 29 | |
intrinseca | 0:c7beea49fc91 | 30 | &pb_dec_bytes, |
intrinseca | 0:c7beea49fc91 | 31 | &pb_dec_string, |
intrinseca | 0:c7beea49fc91 | 32 | &pb_dec_submessage |
intrinseca | 0:c7beea49fc91 | 33 | }; |
intrinseca | 0:c7beea49fc91 | 34 | |
intrinseca | 0:c7beea49fc91 | 35 | /************** |
intrinseca | 0:c7beea49fc91 | 36 | * pb_istream * |
intrinseca | 0:c7beea49fc91 | 37 | **************/ |
intrinseca | 0:c7beea49fc91 | 38 | |
intrinseca | 0:c7beea49fc91 | 39 | static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count) |
intrinseca | 0:c7beea49fc91 | 40 | { |
intrinseca | 0:c7beea49fc91 | 41 | uint8_t *source = (uint8_t*)stream->state; |
intrinseca | 0:c7beea49fc91 | 42 | stream->state = source + count; |
intrinseca | 0:c7beea49fc91 | 43 | |
intrinseca | 0:c7beea49fc91 | 44 | if (buf != NULL) |
intrinseca | 0:c7beea49fc91 | 45 | { |
intrinseca | 0:c7beea49fc91 | 46 | while (count--) |
intrinseca | 0:c7beea49fc91 | 47 | *buf++ = *source++; |
intrinseca | 0:c7beea49fc91 | 48 | } |
intrinseca | 0:c7beea49fc91 | 49 | |
intrinseca | 0:c7beea49fc91 | 50 | return true; |
intrinseca | 0:c7beea49fc91 | 51 | } |
intrinseca | 0:c7beea49fc91 | 52 | |
intrinseca | 0:c7beea49fc91 | 53 | bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count) |
intrinseca | 0:c7beea49fc91 | 54 | { |
intrinseca | 0:c7beea49fc91 | 55 | #ifndef PB_BUFFER_ONLY |
intrinseca | 0:c7beea49fc91 | 56 | if (buf == NULL && stream->callback != buf_read) |
intrinseca | 0:c7beea49fc91 | 57 | { |
intrinseca | 0:c7beea49fc91 | 58 | /* Skip input bytes */ |
intrinseca | 0:c7beea49fc91 | 59 | uint8_t tmp[16]; |
intrinseca | 0:c7beea49fc91 | 60 | while (count > 16) |
intrinseca | 0:c7beea49fc91 | 61 | { |
intrinseca | 0:c7beea49fc91 | 62 | if (!pb_read(stream, tmp, 16)) |
intrinseca | 0:c7beea49fc91 | 63 | return false; |
intrinseca | 0:c7beea49fc91 | 64 | |
intrinseca | 0:c7beea49fc91 | 65 | count -= 16; |
intrinseca | 0:c7beea49fc91 | 66 | } |
intrinseca | 0:c7beea49fc91 | 67 | |
intrinseca | 0:c7beea49fc91 | 68 | return pb_read(stream, tmp, count); |
intrinseca | 0:c7beea49fc91 | 69 | } |
intrinseca | 0:c7beea49fc91 | 70 | #endif |
intrinseca | 0:c7beea49fc91 | 71 | |
intrinseca | 0:c7beea49fc91 | 72 | if (stream->bytes_left < count) |
intrinseca | 0:c7beea49fc91 | 73 | PB_RETURN_ERROR(stream, "end-of-stream"); |
intrinseca | 0:c7beea49fc91 | 74 | |
intrinseca | 0:c7beea49fc91 | 75 | #ifndef PB_BUFFER_ONLY |
intrinseca | 0:c7beea49fc91 | 76 | if (!stream->callback(stream, buf, count)) |
intrinseca | 0:c7beea49fc91 | 77 | PB_RETURN_ERROR(stream, "io error"); |
intrinseca | 0:c7beea49fc91 | 78 | #else |
intrinseca | 0:c7beea49fc91 | 79 | if (!buf_read(stream, buf, count)) |
intrinseca | 0:c7beea49fc91 | 80 | return false; |
intrinseca | 0:c7beea49fc91 | 81 | #endif |
intrinseca | 0:c7beea49fc91 | 82 | |
intrinseca | 0:c7beea49fc91 | 83 | stream->bytes_left -= count; |
intrinseca | 0:c7beea49fc91 | 84 | return true; |
intrinseca | 0:c7beea49fc91 | 85 | } |
intrinseca | 0:c7beea49fc91 | 86 | |
intrinseca | 0:c7beea49fc91 | 87 | pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize) |
intrinseca | 0:c7beea49fc91 | 88 | { |
intrinseca | 0:c7beea49fc91 | 89 | pb_istream_t stream; |
intrinseca | 0:c7beea49fc91 | 90 | #ifdef PB_BUFFER_ONLY |
intrinseca | 0:c7beea49fc91 | 91 | stream.callback = NULL; |
intrinseca | 0:c7beea49fc91 | 92 | #else |
intrinseca | 0:c7beea49fc91 | 93 | stream.callback = &buf_read; |
intrinseca | 0:c7beea49fc91 | 94 | #endif |
intrinseca | 0:c7beea49fc91 | 95 | stream.state = buf; |
intrinseca | 0:c7beea49fc91 | 96 | stream.bytes_left = bufsize; |
intrinseca | 0:c7beea49fc91 | 97 | #ifndef PB_NO_ERRMSG |
intrinseca | 0:c7beea49fc91 | 98 | stream.errmsg = NULL; |
intrinseca | 0:c7beea49fc91 | 99 | #endif |
intrinseca | 0:c7beea49fc91 | 100 | return stream; |
intrinseca | 0:c7beea49fc91 | 101 | } |
intrinseca | 0:c7beea49fc91 | 102 | |
intrinseca | 0:c7beea49fc91 | 103 | /******************** |
intrinseca | 0:c7beea49fc91 | 104 | * Helper functions * |
intrinseca | 0:c7beea49fc91 | 105 | ********************/ |
intrinseca | 0:c7beea49fc91 | 106 | |
intrinseca | 0:c7beea49fc91 | 107 | static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) |
intrinseca | 0:c7beea49fc91 | 108 | { |
intrinseca | 0:c7beea49fc91 | 109 | uint8_t byte; |
intrinseca | 0:c7beea49fc91 | 110 | uint32_t result; |
intrinseca | 0:c7beea49fc91 | 111 | |
intrinseca | 0:c7beea49fc91 | 112 | if (!pb_read(stream, &byte, 1)) |
intrinseca | 0:c7beea49fc91 | 113 | return false; |
intrinseca | 0:c7beea49fc91 | 114 | |
intrinseca | 0:c7beea49fc91 | 115 | if (!(byte & 0x80)) |
intrinseca | 0:c7beea49fc91 | 116 | { |
intrinseca | 0:c7beea49fc91 | 117 | /* Quick case, 1 byte value */ |
intrinseca | 0:c7beea49fc91 | 118 | result = byte; |
intrinseca | 0:c7beea49fc91 | 119 | } |
intrinseca | 0:c7beea49fc91 | 120 | else |
intrinseca | 0:c7beea49fc91 | 121 | { |
intrinseca | 0:c7beea49fc91 | 122 | /* Multibyte case */ |
intrinseca | 0:c7beea49fc91 | 123 | uint8_t bitpos = 7; |
intrinseca | 0:c7beea49fc91 | 124 | result = byte & 0x7F; |
intrinseca | 0:c7beea49fc91 | 125 | |
intrinseca | 0:c7beea49fc91 | 126 | do |
intrinseca | 0:c7beea49fc91 | 127 | { |
intrinseca | 0:c7beea49fc91 | 128 | if (bitpos >= 32) |
intrinseca | 0:c7beea49fc91 | 129 | PB_RETURN_ERROR(stream, "varint overflow"); |
intrinseca | 0:c7beea49fc91 | 130 | |
intrinseca | 0:c7beea49fc91 | 131 | if (!pb_read(stream, &byte, 1)) |
intrinseca | 0:c7beea49fc91 | 132 | return false; |
intrinseca | 0:c7beea49fc91 | 133 | |
intrinseca | 0:c7beea49fc91 | 134 | result |= (uint32_t)(byte & 0x7F) << bitpos; |
intrinseca | 0:c7beea49fc91 | 135 | bitpos = (uint8_t)(bitpos + 7); |
intrinseca | 0:c7beea49fc91 | 136 | } while (byte & 0x80); |
intrinseca | 0:c7beea49fc91 | 137 | } |
intrinseca | 0:c7beea49fc91 | 138 | |
intrinseca | 0:c7beea49fc91 | 139 | *dest = result; |
intrinseca | 0:c7beea49fc91 | 140 | return true; |
intrinseca | 0:c7beea49fc91 | 141 | } |
intrinseca | 0:c7beea49fc91 | 142 | |
intrinseca | 0:c7beea49fc91 | 143 | bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) |
intrinseca | 0:c7beea49fc91 | 144 | { |
intrinseca | 0:c7beea49fc91 | 145 | uint8_t byte; |
intrinseca | 0:c7beea49fc91 | 146 | uint8_t bitpos = 0; |
intrinseca | 0:c7beea49fc91 | 147 | uint64_t result = 0; |
intrinseca | 0:c7beea49fc91 | 148 | |
intrinseca | 0:c7beea49fc91 | 149 | do |
intrinseca | 0:c7beea49fc91 | 150 | { |
intrinseca | 0:c7beea49fc91 | 151 | if (bitpos >= 64) |
intrinseca | 0:c7beea49fc91 | 152 | PB_RETURN_ERROR(stream, "varint overflow"); |
intrinseca | 0:c7beea49fc91 | 153 | |
intrinseca | 0:c7beea49fc91 | 154 | if (!pb_read(stream, &byte, 1)) |
intrinseca | 0:c7beea49fc91 | 155 | return false; |
intrinseca | 0:c7beea49fc91 | 156 | |
intrinseca | 0:c7beea49fc91 | 157 | result |= (uint64_t)(byte & 0x7F) << bitpos; |
intrinseca | 0:c7beea49fc91 | 158 | bitpos = (uint8_t)(bitpos + 7); |
intrinseca | 0:c7beea49fc91 | 159 | } while (byte & 0x80); |
intrinseca | 0:c7beea49fc91 | 160 | |
intrinseca | 0:c7beea49fc91 | 161 | *dest = result; |
intrinseca | 0:c7beea49fc91 | 162 | return true; |
intrinseca | 0:c7beea49fc91 | 163 | } |
intrinseca | 0:c7beea49fc91 | 164 | |
intrinseca | 0:c7beea49fc91 | 165 | bool checkreturn pb_skip_varint(pb_istream_t *stream) |
intrinseca | 0:c7beea49fc91 | 166 | { |
intrinseca | 0:c7beea49fc91 | 167 | uint8_t byte; |
intrinseca | 0:c7beea49fc91 | 168 | do |
intrinseca | 0:c7beea49fc91 | 169 | { |
intrinseca | 0:c7beea49fc91 | 170 | if (!pb_read(stream, &byte, 1)) |
intrinseca | 0:c7beea49fc91 | 171 | return false; |
intrinseca | 0:c7beea49fc91 | 172 | } while (byte & 0x80); |
intrinseca | 0:c7beea49fc91 | 173 | return true; |
intrinseca | 0:c7beea49fc91 | 174 | } |
intrinseca | 0:c7beea49fc91 | 175 | |
intrinseca | 0:c7beea49fc91 | 176 | bool checkreturn pb_skip_string(pb_istream_t *stream) |
intrinseca | 0:c7beea49fc91 | 177 | { |
intrinseca | 0:c7beea49fc91 | 178 | uint32_t length; |
intrinseca | 0:c7beea49fc91 | 179 | if (!pb_decode_varint32(stream, &length)) |
intrinseca | 0:c7beea49fc91 | 180 | return false; |
intrinseca | 0:c7beea49fc91 | 181 | |
intrinseca | 0:c7beea49fc91 | 182 | return pb_read(stream, NULL, length); |
intrinseca | 0:c7beea49fc91 | 183 | } |
intrinseca | 0:c7beea49fc91 | 184 | |
intrinseca | 0:c7beea49fc91 | 185 | bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof) |
intrinseca | 0:c7beea49fc91 | 186 | { |
intrinseca | 0:c7beea49fc91 | 187 | uint32_t temp; |
intrinseca | 0:c7beea49fc91 | 188 | *eof = false; |
intrinseca | 0:c7beea49fc91 | 189 | *wire_type = (pb_wire_type_t) 0; |
intrinseca | 0:c7beea49fc91 | 190 | *tag = 0; |
intrinseca | 0:c7beea49fc91 | 191 | |
intrinseca | 0:c7beea49fc91 | 192 | if (!pb_decode_varint32(stream, &temp)) |
intrinseca | 0:c7beea49fc91 | 193 | { |
intrinseca | 0:c7beea49fc91 | 194 | if (stream->bytes_left == 0) |
intrinseca | 0:c7beea49fc91 | 195 | *eof = true; |
intrinseca | 0:c7beea49fc91 | 196 | |
intrinseca | 0:c7beea49fc91 | 197 | return false; |
intrinseca | 0:c7beea49fc91 | 198 | } |
intrinseca | 0:c7beea49fc91 | 199 | |
intrinseca | 0:c7beea49fc91 | 200 | if (temp == 0) |
intrinseca | 0:c7beea49fc91 | 201 | { |
intrinseca | 0:c7beea49fc91 | 202 | *eof = true; /* Special feature: allow 0-terminated messages. */ |
intrinseca | 0:c7beea49fc91 | 203 | return false; |
intrinseca | 0:c7beea49fc91 | 204 | } |
intrinseca | 0:c7beea49fc91 | 205 | |
intrinseca | 0:c7beea49fc91 | 206 | *tag = temp >> 3; |
intrinseca | 0:c7beea49fc91 | 207 | *wire_type = (pb_wire_type_t)(temp & 7); |
intrinseca | 0:c7beea49fc91 | 208 | return true; |
intrinseca | 0:c7beea49fc91 | 209 | } |
intrinseca | 0:c7beea49fc91 | 210 | |
intrinseca | 0:c7beea49fc91 | 211 | bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) |
intrinseca | 0:c7beea49fc91 | 212 | { |
intrinseca | 0:c7beea49fc91 | 213 | switch (wire_type) |
intrinseca | 0:c7beea49fc91 | 214 | { |
intrinseca | 0:c7beea49fc91 | 215 | case PB_WT_VARINT: return pb_skip_varint(stream); |
intrinseca | 0:c7beea49fc91 | 216 | case PB_WT_64BIT: return pb_read(stream, NULL, 8); |
intrinseca | 0:c7beea49fc91 | 217 | case PB_WT_STRING: return pb_skip_string(stream); |
intrinseca | 0:c7beea49fc91 | 218 | case PB_WT_32BIT: return pb_read(stream, NULL, 4); |
intrinseca | 0:c7beea49fc91 | 219 | default: PB_RETURN_ERROR(stream, "invalid wire_type"); |
intrinseca | 0:c7beea49fc91 | 220 | } |
intrinseca | 0:c7beea49fc91 | 221 | } |
intrinseca | 0:c7beea49fc91 | 222 | |
intrinseca | 0:c7beea49fc91 | 223 | /* Read a raw value to buffer, for the purpose of passing it to callback as |
intrinseca | 0:c7beea49fc91 | 224 | * a substream. Size is maximum size on call, and actual size on return. |
intrinseca | 0:c7beea49fc91 | 225 | */ |
intrinseca | 0:c7beea49fc91 | 226 | static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, uint8_t *buf, size_t *size) |
intrinseca | 0:c7beea49fc91 | 227 | { |
intrinseca | 0:c7beea49fc91 | 228 | size_t max_size = *size; |
intrinseca | 0:c7beea49fc91 | 229 | switch (wire_type) |
intrinseca | 0:c7beea49fc91 | 230 | { |
intrinseca | 0:c7beea49fc91 | 231 | case PB_WT_VARINT: |
intrinseca | 0:c7beea49fc91 | 232 | *size = 0; |
intrinseca | 0:c7beea49fc91 | 233 | do |
intrinseca | 0:c7beea49fc91 | 234 | { |
intrinseca | 0:c7beea49fc91 | 235 | (*size)++; |
intrinseca | 0:c7beea49fc91 | 236 | if (*size > max_size) return false; |
intrinseca | 0:c7beea49fc91 | 237 | if (!pb_read(stream, buf, 1)) return false; |
intrinseca | 0:c7beea49fc91 | 238 | } while (*buf++ & 0x80); |
intrinseca | 0:c7beea49fc91 | 239 | return true; |
intrinseca | 0:c7beea49fc91 | 240 | |
intrinseca | 0:c7beea49fc91 | 241 | case PB_WT_64BIT: |
intrinseca | 0:c7beea49fc91 | 242 | *size = 8; |
intrinseca | 0:c7beea49fc91 | 243 | return pb_read(stream, buf, 8); |
intrinseca | 0:c7beea49fc91 | 244 | |
intrinseca | 0:c7beea49fc91 | 245 | case PB_WT_32BIT: |
intrinseca | 0:c7beea49fc91 | 246 | *size = 4; |
intrinseca | 0:c7beea49fc91 | 247 | return pb_read(stream, buf, 4); |
intrinseca | 0:c7beea49fc91 | 248 | |
intrinseca | 0:c7beea49fc91 | 249 | default: PB_RETURN_ERROR(stream, "invalid wire_type"); |
intrinseca | 0:c7beea49fc91 | 250 | } |
intrinseca | 0:c7beea49fc91 | 251 | } |
intrinseca | 0:c7beea49fc91 | 252 | |
intrinseca | 0:c7beea49fc91 | 253 | /* Decode string length from stream and return a substream with limited length. |
intrinseca | 0:c7beea49fc91 | 254 | * Remember to close the substream using pb_close_string_substream(). |
intrinseca | 0:c7beea49fc91 | 255 | */ |
intrinseca | 0:c7beea49fc91 | 256 | bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream) |
intrinseca | 0:c7beea49fc91 | 257 | { |
intrinseca | 0:c7beea49fc91 | 258 | uint32_t size; |
intrinseca | 0:c7beea49fc91 | 259 | if (!pb_decode_varint32(stream, &size)) |
intrinseca | 0:c7beea49fc91 | 260 | return false; |
intrinseca | 0:c7beea49fc91 | 261 | |
intrinseca | 0:c7beea49fc91 | 262 | *substream = *stream; |
intrinseca | 0:c7beea49fc91 | 263 | if (substream->bytes_left < size) |
intrinseca | 0:c7beea49fc91 | 264 | PB_RETURN_ERROR(stream, "parent stream too short"); |
intrinseca | 0:c7beea49fc91 | 265 | |
intrinseca | 0:c7beea49fc91 | 266 | substream->bytes_left = size; |
intrinseca | 0:c7beea49fc91 | 267 | stream->bytes_left -= size; |
intrinseca | 0:c7beea49fc91 | 268 | return true; |
intrinseca | 0:c7beea49fc91 | 269 | } |
intrinseca | 0:c7beea49fc91 | 270 | |
intrinseca | 0:c7beea49fc91 | 271 | void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) |
intrinseca | 0:c7beea49fc91 | 272 | { |
intrinseca | 0:c7beea49fc91 | 273 | stream->state = substream->state; |
intrinseca | 0:c7beea49fc91 | 274 | |
intrinseca | 0:c7beea49fc91 | 275 | #ifndef PB_NO_ERRMSG |
intrinseca | 0:c7beea49fc91 | 276 | stream->errmsg = substream->errmsg; |
intrinseca | 0:c7beea49fc91 | 277 | #endif |
intrinseca | 0:c7beea49fc91 | 278 | } |
intrinseca | 0:c7beea49fc91 | 279 | |
intrinseca | 0:c7beea49fc91 | 280 | /* Iterator for pb_field_t list */ |
intrinseca | 0:c7beea49fc91 | 281 | typedef struct { |
intrinseca | 0:c7beea49fc91 | 282 | const pb_field_t *start; /* Start of the pb_field_t array */ |
intrinseca | 0:c7beea49fc91 | 283 | const pb_field_t *current; /* Current position of the iterator */ |
intrinseca | 0:c7beea49fc91 | 284 | unsigned field_index; /* Zero-based index of the field. */ |
intrinseca | 0:c7beea49fc91 | 285 | unsigned required_field_index; /* Zero-based index that counts only the required fields */ |
intrinseca | 0:c7beea49fc91 | 286 | void *dest_struct; /* Pointer to the destination structure to decode to */ |
intrinseca | 0:c7beea49fc91 | 287 | void *pData; /* Pointer where to store current field value */ |
intrinseca | 0:c7beea49fc91 | 288 | void *pSize; /* Pointer where to store the size of current array field */ |
intrinseca | 0:c7beea49fc91 | 289 | } pb_field_iterator_t; |
intrinseca | 0:c7beea49fc91 | 290 | |
intrinseca | 0:c7beea49fc91 | 291 | static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct) |
intrinseca | 0:c7beea49fc91 | 292 | { |
intrinseca | 0:c7beea49fc91 | 293 | iter->start = iter->current = fields; |
intrinseca | 0:c7beea49fc91 | 294 | iter->field_index = 0; |
intrinseca | 0:c7beea49fc91 | 295 | iter->required_field_index = 0; |
intrinseca | 0:c7beea49fc91 | 296 | iter->pData = (char*)dest_struct + iter->current->data_offset; |
intrinseca | 0:c7beea49fc91 | 297 | iter->pSize = (char*)iter->pData + iter->current->size_offset; |
intrinseca | 0:c7beea49fc91 | 298 | iter->dest_struct = dest_struct; |
intrinseca | 0:c7beea49fc91 | 299 | } |
intrinseca | 0:c7beea49fc91 | 300 | |
intrinseca | 0:c7beea49fc91 | 301 | static bool pb_field_next(pb_field_iterator_t *iter) |
intrinseca | 0:c7beea49fc91 | 302 | { |
intrinseca | 0:c7beea49fc91 | 303 | bool notwrapped = true; |
intrinseca | 0:c7beea49fc91 | 304 | size_t prev_size = iter->current->data_size; |
intrinseca | 0:c7beea49fc91 | 305 | |
intrinseca | 0:c7beea49fc91 | 306 | if (PB_HTYPE(iter->current->type) == PB_HTYPE_ARRAY) |
intrinseca | 0:c7beea49fc91 | 307 | prev_size *= iter->current->array_size; |
intrinseca | 0:c7beea49fc91 | 308 | |
intrinseca | 0:c7beea49fc91 | 309 | if (PB_HTYPE(iter->current->type) == PB_HTYPE_REQUIRED) |
intrinseca | 0:c7beea49fc91 | 310 | iter->required_field_index++; |
intrinseca | 0:c7beea49fc91 | 311 | |
intrinseca | 0:c7beea49fc91 | 312 | iter->current++; |
intrinseca | 0:c7beea49fc91 | 313 | iter->field_index++; |
intrinseca | 0:c7beea49fc91 | 314 | if (iter->current->tag == 0) |
intrinseca | 0:c7beea49fc91 | 315 | { |
intrinseca | 0:c7beea49fc91 | 316 | iter->current = iter->start; |
intrinseca | 0:c7beea49fc91 | 317 | iter->field_index = 0; |
intrinseca | 0:c7beea49fc91 | 318 | iter->required_field_index = 0; |
intrinseca | 0:c7beea49fc91 | 319 | iter->pData = iter->dest_struct; |
intrinseca | 0:c7beea49fc91 | 320 | prev_size = 0; |
intrinseca | 0:c7beea49fc91 | 321 | notwrapped = false; |
intrinseca | 0:c7beea49fc91 | 322 | } |
intrinseca | 0:c7beea49fc91 | 323 | |
intrinseca | 0:c7beea49fc91 | 324 | iter->pData = (char*)iter->pData + prev_size + iter->current->data_offset; |
intrinseca | 0:c7beea49fc91 | 325 | iter->pSize = (char*)iter->pData + iter->current->size_offset; |
intrinseca | 0:c7beea49fc91 | 326 | return notwrapped; |
intrinseca | 0:c7beea49fc91 | 327 | } |
intrinseca | 0:c7beea49fc91 | 328 | |
intrinseca | 0:c7beea49fc91 | 329 | static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag) |
intrinseca | 0:c7beea49fc91 | 330 | { |
intrinseca | 0:c7beea49fc91 | 331 | unsigned start = iter->field_index; |
intrinseca | 0:c7beea49fc91 | 332 | |
intrinseca | 0:c7beea49fc91 | 333 | do { |
intrinseca | 0:c7beea49fc91 | 334 | if (iter->current->tag == tag) |
intrinseca | 0:c7beea49fc91 | 335 | return true; |
intrinseca | 0:c7beea49fc91 | 336 | pb_field_next(iter); |
intrinseca | 0:c7beea49fc91 | 337 | } while (iter->field_index != start); |
intrinseca | 0:c7beea49fc91 | 338 | |
intrinseca | 0:c7beea49fc91 | 339 | return false; |
intrinseca | 0:c7beea49fc91 | 340 | } |
intrinseca | 0:c7beea49fc91 | 341 | |
intrinseca | 0:c7beea49fc91 | 342 | /************************* |
intrinseca | 0:c7beea49fc91 | 343 | * Decode a single field * |
intrinseca | 0:c7beea49fc91 | 344 | *************************/ |
intrinseca | 0:c7beea49fc91 | 345 | |
intrinseca | 0:c7beea49fc91 | 346 | static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) |
intrinseca | 0:c7beea49fc91 | 347 | { |
intrinseca | 0:c7beea49fc91 | 348 | pb_decoder_t func = PB_DECODERS[PB_LTYPE(iter->current->type)]; |
intrinseca | 0:c7beea49fc91 | 349 | |
intrinseca | 0:c7beea49fc91 | 350 | switch (PB_HTYPE(iter->current->type)) |
intrinseca | 0:c7beea49fc91 | 351 | { |
intrinseca | 0:c7beea49fc91 | 352 | case PB_HTYPE_REQUIRED: |
intrinseca | 0:c7beea49fc91 | 353 | return func(stream, iter->current, iter->pData); |
intrinseca | 0:c7beea49fc91 | 354 | |
intrinseca | 0:c7beea49fc91 | 355 | case PB_HTYPE_OPTIONAL: |
intrinseca | 0:c7beea49fc91 | 356 | *(bool*)iter->pSize = true; |
intrinseca | 0:c7beea49fc91 | 357 | return func(stream, iter->current, iter->pData); |
intrinseca | 0:c7beea49fc91 | 358 | |
intrinseca | 0:c7beea49fc91 | 359 | case PB_HTYPE_ARRAY: |
intrinseca | 0:c7beea49fc91 | 360 | if (wire_type == PB_WT_STRING |
intrinseca | 0:c7beea49fc91 | 361 | && PB_LTYPE(iter->current->type) <= PB_LTYPE_LAST_PACKABLE) |
intrinseca | 0:c7beea49fc91 | 362 | { |
intrinseca | 0:c7beea49fc91 | 363 | /* Packed array */ |
intrinseca | 0:c7beea49fc91 | 364 | bool status = true; |
intrinseca | 0:c7beea49fc91 | 365 | size_t *size = (size_t*)iter->pSize; |
intrinseca | 0:c7beea49fc91 | 366 | pb_istream_t substream; |
intrinseca | 0:c7beea49fc91 | 367 | if (!pb_make_string_substream(stream, &substream)) |
intrinseca | 0:c7beea49fc91 | 368 | return false; |
intrinseca | 0:c7beea49fc91 | 369 | |
intrinseca | 0:c7beea49fc91 | 370 | while (substream.bytes_left && *size < iter->current->array_size) |
intrinseca | 0:c7beea49fc91 | 371 | { |
intrinseca | 0:c7beea49fc91 | 372 | void *pItem = (uint8_t*)iter->pData + iter->current->data_size * (*size); |
intrinseca | 0:c7beea49fc91 | 373 | if (!func(&substream, iter->current, pItem)) |
intrinseca | 0:c7beea49fc91 | 374 | { |
intrinseca | 0:c7beea49fc91 | 375 | status = false; |
intrinseca | 0:c7beea49fc91 | 376 | break; |
intrinseca | 0:c7beea49fc91 | 377 | } |
intrinseca | 0:c7beea49fc91 | 378 | (*size)++; |
intrinseca | 0:c7beea49fc91 | 379 | } |
intrinseca | 0:c7beea49fc91 | 380 | pb_close_string_substream(stream, &substream); |
intrinseca | 0:c7beea49fc91 | 381 | |
intrinseca | 0:c7beea49fc91 | 382 | if (substream.bytes_left != 0) |
intrinseca | 0:c7beea49fc91 | 383 | PB_RETURN_ERROR(stream, "array overflow"); |
intrinseca | 0:c7beea49fc91 | 384 | |
intrinseca | 0:c7beea49fc91 | 385 | return status; |
intrinseca | 0:c7beea49fc91 | 386 | } |
intrinseca | 0:c7beea49fc91 | 387 | else |
intrinseca | 0:c7beea49fc91 | 388 | { |
intrinseca | 0:c7beea49fc91 | 389 | /* Repeated field */ |
intrinseca | 0:c7beea49fc91 | 390 | size_t *size = (size_t*)iter->pSize; |
intrinseca | 0:c7beea49fc91 | 391 | void *pItem = (uint8_t*)iter->pData + iter->current->data_size * (*size); |
intrinseca | 0:c7beea49fc91 | 392 | if (*size >= iter->current->array_size) |
intrinseca | 0:c7beea49fc91 | 393 | PB_RETURN_ERROR(stream, "array overflow"); |
intrinseca | 0:c7beea49fc91 | 394 | |
intrinseca | 0:c7beea49fc91 | 395 | (*size)++; |
intrinseca | 0:c7beea49fc91 | 396 | return func(stream, iter->current, pItem); |
intrinseca | 0:c7beea49fc91 | 397 | } |
intrinseca | 0:c7beea49fc91 | 398 | |
intrinseca | 0:c7beea49fc91 | 399 | case PB_HTYPE_CALLBACK: |
intrinseca | 0:c7beea49fc91 | 400 | { |
intrinseca | 0:c7beea49fc91 | 401 | pb_callback_t *pCallback = (pb_callback_t*)iter->pData; |
intrinseca | 0:c7beea49fc91 | 402 | |
intrinseca | 0:c7beea49fc91 | 403 | if (pCallback->funcs.decode == NULL) |
intrinseca | 0:c7beea49fc91 | 404 | return pb_skip_field(stream, wire_type); |
intrinseca | 0:c7beea49fc91 | 405 | |
intrinseca | 0:c7beea49fc91 | 406 | if (wire_type == PB_WT_STRING) |
intrinseca | 0:c7beea49fc91 | 407 | { |
intrinseca | 0:c7beea49fc91 | 408 | pb_istream_t substream; |
intrinseca | 0:c7beea49fc91 | 409 | |
intrinseca | 0:c7beea49fc91 | 410 | if (!pb_make_string_substream(stream, &substream)) |
intrinseca | 0:c7beea49fc91 | 411 | return false; |
intrinseca | 0:c7beea49fc91 | 412 | |
intrinseca | 0:c7beea49fc91 | 413 | while (substream.bytes_left) |
intrinseca | 0:c7beea49fc91 | 414 | { |
intrinseca | 0:c7beea49fc91 | 415 | if (!pCallback->funcs.decode(&substream, iter->current, pCallback->arg)) |
intrinseca | 0:c7beea49fc91 | 416 | PB_RETURN_ERROR(stream, "callback failed"); |
intrinseca | 0:c7beea49fc91 | 417 | } |
intrinseca | 0:c7beea49fc91 | 418 | |
intrinseca | 0:c7beea49fc91 | 419 | pb_close_string_substream(stream, &substream); |
intrinseca | 0:c7beea49fc91 | 420 | return true; |
intrinseca | 0:c7beea49fc91 | 421 | } |
intrinseca | 0:c7beea49fc91 | 422 | else |
intrinseca | 0:c7beea49fc91 | 423 | { |
intrinseca | 0:c7beea49fc91 | 424 | /* Copy the single scalar value to stack. |
intrinseca | 0:c7beea49fc91 | 425 | * This is required so that we can limit the stream length, |
intrinseca | 0:c7beea49fc91 | 426 | * which in turn allows to use same callback for packed and |
intrinseca | 0:c7beea49fc91 | 427 | * not-packed fields. */ |
intrinseca | 0:c7beea49fc91 | 428 | pb_istream_t substream; |
intrinseca | 0:c7beea49fc91 | 429 | uint8_t buffer[10]; |
intrinseca | 0:c7beea49fc91 | 430 | size_t size = sizeof(buffer); |
intrinseca | 0:c7beea49fc91 | 431 | |
intrinseca | 0:c7beea49fc91 | 432 | if (!read_raw_value(stream, wire_type, buffer, &size)) |
intrinseca | 0:c7beea49fc91 | 433 | return false; |
intrinseca | 0:c7beea49fc91 | 434 | substream = pb_istream_from_buffer(buffer, size); |
intrinseca | 0:c7beea49fc91 | 435 | |
intrinseca | 0:c7beea49fc91 | 436 | return pCallback->funcs.decode(&substream, iter->current, pCallback->arg); |
intrinseca | 0:c7beea49fc91 | 437 | } |
intrinseca | 0:c7beea49fc91 | 438 | } |
intrinseca | 0:c7beea49fc91 | 439 | |
intrinseca | 0:c7beea49fc91 | 440 | default: |
intrinseca | 0:c7beea49fc91 | 441 | PB_RETURN_ERROR(stream, "invalid field type"); |
intrinseca | 0:c7beea49fc91 | 442 | } |
intrinseca | 0:c7beea49fc91 | 443 | } |
intrinseca | 0:c7beea49fc91 | 444 | |
intrinseca | 0:c7beea49fc91 | 445 | /* Initialize message fields to default values, recursively */ |
intrinseca | 0:c7beea49fc91 | 446 | static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) |
intrinseca | 0:c7beea49fc91 | 447 | { |
intrinseca | 0:c7beea49fc91 | 448 | pb_field_iterator_t iter; |
intrinseca | 0:c7beea49fc91 | 449 | pb_field_init(&iter, fields, dest_struct); |
intrinseca | 0:c7beea49fc91 | 450 | |
intrinseca | 0:c7beea49fc91 | 451 | /* Initialize size/has fields and apply default values */ |
intrinseca | 0:c7beea49fc91 | 452 | do |
intrinseca | 0:c7beea49fc91 | 453 | { |
intrinseca | 0:c7beea49fc91 | 454 | if (iter.current->tag == 0) |
intrinseca | 0:c7beea49fc91 | 455 | continue; |
intrinseca | 0:c7beea49fc91 | 456 | |
intrinseca | 0:c7beea49fc91 | 457 | /* Initialize the size field for optional/repeated fields to 0. */ |
intrinseca | 0:c7beea49fc91 | 458 | if (PB_HTYPE(iter.current->type) == PB_HTYPE_OPTIONAL) |
intrinseca | 0:c7beea49fc91 | 459 | { |
intrinseca | 0:c7beea49fc91 | 460 | *(bool*)iter.pSize = false; |
intrinseca | 0:c7beea49fc91 | 461 | } |
intrinseca | 0:c7beea49fc91 | 462 | else if (PB_HTYPE(iter.current->type) == PB_HTYPE_ARRAY) |
intrinseca | 0:c7beea49fc91 | 463 | { |
intrinseca | 0:c7beea49fc91 | 464 | *(size_t*)iter.pSize = 0; |
intrinseca | 0:c7beea49fc91 | 465 | continue; /* Array is empty, no need to initialize contents */ |
intrinseca | 0:c7beea49fc91 | 466 | } |
intrinseca | 0:c7beea49fc91 | 467 | |
intrinseca | 0:c7beea49fc91 | 468 | /* Initialize field contents to default value */ |
intrinseca | 0:c7beea49fc91 | 469 | if (PB_HTYPE(iter.current->type) == PB_HTYPE_CALLBACK) |
intrinseca | 0:c7beea49fc91 | 470 | { |
intrinseca | 0:c7beea49fc91 | 471 | continue; /* Don't overwrite callback */ |
intrinseca | 0:c7beea49fc91 | 472 | } |
intrinseca | 0:c7beea49fc91 | 473 | else if (PB_LTYPE(iter.current->type) == PB_LTYPE_SUBMESSAGE) |
intrinseca | 0:c7beea49fc91 | 474 | { |
intrinseca | 0:c7beea49fc91 | 475 | pb_message_set_to_defaults((const pb_field_t *) iter.current->ptr, iter.pData); |
intrinseca | 0:c7beea49fc91 | 476 | } |
intrinseca | 0:c7beea49fc91 | 477 | else if (iter.current->ptr != NULL) |
intrinseca | 0:c7beea49fc91 | 478 | { |
intrinseca | 0:c7beea49fc91 | 479 | memcpy(iter.pData, iter.current->ptr, iter.current->data_size); |
intrinseca | 0:c7beea49fc91 | 480 | } |
intrinseca | 0:c7beea49fc91 | 481 | else |
intrinseca | 0:c7beea49fc91 | 482 | { |
intrinseca | 0:c7beea49fc91 | 483 | memset(iter.pData, 0, iter.current->data_size); |
intrinseca | 0:c7beea49fc91 | 484 | } |
intrinseca | 0:c7beea49fc91 | 485 | } while (pb_field_next(&iter)); |
intrinseca | 0:c7beea49fc91 | 486 | } |
intrinseca | 0:c7beea49fc91 | 487 | |
intrinseca | 0:c7beea49fc91 | 488 | /********************* |
intrinseca | 0:c7beea49fc91 | 489 | * Decode all fields * |
intrinseca | 0:c7beea49fc91 | 490 | *********************/ |
intrinseca | 0:c7beea49fc91 | 491 | |
intrinseca | 0:c7beea49fc91 | 492 | bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) |
intrinseca | 0:c7beea49fc91 | 493 | { |
intrinseca | 0:c7beea49fc91 | 494 | uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0}; /* Used to check for required fields */ |
intrinseca | 0:c7beea49fc91 | 495 | pb_field_iterator_t iter; |
intrinseca | 0:c7beea49fc91 | 496 | |
intrinseca | 0:c7beea49fc91 | 497 | pb_field_init(&iter, fields, dest_struct); |
intrinseca | 0:c7beea49fc91 | 498 | |
intrinseca | 0:c7beea49fc91 | 499 | while (stream->bytes_left) |
intrinseca | 0:c7beea49fc91 | 500 | { |
intrinseca | 0:c7beea49fc91 | 501 | uint32_t tag; |
intrinseca | 0:c7beea49fc91 | 502 | pb_wire_type_t wire_type; |
intrinseca | 0:c7beea49fc91 | 503 | bool eof; |
intrinseca | 0:c7beea49fc91 | 504 | |
intrinseca | 0:c7beea49fc91 | 505 | if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) |
intrinseca | 0:c7beea49fc91 | 506 | { |
intrinseca | 0:c7beea49fc91 | 507 | if (eof) |
intrinseca | 0:c7beea49fc91 | 508 | break; |
intrinseca | 0:c7beea49fc91 | 509 | else |
intrinseca | 0:c7beea49fc91 | 510 | return false; |
intrinseca | 0:c7beea49fc91 | 511 | } |
intrinseca | 0:c7beea49fc91 | 512 | |
intrinseca | 0:c7beea49fc91 | 513 | if (!pb_field_find(&iter, tag)) |
intrinseca | 0:c7beea49fc91 | 514 | { |
intrinseca | 0:c7beea49fc91 | 515 | /* No match found, skip data */ |
intrinseca | 0:c7beea49fc91 | 516 | if (!pb_skip_field(stream, wire_type)) |
intrinseca | 0:c7beea49fc91 | 517 | return false; |
intrinseca | 0:c7beea49fc91 | 518 | continue; |
intrinseca | 0:c7beea49fc91 | 519 | } |
intrinseca | 0:c7beea49fc91 | 520 | |
intrinseca | 0:c7beea49fc91 | 521 | if (PB_HTYPE(iter.current->type) == PB_HTYPE_REQUIRED |
intrinseca | 0:c7beea49fc91 | 522 | && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) |
intrinseca | 0:c7beea49fc91 | 523 | { |
intrinseca | 0:c7beea49fc91 | 524 | fields_seen[iter.required_field_index >> 3] |= (uint8_t)(1 << (iter.required_field_index & 7)); |
intrinseca | 0:c7beea49fc91 | 525 | } |
intrinseca | 0:c7beea49fc91 | 526 | |
intrinseca | 0:c7beea49fc91 | 527 | if (!decode_field(stream, wire_type, &iter)) |
intrinseca | 0:c7beea49fc91 | 528 | return false; |
intrinseca | 0:c7beea49fc91 | 529 | } |
intrinseca | 0:c7beea49fc91 | 530 | |
intrinseca | 0:c7beea49fc91 | 531 | /* Check that all required fields were present. */ |
intrinseca | 0:c7beea49fc91 | 532 | { |
intrinseca | 0:c7beea49fc91 | 533 | /* First figure out the number of required fields by |
intrinseca | 0:c7beea49fc91 | 534 | * seeking to the end of the field array. Usually we |
intrinseca | 0:c7beea49fc91 | 535 | * are already close to end after decoding. |
intrinseca | 0:c7beea49fc91 | 536 | */ |
intrinseca | 0:c7beea49fc91 | 537 | unsigned req_field_count; |
intrinseca | 0:c7beea49fc91 | 538 | pb_type_t last_type; |
intrinseca | 0:c7beea49fc91 | 539 | unsigned i; |
intrinseca | 0:c7beea49fc91 | 540 | do { |
intrinseca | 0:c7beea49fc91 | 541 | req_field_count = iter.required_field_index; |
intrinseca | 0:c7beea49fc91 | 542 | last_type = iter.current->type; |
intrinseca | 0:c7beea49fc91 | 543 | } while (pb_field_next(&iter)); |
intrinseca | 0:c7beea49fc91 | 544 | |
intrinseca | 0:c7beea49fc91 | 545 | /* Fixup if last field was also required. */ |
intrinseca | 0:c7beea49fc91 | 546 | if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED) |
intrinseca | 0:c7beea49fc91 | 547 | req_field_count++; |
intrinseca | 0:c7beea49fc91 | 548 | |
intrinseca | 0:c7beea49fc91 | 549 | /* Check the whole bytes */ |
intrinseca | 0:c7beea49fc91 | 550 | for (i = 0; i < (req_field_count >> 3); i++) |
intrinseca | 0:c7beea49fc91 | 551 | { |
intrinseca | 0:c7beea49fc91 | 552 | if (fields_seen[i] != 0xFF) |
intrinseca | 0:c7beea49fc91 | 553 | PB_RETURN_ERROR(stream, "missing required field"); |
intrinseca | 0:c7beea49fc91 | 554 | } |
intrinseca | 0:c7beea49fc91 | 555 | |
intrinseca | 0:c7beea49fc91 | 556 | /* Check the remaining bits */ |
intrinseca | 0:c7beea49fc91 | 557 | if (fields_seen[req_field_count >> 3] != (0xFF >> (8 - (req_field_count & 7)))) |
intrinseca | 0:c7beea49fc91 | 558 | PB_RETURN_ERROR(stream, "missing required field"); |
intrinseca | 0:c7beea49fc91 | 559 | } |
intrinseca | 0:c7beea49fc91 | 560 | |
intrinseca | 0:c7beea49fc91 | 561 | return true; |
intrinseca | 0:c7beea49fc91 | 562 | } |
intrinseca | 0:c7beea49fc91 | 563 | |
intrinseca | 0:c7beea49fc91 | 564 | bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) |
intrinseca | 0:c7beea49fc91 | 565 | { |
intrinseca | 0:c7beea49fc91 | 566 | pb_message_set_to_defaults(fields, dest_struct); |
intrinseca | 0:c7beea49fc91 | 567 | return pb_decode_noinit(stream, fields, dest_struct); |
intrinseca | 0:c7beea49fc91 | 568 | } |
intrinseca | 0:c7beea49fc91 | 569 | |
intrinseca | 0:c7beea49fc91 | 570 | /* Field decoders */ |
intrinseca | 0:c7beea49fc91 | 571 | |
intrinseca | 0:c7beea49fc91 | 572 | bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest) |
intrinseca | 0:c7beea49fc91 | 573 | { |
intrinseca | 0:c7beea49fc91 | 574 | uint64_t value; |
intrinseca | 0:c7beea49fc91 | 575 | if (!pb_decode_varint(stream, &value)) |
intrinseca | 0:c7beea49fc91 | 576 | return false; |
intrinseca | 0:c7beea49fc91 | 577 | |
intrinseca | 0:c7beea49fc91 | 578 | if (value & 1) |
intrinseca | 0:c7beea49fc91 | 579 | *dest = (int64_t)(~(value >> 1)); |
intrinseca | 0:c7beea49fc91 | 580 | else |
intrinseca | 0:c7beea49fc91 | 581 | *dest = (int64_t)(value >> 1); |
intrinseca | 0:c7beea49fc91 | 582 | |
intrinseca | 0:c7beea49fc91 | 583 | return true; |
intrinseca | 0:c7beea49fc91 | 584 | } |
intrinseca | 0:c7beea49fc91 | 585 | |
intrinseca | 0:c7beea49fc91 | 586 | bool pb_decode_fixed32(pb_istream_t *stream, void *dest) |
intrinseca | 0:c7beea49fc91 | 587 | { |
intrinseca | 0:c7beea49fc91 | 588 | #ifdef __BIG_ENDIAN__ |
intrinseca | 0:c7beea49fc91 | 589 | uint8_t *bytes = (uint8_t*)dest; |
intrinseca | 0:c7beea49fc91 | 590 | uint8_t lebytes[4]; |
intrinseca | 0:c7beea49fc91 | 591 | |
intrinseca | 0:c7beea49fc91 | 592 | if (!pb_read(stream, lebytes, 4)) |
intrinseca | 0:c7beea49fc91 | 593 | return false; |
intrinseca | 0:c7beea49fc91 | 594 | |
intrinseca | 0:c7beea49fc91 | 595 | bytes[0] = lebytes[3]; |
intrinseca | 0:c7beea49fc91 | 596 | bytes[1] = lebytes[2]; |
intrinseca | 0:c7beea49fc91 | 597 | bytes[2] = lebytes[1]; |
intrinseca | 0:c7beea49fc91 | 598 | bytes[3] = lebytes[0]; |
intrinseca | 0:c7beea49fc91 | 599 | return true; |
intrinseca | 0:c7beea49fc91 | 600 | #else |
intrinseca | 0:c7beea49fc91 | 601 | return pb_read(stream, (uint8_t*)dest, 4); |
intrinseca | 0:c7beea49fc91 | 602 | #endif |
intrinseca | 0:c7beea49fc91 | 603 | } |
intrinseca | 0:c7beea49fc91 | 604 | |
intrinseca | 0:c7beea49fc91 | 605 | bool pb_decode_fixed64(pb_istream_t *stream, void *dest) |
intrinseca | 0:c7beea49fc91 | 606 | { |
intrinseca | 0:c7beea49fc91 | 607 | #ifdef __BIG_ENDIAN__ |
intrinseca | 0:c7beea49fc91 | 608 | uint8_t *bytes = (uint8_t*)dest; |
intrinseca | 0:c7beea49fc91 | 609 | uint8_t lebytes[8]; |
intrinseca | 0:c7beea49fc91 | 610 | |
intrinseca | 0:c7beea49fc91 | 611 | if (!pb_read(stream, lebytes, 8)) |
intrinseca | 0:c7beea49fc91 | 612 | return false; |
intrinseca | 0:c7beea49fc91 | 613 | |
intrinseca | 0:c7beea49fc91 | 614 | bytes[0] = lebytes[7]; |
intrinseca | 0:c7beea49fc91 | 615 | bytes[1] = lebytes[6]; |
intrinseca | 0:c7beea49fc91 | 616 | bytes[2] = lebytes[5]; |
intrinseca | 0:c7beea49fc91 | 617 | bytes[3] = lebytes[4]; |
intrinseca | 0:c7beea49fc91 | 618 | bytes[4] = lebytes[3]; |
intrinseca | 0:c7beea49fc91 | 619 | bytes[5] = lebytes[2]; |
intrinseca | 0:c7beea49fc91 | 620 | bytes[6] = lebytes[1]; |
intrinseca | 0:c7beea49fc91 | 621 | bytes[7] = lebytes[0]; |
intrinseca | 0:c7beea49fc91 | 622 | return true; |
intrinseca | 0:c7beea49fc91 | 623 | #else |
intrinseca | 0:c7beea49fc91 | 624 | return pb_read(stream, (uint8_t*)dest, 8); |
intrinseca | 0:c7beea49fc91 | 625 | #endif |
intrinseca | 0:c7beea49fc91 | 626 | } |
intrinseca | 0:c7beea49fc91 | 627 | |
intrinseca | 0:c7beea49fc91 | 628 | bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) |
intrinseca | 0:c7beea49fc91 | 629 | { |
intrinseca | 0:c7beea49fc91 | 630 | uint64_t value; |
intrinseca | 0:c7beea49fc91 | 631 | bool status = pb_decode_varint(stream, &value); |
intrinseca | 0:c7beea49fc91 | 632 | |
intrinseca | 0:c7beea49fc91 | 633 | switch (field->data_size) |
intrinseca | 0:c7beea49fc91 | 634 | { |
intrinseca | 0:c7beea49fc91 | 635 | case 1: *(uint8_t*)dest = (uint8_t)value; break; |
intrinseca | 0:c7beea49fc91 | 636 | case 2: *(uint16_t*)dest = (uint16_t)value; break; |
intrinseca | 0:c7beea49fc91 | 637 | case 4: *(uint32_t*)dest = (uint32_t)value; break; |
intrinseca | 0:c7beea49fc91 | 638 | case 8: *(uint64_t*)dest = value; break; |
intrinseca | 0:c7beea49fc91 | 639 | default: PB_RETURN_ERROR(stream, "invalid data_size"); |
intrinseca | 0:c7beea49fc91 | 640 | } |
intrinseca | 0:c7beea49fc91 | 641 | |
intrinseca | 0:c7beea49fc91 | 642 | return status; |
intrinseca | 0:c7beea49fc91 | 643 | } |
intrinseca | 0:c7beea49fc91 | 644 | |
intrinseca | 0:c7beea49fc91 | 645 | bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) |
intrinseca | 0:c7beea49fc91 | 646 | { |
intrinseca | 0:c7beea49fc91 | 647 | int64_t value; |
intrinseca | 0:c7beea49fc91 | 648 | bool status = pb_decode_svarint(stream, &value); |
intrinseca | 0:c7beea49fc91 | 649 | |
intrinseca | 0:c7beea49fc91 | 650 | switch (field->data_size) |
intrinseca | 0:c7beea49fc91 | 651 | { |
intrinseca | 0:c7beea49fc91 | 652 | case 4: *(int32_t*)dest = (int32_t)value; break; |
intrinseca | 0:c7beea49fc91 | 653 | case 8: *(int64_t*)dest = value; break; |
intrinseca | 0:c7beea49fc91 | 654 | default: PB_RETURN_ERROR(stream, "invalid data_size"); |
intrinseca | 0:c7beea49fc91 | 655 | } |
intrinseca | 0:c7beea49fc91 | 656 | |
intrinseca | 0:c7beea49fc91 | 657 | return status; |
intrinseca | 0:c7beea49fc91 | 658 | } |
intrinseca | 0:c7beea49fc91 | 659 | |
intrinseca | 0:c7beea49fc91 | 660 | bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) |
intrinseca | 0:c7beea49fc91 | 661 | { |
intrinseca | 0:c7beea49fc91 | 662 | UNUSED(field); |
intrinseca | 0:c7beea49fc91 | 663 | return pb_decode_fixed32(stream, dest); |
intrinseca | 0:c7beea49fc91 | 664 | } |
intrinseca | 0:c7beea49fc91 | 665 | |
intrinseca | 0:c7beea49fc91 | 666 | bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) |
intrinseca | 0:c7beea49fc91 | 667 | { |
intrinseca | 0:c7beea49fc91 | 668 | UNUSED(field); |
intrinseca | 0:c7beea49fc91 | 669 | return pb_decode_fixed64(stream, dest); |
intrinseca | 0:c7beea49fc91 | 670 | } |
intrinseca | 0:c7beea49fc91 | 671 | |
intrinseca | 0:c7beea49fc91 | 672 | bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) |
intrinseca | 0:c7beea49fc91 | 673 | { |
intrinseca | 0:c7beea49fc91 | 674 | pb_bytes_array_t *x = (pb_bytes_array_t*)dest; |
intrinseca | 0:c7beea49fc91 | 675 | |
intrinseca | 0:c7beea49fc91 | 676 | uint32_t temp; |
intrinseca | 0:c7beea49fc91 | 677 | if (!pb_decode_varint32(stream, &temp)) |
intrinseca | 0:c7beea49fc91 | 678 | return false; |
intrinseca | 0:c7beea49fc91 | 679 | x->size = temp; |
intrinseca | 0:c7beea49fc91 | 680 | |
intrinseca | 0:c7beea49fc91 | 681 | /* Check length, noting the space taken by the size_t header. */ |
intrinseca | 0:c7beea49fc91 | 682 | if (x->size > field->data_size - offsetof(pb_bytes_array_t, bytes)) |
intrinseca | 0:c7beea49fc91 | 683 | PB_RETURN_ERROR(stream, "bytes overflow"); |
intrinseca | 0:c7beea49fc91 | 684 | |
intrinseca | 0:c7beea49fc91 | 685 | return pb_read(stream, x->bytes, x->size); |
intrinseca | 0:c7beea49fc91 | 686 | } |
intrinseca | 0:c7beea49fc91 | 687 | |
intrinseca | 0:c7beea49fc91 | 688 | bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) |
intrinseca | 0:c7beea49fc91 | 689 | { |
intrinseca | 0:c7beea49fc91 | 690 | uint32_t size; |
intrinseca | 0:c7beea49fc91 | 691 | bool status; |
intrinseca | 0:c7beea49fc91 | 692 | if (!pb_decode_varint32(stream, &size)) |
intrinseca | 0:c7beea49fc91 | 693 | return false; |
intrinseca | 0:c7beea49fc91 | 694 | |
intrinseca | 0:c7beea49fc91 | 695 | /* Check length, noting the null terminator */ |
intrinseca | 0:c7beea49fc91 | 696 | if (size + 1 > field->data_size) |
intrinseca | 0:c7beea49fc91 | 697 | PB_RETURN_ERROR(stream, "string overflow"); |
intrinseca | 0:c7beea49fc91 | 698 | |
intrinseca | 0:c7beea49fc91 | 699 | status = pb_read(stream, (uint8_t*)dest, size); |
intrinseca | 0:c7beea49fc91 | 700 | *((uint8_t*)dest + size) = 0; |
intrinseca | 0:c7beea49fc91 | 701 | return status; |
intrinseca | 0:c7beea49fc91 | 702 | } |
intrinseca | 0:c7beea49fc91 | 703 | |
intrinseca | 0:c7beea49fc91 | 704 | bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) |
intrinseca | 0:c7beea49fc91 | 705 | { |
intrinseca | 0:c7beea49fc91 | 706 | bool status; |
intrinseca | 0:c7beea49fc91 | 707 | pb_istream_t substream; |
intrinseca | 0:c7beea49fc91 | 708 | const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr; |
intrinseca | 0:c7beea49fc91 | 709 | |
intrinseca | 0:c7beea49fc91 | 710 | if (!pb_make_string_substream(stream, &substream)) |
intrinseca | 0:c7beea49fc91 | 711 | return false; |
intrinseca | 0:c7beea49fc91 | 712 | |
intrinseca | 0:c7beea49fc91 | 713 | if (field->ptr == NULL) |
intrinseca | 0:c7beea49fc91 | 714 | PB_RETURN_ERROR(stream, "invalid field descriptor"); |
intrinseca | 0:c7beea49fc91 | 715 | |
intrinseca | 0:c7beea49fc91 | 716 | /* New array entries need to be initialized, while required and optional |
intrinseca | 0:c7beea49fc91 | 717 | * submessages have already been initialized in the top-level pb_decode. */ |
intrinseca | 0:c7beea49fc91 | 718 | if (PB_HTYPE(field->type) == PB_HTYPE_ARRAY) |
intrinseca | 0:c7beea49fc91 | 719 | status = pb_decode(&substream, submsg_fields, dest); |
intrinseca | 0:c7beea49fc91 | 720 | else |
intrinseca | 0:c7beea49fc91 | 721 | status = pb_decode_noinit(&substream, submsg_fields, dest); |
intrinseca | 0:c7beea49fc91 | 722 | |
intrinseca | 0:c7beea49fc91 | 723 | pb_close_string_substream(stream, &substream); |
intrinseca | 0:c7beea49fc91 | 724 | return status; |
intrinseca | 0:c7beea49fc91 | 725 | } |