1/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
2 *
3 * This program and the accompanying materials are made available under
4 * the terms of the Common Public License v1.0 which accompanies this distribution,
5 * and is available at http://www.eclipse.org/legal/cpl-v10.html
6 *
7 * $Id: Descriptors.java,v 1.1.1.1 2004/05/09 16:57:52 vlad_r Exp $
8 */
9package com.vladium.util;
10
11import com.vladium.jcd.cls.IClassDefConstants;
12
13// ----------------------------------------------------------------------------
14/**
15 * @author Vlad Roubtsov, (C) 2003
16 */
17public
18abstract class Descriptors
19{
20    // public: ................................................................
21
22    // TODO: some overlap with Types in c.v.jcp.lib
23
24    public static final char JAVA_NAME_SEPARATOR = '.';
25    public static final char VM_NAME_SEPARATOR = '/';
26
27    public static String combine (final String packageName, final String name, final char separator)
28    {
29        if ((name == null) || (name.length () == 0))
30            throw new IllegalArgumentException ("null or empty input: name");
31
32        if ((packageName == null) || (packageName.length () == 0))
33            return name;
34        else
35            return new StringBuffer (packageName).append (separator).append (name).toString ();
36    }
37
38    public static String combineJavaName (final String packageName, final String name)
39    {
40        return combine (packageName, name, JAVA_NAME_SEPARATOR);
41    }
42
43    public static String combineVMName (final String packageName, final String name)
44    {
45        return combine (packageName, name, VM_NAME_SEPARATOR);
46    }
47
48    /**
49     * Converts a Java package/class name to how it would be
50     * represented in the VM.<P>
51     *
52     * Example:
53     * <PRE><CODE>
54     * javaNameToVMName("java.lang.Object") = "java/lang/Object"
55     * </CODE></PRE>
56     *
57     * @see #vmNameToJavaName
58     */
59    public static String javaNameToVMName (final String javaName)
60    {
61        if (javaName == null) return null;
62
63        return javaName.replace ('.', '/');
64    }
65
66    /**
67     * Converts a JVM package/class name to how it would be
68     * represented in Java.<P>
69     *
70     * Example:
71     * <PRE><CODE>
72     * vmNameToJavaName("java/lang/Object") = "java.lang.Object"
73     * </CODE></PRE>
74     *
75     * @see #javaNameToVMName
76     */
77    public static String vmNameToJavaName (final String vmName)
78    {
79        if (vmName == null) return null;
80
81        return vmName.replace ('/', '.');
82    }
83
84    /**
85     * NOTE: With 'shortTypeNames'=true the output is potentially lossy (truncates
86     * package name) and can result in method signature collisions in very rare
87     * circumstances (e.g., java.awt.List = java.util.List).<P>
88     *
89     * Return type info is also lost.
90     *
91     * @return method name (signature), no package prefix, no return type
92     */
93    public static String methodVMNameToJavaName (final String className,
94                                                 final String methodVMName,
95                                                 final String descriptor,
96                                                 final boolean renameInits,
97                                                 final boolean shortTypeNames,
98                                                 final boolean appendReturnType)
99    {
100        final StringBuffer out = new StringBuffer ();
101
102        if (renameInits)
103        {
104            if (IClassDefConstants.CLINIT_NAME.equals (methodVMName))
105                return "<static initializer>";
106            else if (IClassDefConstants.INIT_NAME.equals (methodVMName))
107                out.append (className);
108            else
109                out.append (methodVMName);
110        }
111        else
112        {
113            if (IClassDefConstants.CLINIT_NAME.equals (methodVMName))
114                return IClassDefConstants.CLINIT_NAME;
115            else
116                out.append (methodVMName);
117        }
118
119        final char [] chars = descriptor.toCharArray ();
120        int end;
121
122        out.append (" (");
123        {
124            for (end = chars.length; chars [-- end] != ')'; );
125
126            for (int start = 1; start < end; )
127            {
128                if (start > 1) out.append (", ");
129                start = typeDescriptorToJavaName (chars, start, shortTypeNames, out);
130            }
131        }
132
133        if (appendReturnType)
134        {
135            out.append ("): ");
136
137            typeDescriptorToJavaName (chars, end + 1, shortTypeNames, out);
138        }
139        else
140        {
141            out.append (')');
142        }
143
144        return out.toString ();
145    }
146
147
148
149    // protected: .............................................................
150
151    // package: ...............................................................
152
153    // private: ...............................................................
154
155//    private static int typeSignatureToJavaName (final char [] signature, int start,
156//                                                final boolean shortTypeNames,
157//                                                final StringBuffer out)
158//    {
159//
160//    }
161
162
163    private static int typeDescriptorToJavaName (final char [] descriptor, int start,
164                                                 final boolean shortTypeNames,
165                                                 final StringBuffer out)
166    {
167        int dims;
168        for (dims = 0; descriptor [start] == '['; ++ dims, ++ start);
169
170        char c = descriptor [start ++];
171        switch (c)
172        {
173            case 'L':
174            {
175                if (shortTypeNames)
176                {
177                    int lastSlash = -1;
178                    for (int s = start; descriptor [s] != ';'; ++ s)
179                    {
180                        if (descriptor [s] == '/') lastSlash = s;
181                    }
182
183                    for (start = lastSlash > 0 ? lastSlash + 1 : start; descriptor [start] != ';'; ++ start)
184                    {
185                        c = descriptor [start];
186                        if (RENAME_INNER_CLASSES)
187                            out.append (c != '$' ? c : '.');
188                        else
189                            out.append (c);
190                    }
191                }
192                else
193                {
194                    for (; descriptor [start] != ';'; ++ start)
195                    {
196                        c = descriptor [start];
197                        out.append (c != '/' ? c : '.');
198                    }
199                }
200
201                ++ start;
202            }
203            break;
204
205            case 'B': out.append ("byte"); break;
206            case 'C': out.append ("char"); break;
207            case 'D': out.append ("double"); break;
208            case 'F': out.append ("float"); break;
209            case 'I': out.append ("int"); break;
210            case 'J': out.append ("long"); break;
211            case 'S': out.append ("short"); break;
212            case 'Z': out.append ("boolean"); break;
213
214            case 'V': out.append ("void"); break;
215
216            default:
217                throw new IllegalStateException ("unknown type descriptor element: " + c);
218
219        } // end of switch
220
221        if (dims > 0)
222        {
223            out.append (' ');
224            for (int d = 0; d < dims; ++ d) out.append ("[]");
225        }
226
227        return start;
228    }
229
230
231    private Descriptors () {} // prevent subclassing
232
233
234    // note: setting this to 'true' is not 100% reliable because it is legal
235    // to have $'s in regular class names as well:
236    private static final boolean RENAME_INNER_CLASSES = false;
237
238} // end of class
239// ----------------------------------------------------------------------------