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