1 /* A small tool that decodes a raw binary message, while providing useful
2 * info on corrupted messages also. */
3
4 /* Define _ISOC99_SOURCE to get snprintf() even though otherwise in ansi-C mode */
5 #define _ISOC99_SOURCE 1
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <pb_decode.h>
10 #include "test_helpers.h"
11
12 #define HISTORY_LEN 32
13 static pb_byte_t g_history[HISTORY_LEN];
14 static int g_position;
15
16 /* This binds the pb_istream_t to stdin and logs the most recent bytes read. */
callback(pb_istream_t * stream,uint8_t * buf,size_t count)17 bool callback(pb_istream_t *stream, uint8_t *buf, size_t count)
18 {
19 FILE *file = (FILE*)stream->state;
20 size_t len = fread(buf, 1, count, file);
21
22 if (len < HISTORY_LEN)
23 {
24 memmove(g_history, g_history + len, HISTORY_LEN - len);
25 memcpy(g_history + HISTORY_LEN - len, buf, len);
26 }
27 else
28 {
29 memcpy(g_history, buf + len - HISTORY_LEN, HISTORY_LEN);
30 }
31
32 g_position += len;
33
34 if (len == count)
35 {
36 return true;
37 }
38 else
39 {
40 stream->bytes_left = 0;
41 return false;
42 }
43 }
44
print_history(int position)45 void print_history(int position)
46 {
47 int i;
48
49 if (position < g_position - HISTORY_LEN)
50 position = g_position - HISTORY_LEN;
51
52 printf("LATEST BYTES READ (%d to %d): ", position, g_position);
53
54 for (i = HISTORY_LEN - (g_position - position); i < HISTORY_LEN; i++)
55 {
56 printf("%02x ", g_history[i]);
57 }
58
59 printf("\n");
60 }
61
raw_decode(pb_istream_t * stream,const char * indent)62 bool raw_decode(pb_istream_t *stream, const char *indent)
63 {
64 const char *wiretypes[8] = {"VARINT", "64BIT", "STRING", "SGRP", "EGRP", "32BIT", "????", "????"};
65
66 while (stream->bytes_left)
67 {
68 uint32_t tag;
69 pb_wire_type_t wire_type;
70 bool eof;
71 int position = g_position;
72
73 if (!pb_decode_tag(stream, &wire_type, &tag, &eof))
74 {
75 if (eof)
76 {
77 break;
78 }
79 else
80 {
81 printf("ERROR: Failed to parse tag: %s\n", PB_GET_ERROR(stream));
82 print_history(position);
83 return false;
84 }
85 }
86
87 if (tag == 0)
88 {
89 printf("%sterminating on zero tag\n", indent);
90 return true;
91 }
92
93 printf("%sAt %d: field tag %d, wire type %d (%s)",
94 indent, position, (int)tag, wire_type, wiretypes[wire_type]);
95
96 if (wire_type == PB_WT_VARINT)
97 {
98 uint64_t value;
99 position = g_position;
100 if (!pb_decode_varint(stream, &value))
101 {
102 printf("\n%sERROR: Failed to parse varint: %s\n", indent, PB_GET_ERROR(stream));
103 print_history(position);
104 return false;
105 }
106
107 printf(", varint value (%d bytes): %llu\n",
108 g_position - position, (unsigned long long)value);
109 }
110 else if (wire_type == PB_WT_64BIT)
111 {
112 uint64_t value;
113 position = g_position;
114 if (!pb_decode_fixed64(stream, &value))
115 {
116 printf("\n%sERROR: Failed to parse fixed64: %s\n", indent, PB_GET_ERROR(stream));
117 print_history(position);
118 return false;
119 }
120
121 printf(", fixed64 value (%d bytes): 0x%016llx\n",
122 g_position - position, (unsigned long long)value);
123 }
124 else if (wire_type == PB_WT_32BIT)
125 {
126 uint32_t value;
127 position = g_position;
128 if (!pb_decode_fixed32(stream, &value))
129 {
130 printf("\n%sERROR: Failed to parse fixed32: %s\n", indent, PB_GET_ERROR(stream));
131 print_history(position);
132 return false;
133 }
134
135 printf(", fixed32 value (%d bytes): 0x%08lx\n",
136 g_position - position, (unsigned long)value);
137 }
138 else if (wire_type == PB_WT_STRING)
139 {
140 pb_istream_t substream;
141 position = g_position;
142 if (!pb_make_string_substream(stream, &substream))
143 {
144 printf("ERROR: Failed to parse string length: %s\n", PB_GET_ERROR(stream));
145 print_history(position);
146 return false;
147 }
148 else
149 {
150
151 if (substream.bytes_left == 0)
152 {
153 printf(", empty string\n");
154 }
155 else
156 {
157 char prefix[8];
158 snprintf(prefix, sizeof(prefix), "f%d> ", (int)tag);
159
160 printf(", string len %d bytes, attempting recursive decode\n",
161 (int)substream.bytes_left);
162
163 if (!raw_decode(&substream, prefix))
164 {
165 printf("%sfield %d: recursive decode failed, continuing with upper level\n\n",
166 indent, (int)tag);
167 }
168
169 pb_close_string_substream(stream, &substream);
170 }
171 }
172 }
173 else
174 {
175 printf("\n");
176 }
177 }
178
179 return true;
180 }
181
main()182 int main()
183 {
184 pb_istream_t stream = {&callback, NULL, SIZE_MAX};
185 stream.state = stdin;
186 SET_BINARY_MODE(stdin);
187
188 if (!raw_decode(&stream, ""))
189 {
190 return 1;
191 } else {
192 return 0;
193 }
194 }
195