2 * Copyright (c) 2008-2014, Dave Benson and the protobuf-c authors.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * Support library for `protoc-c` generated code.
33 * This file implements the public API used by the code generated
36 * \authors Dave Benson and the protobuf-c authors
38 * \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license.
42 * \todo 64-BIT OPTIMIZATION: certain implementations use 32-bit math
43 * even on 64-bit platforms (uint64_size, uint64_pack, parse_uint64).
45 * \todo Use size_t consistently.
48 #include <stdlib.h> /* for malloc, free */
49 #include <string.h> /* for strcmp, strlen, memcpy, memmove, memset */
51 /* Pull WORDS_BIGENDIAN etc */
54 #include "protobuf-c.h"
59 #define PROTOBUF_C__ASSERT_NOT_REACHED() assert(0)
61 /* Workaround for Microsoft compilers. */
63 # define inline __inline
67 * \defgroup internal Internal functions and macros
69 * These are not exported by the library but are useful to developers working
70 * on `libprotobuf-c` itself.
74 * \defgroup macros Utility macros for manipulating structures
76 * Macros and constants used to manipulate the base "classes" generated by
77 * `protobuf-c`. They also define limits and check correctness.
83 /** The maximum length of a 64-bit integer in varint encoding. */
84 #define MAX_UINT64_ENCODED_SIZE 10
86 #ifndef PROTOBUF_C_UNPACK_ERROR
87 # define PROTOBUF_C_UNPACK_ERROR(...)
91 * Internal `ProtobufCMessage` manipulation macro.
93 * Base macro for manipulating a `ProtobufCMessage`. Used by STRUCT_MEMBER() and
94 * STRUCT_MEMBER_PTR().
96 #define STRUCT_MEMBER_P(struct_p, struct_offset) \
97 ((void *) ((uint8_t *) (struct_p) + (struct_offset)))
100 * Return field in a `ProtobufCMessage` based on offset.
102 * Take a pointer to a `ProtobufCMessage` and find the field at the offset.
103 * Cast it to the passed type.
105 #define STRUCT_MEMBER(member_type, struct_p, struct_offset) \
106 (*(member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset)))
109 * Return field in a `ProtobufCMessage` based on offset.
111 * Take a pointer to a `ProtobufCMessage` and find the field at the offset. Cast
112 * it to a pointer to the passed type.
114 #define STRUCT_MEMBER_PTR(member_type, struct_p, struct_offset) \
115 ((member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset)))
117 /* Assertions for magic numbers. */
119 #define ASSERT_IS_ENUM_DESCRIPTOR(desc) \
120 assert((desc)->magic == PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC)
122 #define ASSERT_IS_MESSAGE_DESCRIPTOR(desc) \
123 assert((desc)->magic == PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC)
125 #define ASSERT_IS_MESSAGE(message) \
126 ASSERT_IS_MESSAGE_DESCRIPTOR((message)->descriptor)
128 #define ASSERT_IS_SERVICE_DESCRIPTOR(desc) \
129 assert((desc)->magic == PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC)
133 /* --- version --- */
136 protobuf_c_version(void)
138 return PROTOBUF_C_VERSION
;
142 protobuf_c_version_number(void)
144 return PROTOBUF_C_VERSION_NUMBER
;
147 /* --- allocator --- */
150 system_alloc(void *allocator_data
, size_t size
)
156 system_free(void *allocator_data
, void *data
)
162 do_alloc(ProtobufCAllocator
*allocator
, size_t size
)
164 return allocator
->alloc(allocator
->allocator_data
, size
);
168 do_free(ProtobufCAllocator
*allocator
, void *data
)
171 allocator
->free(allocator
->allocator_data
, data
);
175 * This allocator uses the system's malloc() and free(). It is the default
176 * allocator used if NULL is passed as the ProtobufCAllocator to an exported
179 static ProtobufCAllocator protobuf_c__allocator
= {
180 .alloc
= &system_alloc
,
181 .free
= &system_free
,
182 .allocator_data
= NULL
,
185 /* === buffer-simple === */
188 protobuf_c_buffer_simple_append(ProtobufCBuffer
*buffer
,
189 size_t len
, const uint8_t *data
)
191 ProtobufCBufferSimple
*simp
= (ProtobufCBufferSimple
*) buffer
;
192 size_t new_len
= simp
->len
+ len
;
194 if (new_len
> simp
->alloced
) {
195 ProtobufCAllocator
*allocator
= simp
->allocator
;
196 size_t new_alloced
= simp
->alloced
* 2;
199 if (allocator
== NULL
)
200 allocator
= &protobuf_c__allocator
;
201 while (new_alloced
< new_len
)
202 new_alloced
+= new_alloced
;
203 new_data
= do_alloc(allocator
, new_alloced
);
206 memcpy(new_data
, simp
->data
, simp
->len
);
207 if (simp
->must_free_data
)
208 do_free(allocator
, simp
->data
);
210 simp
->must_free_data
= TRUE
;
211 simp
->data
= new_data
;
212 simp
->alloced
= new_alloced
;
214 memcpy(simp
->data
+ simp
->len
, data
, len
);
219 * \defgroup packedsz protobuf_c_message_get_packed_size() implementation
221 * Routines mainly used by protobuf_c_message_get_packed_size().
228 * Return the number of bytes required to store the tag for the field. Includes
229 * 3 bits for the wire-type, and a single bit that denotes the end-of-tag.
232 * Field tag to encode.
234 * Number of bytes required.
237 get_tag_size(unsigned number
)
239 if (number
< (1 << 4)) {
241 } else if (number
< (1 << 11)) {
243 } else if (number
< (1 << 18)) {
245 } else if (number
< (1 << 25)) {
253 * Return the number of bytes required to store a variable-length unsigned
254 * 32-bit integer in base-128 varint encoding.
259 * Number of bytes required.
262 uint32_size(uint32_t v
)
266 } else if (v
< (1 << 14)) {
268 } else if (v
< (1 << 21)) {
270 } else if (v
< (1 << 28)) {
278 * Return the number of bytes required to store a variable-length signed 32-bit
279 * integer in base-128 varint encoding.
284 * Number of bytes required.
287 int32_size(int32_t v
)
291 } else if (v
< (1 << 7)) {
293 } else if (v
< (1 << 14)) {
295 } else if (v
< (1 << 21)) {
297 } else if (v
< (1 << 28)) {
305 * Return the ZigZag-encoded 32-bit unsigned integer form of a 32-bit signed
311 * ZigZag encoded integer.
313 static inline uint32_t
317 return ((uint32_t) (-v
)) * 2 - 1;
323 * Return the number of bytes required to store a signed 32-bit integer,
324 * converted to an unsigned 32-bit integer with ZigZag encoding, using base-128
330 * Number of bytes required.
333 sint32_size(int32_t v
)
335 return uint32_size(zigzag32(v
));
339 * Return the number of bytes required to store a 64-bit unsigned integer in
340 * base-128 varint encoding.
345 * Number of bytes required.
348 uint64_size(uint64_t v
)
350 uint32_t upper_v
= (uint32_t) (v
>> 32);
353 return uint32_size((uint32_t) v
);
354 } else if (upper_v
< (1 << 3)) {
356 } else if (upper_v
< (1 << 10)) {
358 } else if (upper_v
< (1 << 17)) {
360 } else if (upper_v
< (1 << 24)) {
362 } else if (upper_v
< (1U << 31)) {
370 * Return the ZigZag-encoded 64-bit unsigned integer form of a 64-bit signed
376 * ZigZag encoded integer.
378 static inline uint64_t
382 return ((uint64_t) (-v
)) * 2 - 1;
388 * Return the number of bytes required to store a signed 64-bit integer,
389 * converted to an unsigned 64-bit integer with ZigZag encoding, using base-128
395 * Number of bytes required.
398 sint64_size(int64_t v
)
400 return uint64_size(zigzag64(v
));
404 * Calculate the serialized size of a single required message field, including
405 * the space needed by the preceding tag.
408 * Field descriptor for member.
412 * Number of bytes required.
415 required_field_get_packed_size(const ProtobufCFieldDescriptor
*field
,
418 size_t rv
= get_tag_size(field
->id
);
420 switch (field
->type
) {
421 case PROTOBUF_C_TYPE_SINT32
:
422 return rv
+ sint32_size(*(const int32_t *) member
);
423 case PROTOBUF_C_TYPE_INT32
:
424 return rv
+ int32_size(*(const uint32_t *) member
);
425 case PROTOBUF_C_TYPE_UINT32
:
426 return rv
+ uint32_size(*(const uint32_t *) member
);
427 case PROTOBUF_C_TYPE_SINT64
:
428 return rv
+ sint64_size(*(const int64_t *) member
);
429 case PROTOBUF_C_TYPE_INT64
:
430 case PROTOBUF_C_TYPE_UINT64
:
431 return rv
+ uint64_size(*(const uint64_t *) member
);
432 case PROTOBUF_C_TYPE_SFIXED32
:
433 case PROTOBUF_C_TYPE_FIXED32
:
435 case PROTOBUF_C_TYPE_SFIXED64
:
436 case PROTOBUF_C_TYPE_FIXED64
:
438 case PROTOBUF_C_TYPE_BOOL
:
440 case PROTOBUF_C_TYPE_FLOAT
:
442 case PROTOBUF_C_TYPE_DOUBLE
:
444 case PROTOBUF_C_TYPE_ENUM
:
445 /* \todo Is this correct for negative-valued enums? */
446 return rv
+ uint32_size(*(const uint32_t *) member
);
447 case PROTOBUF_C_TYPE_STRING
: {
448 const char *str
= *(char * const *) member
;
449 size_t len
= str
? strlen(str
) : 0;
450 return rv
+ uint32_size(len
) + len
;
452 case PROTOBUF_C_TYPE_BYTES
: {
453 size_t len
= ((const ProtobufCBinaryData
*) member
)->len
;
454 return rv
+ uint32_size(len
) + len
;
456 case PROTOBUF_C_TYPE_MESSAGE
: {
457 const ProtobufCMessage
*msg
= *(ProtobufCMessage
* const *) member
;
458 size_t subrv
= msg
? protobuf_c_message_get_packed_size(msg
) : 0;
459 return rv
+ uint32_size(subrv
) + subrv
;
462 PROTOBUF_C__ASSERT_NOT_REACHED();
467 * Calculate the serialized size of a single optional message field, including
468 * the space needed by the preceding tag. Returns 0 if the optional field isn't
472 * Field descriptor for member.
474 * True if the field exists, false if not.
478 * Number of bytes required.
481 optional_field_get_packed_size(const ProtobufCFieldDescriptor
*field
,
482 const protobuf_c_boolean
*has
,
485 if (field
->type
== PROTOBUF_C_TYPE_MESSAGE
||
486 field
->type
== PROTOBUF_C_TYPE_STRING
)
488 const void *ptr
= *(const void * const *) member
;
489 if (ptr
== NULL
|| ptr
== field
->default_value
)
495 return required_field_get_packed_size(field
, member
);
499 * Calculate the serialized size of repeated message fields, which may consist
500 * of any number of values (including 0). Includes the space needed by the
501 * preceding tags (as needed).
504 * Field descriptor for member.
506 * Number of repeated field members.
510 * Number of bytes required.
513 repeated_field_get_packed_size(const ProtobufCFieldDescriptor
*field
,
514 size_t count
, const void *member
)
519 void *array
= *(void * const *) member
;
523 header_size
= get_tag_size(field
->id
);
524 if (0 == (field
->flags
& PROTOBUF_C_FIELD_FLAG_PACKED
))
525 header_size
*= count
;
527 switch (field
->type
) {
528 case PROTOBUF_C_TYPE_SINT32
:
529 for (i
= 0; i
< count
; i
++)
530 rv
+= sint32_size(((int32_t *) array
)[i
]);
532 case PROTOBUF_C_TYPE_INT32
:
533 for (i
= 0; i
< count
; i
++)
534 rv
+= int32_size(((uint32_t *) array
)[i
]);
536 case PROTOBUF_C_TYPE_UINT32
:
537 case PROTOBUF_C_TYPE_ENUM
:
538 for (i
= 0; i
< count
; i
++)
539 rv
+= uint32_size(((uint32_t *) array
)[i
]);
541 case PROTOBUF_C_TYPE_SINT64
:
542 for (i
= 0; i
< count
; i
++)
543 rv
+= sint64_size(((int64_t *) array
)[i
]);
545 case PROTOBUF_C_TYPE_INT64
:
546 case PROTOBUF_C_TYPE_UINT64
:
547 for (i
= 0; i
< count
; i
++)
548 rv
+= uint64_size(((uint64_t *) array
)[i
]);
550 case PROTOBUF_C_TYPE_SFIXED32
:
551 case PROTOBUF_C_TYPE_FIXED32
:
552 case PROTOBUF_C_TYPE_FLOAT
:
555 case PROTOBUF_C_TYPE_SFIXED64
:
556 case PROTOBUF_C_TYPE_FIXED64
:
557 case PROTOBUF_C_TYPE_DOUBLE
:
560 case PROTOBUF_C_TYPE_BOOL
:
563 case PROTOBUF_C_TYPE_STRING
:
564 for (i
= 0; i
< count
; i
++) {
565 size_t len
= strlen(((char **) array
)[i
]);
566 rv
+= uint32_size(len
) + len
;
569 case PROTOBUF_C_TYPE_BYTES
:
570 for (i
= 0; i
< count
; i
++) {
571 size_t len
= ((ProtobufCBinaryData
*) array
)[i
].len
;
572 rv
+= uint32_size(len
) + len
;
575 case PROTOBUF_C_TYPE_MESSAGE
:
576 for (i
= 0; i
< count
; i
++) {
577 size_t len
= protobuf_c_message_get_packed_size(
578 ((ProtobufCMessage
**) array
)[i
]);
579 rv
+= uint32_size(len
) + len
;
584 if (0 != (field
->flags
& PROTOBUF_C_FIELD_FLAG_PACKED
))
585 header_size
+= uint32_size(rv
);
586 return header_size
+ rv
;
590 * Calculate the serialized size of an unknown field, i.e. one that is passed
591 * through mostly uninterpreted. This is required for forward compatibility if
592 * new fields are added to the message descriptor.
595 * Unknown field type.
597 * Number of bytes required.
600 unknown_field_get_packed_size(const ProtobufCMessageUnknownField
*field
)
602 return get_tag_size(field
->tag
) + field
->len
;
608 * Calculate the serialized size of the message.
610 size_t protobuf_c_message_get_packed_size(const ProtobufCMessage
*message
)
615 ASSERT_IS_MESSAGE(message
);
616 for (i
= 0; i
< message
->descriptor
->n_fields
; i
++) {
617 const ProtobufCFieldDescriptor
*field
=
618 message
->descriptor
->fields
+ i
;
620 ((const char *) message
) + field
->offset
;
621 const void *qmember
=
622 ((const char *) message
) + field
->quantifier_offset
;
624 if (field
->label
== PROTOBUF_C_LABEL_REQUIRED
) {
625 rv
+= required_field_get_packed_size(field
, member
);
626 } else if (field
->label
== PROTOBUF_C_LABEL_OPTIONAL
) {
627 rv
+= optional_field_get_packed_size(field
, qmember
, member
);
629 rv
+= repeated_field_get_packed_size(
631 *(const size_t *) qmember
,
636 for (i
= 0; i
< message
->n_unknown_fields
; i
++)
637 rv
+= unknown_field_get_packed_size(&message
->unknown_fields
[i
]);
642 * \defgroup pack protobuf_c_message_pack() implementation
644 * Routines mainly used by protobuf_c_message_pack().
651 * Pack an unsigned 32-bit integer in base-128 varint encoding and return the
652 * number of bytes written, which must be 5 or less.
659 * Number of bytes written to `out`.
662 uint32_pack(uint32_t value
, uint8_t *out
)
667 out
[rv
++] = value
| 0x80;
670 out
[rv
++] = value
| 0x80;
673 out
[rv
++] = value
| 0x80;
676 out
[rv
++] = value
| 0x80;
682 /* assert: value<128 */
688 * Pack a signed 32-bit integer and return the number of bytes written.
689 * Negative numbers are encoded as two's complement 64-bit integers.
696 * Number of bytes written to `out`.
699 int32_pack(int32_t value
, uint8_t *out
)
702 out
[0] = value
| 0x80;
703 out
[1] = (value
>> 7) | 0x80;
704 out
[2] = (value
>> 14) | 0x80;
705 out
[3] = (value
>> 21) | 0x80;
706 out
[4] = (value
>> 28) | 0x80;
707 out
[5] = out
[6] = out
[7] = out
[8] = 0xff;
711 return uint32_pack(value
, out
);
716 * Pack a signed 32-bit integer using ZigZag encoding and return the number of
724 * Number of bytes written to `out`.
727 sint32_pack(int32_t value
, uint8_t *out
)
729 return uint32_pack(zigzag32(value
), out
);
733 * Pack a 64-bit unsigned integer using base-128 varint encoding and return the
734 * number of bytes written.
741 * Number of bytes written to `out`.
744 uint64_pack(uint64_t value
, uint8_t *out
)
746 uint32_t hi
= (uint32_t) (value
>> 32);
747 uint32_t lo
= (uint32_t) value
;
751 return uint32_pack((uint32_t) lo
, out
);
752 out
[0] = (lo
) | 0x80;
753 out
[1] = (lo
>> 7) | 0x80;
754 out
[2] = (lo
>> 14) | 0x80;
755 out
[3] = (lo
>> 21) | 0x80;
757 out
[4] = (hi
<< 4) | (lo
>> 28);
760 out
[4] = ((hi
& 7) << 4) | (lo
>> 28) | 0x80;
765 out
[rv
++] = hi
| 0x80;
773 * Pack a 64-bit signed integer in ZigZag encoding and return the number of
781 * Number of bytes written to `out`.
784 sint64_pack(int64_t value
, uint8_t *out
)
786 return uint64_pack(zigzag64(value
), out
);
790 * Pack a 32-bit quantity in little-endian byte order. Used for protobuf wire
791 * types fixed32, sfixed32, float. Similar to "htole32".
798 * Number of bytes written to `out`.
801 fixed32_pack(uint32_t value
, void *out
)
803 #if !defined(WORDS_BIGENDIAN)
804 memcpy(out
, &value
, 4);
810 buf
[2] = value
>> 16;
811 buf
[3] = value
>> 24;
817 * Pack a 64-bit quantity in little-endian byte order. Used for protobuf wire
818 * types fixed64, sfixed64, double. Similar to "htole64".
820 * \todo The big-endian impl is really only good for 32-bit machines, a 64-bit
821 * version would be appreciated, plus a way to decide to use 64-bit math where
829 * Number of bytes written to `out`.
832 fixed64_pack(uint64_t value
, void *out
)
834 #if !defined(WORDS_BIGENDIAN)
835 memcpy(out
, &value
, 8);
837 fixed32_pack(value
, out
);
838 fixed32_pack(value
>> 32, ((char *) out
) + 4);
844 * Pack a boolean value as an integer and return the number of bytes written.
846 * \todo Perhaps on some platforms *out = !!value would be a better impl, b/c
847 * that is idiomatic C++ in some STL implementations.
854 * Number of bytes written to `out`.
857 boolean_pack(protobuf_c_boolean value
, uint8_t *out
)
859 *out
= value
? TRUE
: FALSE
;
864 * Pack a NUL-terminated C string and return the number of bytes written. The
865 * output includes a length delimiter.
867 * The NULL pointer is treated as an empty string. This isn't really necessary,
868 * but it allows people to leave required strings blank. (See Issue #13 in the
869 * bug tracker for a little more explanation).
876 * Number of bytes written to `out`.
879 string_pack(const char *str
, uint8_t *out
)
885 size_t len
= strlen(str
);
886 size_t rv
= uint32_pack(len
, out
);
887 memcpy(out
+ rv
, str
, len
);
893 * Pack a ProtobufCBinaryData and return the number of bytes written. The output
894 * includes a length delimiter.
897 * ProtobufCBinaryData to encode.
901 * Number of bytes written to `out`.
904 binary_data_pack(const ProtobufCBinaryData
*bd
, uint8_t *out
)
906 size_t len
= bd
->len
;
907 size_t rv
= uint32_pack(len
, out
);
908 memcpy(out
+ rv
, bd
->data
, len
);
913 * Pack a ProtobufCMessage and return the number of bytes written. The output
914 * includes a length delimiter.
917 * ProtobufCMessage object to pack.
921 * Number of bytes written to `out`.
924 prefixed_message_pack(const ProtobufCMessage
*message
, uint8_t *out
)
926 if (message
== NULL
) {
930 size_t rv
= protobuf_c_message_pack(message
, out
+ 1);
931 uint32_t rv_packed_size
= uint32_size(rv
);
932 if (rv_packed_size
!= 1)
933 memmove(out
+ rv_packed_size
, out
+ 1, rv
);
934 return uint32_pack(rv
, out
) + rv
;
941 * Wire-type will be added in required_field_pack().
943 * \todo Just call uint64_pack on 64-bit platforms.
946 * Tag value to encode.
950 * Number of bytes written to `out`.
953 tag_pack(uint32_t id
, uint8_t *out
)
955 if (id
< (1 << (32 - 3)))
956 return uint32_pack(id
<< 3, out
);
958 return uint64_pack(((uint64_t) id
) << 3, out
);
962 * Pack a required field and return the number of bytes written.
971 * Number of bytes written to `out`.
974 required_field_pack(const ProtobufCFieldDescriptor
*field
,
975 const void *member
, uint8_t *out
)
977 size_t rv
= tag_pack(field
->id
, out
);
979 switch (field
->type
) {
980 case PROTOBUF_C_TYPE_SINT32
:
981 out
[0] |= PROTOBUF_C_WIRE_TYPE_VARINT
;
982 return rv
+ sint32_pack(*(const int32_t *) member
, out
+ rv
);
983 case PROTOBUF_C_TYPE_INT32
:
984 out
[0] |= PROTOBUF_C_WIRE_TYPE_VARINT
;
985 return rv
+ int32_pack(*(const uint32_t *) member
, out
+ rv
);
986 case PROTOBUF_C_TYPE_UINT32
:
987 case PROTOBUF_C_TYPE_ENUM
:
988 out
[0] |= PROTOBUF_C_WIRE_TYPE_VARINT
;
989 return rv
+ uint32_pack(*(const uint32_t *) member
, out
+ rv
);
990 case PROTOBUF_C_TYPE_SINT64
:
991 out
[0] |= PROTOBUF_C_WIRE_TYPE_VARINT
;
992 return rv
+ sint64_pack(*(const int64_t *) member
, out
+ rv
);
993 case PROTOBUF_C_TYPE_INT64
:
994 case PROTOBUF_C_TYPE_UINT64
:
995 out
[0] |= PROTOBUF_C_WIRE_TYPE_VARINT
;
996 return rv
+ uint64_pack(*(const uint64_t *) member
, out
+ rv
);
997 case PROTOBUF_C_TYPE_SFIXED32
:
998 case PROTOBUF_C_TYPE_FIXED32
:
999 case PROTOBUF_C_TYPE_FLOAT
:
1000 out
[0] |= PROTOBUF_C_WIRE_TYPE_32BIT
;
1001 return rv
+ fixed32_pack(*(const uint32_t *) member
, out
+ rv
);
1002 case PROTOBUF_C_TYPE_SFIXED64
:
1003 case PROTOBUF_C_TYPE_FIXED64
:
1004 case PROTOBUF_C_TYPE_DOUBLE
:
1005 out
[0] |= PROTOBUF_C_WIRE_TYPE_64BIT
;
1006 return rv
+ fixed64_pack(*(const uint64_t *) member
, out
+ rv
);
1007 case PROTOBUF_C_TYPE_BOOL
:
1008 out
[0] |= PROTOBUF_C_WIRE_TYPE_VARINT
;
1009 return rv
+ boolean_pack(*(const protobuf_c_boolean
*) member
, out
+ rv
);
1010 case PROTOBUF_C_TYPE_STRING
:
1011 out
[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED
;
1012 return rv
+ string_pack(*(char *const *) member
, out
+ rv
);
1013 case PROTOBUF_C_TYPE_BYTES
:
1014 out
[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED
;
1015 return rv
+ binary_data_pack((const ProtobufCBinaryData
*) member
, out
+ rv
);
1016 case PROTOBUF_C_TYPE_MESSAGE
:
1017 out
[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED
;
1018 return rv
+ prefixed_message_pack(*(ProtobufCMessage
* const *) member
, out
+ rv
);
1020 PROTOBUF_C__ASSERT_NOT_REACHED();
1025 * Pack an optional field and return the number of bytes written.
1030 * Whether the field is set.
1036 * Number of bytes written to `out`.
1039 optional_field_pack(const ProtobufCFieldDescriptor
*field
,
1040 const protobuf_c_boolean
*has
,
1041 const void *member
, uint8_t *out
)
1043 if (field
->type
== PROTOBUF_C_TYPE_MESSAGE
||
1044 field
->type
== PROTOBUF_C_TYPE_STRING
)
1046 const void *ptr
= *(const void * const *) member
;
1047 if (ptr
== NULL
|| ptr
== field
->default_value
)
1053 return required_field_pack(field
, member
, out
);
1057 * Given a field type, return the in-memory size.
1059 * \todo Implement as a table lookup.
1064 * Size of the field.
1066 static inline size_t
1067 sizeof_elt_in_repeated_array(ProtobufCType type
)
1070 case PROTOBUF_C_TYPE_SINT32
:
1071 case PROTOBUF_C_TYPE_INT32
:
1072 case PROTOBUF_C_TYPE_UINT32
:
1073 case PROTOBUF_C_TYPE_SFIXED32
:
1074 case PROTOBUF_C_TYPE_FIXED32
:
1075 case PROTOBUF_C_TYPE_FLOAT
:
1076 case PROTOBUF_C_TYPE_ENUM
:
1078 case PROTOBUF_C_TYPE_SINT64
:
1079 case PROTOBUF_C_TYPE_INT64
:
1080 case PROTOBUF_C_TYPE_UINT64
:
1081 case PROTOBUF_C_TYPE_SFIXED64
:
1082 case PROTOBUF_C_TYPE_FIXED64
:
1083 case PROTOBUF_C_TYPE_DOUBLE
:
1085 case PROTOBUF_C_TYPE_BOOL
:
1086 return sizeof(protobuf_c_boolean
);
1087 case PROTOBUF_C_TYPE_STRING
:
1088 case PROTOBUF_C_TYPE_MESSAGE
:
1089 return sizeof(void *);
1090 case PROTOBUF_C_TYPE_BYTES
:
1091 return sizeof(ProtobufCBinaryData
);
1093 PROTOBUF_C__ASSERT_NOT_REACHED();
1098 * Pack an array of 32-bit quantities.
1105 * Number of elements in the source array.
1108 copy_to_little_endian_32(void *out
, const void *in
, const unsigned n
)
1110 #if !defined(WORDS_BIGENDIAN)
1111 memcpy(out
, in
, n
* 4);
1114 const uint32_t *ini
= in
;
1115 for (i
= 0; i
< n
; i
++)
1116 fixed32_pack(ini
[i
], (uint32_t *) out
+ i
);
1121 * Pack an array of 64-bit quantities.
1128 * Number of elements in the source array.
1131 copy_to_little_endian_64(void *out
, const void *in
, const unsigned n
)
1133 #if !defined(WORDS_BIGENDIAN)
1134 memcpy(out
, in
, n
* 8);
1137 const uint64_t *ini
= in
;
1138 for (i
= 0; i
< n
; i
++)
1139 fixed64_pack(ini
[i
], (uint64_t *) out
+ i
);
1144 * Get the minimum number of bytes required to pack a field value of a
1153 get_type_min_size(ProtobufCType type
)
1155 if (type
== PROTOBUF_C_TYPE_SFIXED32
||
1156 type
== PROTOBUF_C_TYPE_FIXED32
||
1157 type
== PROTOBUF_C_TYPE_FLOAT
)
1161 if (type
== PROTOBUF_C_TYPE_SFIXED64
||
1162 type
== PROTOBUF_C_TYPE_FIXED64
||
1163 type
== PROTOBUF_C_TYPE_DOUBLE
)
1171 * Packs the elements of a repeated field and returns the serialised field and
1177 * Number of elements in the repeated field array.
1179 * Pointer to the elements for this repeated field.
1181 * Serialised representation of the repeated field.
1183 * Number of bytes serialised to `out`.
1186 repeated_field_pack(const ProtobufCFieldDescriptor
*field
,
1187 size_t count
, const void *member
, uint8_t *out
)
1189 void *array
= *(void * const *) member
;
1192 if (0 != (field
->flags
& PROTOBUF_C_FIELD_FLAG_PACKED
)) {
1193 unsigned header_len
;
1195 unsigned min_length
;
1196 unsigned payload_len
;
1197 unsigned length_size_min
;
1198 unsigned actual_length_size
;
1199 uint8_t *payload_at
;
1203 header_len
= tag_pack(field
->id
, out
);
1204 out
[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED
;
1205 len_start
= header_len
;
1206 min_length
= get_type_min_size(field
->type
) * count
;
1207 length_size_min
= uint32_size(min_length
);
1208 header_len
+= length_size_min
;
1209 payload_at
= out
+ header_len
;
1211 switch (field
->type
) {
1212 case PROTOBUF_C_TYPE_SFIXED32
:
1213 case PROTOBUF_C_TYPE_FIXED32
:
1214 case PROTOBUF_C_TYPE_FLOAT
:
1215 copy_to_little_endian_32(payload_at
, array
, count
);
1216 payload_at
+= count
* 4;
1218 case PROTOBUF_C_TYPE_SFIXED64
:
1219 case PROTOBUF_C_TYPE_FIXED64
:
1220 case PROTOBUF_C_TYPE_DOUBLE
:
1221 copy_to_little_endian_64(payload_at
, array
, count
);
1222 payload_at
+= count
* 8;
1224 case PROTOBUF_C_TYPE_INT32
: {
1225 const int32_t *arr
= (const int32_t *) array
;
1226 for (i
= 0; i
< count
; i
++)
1227 payload_at
+= int32_pack(arr
[i
], payload_at
);
1230 case PROTOBUF_C_TYPE_SINT32
: {
1231 const int32_t *arr
= (const int32_t *) array
;
1232 for (i
= 0; i
< count
; i
++)
1233 payload_at
+= sint32_pack(arr
[i
], payload_at
);
1236 case PROTOBUF_C_TYPE_SINT64
: {
1237 const int64_t *arr
= (const int64_t *) array
;
1238 for (i
= 0; i
< count
; i
++)
1239 payload_at
+= sint64_pack(arr
[i
], payload_at
);
1242 case PROTOBUF_C_TYPE_ENUM
:
1243 case PROTOBUF_C_TYPE_UINT32
: {
1244 const uint32_t *arr
= (const uint32_t *) array
;
1245 for (i
= 0; i
< count
; i
++)
1246 payload_at
+= uint32_pack(arr
[i
], payload_at
);
1249 case PROTOBUF_C_TYPE_INT64
:
1250 case PROTOBUF_C_TYPE_UINT64
: {
1251 const uint64_t *arr
= (const uint64_t *) array
;
1252 for (i
= 0; i
< count
; i
++)
1253 payload_at
+= uint64_pack(arr
[i
], payload_at
);
1256 case PROTOBUF_C_TYPE_BOOL
: {
1257 const protobuf_c_boolean
*arr
= (const protobuf_c_boolean
*) array
;
1258 for (i
= 0; i
< count
; i
++)
1259 payload_at
+= boolean_pack(arr
[i
], payload_at
);
1263 PROTOBUF_C__ASSERT_NOT_REACHED();
1266 payload_len
= payload_at
- (out
+ header_len
);
1267 actual_length_size
= uint32_size(payload_len
);
1268 if (length_size_min
!= actual_length_size
) {
1269 assert(actual_length_size
== length_size_min
+ 1);
1270 memmove(out
+ header_len
+ 1, out
+ header_len
,
1274 uint32_pack(payload_len
, out
+ len_start
);
1275 return header_len
+ payload_len
;
1277 /* not "packed" cased */
1278 /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */
1280 unsigned siz
= sizeof_elt_in_repeated_array(field
->type
);
1282 for (i
= 0; i
< count
; i
++) {
1283 rv
+= required_field_pack(field
, array
, out
+ rv
);
1284 array
= (char *)array
+ siz
;
1291 unknown_field_pack(const ProtobufCMessageUnknownField
*field
, uint8_t *out
)
1293 size_t rv
= tag_pack(field
->tag
, out
);
1294 out
[0] |= field
->wire_type
;
1295 memcpy(out
+ rv
, field
->data
, field
->len
);
1296 return rv
+ field
->len
;
1302 protobuf_c_message_pack(const ProtobufCMessage
*message
, uint8_t *out
)
1307 ASSERT_IS_MESSAGE(message
);
1308 for (i
= 0; i
< message
->descriptor
->n_fields
; i
++) {
1309 const ProtobufCFieldDescriptor
*field
=
1310 message
->descriptor
->fields
+ i
;
1311 const void *member
= ((const char *) message
) + field
->offset
;
1314 * It doesn't hurt to compute qmember (a pointer to the
1315 * quantifier field of the structure), but the pointer is only
1316 * valid if the field is:
1317 * - a repeated field, or
1318 * - an optional field that isn't a pointer type
1319 * (Meaning: not a message or a string).
1321 const void *qmember
=
1322 ((const char *) message
) + field
->quantifier_offset
;
1324 if (field
->label
== PROTOBUF_C_LABEL_REQUIRED
) {
1325 rv
+= required_field_pack(field
, member
, out
+ rv
);
1326 } else if (field
->label
== PROTOBUF_C_LABEL_OPTIONAL
) {
1328 * Note that qmember is bogus for strings and messages,
1329 * but it isn't used.
1331 rv
+= optional_field_pack(field
, qmember
, member
, out
+ rv
);
1333 rv
+= repeated_field_pack(field
, *(const size_t *) qmember
,
1337 for (i
= 0; i
< message
->n_unknown_fields
; i
++)
1338 rv
+= unknown_field_pack(&message
->unknown_fields
[i
], out
+ rv
);
1343 * \defgroup packbuf protobuf_c_message_pack_to_buffer() implementation
1345 * Routines mainly used by protobuf_c_message_pack_to_buffer().
1352 * Pack a required field to a virtual buffer.
1357 * The element to be packed.
1358 * \param[out] buffer
1359 * Virtual buffer to append data to.
1361 * Number of bytes packed.
1364 required_field_pack_to_buffer(const ProtobufCFieldDescriptor
*field
,
1365 const void *member
, ProtobufCBuffer
*buffer
)
1368 uint8_t scratch
[MAX_UINT64_ENCODED_SIZE
* 2];
1370 rv
= tag_pack(field
->id
, scratch
);
1371 switch (field
->type
) {
1372 case PROTOBUF_C_TYPE_SINT32
:
1373 scratch
[0] |= PROTOBUF_C_WIRE_TYPE_VARINT
;
1374 rv
+= sint32_pack(*(const int32_t *) member
, scratch
+ rv
);
1375 buffer
->append(buffer
, rv
, scratch
);
1377 case PROTOBUF_C_TYPE_INT32
:
1378 scratch
[0] |= PROTOBUF_C_WIRE_TYPE_VARINT
;
1379 rv
+= int32_pack(*(const uint32_t *) member
, scratch
+ rv
);
1380 buffer
->append(buffer
, rv
, scratch
);
1382 case PROTOBUF_C_TYPE_UINT32
:
1383 case PROTOBUF_C_TYPE_ENUM
:
1384 scratch
[0] |= PROTOBUF_C_WIRE_TYPE_VARINT
;
1385 rv
+= uint32_pack(*(const uint32_t *) member
, scratch
+ rv
);
1386 buffer
->append(buffer
, rv
, scratch
);
1388 case PROTOBUF_C_TYPE_SINT64
:
1389 scratch
[0] |= PROTOBUF_C_WIRE_TYPE_VARINT
;
1390 rv
+= sint64_pack(*(const int64_t *) member
, scratch
+ rv
);
1391 buffer
->append(buffer
, rv
, scratch
);
1393 case PROTOBUF_C_TYPE_INT64
:
1394 case PROTOBUF_C_TYPE_UINT64
:
1395 scratch
[0] |= PROTOBUF_C_WIRE_TYPE_VARINT
;
1396 rv
+= uint64_pack(*(const uint64_t *) member
, scratch
+ rv
);
1397 buffer
->append(buffer
, rv
, scratch
);
1399 case PROTOBUF_C_TYPE_SFIXED32
:
1400 case PROTOBUF_C_TYPE_FIXED32
:
1401 case PROTOBUF_C_TYPE_FLOAT
:
1402 scratch
[0] |= PROTOBUF_C_WIRE_TYPE_32BIT
;
1403 rv
+= fixed32_pack(*(const uint32_t *) member
, scratch
+ rv
);
1404 buffer
->append(buffer
, rv
, scratch
);
1406 case PROTOBUF_C_TYPE_SFIXED64
:
1407 case PROTOBUF_C_TYPE_FIXED64
:
1408 case PROTOBUF_C_TYPE_DOUBLE
:
1409 scratch
[0] |= PROTOBUF_C_WIRE_TYPE_64BIT
;
1410 rv
+= fixed64_pack(*(const uint64_t *) member
, scratch
+ rv
);
1411 buffer
->append(buffer
, rv
, scratch
);
1413 case PROTOBUF_C_TYPE_BOOL
:
1414 scratch
[0] |= PROTOBUF_C_WIRE_TYPE_VARINT
;
1415 rv
+= boolean_pack(*(const protobuf_c_boolean
*) member
, scratch
+ rv
);
1416 buffer
->append(buffer
, rv
, scratch
);
1418 case PROTOBUF_C_TYPE_STRING
: {
1419 const char *str
= *(char *const *) member
;
1420 size_t sublen
= str
? strlen(str
) : 0;
1422 scratch
[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED
;
1423 rv
+= uint32_pack(sublen
, scratch
+ rv
);
1424 buffer
->append(buffer
, rv
, scratch
);
1425 buffer
->append(buffer
, sublen
, (const uint8_t *) str
);
1429 case PROTOBUF_C_TYPE_BYTES
: {
1430 const ProtobufCBinaryData
*bd
= ((const ProtobufCBinaryData
*) member
);
1431 size_t sublen
= bd
->len
;
1433 scratch
[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED
;
1434 rv
+= uint32_pack(sublen
, scratch
+ rv
);
1435 buffer
->append(buffer
, rv
, scratch
);
1436 buffer
->append(buffer
, sublen
, bd
->data
);
1440 case PROTOBUF_C_TYPE_MESSAGE
: {
1441 uint8_t simple_buffer_scratch
[256];
1443 const ProtobufCMessage
*msg
= *(ProtobufCMessage
* const *) member
;
1444 ProtobufCBufferSimple simple_buffer
=
1445 PROTOBUF_C_BUFFER_SIMPLE_INIT(simple_buffer_scratch
);
1447 scratch
[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED
;
1451 sublen
= protobuf_c_message_pack_to_buffer(msg
, &simple_buffer
.base
);
1452 rv
+= uint32_pack(sublen
, scratch
+ rv
);
1453 buffer
->append(buffer
, rv
, scratch
);
1454 buffer
->append(buffer
, sublen
, simple_buffer
.data
);
1456 PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple_buffer
);
1460 PROTOBUF_C__ASSERT_NOT_REACHED();
1466 * Pack an optional field to a buffer.
1471 * Whether the field is set.
1473 * The element to be packed.
1474 * \param[out] buffer
1475 * Virtual buffer to append data to.
1477 * Number of bytes serialised to `buffer`.
1480 optional_field_pack_to_buffer(const ProtobufCFieldDescriptor
*field
,
1481 const protobuf_c_boolean
*has
,
1482 const void *member
, ProtobufCBuffer
*buffer
)
1484 if (field
->type
== PROTOBUF_C_TYPE_MESSAGE
||
1485 field
->type
== PROTOBUF_C_TYPE_STRING
)
1487 const void *ptr
= *(const void *const *) member
;
1488 if (ptr
== NULL
|| ptr
== field
->default_value
)
1494 return required_field_pack_to_buffer(field
, member
, buffer
);
1498 * Get the packed size of an array of same field type.
1503 * Number of elements of this type.
1505 * The elements to get the size of.
1507 * Number of bytes required.
1510 get_packed_payload_length(const ProtobufCFieldDescriptor
*field
,
1511 unsigned count
, const void *array
)
1516 switch (field
->type
) {
1517 case PROTOBUF_C_TYPE_SFIXED32
:
1518 case PROTOBUF_C_TYPE_FIXED32
:
1519 case PROTOBUF_C_TYPE_FLOAT
:
1521 case PROTOBUF_C_TYPE_SFIXED64
:
1522 case PROTOBUF_C_TYPE_FIXED64
:
1523 case PROTOBUF_C_TYPE_DOUBLE
:
1525 case PROTOBUF_C_TYPE_INT32
: {
1526 const int32_t *arr
= (const int32_t *) array
;
1527 for (i
= 0; i
< count
; i
++)
1528 rv
+= int32_size(arr
[i
]);
1531 case PROTOBUF_C_TYPE_SINT32
: {
1532 const int32_t *arr
= (const int32_t *) array
;
1533 for (i
= 0; i
< count
; i
++)
1534 rv
+= sint32_size(arr
[i
]);
1537 case PROTOBUF_C_TYPE_ENUM
:
1538 case PROTOBUF_C_TYPE_UINT32
: {
1539 const uint32_t *arr
= (const uint32_t *) array
;
1540 for (i
= 0; i
< count
; i
++)
1541 rv
+= uint32_size(arr
[i
]);
1544 case PROTOBUF_C_TYPE_SINT64
: {
1545 const int64_t *arr
= (const int64_t *) array
;
1546 for (i
= 0; i
< count
; i
++)
1547 rv
+= sint64_size(arr
[i
]);
1550 case PROTOBUF_C_TYPE_INT64
:
1551 case PROTOBUF_C_TYPE_UINT64
: {
1552 const uint64_t *arr
= (const uint64_t *) array
;
1553 for (i
= 0; i
< count
; i
++)
1554 rv
+= uint64_size(arr
[i
]);
1557 case PROTOBUF_C_TYPE_BOOL
:
1560 PROTOBUF_C__ASSERT_NOT_REACHED();
1566 * Pack an array of same field type to a virtual buffer.
1571 * Number of elements of this type.
1573 * The elements to get the size of.
1574 * \param[out] buffer
1575 * Virtual buffer to append data to.
1577 * Number of bytes packed.
1580 pack_buffer_packed_payload(const ProtobufCFieldDescriptor
*field
,
1581 unsigned count
, const void *array
,
1582 ProtobufCBuffer
*buffer
)
1584 uint8_t scratch
[16];
1588 switch (field
->type
) {
1589 case PROTOBUF_C_TYPE_SFIXED32
:
1590 case PROTOBUF_C_TYPE_FIXED32
:
1591 case PROTOBUF_C_TYPE_FLOAT
:
1592 #if !defined(WORDS_BIGENDIAN)
1594 goto no_packing_needed
;
1596 for (i
= 0; i
< count
; i
++) {
1597 unsigned len
= fixed32_pack(((uint32_t *) array
)[i
], scratch
);
1598 buffer
->append(buffer
, len
, scratch
);
1603 case PROTOBUF_C_TYPE_SFIXED64
:
1604 case PROTOBUF_C_TYPE_FIXED64
:
1605 case PROTOBUF_C_TYPE_DOUBLE
:
1606 #if !defined(WORDS_BIGENDIAN)
1608 goto no_packing_needed
;
1610 for (i
= 0; i
< count
; i
++) {
1611 unsigned len
= fixed64_pack(((uint64_t *) array
)[i
], scratch
);
1612 buffer
->append(buffer
, len
, scratch
);
1617 case PROTOBUF_C_TYPE_INT32
:
1618 for (i
= 0; i
< count
; i
++) {
1619 unsigned len
= int32_pack(((int32_t *) array
)[i
], scratch
);
1620 buffer
->append(buffer
, len
, scratch
);
1624 case PROTOBUF_C_TYPE_SINT32
:
1625 for (i
= 0; i
< count
; i
++) {
1626 unsigned len
= sint32_pack(((int32_t *) array
)[i
], scratch
);
1627 buffer
->append(buffer
, len
, scratch
);
1631 case PROTOBUF_C_TYPE_ENUM
:
1632 case PROTOBUF_C_TYPE_UINT32
:
1633 for (i
= 0; i
< count
; i
++) {
1634 unsigned len
= uint32_pack(((uint32_t *) array
)[i
], scratch
);
1635 buffer
->append(buffer
, len
, scratch
);
1639 case PROTOBUF_C_TYPE_SINT64
:
1640 for (i
= 0; i
< count
; i
++) {
1641 unsigned len
= sint64_pack(((int64_t *) array
)[i
], scratch
);
1642 buffer
->append(buffer
, len
, scratch
);
1646 case PROTOBUF_C_TYPE_INT64
:
1647 case PROTOBUF_C_TYPE_UINT64
:
1648 for (i
= 0; i
< count
; i
++) {
1649 unsigned len
= uint64_pack(((uint64_t *) array
)[i
], scratch
);
1650 buffer
->append(buffer
, len
, scratch
);
1654 case PROTOBUF_C_TYPE_BOOL
:
1655 for (i
= 0; i
< count
; i
++) {
1656 unsigned len
= boolean_pack(((protobuf_c_boolean
*) array
)[i
], scratch
);
1657 buffer
->append(buffer
, len
, scratch
);
1662 PROTOBUF_C__ASSERT_NOT_REACHED();
1666 #if !defined(WORDS_BIGENDIAN)
1668 buffer
->append(buffer
, rv
, array
);
1674 repeated_field_pack_to_buffer(const ProtobufCFieldDescriptor
*field
,
1675 unsigned count
, const void *member
,
1676 ProtobufCBuffer
*buffer
)
1678 char *array
= *(char * const *) member
;
1682 if (0 != (field
->flags
& PROTOBUF_C_FIELD_FLAG_PACKED
)) {
1683 uint8_t scratch
[MAX_UINT64_ENCODED_SIZE
* 2];
1684 size_t rv
= tag_pack(field
->id
, scratch
);
1685 size_t payload_len
= get_packed_payload_length(field
, count
, array
);
1688 scratch
[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED
;
1689 rv
+= uint32_pack(payload_len
, scratch
+ rv
);
1690 buffer
->append(buffer
, rv
, scratch
);
1691 tmp
= pack_buffer_packed_payload(field
, count
, array
, buffer
);
1692 assert(tmp
== payload_len
);
1693 return rv
+ payload_len
;
1697 /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */
1700 siz
= sizeof_elt_in_repeated_array(field
->type
);
1701 for (i
= 0; i
< count
; i
++) {
1702 rv
+= required_field_pack_to_buffer(field
, array
, buffer
);
1703 array
= ((char*)array
) + siz
;
1710 unknown_field_pack_to_buffer(const ProtobufCMessageUnknownField
*field
,
1711 ProtobufCBuffer
*buffer
)
1713 uint8_t header
[MAX_UINT64_ENCODED_SIZE
];
1714 size_t rv
= tag_pack(field
->tag
, header
);
1716 header
[0] |= field
->wire_type
;
1717 buffer
->append(buffer
, rv
, header
);
1718 buffer
->append(buffer
, field
->len
, field
->data
);
1719 return rv
+ field
->len
;
1725 protobuf_c_message_pack_to_buffer(const ProtobufCMessage
*message
,
1726 ProtobufCBuffer
*buffer
)
1731 ASSERT_IS_MESSAGE(message
);
1732 for (i
= 0; i
< message
->descriptor
->n_fields
; i
++) {
1733 const ProtobufCFieldDescriptor
*field
=
1734 message
->descriptor
->fields
+ i
;
1735 const void *member
=
1736 ((const char *) message
) + field
->offset
;
1737 const void *qmember
=
1738 ((const char *) message
) + field
->quantifier_offset
;
1740 if (field
->label
== PROTOBUF_C_LABEL_REQUIRED
) {
1741 rv
+= required_field_pack_to_buffer(field
, member
, buffer
);
1742 } else if (field
->label
== PROTOBUF_C_LABEL_OPTIONAL
) {
1743 rv
+= optional_field_pack_to_buffer(
1750 rv
+= repeated_field_pack_to_buffer(
1752 *(const size_t *) qmember
,
1758 for (i
= 0; i
< message
->n_unknown_fields
; i
++)
1759 rv
+= unknown_field_pack_to_buffer(&message
->unknown_fields
[i
], buffer
);
1765 * \defgroup unpack unpacking implementation
1767 * Routines mainly used by the unpacking functions.
1774 int_range_lookup(unsigned n_ranges
, const ProtobufCIntRange
*ranges
, int value
)
1784 unsigned mid
= start
+ n
/ 2;
1786 if (value
< ranges
[mid
].start_value
) {
1788 } else if (value
>= ranges
[mid
].start_value
+
1789 (int) (ranges
[mid
+ 1].orig_index
-
1790 ranges
[mid
].orig_index
))
1792 unsigned new_start
= mid
+ 1;
1793 n
= start
+ n
- new_start
;
1796 return (value
- ranges
[mid
].start_value
) +
1797 ranges
[mid
].orig_index
;
1800 unsigned start_orig_index
= ranges
[start
].orig_index
;
1801 unsigned range_size
=
1802 ranges
[start
+ 1].orig_index
- start_orig_index
;
1804 if (ranges
[start
].start_value
<= value
&&
1805 value
< (int) (ranges
[start
].start_value
+ range_size
))
1807 return (value
- ranges
[start
].start_value
) +
1815 parse_tag_and_wiretype(size_t len
,
1816 const uint8_t *data
,
1818 ProtobufCWireType
*wiretype_out
)
1820 unsigned max_rv
= len
> 5 ? 5 : len
;
1821 uint32_t tag
= (data
[0] & 0x7f) >> 3;
1825 *wiretype_out
= data
[0] & 7;
1826 if ((data
[0] & 0x80) == 0) {
1830 for (rv
= 1; rv
< max_rv
; rv
++) {
1831 if (data
[rv
] & 0x80) {
1832 tag
|= (data
[rv
] & 0x7f) << shift
;
1835 tag
|= data
[rv
] << shift
;
1840 return 0; /* error: bad header */
1843 /* sizeof(ScannedMember) must be <= (1<<BOUND_SIZEOF_SCANNED_MEMBER_LOG2) */
1844 #define BOUND_SIZEOF_SCANNED_MEMBER_LOG2 5
1845 typedef struct _ScannedMember ScannedMember
;
1846 /** Field as it's being read. */
1847 struct _ScannedMember
{
1848 uint32_t tag
; /**< Field tag. */
1849 uint8_t wire_type
; /**< Field type. */
1850 uint8_t length_prefix_len
; /**< Prefix length. */
1851 const ProtobufCFieldDescriptor
*field
; /**< Field descriptor. */
1852 size_t len
; /**< Field length. */
1853 const uint8_t *data
; /**< Pointer to field data. */
1856 static inline uint32_t
1857 scan_length_prefixed_data(size_t len
, const uint8_t *data
,
1858 size_t *prefix_len_out
)
1860 unsigned hdr_max
= len
< 5 ? len
: 5;
1866 for (i
= 0; i
< hdr_max
; i
++) {
1867 val
|= (data
[i
] & 0x7f) << shift
;
1869 if ((data
[i
] & 0x80) == 0)
1873 PROTOBUF_C_UNPACK_ERROR("error parsing length for length-prefixed data");
1877 *prefix_len_out
= hdr_len
;
1878 if (hdr_len
+ val
> len
) {
1879 PROTOBUF_C_UNPACK_ERROR("data too short after length-prefix of %u", val
);
1882 return hdr_len
+ val
;
1886 max_b128_numbers(size_t len
, const uint8_t *data
)
1890 if ((*data
++ & 0x80) == 0)
1898 * Merge earlier message into a latter message.
1900 * For numeric types and strings, if the same value appears multiple
1901 * times, the parser accepts the last value it sees. For embedded
1902 * message fields, the parser merges multiple instances of the same
1903 * field. That is, all singular scalar fields in the latter instance
1904 * replace those in the former, singular embedded messages are merged,
1905 * and repeated fields are concatenated.
1907 * The earlier message should be freed after calling this function, as
1908 * some of its fields may have been reused and changed to their default
1909 * values during the merge.
1911 static protobuf_c_boolean
1912 merge_messages(ProtobufCMessage
*earlier_msg
,
1913 ProtobufCMessage
*latter_msg
,
1914 ProtobufCAllocator
*allocator
)
1917 const ProtobufCFieldDescriptor
*fields
=
1918 earlier_msg
->descriptor
->fields
;
1919 for (i
= 0; i
< latter_msg
->descriptor
->n_fields
; i
++) {
1920 if (fields
[i
].label
== PROTOBUF_C_LABEL_REPEATED
) {
1922 STRUCT_MEMBER_PTR(size_t, earlier_msg
,
1923 fields
[i
].quantifier_offset
);
1924 uint8_t **p_earlier
=
1925 STRUCT_MEMBER_PTR(uint8_t *, earlier_msg
,
1928 STRUCT_MEMBER_PTR(size_t, latter_msg
,
1929 fields
[i
].quantifier_offset
);
1930 uint8_t **p_latter
=
1931 STRUCT_MEMBER_PTR(uint8_t *, latter_msg
,
1934 if (*n_earlier
> 0) {
1935 if (*n_latter
> 0) {
1936 /* Concatenate the repeated field */
1938 sizeof_elt_in_repeated_array(fields
[i
].type
);
1941 new_field
= do_alloc(allocator
,
1942 (*n_earlier
+ *n_latter
) * el_size
);
1946 memcpy(new_field
, *p_earlier
,
1947 *n_earlier
* el_size
);
1949 *n_earlier
* el_size
,
1951 *n_latter
* el_size
);
1953 do_free(allocator
, *p_latter
);
1954 do_free(allocator
, *p_earlier
);
1955 *p_latter
= new_field
;
1956 *n_latter
= *n_earlier
+ *n_latter
;
1958 /* Zero copy the repeated field from the earlier message */
1959 *n_latter
= *n_earlier
;
1960 *p_latter
= *p_earlier
;
1962 /* Make sure the field does not get double freed */
1966 } else if (fields
[i
].type
== PROTOBUF_C_TYPE_MESSAGE
) {
1967 ProtobufCMessage
**em
=
1968 STRUCT_MEMBER_PTR(ProtobufCMessage
*,
1971 ProtobufCMessage
**lm
=
1972 STRUCT_MEMBER_PTR(ProtobufCMessage
*,
1978 (*em
, *lm
, allocator
))
1981 /* Zero copy the optional message */
1982 assert(fields
[i
].label
==
1983 PROTOBUF_C_LABEL_OPTIONAL
);
1988 } else if (fields
[i
].label
== PROTOBUF_C_LABEL_OPTIONAL
) {
1990 protobuf_c_boolean need_to_merge
= FALSE
;
1991 void *earlier_elem
=
1992 STRUCT_MEMBER_P(earlier_msg
, fields
[i
].offset
);
1994 STRUCT_MEMBER_P(latter_msg
, fields
[i
].offset
);
1995 const void *def_val
= fields
[i
].default_value
;
1997 switch (fields
[i
].type
) {
1998 case PROTOBUF_C_TYPE_BYTES
: {
2000 ((ProtobufCBinaryData
*) earlier_elem
)->data
;
2002 ((ProtobufCBinaryData
*) latter_elem
)->data
;
2003 const ProtobufCBinaryData
*d_bd
=
2004 (ProtobufCBinaryData
*) def_val
;
2006 el_size
= sizeof(ProtobufCBinaryData
);
2010 e_data
!= d_bd
->data
)) &&
2013 l_data
== d_bd
->data
));
2016 case PROTOBUF_C_TYPE_STRING
: {
2017 char *e_str
= *(char **) earlier_elem
;
2018 char *l_str
= *(char **) latter_elem
;
2019 const char *d_str
= def_val
;
2021 el_size
= sizeof(char *);
2022 need_to_merge
= e_str
!= d_str
&& l_str
== d_str
;
2026 el_size
= sizeof_elt_in_repeated_array(fields
[i
].type
);
2029 STRUCT_MEMBER(protobuf_c_boolean
,
2031 fields
[i
].quantifier_offset
) &&
2032 !STRUCT_MEMBER(protobuf_c_boolean
,
2034 fields
[i
].quantifier_offset
);
2039 if (need_to_merge
) {
2040 memcpy(latter_elem
, earlier_elem
, el_size
);
2042 * Reset the element from the old message to 0
2043 * to make sure earlier message deallocation
2044 * doesn't corrupt zero-copied data in the new
2045 * message, earlier message will be freed after
2046 * this function is called anyway
2048 memset(earlier_elem
, 0, el_size
);
2050 if (fields
[i
].quantifier_offset
!= 0) {
2051 /* Set the has field, if applicable */
2052 STRUCT_MEMBER(protobuf_c_boolean
,
2055 quantifier_offset
) = TRUE
;
2056 STRUCT_MEMBER(protobuf_c_boolean
,
2059 quantifier_offset
) = FALSE
;
2068 * Count packed elements.
2070 * Given a raw slab of packed-repeated values, determine the number of
2071 * elements. This function detects certain kinds of errors but not
2072 * others; the remaining error checking is done by
2073 * parse_packed_repeated_member().
2075 static protobuf_c_boolean
2076 count_packed_elements(ProtobufCType type
,
2077 size_t len
, const uint8_t *data
, size_t *count_out
)
2080 case PROTOBUF_C_TYPE_SFIXED32
:
2081 case PROTOBUF_C_TYPE_FIXED32
:
2082 case PROTOBUF_C_TYPE_FLOAT
:
2084 PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 4 for fixed-length 32-bit types");
2087 *count_out
= len
/ 4;
2089 case PROTOBUF_C_TYPE_SFIXED64
:
2090 case PROTOBUF_C_TYPE_FIXED64
:
2091 case PROTOBUF_C_TYPE_DOUBLE
:
2093 PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 8 for fixed-length 64-bit types");
2096 *count_out
= len
/ 8;
2098 case PROTOBUF_C_TYPE_INT32
:
2099 case PROTOBUF_C_TYPE_SINT32
:
2100 case PROTOBUF_C_TYPE_ENUM
:
2101 case PROTOBUF_C_TYPE_UINT32
:
2102 case PROTOBUF_C_TYPE_INT64
:
2103 case PROTOBUF_C_TYPE_SINT64
:
2104 case PROTOBUF_C_TYPE_UINT64
:
2105 *count_out
= max_b128_numbers(len
, data
);
2107 case PROTOBUF_C_TYPE_BOOL
:
2110 case PROTOBUF_C_TYPE_STRING
:
2111 case PROTOBUF_C_TYPE_BYTES
:
2112 case PROTOBUF_C_TYPE_MESSAGE
:
2114 PROTOBUF_C_UNPACK_ERROR("bad protobuf-c type %u for packed-repeated", type
);
2119 static inline uint32_t
2120 parse_uint32(unsigned len
, const uint8_t *data
)
2122 uint32_t rv
= data
[0] & 0x7f;
2124 rv
|= ((uint32_t) (data
[1] & 0x7f) << 7);
2126 rv
|= ((uint32_t) (data
[2] & 0x7f) << 14);
2128 rv
|= ((uint32_t) (data
[3] & 0x7f) << 21);
2130 rv
|= ((uint32_t) (data
[4]) << 28);
2137 static inline uint32_t
2138 parse_int32(unsigned len
, const uint8_t *data
)
2140 return parse_uint32(len
, data
);
2143 static inline int32_t
2144 unzigzag32(uint32_t v
)
2147 return -(v
>> 1) - 1;
2152 static inline uint32_t
2153 parse_fixed_uint32(const uint8_t *data
)
2155 #if !defined(WORDS_BIGENDIAN)
2157 memcpy(&t
, data
, 4);
2161 ((uint32_t) (data
[1]) << 8) |
2162 ((uint32_t) (data
[2]) << 16) |
2163 ((uint32_t) (data
[3]) << 24);
2168 parse_uint64(unsigned len
, const uint8_t *data
)
2174 return parse_uint32(len
, data
);
2175 rv
= ((uint64_t) (data
[0] & 0x7f)) |
2176 ((uint64_t) (data
[1] & 0x7f) << 7) |
2177 ((uint64_t) (data
[2] & 0x7f) << 14) |
2178 ((uint64_t) (data
[3] & 0x7f) << 21);
2180 for (i
= 4; i
< len
; i
++) {
2181 rv
|= (((uint64_t) (data
[i
] & 0x7f)) << shift
);
2187 static inline int64_t
2188 unzigzag64(uint64_t v
)
2191 return -(v
>> 1) - 1;
2196 static inline uint64_t
2197 parse_fixed_uint64(const uint8_t *data
)
2199 #if !defined(WORDS_BIGENDIAN)
2201 memcpy(&t
, data
, 8);
2204 return (uint64_t) parse_fixed_uint32(data
) |
2205 (((uint64_t) parse_fixed_uint32(data
+ 4)) << 32);
2209 static protobuf_c_boolean
2210 parse_boolean(unsigned len
, const uint8_t *data
)
2213 for (i
= 0; i
< len
; i
++)
2219 static protobuf_c_boolean
2220 parse_required_member(ScannedMember
*scanned_member
,
2222 ProtobufCAllocator
*allocator
,
2223 protobuf_c_boolean maybe_clear
)
2225 unsigned len
= scanned_member
->len
;
2226 const uint8_t *data
= scanned_member
->data
;
2227 ProtobufCWireType wire_type
= scanned_member
->wire_type
;
2229 switch (scanned_member
->field
->type
) {
2230 case PROTOBUF_C_TYPE_INT32
:
2231 if (wire_type
!= PROTOBUF_C_WIRE_TYPE_VARINT
)
2233 *(uint32_t *) member
= parse_int32(len
, data
);
2235 case PROTOBUF_C_TYPE_UINT32
:
2236 if (wire_type
!= PROTOBUF_C_WIRE_TYPE_VARINT
)
2238 *(uint32_t *) member
= parse_uint32(len
, data
);
2240 case PROTOBUF_C_TYPE_SINT32
:
2241 if (wire_type
!= PROTOBUF_C_WIRE_TYPE_VARINT
)
2243 *(int32_t *) member
= unzigzag32(parse_uint32(len
, data
));
2245 case PROTOBUF_C_TYPE_SFIXED32
:
2246 case PROTOBUF_C_TYPE_FIXED32
:
2247 case PROTOBUF_C_TYPE_FLOAT
:
2248 if (wire_type
!= PROTOBUF_C_WIRE_TYPE_32BIT
)
2250 *(uint32_t *) member
= parse_fixed_uint32(data
);
2252 case PROTOBUF_C_TYPE_INT64
:
2253 case PROTOBUF_C_TYPE_UINT64
:
2254 if (wire_type
!= PROTOBUF_C_WIRE_TYPE_VARINT
)
2256 *(uint64_t *) member
= parse_uint64(len
, data
);
2258 case PROTOBUF_C_TYPE_SINT64
:
2259 if (wire_type
!= PROTOBUF_C_WIRE_TYPE_VARINT
)
2261 *(int64_t *) member
= unzigzag64(parse_uint64(len
, data
));
2263 case PROTOBUF_C_TYPE_SFIXED64
:
2264 case PROTOBUF_C_TYPE_FIXED64
:
2265 case PROTOBUF_C_TYPE_DOUBLE
:
2266 if (wire_type
!= PROTOBUF_C_WIRE_TYPE_64BIT
)
2268 *(uint64_t *) member
= parse_fixed_uint64(data
);
2270 case PROTOBUF_C_TYPE_BOOL
:
2271 *(protobuf_c_boolean
*) member
= parse_boolean(len
, data
);
2273 case PROTOBUF_C_TYPE_ENUM
:
2274 if (wire_type
!= PROTOBUF_C_WIRE_TYPE_VARINT
)
2276 *(uint32_t *) member
= parse_uint32(len
, data
);
2278 case PROTOBUF_C_TYPE_STRING
: {
2279 char **pstr
= member
;
2280 unsigned pref_len
= scanned_member
->length_prefix_len
;
2282 if (wire_type
!= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED
)
2285 if (maybe_clear
&& *pstr
!= NULL
) {
2286 const char *def
= scanned_member
->field
->default_value
;
2287 if (*pstr
!= NULL
&& *pstr
!= def
)
2288 do_free(allocator
, *pstr
);
2290 *pstr
= do_alloc(allocator
, len
- pref_len
+ 1);
2293 memcpy(*pstr
, data
+ pref_len
, len
- pref_len
);
2294 (*pstr
)[len
- pref_len
] = 0;
2297 case PROTOBUF_C_TYPE_BYTES
: {
2298 ProtobufCBinaryData
*bd
= member
;
2299 const ProtobufCBinaryData
*def_bd
;
2300 unsigned pref_len
= scanned_member
->length_prefix_len
;
2302 if (wire_type
!= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED
)
2305 def_bd
= scanned_member
->field
->default_value
;
2308 (def_bd
== NULL
|| bd
->data
!= def_bd
->data
))
2310 do_free(allocator
, bd
->data
);
2312 if (len
- pref_len
> 0) {
2313 bd
->data
= do_alloc(allocator
, len
- pref_len
);
2314 if (bd
->data
== NULL
)
2316 memcpy(bd
->data
, data
+ pref_len
, len
- pref_len
);
2320 bd
->len
= len
- pref_len
;
2323 case PROTOBUF_C_TYPE_MESSAGE
: {
2324 ProtobufCMessage
**pmessage
= member
;
2325 ProtobufCMessage
*subm
;
2326 const ProtobufCMessage
*def_mess
;
2327 protobuf_c_boolean merge_successful
= TRUE
;
2328 unsigned pref_len
= scanned_member
->length_prefix_len
;
2330 if (wire_type
!= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED
)
2333 def_mess
= scanned_member
->field
->default_value
;
2334 subm
= protobuf_c_message_unpack(scanned_member
->field
->descriptor
,
2340 *pmessage
!= NULL
&&
2341 *pmessage
!= def_mess
)
2344 merge_successful
= merge_messages(*pmessage
, subm
, allocator
);
2345 /* Delete the previous message */
2346 protobuf_c_message_free_unpacked(*pmessage
, allocator
);
2349 if (subm
== NULL
|| !merge_successful
)
2357 static protobuf_c_boolean
2358 parse_optional_member(ScannedMember
*scanned_member
,
2360 ProtobufCMessage
*message
,
2361 ProtobufCAllocator
*allocator
)
2363 if (!parse_required_member(scanned_member
, member
, allocator
, TRUE
))
2365 if (scanned_member
->field
->quantifier_offset
!= 0)
2366 STRUCT_MEMBER(protobuf_c_boolean
,
2368 scanned_member
->field
->quantifier_offset
) = TRUE
;
2372 static protobuf_c_boolean
2373 parse_repeated_member(ScannedMember
*scanned_member
,
2375 ProtobufCMessage
*message
,
2376 ProtobufCAllocator
*allocator
)
2378 const ProtobufCFieldDescriptor
*field
= scanned_member
->field
;
2379 size_t *p_n
= STRUCT_MEMBER_PTR(size_t, message
, field
->quantifier_offset
);
2380 size_t siz
= sizeof_elt_in_repeated_array(field
->type
);
2381 char *array
= *(char **) member
;
2383 if (!parse_required_member(scanned_member
, array
+ siz
* (*p_n
),
2393 scan_varint(unsigned len
, const uint8_t *data
)
2398 for (i
= 0; i
< len
; i
++)
2399 if ((data
[i
] & 0x80) == 0)
2406 static protobuf_c_boolean
2407 parse_packed_repeated_member(ScannedMember
*scanned_member
,
2409 ProtobufCMessage
*message
)
2411 const ProtobufCFieldDescriptor
*field
= scanned_member
->field
;
2412 size_t *p_n
= STRUCT_MEMBER_PTR(size_t, message
, field
->quantifier_offset
);
2413 size_t siz
= sizeof_elt_in_repeated_array(field
->type
);
2414 void *array
= *(char **) member
+ siz
* (*p_n
);
2415 const uint8_t *at
= scanned_member
->data
+ scanned_member
->length_prefix_len
;
2416 size_t rem
= scanned_member
->len
- scanned_member
->length_prefix_len
;
2420 switch (field
->type
) {
2421 case PROTOBUF_C_TYPE_SFIXED32
:
2422 case PROTOBUF_C_TYPE_FIXED32
:
2423 case PROTOBUF_C_TYPE_FLOAT
:
2424 count
= (scanned_member
->len
- scanned_member
->length_prefix_len
) / 4;
2425 #if !defined(WORDS_BIGENDIAN)
2426 goto no_unpacking_needed
;
2428 for (i
= 0; i
< count
; i
++) {
2429 ((uint32_t *) array
)[i
] = parse_fixed_uint32(at
);
2434 case PROTOBUF_C_TYPE_SFIXED64
:
2435 case PROTOBUF_C_TYPE_FIXED64
:
2436 case PROTOBUF_C_TYPE_DOUBLE
:
2437 count
= (scanned_member
->len
- scanned_member
->length_prefix_len
) / 8;
2438 #if !defined(WORDS_BIGENDIAN)
2439 goto no_unpacking_needed
;
2441 for (i
= 0; i
< count
; i
++) {
2442 ((uint64_t *) array
)[i
] = parse_fixed_uint64(at
);
2447 case PROTOBUF_C_TYPE_INT32
:
2449 unsigned s
= scan_varint(rem
, at
);
2451 PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int32 value");
2454 ((int32_t *) array
)[count
++] = parse_int32(s
, at
);
2459 case PROTOBUF_C_TYPE_SINT32
:
2461 unsigned s
= scan_varint(rem
, at
);
2463 PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint32 value");
2466 ((int32_t *) array
)[count
++] = unzigzag32(parse_uint32(s
, at
));
2471 case PROTOBUF_C_TYPE_ENUM
:
2472 case PROTOBUF_C_TYPE_UINT32
:
2474 unsigned s
= scan_varint(rem
, at
);
2476 PROTOBUF_C_UNPACK_ERROR("bad packed-repeated enum or uint32 value");
2479 ((uint32_t *) array
)[count
++] = parse_uint32(s
, at
);
2485 case PROTOBUF_C_TYPE_SINT64
:
2487 unsigned s
= scan_varint(rem
, at
);
2489 PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint64 value");
2492 ((int64_t *) array
)[count
++] = unzigzag64(parse_uint64(s
, at
));
2497 case PROTOBUF_C_TYPE_INT64
:
2498 case PROTOBUF_C_TYPE_UINT64
:
2500 unsigned s
= scan_varint(rem
, at
);
2502 PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int64/uint64 value");
2505 ((int64_t *) array
)[count
++] = parse_uint64(s
, at
);
2510 case PROTOBUF_C_TYPE_BOOL
:
2512 for (i
= 0; i
< count
; i
++) {
2514 PROTOBUF_C_UNPACK_ERROR("bad packed-repeated boolean value");
2517 ((protobuf_c_boolean
*) array
)[i
] = at
[i
];
2521 PROTOBUF_C__ASSERT_NOT_REACHED();
2526 #if !defined(WORDS_BIGENDIAN)
2527 no_unpacking_needed
:
2528 memcpy(array
, at
, count
* siz
);
2534 static protobuf_c_boolean
2535 is_packable_type(ProtobufCType type
)
2538 type
!= PROTOBUF_C_TYPE_STRING
&&
2539 type
!= PROTOBUF_C_TYPE_BYTES
&&
2540 type
!= PROTOBUF_C_TYPE_MESSAGE
;
2543 static protobuf_c_boolean
2544 parse_member(ScannedMember
*scanned_member
,
2545 ProtobufCMessage
*message
,
2546 ProtobufCAllocator
*allocator
)
2548 const ProtobufCFieldDescriptor
*field
= scanned_member
->field
;
2551 if (field
== NULL
) {
2552 ProtobufCMessageUnknownField
*ufield
=
2553 message
->unknown_fields
+
2554 (message
->n_unknown_fields
++);
2555 ufield
->tag
= scanned_member
->tag
;
2556 ufield
->wire_type
= scanned_member
->wire_type
;
2557 ufield
->len
= scanned_member
->len
;
2558 ufield
->data
= do_alloc(allocator
, scanned_member
->len
);
2559 if (ufield
->data
== NULL
)
2561 memcpy(ufield
->data
, scanned_member
->data
, ufield
->len
);
2564 member
= (char *) message
+ field
->offset
;
2565 switch (field
->label
) {
2566 case PROTOBUF_C_LABEL_REQUIRED
:
2567 return parse_required_member(scanned_member
, member
,
2569 case PROTOBUF_C_LABEL_OPTIONAL
:
2570 return parse_optional_member(scanned_member
, member
,
2571 message
, allocator
);
2572 case PROTOBUF_C_LABEL_REPEATED
:
2573 if (scanned_member
->wire_type
==
2574 PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED
&&
2575 (0 != (field
->flags
& PROTOBUF_C_FIELD_FLAG_PACKED
) ||
2576 is_packable_type(field
->type
)))
2578 return parse_packed_repeated_member(scanned_member
,
2581 return parse_repeated_member(scanned_member
,
2586 PROTOBUF_C__ASSERT_NOT_REACHED();
2591 * Initialise messages generated by old code.
2593 * This function is used if desc->message_init == NULL (which occurs
2594 * for old code, and which would be useful to support allocating
2595 * descriptors dynamically).
2598 message_init_generic(const ProtobufCMessageDescriptor
*desc
,
2599 ProtobufCMessage
*message
)
2603 memset(message
, 0, desc
->sizeof_message
);
2604 message
->descriptor
= desc
;
2605 for (i
= 0; i
< desc
->n_fields
; i
++) {
2606 if (desc
->fields
[i
].default_value
!= NULL
&&
2607 desc
->fields
[i
].label
!= PROTOBUF_C_LABEL_REPEATED
)
2610 STRUCT_MEMBER_P(message
, desc
->fields
[i
].offset
);
2611 const void *dv
= desc
->fields
[i
].default_value
;
2613 switch (desc
->fields
[i
].type
) {
2614 case PROTOBUF_C_TYPE_INT32
:
2615 case PROTOBUF_C_TYPE_SINT32
:
2616 case PROTOBUF_C_TYPE_SFIXED32
:
2617 case PROTOBUF_C_TYPE_UINT32
:
2618 case PROTOBUF_C_TYPE_FIXED32
:
2619 case PROTOBUF_C_TYPE_FLOAT
:
2620 case PROTOBUF_C_TYPE_ENUM
:
2621 memcpy(field
, dv
, 4);
2623 case PROTOBUF_C_TYPE_INT64
:
2624 case PROTOBUF_C_TYPE_SINT64
:
2625 case PROTOBUF_C_TYPE_SFIXED64
:
2626 case PROTOBUF_C_TYPE_UINT64
:
2627 case PROTOBUF_C_TYPE_FIXED64
:
2628 case PROTOBUF_C_TYPE_DOUBLE
:
2629 memcpy(field
, dv
, 8);
2631 case PROTOBUF_C_TYPE_BOOL
:
2632 memcpy(field
, dv
, sizeof(protobuf_c_boolean
));
2634 case PROTOBUF_C_TYPE_BYTES
:
2635 memcpy(field
, dv
, sizeof(ProtobufCBinaryData
));
2638 case PROTOBUF_C_TYPE_STRING
:
2639 case PROTOBUF_C_TYPE_MESSAGE
:
2641 * The next line essentially implements a cast
2642 * from const, which is totally unavoidable.
2644 *(const void **) field
= dv
;
2654 * ScannedMember slabs (an unpacking implementation detail). Before doing real
2655 * unpacking, we first scan through the elements to see how many there are (for
2656 * repeated fields), and which field to use (for non-repeated fields given
2659 * In order to avoid allocations for small messages, we keep a stack-allocated
2660 * slab of ScannedMembers of size FIRST_SCANNED_MEMBER_SLAB_SIZE (16). After we
2661 * fill that up, we allocate each slab twice as large as the previous one.
2663 #define FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2 4
2666 * The number of slabs, including the stack-allocated ones; choose the number so
2667 * that we would overflow if we needed a slab larger than provided.
2669 #define MAX_SCANNED_MEMBER_SLAB \
2670 (sizeof(unsigned int)*8 - 1 \
2671 - BOUND_SIZEOF_SCANNED_MEMBER_LOG2 \
2672 - FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2)
2674 #define REQUIRED_FIELD_BITMAP_SET(index) \
2675 (required_fields_bitmap[(index)/8] |= (1<<((index)%8)))
2677 #define REQUIRED_FIELD_BITMAP_IS_SET(index) \
2678 (required_fields_bitmap[(index)/8] & (1<<((index)%8)))
2681 protobuf_c_message_unpack(const ProtobufCMessageDescriptor
*desc
,
2682 ProtobufCAllocator
*allocator
,
2683 size_t len
, const uint8_t *data
)
2685 ProtobufCMessage
*rv
;
2687 const uint8_t *at
= data
;
2688 const ProtobufCFieldDescriptor
*last_field
= desc
->fields
+ 0;
2689 ScannedMember first_member_slab
[1 <<
2690 FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2
];
2693 * scanned_member_slabs[i] is an array of arrays of ScannedMember.
2694 * The first slab (scanned_member_slabs[0] is just a pointer to
2695 * first_member_slab), above. All subsequent slabs will be allocated
2696 * using the allocator.
2698 ScannedMember
*scanned_member_slabs
[MAX_SCANNED_MEMBER_SLAB
+ 1];
2699 unsigned which_slab
= 0; /* the slab we are currently populating */
2700 unsigned in_slab_index
= 0; /* number of members in the slab */
2701 size_t n_unknown
= 0;
2705 unsigned last_field_index
= 0;
2706 unsigned required_fields_bitmap_len
;
2707 unsigned char required_fields_bitmap_stack
[16];
2708 unsigned char *required_fields_bitmap
= required_fields_bitmap_stack
;
2709 protobuf_c_boolean required_fields_bitmap_alloced
= FALSE
;
2711 ASSERT_IS_MESSAGE_DESCRIPTOR(desc
);
2713 if (allocator
== NULL
)
2714 allocator
= &protobuf_c__allocator
;
2716 rv
= do_alloc(allocator
, desc
->sizeof_message
);
2719 scanned_member_slabs
[0] = first_member_slab
;
2721 required_fields_bitmap_len
= (desc
->n_fields
+ 7) / 8;
2722 if (required_fields_bitmap_len
> sizeof(required_fields_bitmap_stack
)) {
2723 required_fields_bitmap
= do_alloc(allocator
, required_fields_bitmap_len
);
2724 if (!required_fields_bitmap
) {
2725 do_free(allocator
, rv
);
2728 required_fields_bitmap_alloced
= TRUE
;
2730 memset(required_fields_bitmap
, 0, required_fields_bitmap_len
);
2733 * Generated code always defines "message_init". However, we provide a
2734 * fallback for (1) users of old protobuf-c generated-code that do not
2735 * provide the function, and (2) descriptors constructed from some other
2736 * source (most likely, direct construction from the .proto file).
2738 if (desc
->message_init
!= NULL
)
2739 protobuf_c_message_init(desc
, rv
);
2741 message_init_generic(desc
, rv
);
2745 ProtobufCWireType wire_type
;
2746 size_t used
= parse_tag_and_wiretype(rem
, at
, &tag
, &wire_type
);
2747 const ProtobufCFieldDescriptor
*field
;
2750 memset(&tmp
, 0, sizeof(ScannedMember
));
2753 PROTOBUF_C_UNPACK_ERROR("error parsing tag/wiretype at offset %u",
2754 (unsigned) (at
- data
));
2755 goto error_cleanup_during_scan
;
2758 * \todo Consider optimizing for field[1].id == tag, if field[1]
2761 if (last_field
== NULL
|| last_field
->id
!= tag
) {
2764 int_range_lookup(desc
->n_field_ranges
,
2767 if (field_index
< 0) {
2771 field
= desc
->fields
+ field_index
;
2773 last_field_index
= field_index
;
2779 if (field
!= NULL
&& field
->label
== PROTOBUF_C_LABEL_REQUIRED
)
2780 REQUIRED_FIELD_BITMAP_SET(last_field_index
);
2785 tmp
.wire_type
= wire_type
;
2788 tmp
.length_prefix_len
= 0;
2790 switch (wire_type
) {
2791 case PROTOBUF_C_WIRE_TYPE_VARINT
: {
2792 unsigned max_len
= rem
< 10 ? rem
: 10;
2795 for (i
= 0; i
< max_len
; i
++)
2796 if ((at
[i
] & 0x80) == 0)
2799 PROTOBUF_C_UNPACK_ERROR("unterminated varint at offset %u",
2800 (unsigned) (at
- data
));
2801 goto error_cleanup_during_scan
;
2806 case PROTOBUF_C_WIRE_TYPE_64BIT
:
2808 PROTOBUF_C_UNPACK_ERROR("too short after 64bit wiretype at offset %u",
2809 (unsigned) (at
- data
));
2810 goto error_cleanup_during_scan
;
2814 case PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED
: {
2817 tmp
.len
= scan_length_prefixed_data(rem
, at
, &pref_len
);
2819 /* NOTE: scan_length_prefixed_data calls UNPACK_ERROR */
2820 goto error_cleanup_during_scan
;
2822 tmp
.length_prefix_len
= pref_len
;
2825 case PROTOBUF_C_WIRE_TYPE_32BIT
:
2827 PROTOBUF_C_UNPACK_ERROR("too short after 32bit wiretype at offset %u",
2828 (unsigned) (at
- data
));
2829 goto error_cleanup_during_scan
;
2834 PROTOBUF_C_UNPACK_ERROR("unsupported tag %u at offset %u",
2835 wire_type
, (unsigned) (at
- data
));
2836 goto error_cleanup_during_scan
;
2839 if (in_slab_index
== (1U <<
2840 (which_slab
+ FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2
)))
2845 if (which_slab
== MAX_SCANNED_MEMBER_SLAB
) {
2846 PROTOBUF_C_UNPACK_ERROR("too many fields");
2847 goto error_cleanup_during_scan
;
2850 size
= sizeof(ScannedMember
)
2851 << (which_slab
+ FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2
);
2852 scanned_member_slabs
[which_slab
] = do_alloc(allocator
, size
);
2853 if (scanned_member_slabs
[which_slab
] == NULL
)
2854 goto error_cleanup_during_scan
;
2856 scanned_member_slabs
[which_slab
][in_slab_index
++] = tmp
;
2858 if (field
!= NULL
&& field
->label
== PROTOBUF_C_LABEL_REPEATED
) {
2859 size_t *n
= STRUCT_MEMBER_PTR(size_t, rv
,
2860 field
->quantifier_offset
);
2861 if (wire_type
== PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED
&&
2862 (0 != (field
->flags
& PROTOBUF_C_FIELD_FLAG_PACKED
) ||
2863 is_packable_type(field
->type
)))
2866 if (!count_packed_elements(field
->type
,
2868 tmp
.length_prefix_len
,
2870 tmp
.length_prefix_len
,
2873 PROTOBUF_C_UNPACK_ERROR("counting packed elements");
2874 goto error_cleanup_during_scan
;
2886 /* allocate space for repeated fields, also check that all required fields have been set */
2887 for (f
= 0; f
< desc
->n_fields
; f
++) {
2888 const ProtobufCFieldDescriptor
*field
= desc
->fields
+ f
;
2889 if (field
->label
== PROTOBUF_C_LABEL_REPEATED
) {
2891 sizeof_elt_in_repeated_array(field
->type
);
2893 STRUCT_MEMBER_PTR(size_t, rv
,
2894 field
->quantifier_offset
);
2896 unsigned n
= *n_ptr
;
2899 assert(rv
->descriptor
!= NULL
);
2900 #define CLEAR_REMAINING_N_PTRS() \
2901 for(f++;f < desc->n_fields; f++) \
2903 field = desc->fields + f; \
2904 if (field->label == PROTOBUF_C_LABEL_REPEATED) \
2905 STRUCT_MEMBER (size_t, rv, field->quantifier_offset) = 0; \
2907 a
= do_alloc(allocator
, siz
* n
);
2909 CLEAR_REMAINING_N_PTRS();
2912 STRUCT_MEMBER(void *, rv
, field
->offset
) = a
;
2914 } else if (field
->label
== PROTOBUF_C_LABEL_REQUIRED
) {
2915 if (field
->default_value
== NULL
&&
2916 !REQUIRED_FIELD_BITMAP_IS_SET(f
))
2918 CLEAR_REMAINING_N_PTRS();
2919 PROTOBUF_C_UNPACK_ERROR("message '%s': missing required field '%s'",
2920 desc
->name
, field
->name
);
2925 #undef CLEAR_REMAINING_N_PTRS
2927 /* allocate space for unknown fields */
2929 rv
->unknown_fields
= do_alloc(allocator
,
2930 n_unknown
* sizeof(ProtobufCMessageUnknownField
));
2931 if (rv
->unknown_fields
== NULL
)
2935 /* do real parsing */
2936 for (i_slab
= 0; i_slab
<= which_slab
; i_slab
++) {
2937 unsigned max
= (i_slab
== which_slab
) ?
2938 in_slab_index
: (1U << (i_slab
+ 4));
2939 ScannedMember
*slab
= scanned_member_slabs
[i_slab
];
2942 for (j
= 0; j
< max
; j
++) {
2943 if (!parse_member(slab
+ j
, rv
, allocator
)) {
2944 PROTOBUF_C_UNPACK_ERROR("error parsing member %s of %s",
2945 slab
->field
? slab
->field
->name
: "*unknown-field*",
2953 for (j
= 1; j
<= which_slab
; j
++)
2954 do_free(allocator
, scanned_member_slabs
[j
]);
2955 if (required_fields_bitmap_alloced
)
2956 do_free(allocator
, required_fields_bitmap
);
2960 protobuf_c_message_free_unpacked(rv
, allocator
);
2961 for (j
= 1; j
<= which_slab
; j
++)
2962 do_free(allocator
, scanned_member_slabs
[j
]);
2963 if (required_fields_bitmap_alloced
)
2964 do_free(allocator
, required_fields_bitmap
);
2967 error_cleanup_during_scan
:
2968 do_free(allocator
, rv
);
2969 for (j
= 1; j
<= which_slab
; j
++)
2970 do_free(allocator
, scanned_member_slabs
[j
]);
2971 if (required_fields_bitmap_alloced
)
2972 do_free(allocator
, required_fields_bitmap
);
2977 protobuf_c_message_free_unpacked(ProtobufCMessage
*message
,
2978 ProtobufCAllocator
*allocator
)
2980 const ProtobufCMessageDescriptor
*desc
= message
->descriptor
;
2983 ASSERT_IS_MESSAGE(message
);
2984 if (allocator
== NULL
)
2985 allocator
= &protobuf_c__allocator
;
2986 message
->descriptor
= NULL
;
2987 for (f
= 0; f
< desc
->n_fields
; f
++) {
2988 if (desc
->fields
[f
].label
== PROTOBUF_C_LABEL_REPEATED
) {
2989 size_t n
= STRUCT_MEMBER(size_t,
2991 desc
->fields
[f
].quantifier_offset
);
2992 void *arr
= STRUCT_MEMBER(void *,
2994 desc
->fields
[f
].offset
);
2996 if (desc
->fields
[f
].type
== PROTOBUF_C_TYPE_STRING
) {
2998 for (i
= 0; i
< n
; i
++)
2999 do_free(allocator
, ((char **) arr
)[i
]);
3000 } else if (desc
->fields
[f
].type
== PROTOBUF_C_TYPE_BYTES
) {
3002 for (i
= 0; i
< n
; i
++)
3003 do_free(allocator
, ((ProtobufCBinaryData
*) arr
)[i
].data
);
3004 } else if (desc
->fields
[f
].type
== PROTOBUF_C_TYPE_MESSAGE
) {
3006 for (i
= 0; i
< n
; i
++)
3007 protobuf_c_message_free_unpacked(
3008 ((ProtobufCMessage
**) arr
)[i
],
3013 do_free(allocator
, arr
);
3014 } else if (desc
->fields
[f
].type
== PROTOBUF_C_TYPE_STRING
) {
3015 char *str
= STRUCT_MEMBER(char *, message
,
3016 desc
->fields
[f
].offset
);
3018 if (str
&& str
!= desc
->fields
[f
].default_value
)
3019 do_free(allocator
, str
);
3020 } else if (desc
->fields
[f
].type
== PROTOBUF_C_TYPE_BYTES
) {
3021 void *data
= STRUCT_MEMBER(ProtobufCBinaryData
, message
,
3022 desc
->fields
[f
].offset
).data
;
3023 const ProtobufCBinaryData
*default_bd
;
3025 default_bd
= desc
->fields
[f
].default_value
;
3027 (default_bd
== NULL
||
3028 default_bd
->data
!= data
))
3030 do_free(allocator
, data
);
3032 } else if (desc
->fields
[f
].type
== PROTOBUF_C_TYPE_MESSAGE
) {
3033 ProtobufCMessage
*sm
;
3035 sm
= STRUCT_MEMBER(ProtobufCMessage
*, message
,
3036 desc
->fields
[f
].offset
);
3037 if (sm
&& sm
!= desc
->fields
[f
].default_value
)
3038 protobuf_c_message_free_unpacked(sm
, allocator
);
3042 for (f
= 0; f
< message
->n_unknown_fields
; f
++)
3043 do_free(allocator
, message
->unknown_fields
[f
].data
);
3044 if (message
->unknown_fields
!= NULL
)
3045 do_free(allocator
, message
->unknown_fields
);
3047 do_free(allocator
, message
);
3051 protobuf_c_message_init(const ProtobufCMessageDescriptor
* descriptor
,
3054 descriptor
->message_init((ProtobufCMessage
*) (message
));
3058 protobuf_c_message_check(const ProtobufCMessage
*message
)
3063 !message
->descriptor
||
3064 message
->descriptor
->magic
!= PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC
)
3069 for (i
= 0; i
< message
->descriptor
->n_fields
; i
++) {
3070 const ProtobufCFieldDescriptor
*f
= message
->descriptor
->fields
+ i
;
3071 ProtobufCType type
= f
->type
;
3072 ProtobufCLabel label
= f
->label
;
3073 void *field
= STRUCT_MEMBER_P (message
, f
->offset
);
3075 if (label
== PROTOBUF_C_LABEL_REPEATED
) {
3076 size_t *quantity
= STRUCT_MEMBER_P (message
, f
->quantifier_offset
);
3078 if (*quantity
> 0 && *(void **) field
== NULL
) {
3082 if (type
== PROTOBUF_C_TYPE_MESSAGE
) {
3083 ProtobufCMessage
**submessage
= *(ProtobufCMessage
***) field
;
3085 for (j
= 0; j
< *quantity
; j
++) {
3086 if (!protobuf_c_message_check(submessage
[j
]))
3089 } else if (type
== PROTOBUF_C_TYPE_STRING
) {
3090 char **string
= *(char ***) field
;
3092 for (j
= 0; j
< *quantity
; j
++) {
3096 } else if (type
== PROTOBUF_C_TYPE_BYTES
) {
3097 ProtobufCBinaryData
*bd
= *(ProtobufCBinaryData
**) field
;
3099 for (j
= 0; j
< *quantity
; j
++) {
3100 if (bd
[j
].len
> 0 && bd
[j
].data
== NULL
)
3105 } else { /* PROTOBUF_C_LABEL_REQUIRED or PROTOBUF_C_LABEL_OPTIONAL */
3107 if (type
== PROTOBUF_C_TYPE_MESSAGE
) {
3108 ProtobufCMessage
*submessage
= *(ProtobufCMessage
**) field
;
3109 if (label
== PROTOBUF_C_LABEL_REQUIRED
|| submessage
!= NULL
) {
3110 if (!protobuf_c_message_check(submessage
))
3113 } else if (type
== PROTOBUF_C_TYPE_STRING
) {
3114 char *string
= *(char **) field
;
3115 if (label
== PROTOBUF_C_LABEL_REQUIRED
&& string
== NULL
)
3117 } else if (type
== PROTOBUF_C_TYPE_BYTES
) {
3118 protobuf_c_boolean
*has
= STRUCT_MEMBER_P (message
, f
->quantifier_offset
);
3119 ProtobufCBinaryData
*bd
= field
;
3120 if (label
== PROTOBUF_C_LABEL_REQUIRED
|| *has
== TRUE
) {
3121 if (bd
->len
> 0 && bd
->data
== NULL
)
3131 /* === services === */
3133 typedef void (*GenericHandler
) (void *service
,
3134 const ProtobufCMessage
*input
,
3135 ProtobufCClosure closure
,
3136 void *closure_data
);
3138 protobuf_c_service_invoke_internal(ProtobufCService
*service
,
3139 unsigned method_index
,
3140 const ProtobufCMessage
*input
,
3141 ProtobufCClosure closure
,
3144 GenericHandler
*handlers
;
3145 GenericHandler handler
;
3148 * Verify that method_index is within range. If this fails, you are
3149 * likely invoking a newly added method on an old service. (Although
3150 * other memory corruption bugs can cause this assertion too.)
3152 assert(method_index
< service
->descriptor
->n_methods
);
3155 * Get the array of virtual methods (which are enumerated by the
3158 handlers
= (GenericHandler
*) (service
+ 1);
3161 * Get our method and invoke it.
3162 * \todo Seems like handler == NULL is a situation that needs handling.
3164 handler
= handlers
[method_index
];
3165 (*handler
)(service
, input
, closure
, closure_data
);
3169 protobuf_c_service_generated_init(ProtobufCService
*service
,
3170 const ProtobufCServiceDescriptor
*descriptor
,
3171 ProtobufCServiceDestroy destroy
)
3173 ASSERT_IS_SERVICE_DESCRIPTOR(descriptor
);
3174 service
->descriptor
= descriptor
;
3175 service
->destroy
= destroy
;
3176 service
->invoke
= protobuf_c_service_invoke_internal
;
3177 memset(service
+ 1, 0, descriptor
->n_methods
* sizeof(GenericHandler
));
3180 void protobuf_c_service_destroy(ProtobufCService
*service
)
3182 service
->destroy(service
);
3185 /* --- querying the descriptors --- */
3187 const ProtobufCEnumValue
*
3188 protobuf_c_enum_descriptor_get_value_by_name(const ProtobufCEnumDescriptor
*desc
,
3192 unsigned count
= desc
->n_value_names
;
3195 unsigned mid
= start
+ count
/ 2;
3196 int rv
= strcmp(desc
->values_by_name
[mid
].name
, name
);
3198 return desc
->values
+ desc
->values_by_name
[mid
].index
;
3200 count
= start
+ count
- (mid
+ 1);
3203 count
= mid
- start
;
3207 if (purple_strequal(desc
->values_by_name
[start
].name
, name
))
3208 return desc
->values
+ desc
->values_by_name
[start
].index
;
3212 const ProtobufCEnumValue
*
3213 protobuf_c_enum_descriptor_get_value(const ProtobufCEnumDescriptor
*desc
,
3216 int rv
= int_range_lookup(desc
->n_value_ranges
, desc
->value_ranges
, value
);
3219 return desc
->values
+ rv
;
3222 const ProtobufCFieldDescriptor
*
3223 protobuf_c_message_descriptor_get_field_by_name(const ProtobufCMessageDescriptor
*desc
,
3227 unsigned count
= desc
->n_fields
;
3228 const ProtobufCFieldDescriptor
*field
;
3231 unsigned mid
= start
+ count
/ 2;
3233 field
= desc
->fields
+ desc
->fields_sorted_by_name
[mid
];
3234 rv
= strcmp(field
->name
, name
);
3238 count
= start
+ count
- (mid
+ 1);
3241 count
= mid
- start
;
3245 field
= desc
->fields
+ desc
->fields_sorted_by_name
[start
];
3246 if (purple_strequal(field
->name
, name
))
3251 const ProtobufCFieldDescriptor
*
3252 protobuf_c_message_descriptor_get_field(const ProtobufCMessageDescriptor
*desc
,
3255 int rv
= int_range_lookup(desc
->n_field_ranges
,desc
->field_ranges
, value
);
3258 return desc
->fields
+ rv
;
3261 const ProtobufCMethodDescriptor
*
3262 protobuf_c_service_descriptor_get_method_by_name(const ProtobufCServiceDescriptor
*desc
,
3266 unsigned count
= desc
->n_methods
;
3269 unsigned mid
= start
+ count
/ 2;
3270 unsigned mid_index
= desc
->method_indices_by_name
[mid
];
3271 const char *mid_name
= desc
->methods
[mid_index
].name
;
3272 int rv
= strcmp(mid_name
, name
);
3275 return desc
->methods
+ desc
->method_indices_by_name
[mid
];
3277 count
= start
+ count
- (mid
+ 1);
3280 count
= mid
- start
;
3285 if (purple_strequal(desc
->methods
[desc
->method_indices_by_name
[start
]].name
, name
))
3286 return desc
->methods
+ desc
->method_indices_by_name
[start
];