Line data Source code
1 : #ifndef HEADER_fd_src_ballet_pb_fd_pb_tokenize_h 2 : #define HEADER_fd_src_ballet_pb_fd_pb_tokenize_h 3 : 4 : /* fd_pb_tokenize.h provides an API to iterate over tokens in Protobuf 5 : wire format. It can be used to deserialize Protobuf. */ 6 : 7 : #include "fd_pb_wire.h" 8 : #include "../base58/fd_base58.h" 9 : 10 : struct fd_pb_inbuf { 11 : uchar const * cur; 12 : uchar const * end; 13 : }; 14 : 15 : typedef struct fd_pb_inbuf fd_pb_inbuf_t; 16 : 17 : FD_PROTOTYPES_BEGIN 18 : 19 : static inline fd_pb_inbuf_t * 20 : fd_pb_inbuf_init( fd_pb_inbuf_t * buf, 21 : void const * data, 22 71963 : ulong data_sz ) { 23 71963 : buf->cur = data; 24 71963 : buf->end = buf->cur + data_sz; 25 71963 : return buf; 26 71963 : } 27 : 28 : static inline ulong 29 32279713 : fd_pb_inbuf_sz( fd_pb_inbuf_t const * buf ) { 30 32279713 : return (ulong)( buf->end - buf->cur ); 31 32279713 : } 32 : 33 : static inline void 34 : fd_pb_inbuf_skip( fd_pb_inbuf_t * buf, 35 0 : ulong sz ) { 36 0 : FD_CHECK_CRIT( sz<=fd_pb_inbuf_sz( buf ), "Attempt to skip past end of buffer" ); 37 0 : buf->cur += sz; 38 0 : } 39 : 40 : FD_PROTOTYPES_END 41 : 42 : struct fd_pb_tlv { 43 : uint wire_type; /* FD_PB_WIRE_TYPE_* */ 44 : uint field_id; 45 : 46 : union { 47 : ulong varint; 48 : ulong i64; 49 : ulong len; 50 : uint i32; 51 : }; 52 : }; 53 : 54 : typedef struct fd_pb_tlv fd_pb_tlv_t; 55 : 56 : FD_PROTOTYPES_BEGIN 57 : 58 : /* fd_pb_read_varint reads a base-128 varint of up to 10 bytes. On 59 : success, stores the value to *out, advances buf, and returns buf. On 60 : failure (EOF, overflow), returns NULL without advancing buf. */ 61 : 62 : fd_pb_inbuf_t * 63 : fd_pb_read_varint( fd_pb_inbuf_t * buf, 64 : ulong * out ); 65 : 66 : /* fd_pb_tlv_read reads a Protobuf TLV. This includes a wire type, a 67 : field ID, and data. Data is either a scalar value field, or a length 68 : prefix. Populates *tlv, advances buf, and returns tlv on success. 69 : On failure, silently returns NULL without advancing buf. Reasons for 70 : failure include: parse failure, unexpected EOF. 71 : 72 : buf is advanced as follows: 73 : - VARINT, I32, and I64 TLVs are fully consumed 74 : - For LEN TLVs, only the length prefix is consumed (the next tlv.len 75 : bytes of buf are the value) */ 76 : 77 : fd_pb_tlv_t * 78 : fd_pb_tlv_read( fd_pb_inbuf_t * buf, 79 : fd_pb_tlv_t * tlv ); 80 : 81 : /* fd_pb_tlv_bytes interprets a TLV as a byte array value. */ 82 : 83 : static inline uchar const * 84 : fd_pb_tlv_bytes( fd_pb_inbuf_t const * buf, 85 4530648 : fd_pb_tlv_t const * tlv ) { 86 4530648 : if( FD_UNLIKELY( tlv->wire_type!=FD_PB_WIRE_TYPE_LEN || 87 4530648 : tlv->len > fd_pb_inbuf_sz( buf ) ) ) { 88 0 : return NULL; 89 0 : } 90 4530648 : return buf->cur; 91 4530648 : } 92 : 93 : /* fd_pb_tlv_cstr interprets converts a byte array TLV into a NULL- 94 : terminated C string. cstr_max is the cstr buffer size and includes 95 : the NULL terminator. */ 96 : 97 : static inline char * 98 : fd_pb_tlv_cstr( fd_pb_inbuf_t const * buf, 99 : fd_pb_tlv_t const * tlv, 100 : char * cstr, 101 71485 : ulong cstr_max ) { 102 71485 : if( FD_UNLIKELY( !cstr_max || 103 71485 : tlv->wire_type!=FD_PB_WIRE_TYPE_LEN || 104 71485 : tlv->len > fd_pb_inbuf_sz( buf ) || 105 71485 : tlv->len > cstr_max-1UL ) ) { 106 0 : return NULL; 107 0 : } 108 71485 : char * p = fd_cstr_init( cstr ); 109 71485 : p = fd_cstr_append_text( p, (char const *)buf->cur, tlv->len ); 110 71485 : fd_cstr_fini( p ); 111 71485 : return cstr; 112 71485 : } 113 : 114 : /* fd_pb_tlv_base58_32 interprets a TLV as a Base58-encoded 32-byte 115 : string. */ 116 : 117 : static FD_FN_UNUSED uchar const * 118 : fd_pb_tlv_base58_32( fd_pb_inbuf_t const * buf, 119 : fd_pb_tlv_t const * tlv, 120 0 : uchar out[ 32 ] ) { 121 0 : char str[ FD_BASE58_ENCODED_32_SZ ]; 122 0 : if( FD_UNLIKELY( !fd_pb_tlv_cstr( buf, tlv, str, sizeof(str) ) ) ) { 123 0 : return NULL; 124 0 : } 125 0 : if( FD_UNLIKELY( !fd_base58_decode_32( str, out ) ) ) { 126 0 : return NULL; 127 0 : } 128 0 : return out; 129 0 : } 130 : 131 : /* fd_pb_tlv_submsg interprets a TLV as a Protobuf submessage. */ 132 : 133 : static FD_FN_UNUSED fd_pb_inbuf_t * 134 : fd_pb_tlv_submsg( fd_pb_inbuf_t const * buf, 135 : fd_pb_tlv_t const * tlv, 136 3359357 : fd_pb_inbuf_t * submsg ) { 137 3359357 : if( FD_UNLIKELY( tlv->wire_type!=FD_PB_WIRE_TYPE_LEN || 138 3359357 : tlv->len > fd_pb_inbuf_sz( buf ) ) ) { 139 0 : return NULL; 140 0 : } 141 3359357 : submsg->cur = buf->cur; 142 3359357 : submsg->end = submsg->cur + tlv->len; 143 3359357 : return submsg; 144 3359357 : } 145 : 146 : /* fd_pb_tlv_skip skips the value of a TLV. Returns the value that was 147 : skipped on success. On failure (corrupt Protobuf), returns NULL. */ 148 : 149 : static inline uchar const * 150 : fd_pb_tlv_skip( fd_pb_inbuf_t * buf, 151 0 : fd_pb_tlv_t const * tlv ) { 152 0 : uchar const * ret = buf->cur; 153 0 : if( tlv->wire_type==FD_PB_WIRE_TYPE_LEN ) { 154 0 : if( FD_UNLIKELY( tlv->len > fd_pb_inbuf_sz( buf ) ) ) return NULL; 155 0 : buf->cur += tlv->len; 156 0 : } 157 0 : return ret; 158 0 : } 159 : 160 : FD_PROTOTYPES_END 161 : 162 : #endif /* HEADER_fd_src_ballet_pb_fd_pb_tokenize_h */