1 /* This program parses an input string in a format a bit like JSON:
2  * {'foobar': 1234, 'xyz': 'abc', 'tree': [[[1, 2], 3], [4, 5]]}
3  * and encodes it as protobuf
4  *
5  * Note: The string parsing here is not in any way intended to be robust
6  *       nor safe against buffer overflows. It is just for this test.
7  */
8 
9 #include <pb_encode.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include "cyclic_callback.pb.h"
14 
find_end_of_item(char * p)15 static char *find_end_of_item(char *p)
16 {
17     int depth = 0;
18     do {
19         if (*p == '[' || *p == '{') depth++;
20         if (*p == ']' || *p == '}') depth--;
21         p++;
22     } while (depth > 0 || (*p != ',' && *p != '}'));
23 
24     if (*p == '}')
25         return p; /* End of parent dict */
26 
27     p++;
28     while (*p == ' ') p++;
29     return p;
30 }
31 
32 /* Parse a tree in format [[1 2] 3] and encode it directly to protobuf */
encode_tree(pb_ostream_t * stream,const pb_field_t * field,void * const * arg)33 static bool encode_tree(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
34 {
35     TreeNode tree = TreeNode_init_zero;
36     char *p = (char*)*arg;
37 
38     if (*p == '[')
39     {
40         /* This is a tree branch */
41         p++;
42         tree.left.funcs.encode = encode_tree;
43         tree.left.arg = p;
44 
45         p = find_end_of_item(p);
46         tree.right.funcs.encode = encode_tree;
47         tree.right.arg = p;
48     }
49     else
50     {
51         /* This is a leaf node */
52         tree.has_leaf = true;
53         tree.leaf = atoi(p);
54     }
55 
56     return pb_encode_tag_for_field(stream, field) &&
57            pb_encode_submessage(stream, TreeNode_fields, &tree);
58 }
59 
60 /* Parse a dictionary in format {'name': value} and encode it directly to protobuf */
encode_dictionary(pb_ostream_t * stream,const pb_field_t * field,void * const * arg)61 static bool encode_dictionary(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
62 {
63     int textlen;
64     char *p = (char*)*arg;
65     if (*p == '{') p++;
66     while (*p != '}')
67     {
68         KeyValuePair pair = KeyValuePair_init_zero;
69 
70         if (*p != '\'')
71             PB_RETURN_ERROR(stream, "invalid key, missing quote");
72 
73         p++; /* Starting quote of key */
74         textlen = strchr(p, '\'') - p;
75         strncpy(pair.key, p, textlen);
76         pair.key[textlen] = 0;
77         p += textlen + 2;
78 
79         while (*p == ' ') p++;
80 
81         if (*p == '[')
82         {
83             /* Value is a tree */
84             pair.treeValue.funcs.encode = encode_tree;
85             pair.treeValue.arg = p;
86         }
87         else if (*p == '\'')
88         {
89             /* Value is a string */
90             pair.has_stringValue = true;
91             p++;
92             textlen = strchr(p, '\'') - p;
93             strncpy(pair.stringValue, p, textlen);
94             pair.stringValue[textlen] = 0;
95         }
96         else if (*p == '{')
97         {
98             /* Value is a dictionary */
99             pair.has_dictValue = true;
100             pair.dictValue.dictItem.funcs.encode = encode_dictionary;
101             pair.dictValue.dictItem.arg = p;
102         }
103         else
104         {
105             /* Value is integer */
106             pair.has_intValue = true;
107             pair.intValue = atoi(p);
108         }
109 
110         p = find_end_of_item(p);
111 
112         if (!pb_encode_tag_for_field(stream, field))
113             return false;
114 
115         if (!pb_encode_submessage(stream, KeyValuePair_fields, &pair))
116             return false;
117     }
118 
119     return true;
120 }
121 
122 
main(int argc,char * argv[])123 int main(int argc, char *argv[])
124 {
125     uint8_t buffer[256];
126     pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
127     Dictionary dict = Dictionary_init_zero;
128 
129     if (argc <= 1)
130     {
131         fprintf(stderr, "Usage: %s \"{'foobar': 1234, ...}\"\n", argv[0]);
132         return 1;
133     }
134 
135     dict.dictItem.funcs.encode = encode_dictionary;
136     dict.dictItem.arg = argv[1];
137 
138     if (!pb_encode(&stream, Dictionary_fields, &dict))
139     {
140         fprintf(stderr, "Encoding error: %s\n", PB_GET_ERROR(&stream));
141         return 1;
142     }
143 
144     fwrite(buffer, 1, stream.bytes_written, stdout);
145     return 0;
146 }
147 
148 
149