1 /* radare2 - LGPL - Copyright 2017-2019 - wargio */
2
3 #include <r_util.h>
4 #include <r_cons.h>
5
6 typedef float ft32;
7 typedef double ft64;
8
9 #define WIRE_VARINT 0 // int32, int64, uint32, uint64, sint32, sint64, bool, enum
10 #define WIRE_64_BIT 1 // fixed64, sfixed64, double
11 #define WIRE_LEN_DELIM 2 // string, bytes, embedded messages, packed repeated fields
12 #define WIRE_START_GRP 3 // groups (deprecated)
13 #define WIRE_END_GRP 4 // groups (deprecated)
14 #define WIRE_32_BIT 5 // fixed32, sfixed32, float
15
s_wire(const ut8 byte)16 static const char* s_wire(const ut8 byte) {
17 switch (byte) {
18 case WIRE_VARINT:
19 return "[VARINT]";
20 case WIRE_64_BIT:
21 return "[64_BIT]";
22 case WIRE_LEN_DELIM:
23 return "[LEN_DELIM]";
24 case WIRE_START_GRP:
25 return "[START_GROUP]";
26 case WIRE_END_GRP:
27 return "[END_GROUP]";
28 case WIRE_32_BIT:
29 return "[32_BIT]";
30 default:
31 return "[UNKN]";
32 }
33 }
34
pad(RStrBuf * sb,ut32 count)35 static void pad(RStrBuf *sb, ut32 count) {
36 ut32 i;
37 for (i = 0; i < count; i++) {
38 r_strbuf_appendf (sb, " ");
39 }
40 }
41
is_string(const ut8 * start,const ut8 * end)42 static bool is_string(const ut8* start, const ut8* end) {
43 while (start < end) {
44 // TODO UTF-8 Support.
45 if (!IS_PRINTABLE (*start)) {
46 return false;
47 }
48 start++;
49 }
50 return true;
51 }
52
decode_array(RStrBuf * sb,const ut8 * start,const ut8 * end)53 static void decode_array(RStrBuf *sb, const ut8* start, const ut8* end) {
54 while (start < end) {
55 r_strbuf_appendf (sb, "%02x ", *start);
56 start++;
57 }
58 r_strbuf_appendf (sb, "\n");
59 }
60
decode_buffer(RStrBuf * sb,const ut8 * start,const ut8 * end,ut32 padcnt,bool debug)61 static void decode_buffer(RStrBuf *sb, const ut8* start, const ut8* end, ut32 padcnt, bool debug) {
62 size_t bytes_read = 0;
63 ut32 var32 = 0;
64 ut64 var64 = 0;
65 const ut8* buffer = start;
66 while (buffer >= start && buffer < end) {
67 if (!*buffer) {
68 return;
69 }
70 //ut8 byte = *buffer;
71 ut8 number = buffer[0] >> 3;
72 ut8 wire = buffer[0] & 0x3;
73 buffer++;
74 if (buffer < start || buffer >= end) {
75 eprintf ("\ninvalid buffer pointer.\n");
76 break;
77 } else if (wire > WIRE_32_BIT) {
78 eprintf ("\nunknown wire id (%u).\n", wire);
79 return;
80 }
81 if (wire != WIRE_END_GRP) {
82 pad (sb, padcnt);
83 if (debug) {
84 r_strbuf_appendf (sb, "%u %-13s", number, s_wire(wire));
85 } else {
86 r_strbuf_appendf (sb, "%u", number);
87 }
88 }
89 switch (wire) {
90 case WIRE_VARINT:
91 {
92 st64* i = (st64*) &var64;
93 bytes_read = read_u64_leb128 (buffer, end, &var64);
94 r_strbuf_appendf (sb, ": %"PFMT64u" | %"PFMT64d"\n", var64, *i);
95 }
96 break;
97 case WIRE_64_BIT:
98 {
99 ft64* f = (ft64*) &var64;
100 st64* i = (st64*) &var64;
101 bytes_read = read_u64_leb128 (buffer, end, &var64);
102 r_strbuf_appendf (sb, ": %"PFMT64u" | %"PFMT64d" | %f\n", var64, *i, *f);
103 }
104 break;
105 case WIRE_LEN_DELIM:
106 {
107 bytes_read = read_u64_leb128 (buffer, end, &var64);
108 const ut8* ps = buffer + bytes_read;
109 const ut8* pe = ps + var64;
110 if (ps > buffer && pe <= end) {
111 if (is_string (ps, pe)) {
112 r_strbuf_appendf (sb, ": \"%.*s\"\n", (int)var64, (const char*) ps);
113 } else {
114 r_strbuf_appendf (sb, " {\n");
115 decode_buffer (sb, ps, pe, padcnt + 1, debug);
116 pad (sb, padcnt);
117 r_strbuf_appendf (sb, "}\n");
118 }
119 bytes_read += var64;
120 } else {
121 eprintf ("\ninvalid delimited length (%"PFMT64u").\n", var64);
122 return;
123 }
124 }
125 break;
126 case WIRE_START_GRP:
127 r_strbuf_appendf (sb, " {\n");
128 padcnt++;
129 break;
130 case WIRE_END_GRP:
131 if (padcnt > 1) {
132 padcnt--;
133 }
134 pad (sb, padcnt);
135 r_strbuf_appendf (sb, "}\n");
136 break;
137 case WIRE_32_BIT:
138 {
139 ft32* f = (ft32*) &var32;
140 st32* i = (st32*) &var32;
141 bytes_read = read_u32_leb128 (buffer, end, &var32);
142 r_strbuf_appendf (sb, ": %u | %d | %f\n", var32, *i, *f);
143 }
144 break;
145 default:
146 decode_array (sb, buffer - 1, end);
147 return;
148 }
149 buffer += bytes_read;
150 }
151 }
152
r_protobuf_decode(const ut8 * start,const ut64 size,bool debug)153 R_API char *r_protobuf_decode(const ut8* start, const ut64 size, bool debug) {
154 if (!start || !size) {
155 eprintf ("Invalid buffer pointer or size.\n");
156 return NULL;
157 }
158 const ut8* end = start + size;
159 RStrBuf *sb = r_strbuf_new ("");
160 decode_buffer (sb, start, end, 0u, debug);
161 return r_strbuf_drain (sb);
162 }
163