1 /* protobuf_lang_tree.h
2  *
3  * Routines of building and reading Protocol Buffers Language grammar tree.
4  * Copyright 2019, Huang Qiangxiong <qiangxiong.huang@qq.com>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * SPDX-License-Identifier: GPL-2.0-or-later
11  */
12 
13 #ifndef __PROTOBUF_LANG_TREE_H__
14 #define __PROTOBUF_LANG_TREE_H__
15 
16 #include <glib.h>
17 
18 #include <stdio.h>
19 #include <stdarg.h>
20 #include "ws_attributes.h"
21 
22 #ifdef __cplusplus
23 extern "C" {
24 #endif /* __cplusplus */
25 
26 #define PBL_DEFAULT_PACKAGE_NAME ""
27 
28 typedef void(*pbl_report_error_cb_t)(const char *msg_format, ...);
29 
30 /* Node types of protocol buffers language */
31 typedef enum {
32     PBL_UNKNOWN = 0,
33     PBL_PACKAGE,
34     PBL_MESSAGE,
35     PBL_FIELD,
36     PBL_ONEOF,
37     PBL_MAP_FIELD,
38     PBL_ENUM,
39     PBL_ENUM_VALUE,
40     PBL_SERVICE,
41     PBL_METHOD, /* contains the rpc and stream node of service */
42     PBL_OPTIONS,
43     PBL_OPTION
44 } pbl_node_type_t;
45 
46 /* like google::protobuf::descriptor_pool of protobuf cpp library */
47 typedef struct {
48     GSList* source_paths; /* the directories in which to search for proto file */
49     pbl_report_error_cb_t error_cb; /* error call back function */
50     GHashTable* packages; /* all packages parsed from proto files */
51     GHashTable* proto_files; /* all proto files that are parsed or to be parsed */
52     GSList* proto_files_to_be_parsed; /* files is to be parsed */
53     struct _protobuf_lang_state_t *parser_state; /* current parser state */
54 } pbl_descriptor_pool_t;
55 
56 /* file descriptor */
57 typedef struct {
58     const char* filename;
59     int syntax_version;
60     const char* package_name;
61     int package_name_lineno;
62     pbl_descriptor_pool_t* pool;
63 } pbl_file_descriptor_t;
64 
65 /* Basic information of node */
66 typedef struct pbl_node_t{
67     pbl_node_type_t nodetype;
68     gchar* name;
69     gchar* full_name; /* constructed during first access */
70     struct pbl_node_t* parent;
71     GSList* children; /* child is a pbl_node_t */
72     GHashTable* children_by_name; /* take children names as keys */
73     pbl_file_descriptor_t* file;
74     int lineno;
75 } pbl_node_t;
76 
77 /* like google::protobuf::MethodDescriptor of protobuf cpp library */
78 typedef struct {
79     pbl_node_t basic_info;
80     gchar* in_msg_type;
81     gboolean in_is_stream;
82     gchar* out_msg_type;
83     gboolean out_is_stream;
84 } pbl_method_descriptor_t;
85 
86 /* like google::protobuf::Descriptor of protobuf cpp library */
87 typedef struct {
88     pbl_node_t basic_info;
89     GSList* fields;
90     GHashTable* fields_by_number;
91 } pbl_message_descriptor_t;
92 
93 /* like google::protobuf::EnumValueDescriptor of protobuf cpp library */
94 typedef struct {
95     pbl_node_t basic_info;
96     int number;
97 } pbl_enum_value_descriptor_t;
98 
99 /* like google::protobuf::FieldDescriptor of protobuf cpp library */
100 typedef struct {
101     pbl_node_t basic_info;
102     int number;
103     int type; /* refer to PROTOBUF_TYPE_XXX of protobuf-helper.h */
104     gchar* type_name;
105     pbl_node_t* options_node;
106     gboolean is_repeated;
107     gboolean is_required;
108     gboolean has_default_value; /* Does this field have an explicitly-declared default value? */
109     gchar* orig_default_value;
110     int string_or_bytes_default_value_length;
111     union {
112         gint32 i32;
113         gint64 i64;
114         guint32 u32;
115         guint64 u64;
116         gfloat f;
117         gdouble d;
118         gboolean b;
119         gchar* s;
120         const pbl_enum_value_descriptor_t* e;
121     } default_value;
122 } pbl_field_descriptor_t;
123 
124 /* like google::protobuf::EnumDescriptor of protobuf cpp library */
125 typedef struct {
126     pbl_node_t basic_info;
127     GSList* values;
128     GHashTable* values_by_number;
129 } pbl_enum_descriptor_t;
130 
131 /* Option node. The name of basic_info is optionName.
132    Now, we only care about fieldOption. */
133 typedef struct {
134     pbl_node_t basic_info;
135     char* value;
136 } pbl_option_descriptor_t;
137 
138 /* the struct of token used by the parser */
139 typedef struct _protobuf_lang_token_t {
140     gchar* v; /* token string value */
141     int ln; /* line number of this token in the .proto file */
142 } protobuf_lang_token_t;
143 
144 /* parser state */
145 typedef struct _protobuf_lang_state_t {
146     pbl_descriptor_pool_t* pool; /* pool will keep the parsing result */
147     pbl_file_descriptor_t* file; /* info of current parsing file */
148     GSList* lex_string_tokens;
149     GSList* lex_struct_tokens;
150     void* scanner;
151     void* pParser;
152     gboolean grammar_error;
153     protobuf_lang_token_t* tmp_token; /* just for passing token value from protobuf_lang_lex() to ProtobufLangParser() */
154 } protobuf_lang_state_t;
155 
156 /* Store chars created by strdup or g_strconcat into protobuf_lang_state_t temporarily,
157    and return back the input chars pointer.
158    It will be freed when protobuf_lang_state_t is released */
159 static inline gchar*
pbl_store_string_token(protobuf_lang_state_t * parser_state,char * dupstr)160 pbl_store_string_token(protobuf_lang_state_t* parser_state, char* dupstr)
161 {
162     parser_state->lex_string_tokens = g_slist_append(parser_state->lex_string_tokens, dupstr);
163     return dupstr;
164 }
165 
166 /* Store a protobuf_lang_token_t in protobuf_lang_state_t temporarily, and return back
167    the input pointer. It will be freed when protobuf_lang_state_t is released */
168 static inline protobuf_lang_token_t*
pbl_store_struct_token(protobuf_lang_state_t * parser_state,protobuf_lang_token_t * newtoken)169 pbl_store_struct_token(protobuf_lang_state_t* parser_state, protobuf_lang_token_t* newtoken)
170 {
171     parser_state->lex_struct_tokens = g_slist_append(parser_state->lex_struct_tokens, newtoken);
172     return newtoken;
173 }
174 
175 /* default error_cb */
176 static inline void
pbl_printf(const char * fmt,...)177 pbl_printf(const char* fmt, ...)
178 {
179     va_list ap;
180     va_start(ap, fmt);
181     vprintf(fmt, ap);
182     va_end(ap);
183 }
184 
185 /**
186  Reinitialize the protocol buffers pool according to proto files directories.
187  @param ppool The output descriptor_pool will be created. If *pool is not NULL, it will free it first.
188  @param directories  The root directories containing proto files. Must end with NULL element.
189  @param error_cb The error reporter callback function. */
190 void
191 pbl_reinit_descriptor_pool(pbl_descriptor_pool_t** ppool, const char** directories, pbl_report_error_cb_t error_cb);
192 
193 /* free all memory used by this protocol buffers languange pool */
194 void
195 pbl_free_pool(pbl_descriptor_pool_t* pool);
196 
197 /* add a proto file to pool. this file will not be parsed until run_pbl_parser function is invoked. */
198 gboolean
199 pbl_add_proto_file_to_be_parsed(pbl_descriptor_pool_t* pool, const char* filepath);
200 
201 /* run C protocol buffers languange parser, return 0 if successed */
202 int run_pbl_parser(pbl_descriptor_pool_t* pool);
203 
204 /* like descriptor_pool::FindMethodByName */
205 const pbl_method_descriptor_t*
206 pbl_message_descriptor_pool_FindMethodByName(const pbl_descriptor_pool_t* pool, const char* name);
207 
208 /* like MethodDescriptor::name() */
209 const char*
210 pbl_method_descriptor_name(const pbl_method_descriptor_t* method);
211 
212 /* like MethodDescriptor::full_name() */
213 const char*
214 pbl_method_descriptor_full_name(const pbl_method_descriptor_t* method);
215 
216 /* like MethodDescriptor::input_type() */
217 const pbl_message_descriptor_t*
218 pbl_method_descriptor_input_type(const pbl_method_descriptor_t* method);
219 
220 /* like MethodDescriptor::output_type() */
221 const pbl_message_descriptor_t*
222 pbl_method_descriptor_output_type(const pbl_method_descriptor_t* method);
223 
224 /* like descriptor_pool::FindMessageTypeByName() */
225 const pbl_message_descriptor_t*
226 pbl_message_descriptor_pool_FindMessageTypeByName(const pbl_descriptor_pool_t* pool, const char* name);
227 
228 /* like Descriptor::name() */
229 const char*
230 pbl_message_descriptor_name(const pbl_message_descriptor_t* message);
231 
232 /* like Descriptor::full_name() */
233 const char*
234 pbl_message_descriptor_full_name(const pbl_message_descriptor_t* message);
235 
236 /* like Descriptor::field_count() */
237 int
238 pbl_message_descriptor_field_count(const pbl_message_descriptor_t* message);
239 
240 /* like Descriptor::field() */
241 const pbl_field_descriptor_t*
242 pbl_message_descriptor_field(const pbl_message_descriptor_t* message, int field_index);
243 
244 /* like Descriptor::FindFieldByNumber() */
245 const pbl_field_descriptor_t*
246 pbl_message_descriptor_FindFieldByNumber(const pbl_message_descriptor_t* message, int number);
247 
248 /* like Descriptor::FindFieldByName() */
249 const pbl_field_descriptor_t*
250 pbl_message_descriptor_FindFieldByName(const pbl_message_descriptor_t* message, const char* name);
251 
252 /* like FieldDescriptor::full_name() */
253 const char*
254 pbl_field_descriptor_full_name(const pbl_field_descriptor_t* field);
255 
256 /* like FieldDescriptor::name() */
257 const char*
258 pbl_field_descriptor_name(const pbl_field_descriptor_t* field);
259 
260 /* like FieldDescriptor::number() */
261 int
262 pbl_field_descriptor_number(const pbl_field_descriptor_t* field);
263 
264 /* like FieldDescriptor::type() */
265 int
266 pbl_field_descriptor_type(const pbl_field_descriptor_t* field);
267 
268 /* like FieldDescriptor::is_repeated() */
269 int
270 pbl_field_descriptor_is_repeated(const pbl_field_descriptor_t* field);
271 
272 /* like FieldDescriptor::is_packed() */
273 int
274 pbl_field_descriptor_is_packed(const pbl_field_descriptor_t* field);
275 
276 /* like FieldDescriptor::TypeName() */
277 const char*
278 pbl_field_descriptor_TypeName(int field_type);
279 
280 /* like FieldDescriptor::message_type() */
281 const pbl_message_descriptor_t*
282 pbl_field_descriptor_message_type(const pbl_field_descriptor_t* field);
283 
284 /* like FieldDescriptor::enum_type() */
285 const pbl_enum_descriptor_t*
286 pbl_field_descriptor_enum_type(const pbl_field_descriptor_t* field);
287 
288 /* like FieldDescriptor::is_required() */
289 gboolean
290 pbl_field_descriptor_is_required(const pbl_field_descriptor_t* field);
291 
292 /* like FieldDescriptor::has_default_value().
293  * Does this field have an explicitly-declared default value? */
294 gboolean
295 pbl_field_descriptor_has_default_value(const pbl_field_descriptor_t* field);
296 
297 /* like FieldDescriptor::default_value_int32() */
298 gint32
299 pbl_field_descriptor_default_value_int32(const pbl_field_descriptor_t* field);
300 
301 /* like FieldDescriptor::default_value_int64() */
302 gint64
303 pbl_field_descriptor_default_value_int64(const pbl_field_descriptor_t* field);
304 
305 /* like FieldDescriptor::default_value_uint32() */
306 guint32
307 pbl_field_descriptor_default_value_uint32(const pbl_field_descriptor_t* field);
308 
309 /* like FieldDescriptor::default_value_uint64() */
310 guint64
311 pbl_field_descriptor_default_value_uint64(const pbl_field_descriptor_t* field);
312 
313 /* like FieldDescriptor::default_value_float() */
314 gfloat
315 pbl_field_descriptor_default_value_float(const pbl_field_descriptor_t* field);
316 
317 /* like FieldDescriptor::default_value_double() */
318 gdouble
319 pbl_field_descriptor_default_value_double(const pbl_field_descriptor_t* field);
320 
321 /* like FieldDescriptor::default_value_bool() */
322 gboolean
323 pbl_field_descriptor_default_value_bool(const pbl_field_descriptor_t* field);
324 
325 /* like FieldDescriptor::default_value_string() */
326 const gchar*
327 pbl_field_descriptor_default_value_string(const pbl_field_descriptor_t* field, int* size);
328 
329 /* like FieldDescriptor::default_value_enum() */
330 const pbl_enum_value_descriptor_t*
331 pbl_field_descriptor_default_value_enum(const pbl_field_descriptor_t* field);
332 
333 /* like EnumDescriptor::name() */
334 const char*
335 pbl_enum_descriptor_name(const pbl_enum_descriptor_t* anEnum);
336 
337 /* like EnumDescriptor::full_name() */
338 const char*
339 pbl_enum_descriptor_full_name(const pbl_enum_descriptor_t* anEnum);
340 
341 /* like EnumDescriptor::value_count() */
342 int
343 pbl_enum_descriptor_value_count(const pbl_enum_descriptor_t* anEnum);
344 
345 /* like EnumDescriptor::value() */
346 const pbl_enum_value_descriptor_t*
347 pbl_enum_descriptor_value(const pbl_enum_descriptor_t* anEnum, int value_index);
348 
349 /* like EnumDescriptor::FindValueByNumber() */
350 const pbl_enum_value_descriptor_t*
351 pbl_enum_descriptor_FindValueByNumber(const pbl_enum_descriptor_t* anEnum, int number);
352 
353 /* like EnumDescriptor::FindValueByName() */
354 const pbl_enum_value_descriptor_t*
355 pbl_enum_descriptor_FindValueByName(const pbl_enum_descriptor_t* anEnum, const gchar* name);
356 
357 /* like EnumValueDescriptor::name() */
358 const char*
359 pbl_enum_value_descriptor_name(const pbl_enum_value_descriptor_t* enumValue);
360 
361 /* like EnumValueDescriptor::full_name() */
362 const char*
363 pbl_enum_value_descriptor_full_name(const pbl_enum_value_descriptor_t* enumValue);
364 
365 /* like EnumValueDescriptor::number() */
366 int
367 pbl_enum_value_descriptor_number(const pbl_enum_value_descriptor_t* enumValue);
368 
369 /* visit all message in this pool */
370 void
371 pbl_foreach_message(const pbl_descriptor_pool_t* pool, void (*cb)(const pbl_message_descriptor_t*, void*), void* userdata);
372 
373 /*
374  * Following are tree building functions.
375  */
376 
377 /* create a normal node */
378 pbl_node_t*
379 pbl_create_node(pbl_file_descriptor_t* file, int lineno, pbl_node_type_t nodetype, const char* name);
380 
381 /* change the name of node */
382 pbl_node_t*
383 pbl_set_node_name(pbl_node_t* node, int lineno, const char* newname);
384 
385 /* get the name of node */
386 static inline const char*
pbl_get_node_name(pbl_node_t * node)387 pbl_get_node_name(pbl_node_t* node)
388 {
389     return node->name;
390 }
391 
392 /* get the full name of node. if it is NULL, it will be built. */
393 const char*
394 pbl_get_node_full_name(pbl_node_t* node);
395 
396 /* append a node as a child of the parent node, and return the parent pointer */
397 pbl_node_t*
398 pbl_add_child(pbl_node_t* parent, pbl_node_t* child);
399 
400 /* create an enumeration field node */
401 pbl_node_t*
402 pbl_create_enum_value_node(pbl_file_descriptor_t* file, int lineno, const char* name, int number);
403 
404 /* merge one('from') node's children to another('to') node, and return the 'to' pointer */
405 pbl_node_t*
406 pbl_merge_children(pbl_node_t* to, pbl_node_t* from);
407 
408 /* create a field node */
409 pbl_node_t*
410 pbl_create_field_node(pbl_file_descriptor_t* file, int lineno, const char* label, const char* type_name, const char* name, int number, pbl_node_t* options);
411 
412 /* create a map field node */
413 pbl_node_t*
414 pbl_create_map_field_node(pbl_file_descriptor_t* file, int lineno, const char* name, int number, pbl_node_t* options);
415 
416 /* create a method (rpc or stream of service) node */
417 pbl_node_t*
418 pbl_create_method_node(pbl_file_descriptor_t* file, int lineno, const char* name, const char* in_msg_type, gboolean in_is_stream, const char* out_msg_type, gboolean out_is_stream);
419 
420 /* create an option node */
421 pbl_node_t*
422 pbl_create_option_node(pbl_file_descriptor_t* file, int lineno, const char* name, const char* value);
423 
424 /* free a pbl_node_t and its children. */
425 void
426 pbl_free_node(gpointer anode);
427 
428 #ifdef __cplusplus
429 }
430 #endif /* __cplusplus */
431 
432 #endif /* __PROTOBUF_LANG_TREE_H__ */
433 
434 /*
435  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
436  *
437  * Local variables:
438  * c-basic-offset: 4
439  * tab-width: 8
440  * indent-tabs-mode: nil
441  * End:
442  *
443  * vi: set shiftwidth=4 tabstop=8 expandtab:
444  * :indentSize=4:tabSize=8:noTabs=true:
445  */
446