1/*
2 * Copyright (c) 2002, 2012, 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.javah;
27
28import javax.lang.model.element.ExecutableElement;
29import javax.lang.model.element.TypeElement;
30import javax.lang.model.element.VariableElement;
31import javax.lang.model.util.Elements;
32import javax.lang.model.util.Types;
33
34/**
35 * A utility for mangling java identifiers into C names.  Should make
36 * this more fine grained and distribute the functionality to the
37 * generators.
38 *
39 * <p><b>This is NOT part of any supported API.
40 * If you write code that depends on this, you do so at your own
41 * risk.  This code and its internal interfaces are subject to change
42 * or deletion without notice.</b></p>
43 *
44 * @author  Sucheta Dambalkar(Revised)
45 */
46public class Mangle {
47
48    public static class Type {
49        public static final int CLASS            = 1;
50        public static final int FIELDSTUB        = 2;
51        public static final int FIELD            = 3;
52        public static final int JNI              = 4;
53        public static final int SIGNATURE        = 5;
54        public static final int METHOD_JDK_1     = 6;
55        public static final int METHOD_JNI_SHORT = 7;
56        public static final int METHOD_JNI_LONG  = 8;
57    }
58
59    private Elements elems;
60    private Types types;
61
62    Mangle(Elements elems, Types types) {
63        this.elems = elems;
64        this.types = types;
65    }
66
67    public final String mangle(CharSequence name, int mtype) {
68        StringBuilder result = new StringBuilder(100);
69        int length = name.length();
70
71        for (int i = 0; i < length; i++) {
72            char ch = name.charAt(i);
73            if (isalnum(ch)) {
74                result.append(ch);
75            } else if ((ch == '.') &&
76                       mtype == Mangle.Type.CLASS) {
77                result.append('_');
78            } else if (( ch == '$') &&
79                       mtype == Mangle.Type.CLASS) {
80                result.append('_');
81                result.append('_');
82            } else if (ch == '_' && mtype == Mangle.Type.FIELDSTUB) {
83                result.append('_');
84            } else if (ch == '_' && mtype == Mangle.Type.CLASS) {
85                result.append('_');
86            } else if (mtype == Mangle.Type.JNI) {
87                String esc = null;
88                if (ch == '_')
89                    esc = "_1";
90                else if (ch == '.')
91                    esc = "_";
92                else if (ch == ';')
93                    esc = "_2";
94                else if (ch == '[')
95                    esc = "_3";
96                if (esc != null) {
97                    result.append(esc);
98                } else {
99                    result.append(mangleChar(ch));
100                }
101            } else if (mtype == Mangle.Type.SIGNATURE) {
102                if (isprint(ch)) {
103                    result.append(ch);
104                } else {
105                    result.append(mangleChar(ch));
106                }
107            } else {
108                result.append(mangleChar(ch));
109            }
110        }
111
112        return result.toString();
113    }
114
115    public String mangleMethod(ExecutableElement method, TypeElement clazz,
116                                      int mtype) throws TypeSignature.SignatureException {
117        StringBuilder result = new StringBuilder(100);
118        result.append("Java_");
119
120        if (mtype == Mangle.Type.METHOD_JDK_1) {
121            result.append(mangle(clazz.getQualifiedName(), Mangle.Type.CLASS));
122            result.append('_');
123            result.append(mangle(method.getSimpleName(),
124                                 Mangle.Type.FIELD));
125            result.append("_stub");
126            return result.toString();
127        }
128
129        /* JNI */
130        result.append(mangle(getInnerQualifiedName(clazz), Mangle.Type.JNI));
131        result.append('_');
132        result.append(mangle(method.getSimpleName(),
133                             Mangle.Type.JNI));
134        if (mtype == Mangle.Type.METHOD_JNI_LONG) {
135            result.append("__");
136            String typesig = signature(method);
137            TypeSignature newTypeSig = new TypeSignature(elems);
138            String sig = newTypeSig.getTypeSignature(typesig,  method.getReturnType());
139            sig = sig.substring(1);
140            sig = sig.substring(0, sig.lastIndexOf(')'));
141            sig = sig.replace('/', '.');
142            result.append(mangle(sig, Mangle.Type.JNI));
143        }
144
145        return result.toString();
146    }
147    //where
148        private String getInnerQualifiedName(TypeElement clazz) {
149            return elems.getBinaryName(clazz).toString();
150        }
151
152    public final String mangleChar(char ch) {
153        String s = Integer.toHexString(ch);
154        int nzeros = 5 - s.length();
155        char[] result = new char[6];
156        result[0] = '_';
157        for (int i = 1; i <= nzeros; i++)
158            result[i] = '0';
159        for (int i = nzeros+1, j = 0; i < 6; i++, j++)
160            result[i] = s.charAt(j);
161        return new String(result);
162    }
163
164    // Warning: duplicated in Gen
165    private String signature(ExecutableElement e) {
166        StringBuilder sb = new StringBuilder();
167        String sep = "(";
168        for (VariableElement p: e.getParameters()) {
169            sb.append(sep);
170            sb.append(types.erasure(p.asType()).toString());
171            sep = ",";
172        }
173        sb.append(")");
174        return sb.toString();
175    }
176
177    /* Warning: Intentional ASCII operation. */
178    private static boolean isalnum(char ch) {
179        return ch <= 0x7f && /* quick test */
180            ((ch >= 'A' && ch <= 'Z') ||
181             (ch >= 'a' && ch <= 'z') ||
182             (ch >= '0' && ch <= '9'));
183    }
184
185    /* Warning: Intentional ASCII operation. */
186    private static boolean isprint(char ch) {
187        return ch >= 32 && ch <= 126;
188    }
189}
190