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