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 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 */ 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 */ 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 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