/*- * Copyright (c) 2015--2018 Taylor R. Campbell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef LIBPICOPB_PB_H #define LIBPICOPB_PB_H #ifdef __GNUC__ #define PB_GNUC_PREREQ(maj, min) \ ((__GNUC__ > (maj)) || \ ((__GNUC__ == (maj)) && (__GNUC_MINOR__ >= (min)))) #else #define PB_GNUC_PREREQ(maj, min) 0 #endif #if PB_GNUC_PREREQ(4,5) #define pb_attr_alloc_size(n) __attribute__((__alloc_size__(n))) #else #define pb_attr_alloc_size(n) #endif #if PB_GNUC_PREREQ(3,0) #define pb_attr_noinline __attribute__((__noinline__)) #else #define pb_attr_noinline #endif #if PB_GNUC_PREREQ(2,7) #define pb_attr_unused __attribute__((__unused__)) #else #define pb_attr_unused #endif #if defined(__NetBSD__) && defined(_KERNEL) #include #include #include #define PB_CTASSERT CTASSERT #define pb_bug(msg, ...) panic(msg, ##__VA_ARGS__) #define pb_assert KASSERT #if DIAGNOSTIC #define pb_attr_diagused #else #define pb_attr_diagused __unused #endif #else /* !(__NetBSD__ && _KERNEL) */ #include #include #include #include #include #ifdef __COUNTER__ #define PB_CTASSERT(cond) PB_CTASSERT0(cond, pb_ctassert, __COUNTER__) #else #define PB_CTASSERT(cond) PB_CTASSERT0(cond, pb_ctassert, __LINE__) #endif #define PB_CTASSERT0(cond, prefix, suffix) \ PB_CTASSERT1(cond, prefix, suffix) #define PB_CTASSERT1(cond, prefix, suffix) \ typedef char prefix##suffix[(cond) ? 1 : -1] #define pb_bug(msg, ...) abort() #define pb_assert assert #ifdef NDEBUG #define pb_attr_diagused pb_attr_unused #else #define pb_attr_diagused #endif #endif enum pb_wiretype { PB_WIRETYPE_VARINT = 0, PB_WIRETYPE_64BIT = 1, PB_WIRETYPE_LENGTH_DELIMITED = 2, PB_WIRETYPE_START_GROUP = 3, PB_WIRETYPE_END_GROUP = 4, PB_WIRETYPE_32BIT = 5, }; /* * Descriptors -- static data describing the run-time layout of * messages and fields. */ struct pb_msgdesc { uint32_t pbmd_abi_version; const char *pbmd_name; size_t pbmd_size; /* Fields must be ordered by ascending tag. */ const struct pb_field *pbmd_fields; size_t pbmd_nfields; const struct pb_format_cookie *pbmd_format_cookies; size_t pbmd_nformat_cookies; }; struct pb_format { const char *pbfmt_name; }; struct pb_format_cookie { const struct pb_format *pbfc_format; const void *pbfc_cookie; }; struct pb_enumerand { const char *pbed_name; int32_t pbed_number; }; struct pb_enumeration { /* Enumerands must be ordered by ascending value. */ const struct pb_enumerand *pben_enumerands; size_t pben_nenumerands; }; #define PB_MAX_REQUIRED_FIELDS 64 enum pb_basic_type { PB_TYPE_BOOL, PB_TYPE_UINT32, PB_TYPE_UINT64, PB_TYPE_FIXED32, PB_TYPE_FIXED64, PB_TYPE_INT32, PB_TYPE_INT64, PB_TYPE_SINT32, PB_TYPE_SINT64, PB_TYPE_SFIXED32, PB_TYPE_SFIXED64, PB_TYPE_ENUM, PB_TYPE_FLOAT, PB_TYPE_DOUBLE, PB_TYPE_BYTES, PB_TYPE_STRING, PB_TYPE_MSG, }; struct pb_type { enum pb_basic_type pbt_type; union { struct { const struct pb_msgdesc *msgdesc; } msg; struct { const struct pb_enumeration *enumeration; } enumerated; } pbt_u; }; enum pb_quantifier { PBQ_REQUIRED, PBQ_OPTIONAL, PBQ_REPEATED, }; struct pb_field { enum pb_quantifier pbf_quant; union { struct { size_t offset; } required; struct { size_t present_offset; size_t value_offset; } optional; struct { size_t hdr_offset; size_t ptr_offset; size_t maximum; } repeated; } pbf_qu; struct pb_type pbf_type; const char *pbf_name; uint32_t pbf_tag; }; /* * Run-time structures */ struct pb_msg_hdr { const struct pb_msgdesc *pbmh_msgdesc; const struct pb_allocator *pbmh_allocator; size_t pbmh_cached_size; }; struct pb_repeated { const struct pb_allocator *pbr_allocator; const struct pb_field *pbr_field; size_t pbr_nused; size_t pbr_nalloc; }; static inline size_t pb_repeated_count(const struct pb_repeated *pbr) { return pbr->pbr_nused; } enum pb_allocation { PB_ALLOC_STATIC, PB_ALLOC_DYNAMIC, #if notyet PB_ALLOC_CALLBACK, #endif }; /* * Strings: UTF-8 sequences, which we store null-terminated for * convenience. Len is the number of nonzero bytes; ptr always has an * extra null byte afterward. */ struct pb_string { const struct pb_allocator *pbs_allocator; enum pb_allocation pbs_allocation; union { struct { const char *ptr; size_t len; } static_alloc; struct { char *ptr; size_t len; } dynamic_alloc; #if notyet struct { int (*producer)(void *, pb_encoder_callback_t *, void *); int (*consumer)(void *, size_t, pb_decoder_callback_t *, void *); void *arg; } callback; #endif } pbs_u; }; /* * Bytes: Arbitrary sequences of bytes. */ struct pb_bytes { const struct pb_allocator *pbb_allocator; enum pb_allocation pbb_allocation; union { struct { const uint8_t *ptr; size_t size; } static_alloc; struct { uint8_t *ptr; size_t size; } dynamic_alloc; #if notyet struct { int (*producer)(void *, pb_encoder_callback_t *, void *); int (*consumer)(void *, size_t, pb_decoder_callback_t *, void *); void *arg; } callback; #endif } pbb_u; }; /* * Parameters */ struct pb_allocator { void *(*pba_alloc)(size_t) pb_attr_alloc_size(1); void *(*pba_realloc)(void *, size_t, size_t) pb_attr_alloc_size(3); void (*pba_free)(void *, size_t); }; struct pb_msg { const struct pb_msgdesc *pbm_msgdesc; void *pbm_ptr; }; struct pb_msg_ptr { const struct pb_msgdesc *pbmp_msgdesc; void *pbmp_ptrp; }; /* * Functions */ static inline size_t pb_type_size(const struct pb_type *type) { switch (type->pbt_type) { case PB_TYPE_BOOL: return sizeof(bool); case PB_TYPE_UINT32: return sizeof(uint32_t); case PB_TYPE_UINT64: return sizeof(uint64_t); case PB_TYPE_FIXED32: return sizeof(uint32_t); case PB_TYPE_FIXED64: return sizeof(uint64_t); case PB_TYPE_INT32: return sizeof(int32_t); case PB_TYPE_INT64: return sizeof(int64_t); case PB_TYPE_SINT32: return sizeof(int32_t); case PB_TYPE_SINT64: return sizeof(int64_t); case PB_TYPE_SFIXED32: return sizeof(int32_t); case PB_TYPE_SFIXED64: return sizeof(int64_t); case PB_TYPE_FLOAT: return sizeof(float); case PB_TYPE_DOUBLE: return sizeof(double); case PB_TYPE_BYTES: return sizeof(struct pb_bytes); case PB_TYPE_STRING: return sizeof(struct pb_string); case PB_TYPE_MSG: return type->pbt_u.msg.msgdesc->pbmd_size; default: pb_bug("invalid pb type %p: %d", type, (int)type->pbt_type); } } bool pb_abi_compatible(uint32_t /*stored*/, uint32_t /*implemented*/); void pb_init(struct pb_msg); void pb_allocator_init(const struct pb_allocator *, struct pb_msg); void pb_destroy(struct pb_msg); int pb_alloc(struct pb_msg_ptr); int pb_allocator_alloc(const struct pb_allocator *, struct pb_msg_ptr); void pb_free(struct pb_msg_ptr); size_t pb_bytes_size(const struct pb_bytes *); const uint8_t * pb_bytes_ptr(const struct pb_bytes *, size_t *); uint8_t *pb_bytes_ptr_mutable(struct pb_bytes *, size_t *); int pb_bytes_alloc(struct pb_bytes *, size_t); int pb_bytes_set_copy(struct pb_bytes *, const uint8_t *, size_t); void pb_bytes_set_ptr(struct pb_bytes *, const uint8_t *, size_t); size_t pb_string_len(const struct pb_string *); const char * pb_string_ptr(const struct pb_string *); char *pb_string_ptr_mutable(struct pb_string *); int pb_string_alloc(struct pb_string *, size_t); int pb_string_set_copy(struct pb_string *, const char *, size_t); void pb_string_set_ptr(struct pb_string *, const char *, size_t); int pb_string_set_copy_asciz(struct pb_string *, const char *); void pb_string_set_ptr_asciz(struct pb_string *, const char *); int pb_utf8_validate(const char *, size_t); int pb_repeated_add(struct pb_repeated *, size_t *); int pb_repeated_alloc(struct pb_repeated *, size_t); const void * pb_get_format(const struct pb_msgdesc *, const struct pb_format *); #endif /* LIBPICOPB_PB_H */