Line | Count | Source (jump to first uncovered line) |
1 | | /* pb_encode.c -- encode a protobuf using minimal resources |
2 | | * |
3 | | * 2011 Petteri Aimonen <jpa@kapsi.fi> |
4 | | */ |
5 | | |
6 | | #include "pb.h" |
7 | | #include "pb_encode.h" |
8 | | #include "pb_common.h" |
9 | | |
10 | | /* Use the GCC warn_unused_result attribute to check that all return values |
11 | | * are propagated correctly. On other compilers, gcc before 3.4.0 and iar |
12 | | * before 9.40.1 just ignore the annotation. |
13 | | */ |
14 | | #if (defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))) || \ |
15 | | (defined(__IAR_SYSTEMS_ICC__) && (__VER__ >= 9040001)) |
16 | | #define checkreturn __attribute__((warn_unused_result)) |
17 | | #else |
18 | | #define checkreturn |
19 | | #endif |
20 | | |
21 | | /************************************** |
22 | | * Declarations internal to this file * |
23 | | **************************************/ |
24 | | static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); |
25 | | static bool checkreturn encode_array(pb_ostream_t *stream, pb_field_iter_t *field); |
26 | | static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *field); |
27 | | static bool checkreturn encode_basic_field(pb_ostream_t *stream, const pb_field_iter_t *field); |
28 | | static bool checkreturn encode_callback_field(pb_ostream_t *stream, const pb_field_iter_t *field); |
29 | | static bool checkreturn encode_field(pb_ostream_t *stream, pb_field_iter_t *field); |
30 | | static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field); |
31 | | static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension); |
32 | | static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high); |
33 | | static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_iter_t *field); |
34 | | static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_iter_t *field); |
35 | | static bool checkreturn pb_enc_fixed(pb_ostream_t *stream, const pb_field_iter_t *field); |
36 | | static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t *field); |
37 | | static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_iter_t *field); |
38 | | static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_iter_t *field); |
39 | | static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_iter_t *field); |
40 | | |
41 | | #ifdef PB_WITHOUT_64BIT |
42 | | #define pb_int64_t int32_t |
43 | | #define pb_uint64_t uint32_t |
44 | | #else |
45 | 4.97M | #define pb_int64_t int64_t |
46 | 15.6M | #define pb_uint64_t uint64_t |
47 | | #endif |
48 | | |
49 | | /******************************* |
50 | | * pb_ostream_t implementation * |
51 | | *******************************/ |
52 | | |
53 | | static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) |
54 | 33.0M | { |
55 | 33.0M | pb_byte_t *dest = (pb_byte_t*)stream->state; |
56 | 33.0M | stream->state = dest + count; |
57 | | |
58 | 33.0M | memcpy(dest, buf, count * sizeof(pb_byte_t)); |
59 | | |
60 | 33.0M | return true; |
61 | 33.0M | } |
62 | | |
63 | | pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize) |
64 | 2.89k | { |
65 | 2.89k | pb_ostream_t stream; |
66 | | #ifdef PB_BUFFER_ONLY |
67 | | /* In PB_BUFFER_ONLY configuration the callback pointer is just int*. |
68 | | * NULL pointer marks a sizing field, so put a non-NULL value to mark a buffer stream. |
69 | | */ |
70 | | static const int marker = 0; |
71 | | stream.callback = ▮ |
72 | | #else |
73 | 2.89k | stream.callback = &buf_write; |
74 | 2.89k | #endif |
75 | 2.89k | stream.state = buf; |
76 | 2.89k | stream.max_size = bufsize; |
77 | 2.89k | stream.bytes_written = 0; |
78 | 2.89k | #ifndef PB_NO_ERRMSG |
79 | 2.89k | stream.errmsg = NULL; |
80 | 2.89k | #endif |
81 | 2.89k | return stream; |
82 | 2.89k | } |
83 | | |
84 | | bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) |
85 | 36.4M | { |
86 | 36.4M | if (count > 0 && stream->callback != NULL) |
87 | 33.0M | { |
88 | 33.0M | if (stream->bytes_written + count < stream->bytes_written || |
89 | 33.0M | stream->bytes_written + count > stream->max_size) |
90 | 169 | { |
91 | 169 | PB_RETURN_ERROR(stream, "stream full"); |
92 | 169 | } |
93 | | |
94 | | #ifdef PB_BUFFER_ONLY |
95 | | if (!buf_write(stream, buf, count)) |
96 | | PB_RETURN_ERROR(stream, "io error"); |
97 | | #else |
98 | 33.0M | if (!stream->callback(stream, buf, count)) |
99 | 0 | PB_RETURN_ERROR(stream, "io error"); |
100 | 33.0M | #endif |
101 | 33.0M | } |
102 | | |
103 | 36.4M | stream->bytes_written += count; |
104 | 36.4M | return true; |
105 | 36.4M | } |
106 | | |
107 | | /************************* |
108 | | * Encode a single field * |
109 | | *************************/ |
110 | | |
111 | | /* Read a bool value without causing undefined behavior even if the value |
112 | | * is invalid. See issue #434 and |
113 | | * https://stackoverflow.com/questions/27661768/weird-results-for-conditional |
114 | | */ |
115 | | static bool safe_read_bool(const void *pSize) |
116 | 8.47k | { |
117 | 8.47k | const char *p = (const char *)pSize; |
118 | 8.47k | size_t i; |
119 | 15.3k | for (i = 0; i < sizeof(bool); i++) |
120 | 8.47k | { |
121 | 8.47k | if (p[i] != 0) |
122 | 1.59k | return true; |
123 | 8.47k | } |
124 | 6.88k | return false; |
125 | 8.47k | } |
126 | | |
127 | | /* Encode a static array. Handles the size calculations and possible packing. */ |
128 | | static bool checkreturn encode_array(pb_ostream_t *stream, pb_field_iter_t *field) |
129 | 4.26k | { |
130 | 4.26k | pb_size_t i; |
131 | 4.26k | pb_size_t count; |
132 | 4.26k | #ifndef PB_ENCODE_ARRAYS_UNPACKED |
133 | 4.26k | size_t size; |
134 | 4.26k | #endif |
135 | | |
136 | 4.26k | count = *(pb_size_t*)field->pSize; |
137 | | |
138 | 4.26k | if (count == 0) |
139 | 0 | return true; |
140 | | |
141 | 4.26k | if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) |
142 | 0 | PB_RETURN_ERROR(stream, "array max size exceeded"); |
143 | | |
144 | 4.26k | #ifndef PB_ENCODE_ARRAYS_UNPACKED |
145 | | /* We always pack arrays if the datatype allows it. */ |
146 | 4.26k | if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) |
147 | 1.87k | { |
148 | 1.87k | if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) |
149 | 1 | return false; |
150 | | |
151 | | /* Determine the total size of packed array. */ |
152 | 1.87k | if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32) |
153 | 214 | { |
154 | 214 | size = 4 * (size_t)count; |
155 | 214 | } |
156 | 1.65k | else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64) |
157 | 142 | { |
158 | 142 | size = 8 * (size_t)count; |
159 | 142 | } |
160 | 1.51k | else |
161 | 1.51k | { |
162 | 1.51k | pb_ostream_t sizestream = PB_OSTREAM_SIZING; |
163 | 1.51k | void *pData_orig = field->pData; |
164 | 2.96M | for (i = 0; i < count; i++) |
165 | 2.96M | { |
166 | 2.96M | if (!pb_enc_varint(&sizestream, field)) |
167 | 0 | PB_RETURN_ERROR(stream, PB_GET_ERROR(&sizestream)); |
168 | 2.96M | field->pData = (char*)field->pData + field->data_size; |
169 | 2.96M | } |
170 | 1.51k | field->pData = pData_orig; |
171 | 1.51k | size = sizestream.bytes_written; |
172 | 1.51k | } |
173 | | |
174 | 1.87k | if (!pb_encode_varint(stream, (pb_uint64_t)size)) |
175 | 1 | return false; |
176 | | |
177 | 1.87k | if (stream->callback == NULL) |
178 | 0 | return pb_write(stream, NULL, size); /* Just sizing.. */ |
179 | | |
180 | | /* Write the data */ |
181 | 2.97M | for (i = 0; i < count; i++) |
182 | 2.96M | { |
183 | 2.96M | if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32 || PB_LTYPE(field->type) == PB_LTYPE_FIXED64) |
184 | 9.50k | { |
185 | 9.50k | if (!pb_enc_fixed(stream, field)) |
186 | 3 | return false; |
187 | 9.50k | } |
188 | 2.96M | else |
189 | 2.96M | { |
190 | 2.96M | if (!pb_enc_varint(stream, field)) |
191 | 3 | return false; |
192 | 2.96M | } |
193 | | |
194 | 2.96M | field->pData = (char*)field->pData + field->data_size; |
195 | 2.96M | } |
196 | 1.87k | } |
197 | 2.39k | else /* Unpacked fields */ |
198 | 2.39k | #endif |
199 | 2.39k | { |
200 | 10.0M | for (i = 0; i < count; i++) |
201 | 10.0M | { |
202 | | /* Normally the data is stored directly in the array entries, but |
203 | | * for pointer-type string and bytes fields, the array entries are |
204 | | * actually pointers themselves also. So we have to dereference once |
205 | | * more to get to the actual data. */ |
206 | 10.0M | if (PB_ATYPE(field->type) == PB_ATYPE_POINTER && |
207 | 10.0M | (PB_LTYPE(field->type) == PB_LTYPE_STRING || |
208 | 10.0M | PB_LTYPE(field->type) == PB_LTYPE_BYTES)) |
209 | 222k | { |
210 | 222k | bool status; |
211 | 222k | void *pData_orig = field->pData; |
212 | 222k | field->pData = *(void* const*)field->pData; |
213 | | |
214 | 222k | if (!field->pData) |
215 | 0 | { |
216 | | /* Null pointer in array is treated as empty string / bytes */ |
217 | 0 | status = pb_encode_tag_for_field(stream, field) && |
218 | 0 | pb_encode_varint(stream, 0); |
219 | 0 | } |
220 | 222k | else |
221 | 222k | { |
222 | 222k | status = encode_basic_field(stream, field); |
223 | 222k | } |
224 | | |
225 | 222k | field->pData = pData_orig; |
226 | | |
227 | 222k | if (!status) |
228 | 1 | return false; |
229 | 222k | } |
230 | 9.78M | else |
231 | 9.78M | { |
232 | 9.78M | if (!encode_basic_field(stream, field)) |
233 | 14 | return false; |
234 | 9.78M | } |
235 | 10.0M | field->pData = (char*)field->pData + field->data_size; |
236 | 10.0M | } |
237 | 2.39k | } |
238 | | |
239 | 4.24k | return true; |
240 | 4.26k | } |
241 | | |
242 | | /* In proto3, all fields are optional and are only encoded if their value is "non-zero". |
243 | | * This function implements the check for the zero value. */ |
244 | | static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *field) |
245 | 0 | { |
246 | 0 | pb_type_t type = field->type; |
247 | |
|
248 | 0 | if (PB_ATYPE(type) == PB_ATYPE_STATIC) |
249 | 0 | { |
250 | 0 | if (PB_HTYPE(type) == PB_HTYPE_REQUIRED) |
251 | 0 | { |
252 | | /* Required proto2 fields inside proto3 submessage, pretty rare case */ |
253 | 0 | return false; |
254 | 0 | } |
255 | 0 | else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) |
256 | 0 | { |
257 | | /* Repeated fields inside proto3 submessage: present if count != 0 */ |
258 | 0 | return *(const pb_size_t*)field->pSize == 0; |
259 | 0 | } |
260 | 0 | else if (PB_HTYPE(type) == PB_HTYPE_ONEOF) |
261 | 0 | { |
262 | | /* Oneof fields */ |
263 | 0 | return *(const pb_size_t*)field->pSize == 0; |
264 | 0 | } |
265 | 0 | else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->pSize != NULL) |
266 | 0 | { |
267 | | /* Proto2 optional fields inside proto3 message, or proto3 |
268 | | * submessage fields. */ |
269 | 0 | return safe_read_bool(field->pSize) == false; |
270 | 0 | } |
271 | 0 | else if (field->descriptor->default_value) |
272 | 0 | { |
273 | | /* Proto3 messages do not have default values, but proto2 messages |
274 | | * can contain optional fields without has_fields (generator option 'proto3'). |
275 | | * In this case they must always be encoded, to make sure that the |
276 | | * non-zero default value is overwritten. |
277 | | */ |
278 | 0 | return false; |
279 | 0 | } |
280 | | |
281 | | /* Rest is proto3 singular fields */ |
282 | 0 | if (PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) |
283 | 0 | { |
284 | | /* Simple integer / float fields */ |
285 | 0 | pb_size_t i; |
286 | 0 | const char *p = (const char*)field->pData; |
287 | 0 | for (i = 0; i < field->data_size; i++) |
288 | 0 | { |
289 | 0 | if (p[i] != 0) |
290 | 0 | { |
291 | 0 | return false; |
292 | 0 | } |
293 | 0 | } |
294 | | |
295 | 0 | return true; |
296 | 0 | } |
297 | 0 | else if (PB_LTYPE(type) == PB_LTYPE_BYTES) |
298 | 0 | { |
299 | 0 | const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)field->pData; |
300 | 0 | return bytes->size == 0; |
301 | 0 | } |
302 | 0 | else if (PB_LTYPE(type) == PB_LTYPE_STRING) |
303 | 0 | { |
304 | 0 | return *(const char*)field->pData == '\0'; |
305 | 0 | } |
306 | 0 | else if (PB_LTYPE(type) == PB_LTYPE_FIXED_LENGTH_BYTES) |
307 | 0 | { |
308 | | /* Fixed length bytes is only empty if its length is fixed |
309 | | * as 0. Which would be pretty strange, but we can check |
310 | | * it anyway. */ |
311 | 0 | return field->data_size == 0; |
312 | 0 | } |
313 | 0 | else if (PB_LTYPE_IS_SUBMSG(type)) |
314 | 0 | { |
315 | | /* Check all fields in the submessage to find if any of them |
316 | | * are non-zero. The comparison cannot be done byte-per-byte |
317 | | * because the C struct may contain padding bytes that must |
318 | | * be skipped. Note that usually proto3 submessages have |
319 | | * a separate has_field that is checked earlier in this if. |
320 | | */ |
321 | 0 | pb_field_iter_t iter; |
322 | 0 | if (pb_field_iter_begin(&iter, field->submsg_desc, field->pData)) |
323 | 0 | { |
324 | 0 | do |
325 | 0 | { |
326 | 0 | if (!pb_check_proto3_default_value(&iter)) |
327 | 0 | { |
328 | 0 | return false; |
329 | 0 | } |
330 | 0 | } while (pb_field_iter_next(&iter)); |
331 | 0 | } |
332 | 0 | return true; |
333 | 0 | } |
334 | 0 | } |
335 | 0 | else if (PB_ATYPE(type) == PB_ATYPE_POINTER) |
336 | 0 | { |
337 | 0 | return field->pData == NULL; |
338 | 0 | } |
339 | 0 | else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) |
340 | 0 | { |
341 | 0 | if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) |
342 | 0 | { |
343 | 0 | const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData; |
344 | 0 | return extension == NULL; |
345 | 0 | } |
346 | 0 | else if (field->descriptor->field_callback == pb_default_field_callback) |
347 | 0 | { |
348 | 0 | pb_callback_t *pCallback = (pb_callback_t*)field->pData; |
349 | 0 | return pCallback->funcs.encode == NULL; |
350 | 0 | } |
351 | 0 | else |
352 | 0 | { |
353 | 0 | return field->descriptor->field_callback == NULL; |
354 | 0 | } |
355 | 0 | } |
356 | | |
357 | 0 | return false; /* Not typically reached, safe default for weird special cases. */ |
358 | 0 | } |
359 | | |
360 | | /* Encode a field with static or pointer allocation, i.e. one whose data |
361 | | * is available to the encoder directly. */ |
362 | | static bool checkreturn encode_basic_field(pb_ostream_t *stream, const pb_field_iter_t *field) |
363 | 10.2M | { |
364 | 10.2M | if (!field->pData) |
365 | 0 | { |
366 | | /* Missing pointer field */ |
367 | 0 | return true; |
368 | 0 | } |
369 | | |
370 | 10.2M | if (!pb_encode_tag_for_field(stream, field)) |
371 | 76 | return false; |
372 | | |
373 | 10.2M | switch (PB_LTYPE(field->type)) |
374 | 10.2M | { |
375 | 2.93k | case PB_LTYPE_BOOL: |
376 | 2.93k | return pb_enc_bool(stream, field); |
377 | | |
378 | 104k | case PB_LTYPE_VARINT: |
379 | 146k | case PB_LTYPE_UVARINT: |
380 | 164k | case PB_LTYPE_SVARINT: |
381 | 164k | return pb_enc_varint(stream, field); |
382 | | |
383 | 11.2k | case PB_LTYPE_FIXED32: |
384 | 19.9k | case PB_LTYPE_FIXED64: |
385 | 19.9k | return pb_enc_fixed(stream, field); |
386 | | |
387 | 214k | case PB_LTYPE_BYTES: |
388 | 214k | return pb_enc_bytes(stream, field); |
389 | | |
390 | 48.1k | case PB_LTYPE_STRING: |
391 | 48.1k | return pb_enc_string(stream, field); |
392 | | |
393 | 49.8k | case PB_LTYPE_SUBMESSAGE: |
394 | 49.8k | case PB_LTYPE_SUBMSG_W_CB: |
395 | 49.8k | return pb_enc_submessage(stream, field); |
396 | | |
397 | 9.75M | case PB_LTYPE_FIXED_LENGTH_BYTES: |
398 | 9.75M | return pb_enc_fixed_length_bytes(stream, field); |
399 | | |
400 | 0 | default: |
401 | 0 | PB_RETURN_ERROR(stream, "invalid field type"); |
402 | 10.2M | } |
403 | 10.2M | } |
404 | | |
405 | | /* Encode a field with callback semantics. This means that a user function is |
406 | | * called to provide and encode the actual data. */ |
407 | | static bool checkreturn encode_callback_field(pb_ostream_t *stream, const pb_field_iter_t *field) |
408 | 0 | { |
409 | 0 | if (field->descriptor->field_callback != NULL) |
410 | 0 | { |
411 | 0 | if (!field->descriptor->field_callback(NULL, stream, field)) |
412 | 0 | PB_RETURN_ERROR(stream, "callback error"); |
413 | 0 | } |
414 | 0 | return true; |
415 | 0 | } |
416 | | |
417 | | /* Encode a single field of any callback, pointer or static type. */ |
418 | | static bool checkreturn encode_field(pb_ostream_t *stream, pb_field_iter_t *field) |
419 | 409k | { |
420 | | /* Check field presence */ |
421 | 409k | if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF) |
422 | 8.55k | { |
423 | 8.55k | if (*(const pb_size_t*)field->pSize != field->tag) |
424 | 8.31k | { |
425 | | /* Different type oneof field */ |
426 | 8.31k | return true; |
427 | 8.31k | } |
428 | 8.55k | } |
429 | 400k | else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL) |
430 | 96.3k | { |
431 | 96.3k | if (field->pSize) |
432 | 5.54k | { |
433 | 5.54k | if (safe_read_bool(field->pSize) == false) |
434 | 5.37k | { |
435 | | /* Missing optional field */ |
436 | 5.37k | return true; |
437 | 5.37k | } |
438 | 5.54k | } |
439 | 90.8k | else if (PB_ATYPE(field->type) == PB_ATYPE_STATIC) |
440 | 0 | { |
441 | | /* Proto3 singular field */ |
442 | 0 | if (pb_check_proto3_default_value(field)) |
443 | 0 | return true; |
444 | 0 | } |
445 | 96.3k | } |
446 | | |
447 | 395k | if (!field->pData) |
448 | 143k | { |
449 | 143k | if (PB_HTYPE(field->type) == PB_HTYPE_REQUIRED) |
450 | 0 | PB_RETURN_ERROR(stream, "missing required field"); |
451 | | |
452 | | /* Pointer field set to NULL */ |
453 | 143k | return true; |
454 | 143k | } |
455 | | |
456 | | /* Then encode field contents */ |
457 | 251k | if (PB_ATYPE(field->type) == PB_ATYPE_CALLBACK) |
458 | 0 | { |
459 | 0 | return encode_callback_field(stream, field); |
460 | 0 | } |
461 | 251k | else if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED) |
462 | 4.26k | { |
463 | 4.26k | return encode_array(stream, field); |
464 | 4.26k | } |
465 | 247k | else |
466 | 247k | { |
467 | 247k | return encode_basic_field(stream, field); |
468 | 247k | } |
469 | 251k | } |
470 | | |
471 | | /* Default handler for extension fields. Expects to have a pb_msgdesc_t |
472 | | * pointer in the extension->type->arg field, pointing to a message with |
473 | | * only one field in it. */ |
474 | | static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension) |
475 | 2.80k | { |
476 | 2.80k | pb_field_iter_t iter; |
477 | | |
478 | 2.80k | if (!pb_field_iter_begin_extension_const(&iter, extension)) |
479 | 0 | PB_RETURN_ERROR(stream, "invalid extension"); |
480 | | |
481 | 2.80k | return encode_field(stream, &iter); |
482 | 2.80k | } |
483 | | |
484 | | |
485 | | /* Walk through all the registered extensions and give them a chance |
486 | | * to encode themselves. */ |
487 | | static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field) |
488 | 2.80k | { |
489 | 2.80k | const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData; |
490 | | |
491 | 5.56k | while (extension) |
492 | 2.80k | { |
493 | 2.80k | bool status; |
494 | 2.80k | if (extension->type->encode) |
495 | 0 | status = extension->type->encode(stream, extension); |
496 | 2.80k | else |
497 | 2.80k | status = default_extension_encoder(stream, extension); |
498 | | |
499 | 2.80k | if (!status) |
500 | 41 | return false; |
501 | | |
502 | 2.76k | extension = extension->next; |
503 | 2.76k | } |
504 | | |
505 | 2.76k | return true; |
506 | 2.80k | } |
507 | | |
508 | | /********************* |
509 | | * Encode all fields * |
510 | | *********************/ |
511 | | |
512 | | bool checkreturn pb_encode(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct) |
513 | 102k | { |
514 | 102k | pb_field_iter_t iter; |
515 | 102k | if (!pb_field_iter_begin_const(&iter, fields, src_struct)) |
516 | 43.5k | return true; /* Empty message type */ |
517 | | |
518 | 409k | do { |
519 | 409k | if (PB_LTYPE(iter.type) == PB_LTYPE_EXTENSION) |
520 | 2.80k | { |
521 | | /* Special case for the extension field placeholder */ |
522 | 2.80k | if (!encode_extension_field(stream, &iter)) |
523 | 41 | return false; |
524 | 2.80k | } |
525 | 406k | else |
526 | 406k | { |
527 | | /* Regular field */ |
528 | 406k | if (!encode_field(stream, &iter)) |
529 | 162 | return false; |
530 | 406k | } |
531 | 409k | } while (pb_field_iter_next(&iter)); |
532 | | |
533 | 58.7k | return true; |
534 | 58.9k | } |
535 | | |
536 | | bool checkreturn pb_encode_ex(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct, unsigned int flags) |
537 | 0 | { |
538 | 0 | if ((flags & PB_ENCODE_DELIMITED) != 0) |
539 | 0 | { |
540 | 0 | return pb_encode_submessage(stream, fields, src_struct); |
541 | 0 | } |
542 | 0 | else if ((flags & PB_ENCODE_NULLTERMINATED) != 0) |
543 | 0 | { |
544 | 0 | const pb_byte_t zero = 0; |
545 | |
|
546 | 0 | if (!pb_encode(stream, fields, src_struct)) |
547 | 0 | return false; |
548 | | |
549 | 0 | return pb_write(stream, &zero, 1); |
550 | 0 | } |
551 | 0 | else |
552 | 0 | { |
553 | 0 | return pb_encode(stream, fields, src_struct); |
554 | 0 | } |
555 | 0 | } |
556 | | |
557 | | bool pb_get_encoded_size(size_t *size, const pb_msgdesc_t *fields, const void *src_struct) |
558 | 0 | { |
559 | 0 | pb_ostream_t stream = PB_OSTREAM_SIZING; |
560 | | |
561 | 0 | if (!pb_encode(&stream, fields, src_struct)) |
562 | 0 | return false; |
563 | | |
564 | 0 | *size = stream.bytes_written; |
565 | 0 | return true; |
566 | 0 | } |
567 | | |
568 | | /******************** |
569 | | * Helper functions * |
570 | | ********************/ |
571 | | |
572 | | /* This function avoids 64-bit shifts as they are quite slow on many platforms. */ |
573 | | static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high) |
574 | 11.1M | { |
575 | 11.1M | size_t i = 0; |
576 | 11.1M | pb_byte_t buffer[10]; |
577 | 11.1M | pb_byte_t byte = (pb_byte_t)(low & 0x7F); |
578 | 11.1M | low >>= 7; |
579 | | |
580 | 23.4M | while (i < 4 && (low != 0 || high != 0)) |
581 | 12.3M | { |
582 | 12.3M | byte |= 0x80; |
583 | 12.3M | buffer[i++] = byte; |
584 | 12.3M | byte = (pb_byte_t)(low & 0x7F); |
585 | 12.3M | low >>= 7; |
586 | 12.3M | } |
587 | | |
588 | 11.1M | if (high) |
589 | 335k | { |
590 | 335k | byte = (pb_byte_t)(byte | ((high & 0x07) << 4)); |
591 | 335k | high >>= 3; |
592 | | |
593 | 1.95M | while (high) |
594 | 1.62M | { |
595 | 1.62M | byte |= 0x80; |
596 | 1.62M | buffer[i++] = byte; |
597 | 1.62M | byte = (pb_byte_t)(high & 0x7F); |
598 | 1.62M | high >>= 7; |
599 | 1.62M | } |
600 | 335k | } |
601 | | |
602 | 11.1M | buffer[i++] = byte; |
603 | | |
604 | 11.1M | return pb_write(stream, buffer, i); |
605 | 11.1M | } |
606 | | |
607 | | bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value) |
608 | 26.4M | { |
609 | 26.4M | if (value <= 0x7F) |
610 | 15.2M | { |
611 | | /* Fast path: single byte */ |
612 | 15.2M | pb_byte_t byte = (pb_byte_t)value; |
613 | 15.2M | return pb_write(stream, &byte, 1); |
614 | 15.2M | } |
615 | 11.1M | else |
616 | 11.1M | { |
617 | | #ifdef PB_WITHOUT_64BIT |
618 | | return pb_encode_varint_32(stream, value, 0); |
619 | | #else |
620 | 11.1M | return pb_encode_varint_32(stream, (uint32_t)value, (uint32_t)(value >> 32)); |
621 | 11.1M | #endif |
622 | 11.1M | } |
623 | 26.4M | } |
624 | | |
625 | | bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value) |
626 | 2.14M | { |
627 | 2.14M | pb_uint64_t zigzagged; |
628 | 2.14M | pb_uint64_t mask = ((pb_uint64_t)-1) >> 1; /* Satisfy clang -fsanitize=integer */ |
629 | 2.14M | if (value < 0) |
630 | 270k | zigzagged = ~(((pb_uint64_t)value & mask) << 1); |
631 | 1.87M | else |
632 | 1.87M | zigzagged = (pb_uint64_t)value << 1; |
633 | | |
634 | 2.14M | return pb_encode_varint(stream, zigzagged); |
635 | 2.14M | } |
636 | | |
637 | | bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value) |
638 | 17.5k | { |
639 | | #if defined(PB_LITTLE_ENDIAN_8BIT) && PB_LITTLE_ENDIAN_8BIT == 1 |
640 | | /* Fast path if we know that we're on little endian */ |
641 | | return pb_write(stream, (const pb_byte_t*)value, 4); |
642 | | #else |
643 | 17.5k | uint32_t val = *(const uint32_t*)value; |
644 | 17.5k | pb_byte_t bytes[4]; |
645 | 17.5k | bytes[0] = (pb_byte_t)(val & 0xFF); |
646 | 17.5k | bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); |
647 | 17.5k | bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); |
648 | 17.5k | bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); |
649 | 17.5k | return pb_write(stream, bytes, 4); |
650 | 17.5k | #endif |
651 | 17.5k | } |
652 | | |
653 | | #ifndef PB_WITHOUT_64BIT |
654 | | bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value) |
655 | 11.9k | { |
656 | | #if defined(PB_LITTLE_ENDIAN_8BIT) && PB_LITTLE_ENDIAN_8BIT == 1 |
657 | | /* Fast path if we know that we're on little endian */ |
658 | | return pb_write(stream, (const pb_byte_t*)value, 8); |
659 | | #else |
660 | 11.9k | uint64_t val = *(const uint64_t*)value; |
661 | 11.9k | pb_byte_t bytes[8]; |
662 | 11.9k | bytes[0] = (pb_byte_t)(val & 0xFF); |
663 | 11.9k | bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); |
664 | 11.9k | bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); |
665 | 11.9k | bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); |
666 | 11.9k | bytes[4] = (pb_byte_t)((val >> 32) & 0xFF); |
667 | 11.9k | bytes[5] = (pb_byte_t)((val >> 40) & 0xFF); |
668 | 11.9k | bytes[6] = (pb_byte_t)((val >> 48) & 0xFF); |
669 | 11.9k | bytes[7] = (pb_byte_t)((val >> 56) & 0xFF); |
670 | 11.9k | return pb_write(stream, bytes, 8); |
671 | 11.9k | #endif |
672 | 11.9k | } |
673 | | #endif |
674 | | |
675 | | bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) |
676 | 10.2M | { |
677 | 10.2M | pb_uint64_t tag = ((pb_uint64_t)field_number << 3) | wiretype; |
678 | 10.2M | return pb_encode_varint(stream, tag); |
679 | 10.2M | } |
680 | | |
681 | | bool pb_encode_tag_for_field ( pb_ostream_t* stream, const pb_field_iter_t* field ) |
682 | 10.2M | { |
683 | 10.2M | pb_wire_type_t wiretype; |
684 | 10.2M | switch (PB_LTYPE(field->type)) |
685 | 10.2M | { |
686 | 2.93k | case PB_LTYPE_BOOL: |
687 | 107k | case PB_LTYPE_VARINT: |
688 | 149k | case PB_LTYPE_UVARINT: |
689 | 167k | case PB_LTYPE_SVARINT: |
690 | 167k | wiretype = PB_WT_VARINT; |
691 | 167k | break; |
692 | | |
693 | 11.2k | case PB_LTYPE_FIXED32: |
694 | 11.2k | wiretype = PB_WT_32BIT; |
695 | 11.2k | break; |
696 | | |
697 | 8.77k | case PB_LTYPE_FIXED64: |
698 | 8.77k | wiretype = PB_WT_64BIT; |
699 | 8.77k | break; |
700 | | |
701 | 214k | case PB_LTYPE_BYTES: |
702 | 262k | case PB_LTYPE_STRING: |
703 | 312k | case PB_LTYPE_SUBMESSAGE: |
704 | 312k | case PB_LTYPE_SUBMSG_W_CB: |
705 | 10.0M | case PB_LTYPE_FIXED_LENGTH_BYTES: |
706 | 10.0M | wiretype = PB_WT_STRING; |
707 | 10.0M | break; |
708 | | |
709 | 0 | default: |
710 | 0 | PB_RETURN_ERROR(stream, "invalid field type"); |
711 | 10.2M | } |
712 | | |
713 | 10.2M | return pb_encode_tag(stream, wiretype, field->tag); |
714 | 10.2M | } |
715 | | |
716 | | bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size) |
717 | 10.0M | { |
718 | 10.0M | if (!pb_encode_varint(stream, (pb_uint64_t)size)) |
719 | 5 | return false; |
720 | | |
721 | 10.0M | return pb_write(stream, buffer, size); |
722 | 10.0M | } |
723 | | |
724 | | bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct) |
725 | 49.8k | { |
726 | | /* First calculate the message size using a non-writing substream. */ |
727 | 49.8k | pb_ostream_t substream = PB_OSTREAM_SIZING; |
728 | 49.8k | size_t size; |
729 | 49.8k | bool status; |
730 | | |
731 | 49.8k | if (!pb_encode(&substream, fields, src_struct)) |
732 | 0 | { |
733 | 0 | #ifndef PB_NO_ERRMSG |
734 | 0 | stream->errmsg = substream.errmsg; |
735 | 0 | #endif |
736 | 0 | return false; |
737 | 0 | } |
738 | | |
739 | 49.8k | size = substream.bytes_written; |
740 | | |
741 | 49.8k | if (!pb_encode_varint(stream, (pb_uint64_t)size)) |
742 | 22 | return false; |
743 | | |
744 | 49.8k | if (stream->callback == NULL) |
745 | 0 | return pb_write(stream, NULL, size); /* Just sizing */ |
746 | | |
747 | 49.8k | if (stream->bytes_written + size > stream->max_size) |
748 | 34 | PB_RETURN_ERROR(stream, "stream full"); |
749 | | |
750 | | /* Use a substream to verify that a callback doesn't write more than |
751 | | * what it did the first time. */ |
752 | 49.7k | substream.callback = stream->callback; |
753 | 49.7k | substream.state = stream->state; |
754 | 49.7k | substream.max_size = size; |
755 | 49.7k | substream.bytes_written = 0; |
756 | 49.7k | #ifndef PB_NO_ERRMSG |
757 | 49.7k | substream.errmsg = NULL; |
758 | 49.7k | #endif |
759 | | |
760 | 49.7k | status = pb_encode(&substream, fields, src_struct); |
761 | | |
762 | 49.7k | stream->bytes_written += substream.bytes_written; |
763 | 49.7k | stream->state = substream.state; |
764 | 49.7k | #ifndef PB_NO_ERRMSG |
765 | 49.7k | stream->errmsg = substream.errmsg; |
766 | 49.7k | #endif |
767 | | |
768 | 49.7k | if (substream.bytes_written != size) |
769 | 0 | PB_RETURN_ERROR(stream, "submsg size changed"); |
770 | | |
771 | 49.7k | return status; |
772 | 49.7k | } |
773 | | |
774 | | /* Field encoders */ |
775 | | |
776 | | static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_iter_t *field) |
777 | 2.93k | { |
778 | 2.93k | uint32_t value = safe_read_bool(field->pData) ? 1 : 0; |
779 | 2.93k | PB_UNUSED(field); |
780 | 2.93k | return pb_encode_varint(stream, value); |
781 | 2.93k | } |
782 | | |
783 | | static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_iter_t *field) |
784 | 6.08M | { |
785 | 6.08M | if (PB_LTYPE(field->type) == PB_LTYPE_UVARINT) |
786 | 1.11M | { |
787 | | /* Perform unsigned integer extension */ |
788 | 1.11M | pb_uint64_t value = 0; |
789 | | |
790 | 1.11M | if (field->data_size == sizeof(uint_least8_t)) |
791 | 5.68k | value = *(const uint_least8_t*)field->pData; |
792 | 1.10M | else if (field->data_size == sizeof(uint_least16_t)) |
793 | 5.68k | value = *(const uint_least16_t*)field->pData; |
794 | 1.10M | else if (field->data_size == sizeof(uint32_t)) |
795 | 675k | value = *(const uint32_t*)field->pData; |
796 | 426k | else if (field->data_size == sizeof(pb_uint64_t)) |
797 | 426k | value = *(const pb_uint64_t*)field->pData; |
798 | 0 | else |
799 | 0 | PB_RETURN_ERROR(stream, "invalid data_size"); |
800 | | |
801 | 1.11M | return pb_encode_varint(stream, value); |
802 | 1.11M | } |
803 | 4.97M | else |
804 | 4.97M | { |
805 | | /* Perform signed integer extension */ |
806 | 4.97M | pb_int64_t value = 0; |
807 | | |
808 | 4.97M | if (field->data_size == sizeof(int_least8_t)) |
809 | 2.03M | value = *(const int_least8_t*)field->pData; |
810 | 2.93M | else if (field->data_size == sizeof(int_least16_t)) |
811 | 11.3k | value = *(const int_least16_t*)field->pData; |
812 | 2.92M | else if (field->data_size == sizeof(int32_t)) |
813 | 690k | value = *(const int32_t*)field->pData; |
814 | 2.23M | else if (field->data_size == sizeof(pb_int64_t)) |
815 | 2.23M | value = *(const pb_int64_t*)field->pData; |
816 | 0 | else |
817 | 0 | PB_RETURN_ERROR(stream, "invalid data_size"); |
818 | | |
819 | 4.97M | if (PB_LTYPE(field->type) == PB_LTYPE_SVARINT) |
820 | 2.14M | return pb_encode_svarint(stream, value); |
821 | | #ifdef PB_WITHOUT_64BIT |
822 | | else if (value < 0) |
823 | | return pb_encode_varint_32(stream, (uint32_t)value, (uint32_t)-1); |
824 | | #endif |
825 | 2.82M | else |
826 | 2.82M | return pb_encode_varint(stream, (pb_uint64_t)value); |
827 | | |
828 | 4.97M | } |
829 | 6.08M | } |
830 | | |
831 | | static bool checkreturn pb_enc_fixed(pb_ostream_t *stream, const pb_field_iter_t *field) |
832 | 29.5k | { |
833 | | #ifdef PB_CONVERT_DOUBLE_FLOAT |
834 | | if (field->data_size == sizeof(float) && PB_LTYPE(field->type) == PB_LTYPE_FIXED64) |
835 | | { |
836 | | return pb_encode_float_as_double(stream, *(float*)field->pData); |
837 | | } |
838 | | #endif |
839 | | |
840 | 29.5k | if (field->data_size == sizeof(uint32_t)) |
841 | 17.5k | { |
842 | 17.5k | return pb_encode_fixed32(stream, field->pData); |
843 | 17.5k | } |
844 | 11.9k | #ifndef PB_WITHOUT_64BIT |
845 | 11.9k | else if (field->data_size == sizeof(uint64_t)) |
846 | 11.9k | { |
847 | 11.9k | return pb_encode_fixed64(stream, field->pData); |
848 | 11.9k | } |
849 | 0 | #endif |
850 | 0 | else |
851 | 0 | { |
852 | 0 | PB_RETURN_ERROR(stream, "invalid data_size"); |
853 | 0 | } |
854 | 29.5k | } |
855 | | |
856 | | static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t *field) |
857 | 214k | { |
858 | 214k | const pb_bytes_array_t *bytes = NULL; |
859 | | |
860 | 214k | bytes = (const pb_bytes_array_t*)field->pData; |
861 | | |
862 | 214k | if (bytes == NULL) |
863 | 0 | { |
864 | | /* Treat null pointer as an empty bytes field */ |
865 | 0 | return pb_encode_string(stream, NULL, 0); |
866 | 0 | } |
867 | | |
868 | 214k | if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && |
869 | 214k | bytes->size > field->data_size - offsetof(pb_bytes_array_t, bytes)) |
870 | 0 | { |
871 | 0 | PB_RETURN_ERROR(stream, "bytes size exceeded"); |
872 | 0 | } |
873 | | |
874 | 214k | return pb_encode_string(stream, bytes->bytes, (size_t)bytes->size); |
875 | 214k | } |
876 | | |
877 | | static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_iter_t *field) |
878 | 48.1k | { |
879 | 48.1k | size_t size = 0; |
880 | 48.1k | size_t max_size = (size_t)field->data_size; |
881 | 48.1k | const char *str = (const char*)field->pData; |
882 | | |
883 | 48.1k | if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) |
884 | 48.0k | { |
885 | 48.0k | max_size = (size_t)-1; |
886 | 48.0k | } |
887 | 172 | else |
888 | 172 | { |
889 | | /* pb_dec_string() assumes string fields end with a null |
890 | | * terminator when the type isn't PB_ATYPE_POINTER, so we |
891 | | * shouldn't allow more than max-1 bytes to be written to |
892 | | * allow space for the null terminator. |
893 | | */ |
894 | 172 | if (max_size == 0) |
895 | 0 | PB_RETURN_ERROR(stream, "zero-length string"); |
896 | | |
897 | 172 | max_size -= 1; |
898 | 172 | } |
899 | | |
900 | | |
901 | 48.1k | if (str == NULL) |
902 | 0 | { |
903 | 0 | size = 0; /* Treat null pointer as an empty string */ |
904 | 0 | } |
905 | 48.1k | else |
906 | 48.1k | { |
907 | 48.1k | const char *p = str; |
908 | | |
909 | | /* strnlen() is not always available, so just use a loop */ |
910 | 702k | while (size < max_size && *p != '\0') |
911 | 654k | { |
912 | 654k | size++; |
913 | 654k | p++; |
914 | 654k | } |
915 | | |
916 | 48.1k | if (*p != '\0') |
917 | 0 | { |
918 | 0 | PB_RETURN_ERROR(stream, "unterminated string"); |
919 | 0 | } |
920 | 48.1k | } |
921 | | |
922 | | #ifdef PB_VALIDATE_UTF8 |
923 | | if (!pb_validate_utf8(str)) |
924 | | PB_RETURN_ERROR(stream, "invalid utf8"); |
925 | | #endif |
926 | | |
927 | 48.1k | return pb_encode_string(stream, (const pb_byte_t*)str, size); |
928 | 48.1k | } |
929 | | |
930 | | static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_iter_t *field) |
931 | 49.8k | { |
932 | 49.8k | if (field->submsg_desc == NULL) |
933 | 0 | PB_RETURN_ERROR(stream, "invalid field descriptor"); |
934 | | |
935 | 49.8k | if (PB_LTYPE(field->type) == PB_LTYPE_SUBMSG_W_CB && field->pSize != NULL) |
936 | 0 | { |
937 | | /* Message callback is stored right before pSize. */ |
938 | 0 | pb_callback_t *callback = (pb_callback_t*)field->pSize - 1; |
939 | 0 | if (callback->funcs.encode) |
940 | 0 | { |
941 | 0 | if (!callback->funcs.encode(stream, field, &callback->arg)) |
942 | 0 | return false; |
943 | 0 | } |
944 | 0 | } |
945 | | |
946 | 49.8k | return pb_encode_submessage(stream, field->submsg_desc, field->pData); |
947 | 49.8k | } |
948 | | |
949 | | static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_iter_t *field) |
950 | 9.75M | { |
951 | 9.75M | return pb_encode_string(stream, (const pb_byte_t*)field->pData, (size_t)field->data_size); |
952 | 9.75M | } |
953 | | |
954 | | #ifdef PB_CONVERT_DOUBLE_FLOAT |
955 | | bool pb_encode_float_as_double(pb_ostream_t *stream, float value) |
956 | | { |
957 | | union { float f; uint32_t i; } in; |
958 | | uint_least8_t sign; |
959 | | int exponent; |
960 | | uint64_t mantissa; |
961 | | |
962 | | in.f = value; |
963 | | |
964 | | /* Decompose input value */ |
965 | | sign = (uint_least8_t)((in.i >> 31) & 1); |
966 | | exponent = (int)((in.i >> 23) & 0xFF) - 127; |
967 | | mantissa = in.i & 0x7FFFFF; |
968 | | |
969 | | if (exponent == 128) |
970 | | { |
971 | | /* Special value (NaN etc.) */ |
972 | | exponent = 1024; |
973 | | } |
974 | | else if (exponent == -127) |
975 | | { |
976 | | if (!mantissa) |
977 | | { |
978 | | /* Zero */ |
979 | | exponent = -1023; |
980 | | } |
981 | | else |
982 | | { |
983 | | /* Denormalized */ |
984 | | mantissa <<= 1; |
985 | | while (!(mantissa & 0x800000)) |
986 | | { |
987 | | mantissa <<= 1; |
988 | | exponent--; |
989 | | } |
990 | | mantissa &= 0x7FFFFF; |
991 | | } |
992 | | } |
993 | | |
994 | | /* Combine fields */ |
995 | | mantissa <<= 29; |
996 | | mantissa |= (uint64_t)(exponent + 1023) << 52; |
997 | | mantissa |= (uint64_t)sign << 63; |
998 | | |
999 | | return pb_encode_fixed64(stream, &mantissa); |
1000 | | } |
1001 | | #endif |