1/*
2 * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.jdi;
27
28import java.util.List;
29import java.util.ArrayList;
30
31public class JNITypeParser {
32
33    static final char SIGNATURE_ENDCLASS = ';';
34    static final char SIGNATURE_FUNC = '(';
35    static final char SIGNATURE_ENDFUNC = ')';
36
37    private String signature;
38    private List<String> typeNameList;
39    private List<String> signatureList;
40    private int currentIndex;
41
42    JNITypeParser(String signature) {
43        this.signature = signature;
44    }
45
46    static String typeNameToSignature(String signature) {
47        StringBuilder sb = new StringBuilder();
48        int firstIndex = signature.indexOf('[');
49        int index = firstIndex;
50        while (index != -1) {
51            sb.append('[');
52            index = signature.indexOf('[', index + 1);
53        }
54
55        if (firstIndex != -1) {
56            signature = signature.substring(0, firstIndex);
57        }
58
59        if (signature.equals("boolean")) {
60            sb.append('Z');
61        } else if (signature.equals("byte")) {
62            sb.append('B');
63        } else if (signature.equals("char")) {
64            sb.append('C');
65        } else if (signature.equals("short")) {
66            sb.append('S');
67        } else if (signature.equals("int")) {
68            sb.append('I');
69        } else if (signature.equals("long")) {
70            sb.append('J');
71        } else if (signature.equals("float")) {
72            sb.append('F');
73        } else if (signature.equals("double")) {
74            sb.append('D');
75        } else {
76            sb.append('L');
77            sb.append(signature.replace('.', '/'));
78            sb.append(';');
79        }
80
81        return sb.toString();
82    }
83
84    String typeName() {
85        return typeNameList().get(typeNameList().size()-1);
86    }
87
88    List<String> argumentTypeNames() {
89        return typeNameList().subList(0, typeNameList().size() - 1);
90    }
91
92    String signature() {
93        return signatureList().get(signatureList().size()-1);
94    }
95
96    List<String> argumentSignatures() {
97        return signatureList().subList(0, signatureList().size() - 1);
98    }
99
100    int dimensionCount() {
101        int count = 0;
102        String signature = signature();
103        while (signature.charAt(count) == '[') {
104            count++;
105        }
106        return count;
107    }
108
109    String componentSignature(int level) {
110        return signature().substring(level);
111    }
112
113    private synchronized List<String> signatureList() {
114        if (signatureList == null) {
115            signatureList = new ArrayList<String>(10);
116            String elem;
117
118            currentIndex = 0;
119
120            while(currentIndex < signature.length()) {
121                elem = nextSignature();
122                signatureList.add(elem);
123            }
124            if (signatureList.size() == 0) {
125                throw new IllegalArgumentException("Invalid JNI signature '" +
126                                                   signature + "'");
127            }
128        }
129        return signatureList;
130    }
131
132    private synchronized List<String> typeNameList() {
133        if (typeNameList == null) {
134            typeNameList = new ArrayList<String>(10);
135            String elem;
136
137            currentIndex = 0;
138
139            while(currentIndex < signature.length()) {
140                elem = nextTypeName();
141                typeNameList.add(elem);
142            }
143            if (typeNameList.size() == 0) {
144                throw new IllegalArgumentException("Invalid JNI signature '" +
145                                                   signature + "'");
146            }
147        }
148        return typeNameList;
149    }
150
151    private String nextSignature() {
152        char key = signature.charAt(currentIndex++);
153
154        switch(key) {
155            case (JDWP.Tag.ARRAY):
156                return  key + nextSignature();
157
158            case (JDWP.Tag.OBJECT):
159                int endClass = signature.indexOf(SIGNATURE_ENDCLASS,
160                                                 currentIndex);
161                String retVal = signature.substring(currentIndex - 1,
162                                                    endClass + 1);
163                currentIndex = endClass + 1;
164                return retVal;
165
166            case (JDWP.Tag.VOID):
167            case (JDWP.Tag.BOOLEAN):
168            case (JDWP.Tag.BYTE):
169            case (JDWP.Tag.CHAR):
170            case (JDWP.Tag.SHORT):
171            case (JDWP.Tag.INT):
172            case (JDWP.Tag.LONG):
173            case (JDWP.Tag.FLOAT):
174            case (JDWP.Tag.DOUBLE):
175                return String.valueOf(key);
176
177            case SIGNATURE_ENDFUNC:
178            case SIGNATURE_FUNC:
179                return nextSignature();
180
181            default:
182                throw new IllegalArgumentException(
183                    "Invalid JNI signature character '" + key + "'");
184
185        }
186    }
187
188    private String nextTypeName() {
189        char key = signature.charAt(currentIndex++);
190
191        switch(key) {
192            case (JDWP.Tag.ARRAY):
193                return  nextTypeName() + "[]";
194
195            case (JDWP.Tag.BYTE):
196                return "byte";
197
198            case (JDWP.Tag.CHAR):
199                return "char";
200
201            case (JDWP.Tag.OBJECT):
202                int endClass = signature.indexOf(SIGNATURE_ENDCLASS,
203                                                 currentIndex);
204                String retVal = signature.substring(currentIndex,
205                                                    endClass);
206                retVal = retVal.replace('/','.');
207                currentIndex = endClass + 1;
208                return retVal;
209
210            case (JDWP.Tag.FLOAT):
211                return "float";
212
213            case (JDWP.Tag.DOUBLE):
214                return "double";
215
216            case (JDWP.Tag.INT):
217                return "int";
218
219            case (JDWP.Tag.LONG):
220                return "long";
221
222            case (JDWP.Tag.SHORT):
223                return "short";
224
225            case (JDWP.Tag.VOID):
226                return "void";
227
228            case (JDWP.Tag.BOOLEAN):
229                return "boolean";
230
231            case SIGNATURE_ENDFUNC:
232            case SIGNATURE_FUNC:
233                return nextTypeName();
234
235            default:
236                throw new IllegalArgumentException(
237                    "Invalid JNI signature character '" + key + "'");
238
239        }
240    }
241}
242