Nanopb is a plain-C implementation of Google's Protocol Buffers data format. It is targeted at 32 bit microcontrollers, but is also fit for other embedded systems with tight (2-10 kB ROM, <1 kB RAM) memory constraints.

Dependents:   FBRLogger Dumb_box_rev2

Uploaded from http://koti.kapsi.fi/~jpa/nanopb/ Original licence included below.

Copyright (c) 2011 Petteri Aimonen <jpa at nanopb.mail.kapsi.fi>

This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.

  1. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
  2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. This notice may not be removed or altered from any source distribution.
Committer:
intrinseca
Date:
Fri Mar 01 12:41:26 2013 +0000
Revision:
1:e08406101222
Parent:
0:c7beea49fc91
fix bugs

Who changed what in which revision?

UserRevisionLine numberNew 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 }