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