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