1/**
2 * @file demangle_java_symbol.cpp
3 * Demangle a java symbol
4 *
5 * @remark Copyright 2007 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author Philippe Elie
9 */
10
11#include "demangle_java_symbol.h"
12
13#include <algorithm>
14
15using namespace std;
16
17namespace {
18
19/**
20 * The grammar we implement:
21 *
22 * field_type:
23 *    base_type | object_type | array_type
24 * base_type:
25 *    B | C | D | F | I | J | S | Z
26 * object_type:
27 *    L<classname>;
28 * array_type:
29 *    [field_type
30 * method_descriptor:
31 *    ( field_type* ) return_descriptor
32 * return_descriptor:
33 *    field_type | V
34 * method_signature:
35 *    object_type method_name method_descriptor
36 *
37 */
38
39bool array_type(string & result,
40	string::const_iterator & begin, string::const_iterator end);
41bool object_type(string & result,
42	string::const_iterator & begin, string::const_iterator end);
43
44
45bool base_type(string & result,
46	string::const_iterator & begin, string::const_iterator end)
47{
48	bool ret = true;
49
50	if (begin == end)
51		return false;
52
53	switch (*begin) {
54	case 'B': result += "byte";    break;
55	case 'C': result += "char";    break;
56	case 'D': result += "double";  break;
57	case 'F': result += "float";   break;
58	case 'I': result += "int";     break;
59	case 'J': result += "long";    break;
60	case 'S': result += "short";   break;
61	case 'Z': result += "boolean"; break;
62	default:  ret = false;         break;
63	}
64
65	if (ret)
66		++begin;
67	return ret;
68}
69
70
71bool field_type(string & result,
72	string::const_iterator & begin, string::const_iterator end)
73{
74	if (base_type(result, begin, end))
75		return true;
76
77	if (object_type(result, begin, end))
78		return true;
79
80	if (array_type(result, begin, end))
81		return true;
82
83	return false;
84}
85
86
87bool array_type(string & result,
88	string::const_iterator & begin, string::const_iterator end)
89{
90	if (begin == end || *begin != '[')
91		return false;
92
93	++begin;
94	if (field_type(result, begin, end)) {
95		result += "[]";
96		return true;
97	}
98
99	return false;
100}
101
102
103bool list_of_field_type(string & result,
104	string::const_iterator & begin, string::const_iterator end)
105{
106	bool first = false;
107	while (begin != end) {
108		if (first)
109			result += ", ";
110
111		if (!field_type(result, begin, end))
112			return false;
113
114		first = true;
115	}
116
117	return true;
118}
119
120
121bool return_descriptor(string & result,
122	string::const_iterator & begin, string::const_iterator end)
123{
124	if (begin == end)
125		return false;
126	if (*begin == 'V') {
127		++begin;
128		result = "void " + result;
129		return true;
130	}
131
132	string temp;
133	if (!field_type(temp, begin, end))
134		return false;
135	result = temp + " " + result;
136
137	return true;
138}
139
140
141bool method_descriptor(string & result,
142	string::const_iterator & begin, string::const_iterator end)
143{
144	if (begin == end || *begin != '(')
145		return false;
146	++begin;
147	string::const_iterator pos = find(begin, end, ')');
148	if (pos == end)
149		return false;
150
151	result += "(";
152
153	if (!list_of_field_type(result, begin, pos))
154		return false;
155
156	if (begin == end || *begin != ')')
157		return false;
158
159	++begin;
160
161	if (!return_descriptor(result, begin, end))
162		return false;
163
164	result += ')';
165
166	return true;
167}
168
169
170bool methode_name(string & result,
171	string::const_iterator & begin, string::const_iterator end)
172{
173	if (begin == end)
174		return false;
175
176	string::const_iterator pos = find(begin, end, '(');
177	if (pos == end)
178		return false;
179
180	result += '.' +  string(begin, pos);
181	begin = pos;
182
183	return true;
184}
185
186
187bool object_type(string & result,
188	string::const_iterator & begin, string::const_iterator end)
189{
190	if (begin == end || *begin != 'L')
191		return false;
192	string::const_iterator pos = find(begin, end, ';');
193	if (pos == end)
194		return false;
195
196	string temp = string(begin + 1, pos);
197	replace(temp.begin(), temp.end(), '/', '.');
198	result += temp;
199
200	begin = pos + 1;
201
202	return true;
203}
204
205
206string demangle_symbol(string::const_iterator begin,
207		       string::const_iterator end)
208{
209	string result;
210
211	if (!object_type(result, begin, end))
212		return string();
213
214	if (!methode_name(result, begin, end))
215		return string();
216
217	if (!method_descriptor(result, begin, end))
218		return string();
219
220	if (begin != end) {
221		if (*begin == '~') {
222			// special case for disambiguated symbol.
223			result += string(begin, end);
224		} else {
225			return string();
226		}
227	}
228
229	return result;
230}
231
232} // anonymous namespace
233
234
235string const demangle_java_symbol(string const & name)
236{
237	return demangle_symbol(name.begin(), name.end());
238}
239