1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
|
#ifndef _PB_H_
#define _PB_H_
#include <stdint.h>
#include <stddef.h> // size_t
#include <stdbool.h>
#ifdef __GNUC__
// This just reduces memory requirements, but is not required.
#define pb_packed __attribute__((packed))
#else
#define pb_packed
#endif
/* Lightweight input stream.
* If buf is NULL, read but don't store bytes.
* You have to provide a callback function for reading.
* You can use state to store your own data (e.g. buffer pointer),
* and rely on pb_read to verify that no-body reads past bytes_left.
* However, substreams may change bytes_left so don't use that to
* compute any pointers.
*/
typedef struct _pb_istream_t pb_istream_t;
struct _pb_istream_t
{
bool (*callback)(pb_istream_t *stream, uint8_t *buf, size_t count);
void *state; // Free field for use by callback implementation
size_t bytes_left;
};
static inline bool pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
{
if (stream->bytes_left < count)
return false;
bool status = stream->callback(stream, buf, count);
stream->bytes_left -= count;
return status;
}
/* Lightweight output stream. */
typedef struct _pb_ostream_t pb_ostream_t;
struct _pb_ostream_t
{
bool (*callback)(pb_ostream_t *stream, const uint8_t *buf, size_t count);
void *state; // Free field for use by callback implementation
size_t bytes_written;
};
static inline bool pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
{
bool status = stream->callback(stream, buf, count);
stream->bytes_written += count;
return status;
}
/* List of possible field types
* Least-significant 4 bits tell the scalar type
* Most-significant 4 bits specify repeated/required/packed etc.
*
* INT32 and UINT32 are treated the same, as are (U)INT64 and (S)FIXED*
* These types are simply casted to correct field type when they are
* assigned to the memory pointer.
* SINT* is different, though, because it is zig-zag coded.
*/
typedef enum {
// Standard integer types
PB_LTYPE_UINT32 = 0x00,
PB_LTYPE_INT32 = 0x00,
PB_LTYPE_SINT32 = 0x01,
PB_LTYPE_FIXED32 = 0x02,
PB_LTYPE_SFIXED32 = 0x02,
PB_LTYPE_UINT64 = 0x03,
PB_LTYPE_INT64 = 0x03,
PB_LTYPE_SINT64 = 0x04,
PB_LTYPE_FIXED64 = 0x05,
PB_LTYPE_SFIXED64 = 0x05,
PB_LTYPE_BOOL = 0x06,
PB_LTYPE_ENUM = 0x07,
// Standard float types
PB_LTYPE_FLOAT = 0x08,
PB_LTYPE_DOUBLE = 0x09,
// Byte array with pre-allocated buffer.
// data_size is the length of the allocated PB_BYTES_ARRAY structure.
PB_LTYPE_BYTES = 0x0A,
// String with pre-allocated buffer.
// data_size is the maximum length.
PB_LTYPE_STRING = 0x0B,
// Submessage
// submsg_fields is pointer to field descriptions
PB_LTYPE_SUBMESSAGE = 0x0C,
/////////////
// Modifier flags
// Just the basic, write data at data_offset
PB_HTYPE_REQUIRED = 0x00,
// Write true at size_offset
PB_HTYPE_OPTIONAL = 0x10,
// Read to pre-allocated array
// Maximum number of entries is array_size,
// actual number is stored at size_offset
PB_HTYPE_ARRAY = 0x20,
// Works for all required/optional/repeated fields.
// data_offset points to pb_callback_t structure.
// LTYPE is ignored.
PB_HTYPE_CALLBACK = 0x30
} pb_packed pb_type_t;
#define PB_HTYPE(x) ((x) & 0xF0)
#define PB_LTYPE(x) ((x) & 0x0F)
/* This structure is used in auto-generated constants
* to specify struct fields.
* You can change field sizes here if you need structures
* larger than 256 bytes or field tags larger than 256.
* The compiler should complain if your .proto has such
* structures ("initializer too large for type").
*/
typedef struct _pb_field_t pb_field_t;
struct _pb_field_t {
uint8_t tag;
pb_type_t type;
uint8_t data_offset; // Offset of actual data or array start
uint8_t size_offset; // Offset of array size or has-boolean
uint8_t data_size; // Data size in bytes for a single item
uint8_t array_size; // Maximum number of entries in array
// Field definitions for submessage
// OR default value for all other non-array, non-callback types
// If null, then field will zeroed.
const void *ptr;
} pb_packed;
#define PB_LAST_FIELD {0,0,0,0}
// This structure is used for 'bytes' arrays.
// It has the number of bytes in the beginning, and after that an array.
#define PB_BYTES_ARRAY(buffersize) \
struct { \
size_t size; \
uint8_t bytes[buffersize]; \
}
typedef PB_BYTES_ARRAY(1) pb_bytes_array_t;
// This structure is used for giving the callback function.
//
// The decoding callback will be given a limited-length stream
// If the wire type was string, the length is the length of the string.
// If the wire type was a varint/fixed32/fixed64, the length is the length
// of the actual value.
// The function may be called multiple times (especially for repeated types,
// but also otherwise if the message happens to contain the field multiple
// times.)
//
// The encoding callback will receive the actual output stream.
// It should write all the data in one call, including the field tag and
// wire type. It can write multiple fields.
typedef struct _pb_callback_t pb_callback_t;
struct _pb_callback_t {
union {
bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void *arg);
bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void *arg);
} funcs;
// Free arg for use by callback
void *arg;
};
#endif
|