1 /* 2 * Copyright (c) 1998, 2020, 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 26 package com.sun.tools.jdi; 27 28 import java.util.ArrayList; 29 import java.util.List; 30 31 public 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 typeName) { 47 StringBuilder sb = new StringBuilder(); 48 int firstIndex = typeName.indexOf('['); 49 int index = firstIndex; 50 while (index != -1) { 51 sb.append('['); 52 index = typeName.indexOf('[', index + 1); 53 } 54 55 if (firstIndex != -1) { 56 typeName = typeName.substring(0, firstIndex); 57 } 58 59 if (typeName.equals("boolean")) { 60 sb.append('Z'); 61 } else if (typeName.equals("byte")) { 62 sb.append('B'); 63 } else if (typeName.equals("char")) { 64 sb.append('C'); 65 } else if (typeName.equals("short")) { 66 sb.append('S'); 67 } else if (typeName.equals("int")) { 68 sb.append('I'); 69 } else if (typeName.equals("long")) { 70 sb.append('J'); 71 } else if (typeName.equals("float")) { 72 sb.append('F'); 73 } else if (typeName.equals("double")) { 74 sb.append('D'); 75 } else { 76 sb.append('L'); 77 index = typeName.indexOf("/"); // check if it's a hidden class 78 if (index < 0) { 79 sb.append(typeName.replace('.', '/')); 80 sb.append(";"); 81 } else { 82 sb.append(typeName.substring(0, index).replace('.', '/')); 83 sb.append(";"); 84 sb.append(typeName.substring(index, typeName.length())); 85 } 86 } 87 88 return sb.toString(); 89 } 90 91 String typeName() { 92 return typeNameList().get(typeNameList().size()-1); 93 } 94 95 List<String> argumentTypeNames() { 96 return typeNameList().subList(0, typeNameList().size() - 1); 97 } 98 99 String signature() { 100 return signatureList().get(signatureList().size()-1); 101 } 102 103 List<String> argumentSignatures() { 104 return signatureList().subList(0, signatureList().size() - 1); 105 } 106 107 int dimensionCount() { 108 int count = 0; 109 String signature = signature(); 110 while (signature.charAt(count) == '[') { 111 count++; 112 } 113 return count; 114 } 115 116 String componentSignature(int level) { 117 return signature().substring(level); 118 } 119 120 private synchronized List<String> signatureList() { 121 if (signatureList == null) { 122 signatureList = new ArrayList<>(10); 123 String elem; 124 125 currentIndex = 0; 126 127 while(currentIndex < signature.length()) { 128 elem = nextSignature(); 129 signatureList.add(elem); 130 } 131 if (signatureList.size() == 0) { 132 throw new IllegalArgumentException("Invalid JNI signature '" + 133 signature + "'"); 134 } 135 } 136 return signatureList; 137 } 138 139 private synchronized List<String> typeNameList() { 140 if (typeNameList == null) { 141 typeNameList = new ArrayList<>(10); 142 String elem; 143 144 currentIndex = 0; 145 146 while(currentIndex < signature.length()) { 147 elem = nextTypeName(); 148 typeNameList.add(elem); 149 } 150 if (typeNameList.size() == 0) { 151 throw new IllegalArgumentException("Invalid JNI signature '" + 152 signature + "'"); 153 } 154 } 155 return typeNameList; 156 } 157 158 private String nextSignature() { 159 char key = signature.charAt(currentIndex++); 160 161 switch(key) { 162 case (JDWP.Tag.ARRAY): 163 return key + nextSignature(); 164 165 case (JDWP.Tag.OBJECT): 166 int endClass = signature.indexOf(SIGNATURE_ENDCLASS, 167 currentIndex); 168 String retVal; 169 if ((endClass+1) < signature.length() && signature.charAt(endClass+1) == '/') { 170 // hidden class 171 retVal = signature.substring(currentIndex - 1); 172 currentIndex = signature.length(); 173 } else { 174 retVal = signature.substring(currentIndex - 1, endClass + 1); 175 currentIndex = endClass + 1; 176 } 177 return retVal; 178 179 case (JDWP.Tag.VOID): 180 case (JDWP.Tag.BOOLEAN): 181 case (JDWP.Tag.BYTE): 182 case (JDWP.Tag.CHAR): 183 case (JDWP.Tag.SHORT): 184 case (JDWP.Tag.INT): 185 case (JDWP.Tag.LONG): 186 case (JDWP.Tag.FLOAT): 187 case (JDWP.Tag.DOUBLE): 188 return String.valueOf(key); 189 190 case SIGNATURE_ENDFUNC: 191 case SIGNATURE_FUNC: 192 return nextSignature(); 193 194 default: 195 throw new IllegalArgumentException( 196 "Invalid JNI signature character '" + key + "'"); 197 198 } 199 } 200 201 private String nextTypeName() { 202 char key = signature.charAt(currentIndex++); 203 204 switch(key) { 205 case (JDWP.Tag.ARRAY): 206 return nextTypeName() + "[]"; 207 208 case (JDWP.Tag.BYTE): 209 return "byte"; 210 211 case (JDWP.Tag.CHAR): 212 return "char"; 213 214 case (JDWP.Tag.OBJECT): 215 int endClass = signature.indexOf(SIGNATURE_ENDCLASS, 216 currentIndex); 217 String retVal = signature.substring(currentIndex, 218 endClass); 219 if ((endClass+1) < signature.length() && signature.charAt(endClass+1) == '/') { 220 // hidden class 221 retVal = retVal.replace('/', '.') + signature.substring(endClass + 1); 222 currentIndex = signature.length(); 223 } else { 224 retVal = retVal.replace('/', '.'); 225 currentIndex = endClass + 1; 226 } 227 return retVal; 228 229 case (JDWP.Tag.FLOAT): 230 return "float"; 231 232 case (JDWP.Tag.DOUBLE): 233 return "double"; 234 235 case (JDWP.Tag.INT): 236 return "int"; 237 238 case (JDWP.Tag.LONG): 239 return "long"; 240 241 case (JDWP.Tag.SHORT): 242 return "short"; 243 244 case (JDWP.Tag.VOID): 245 return "void"; 246 247 case (JDWP.Tag.BOOLEAN): 248 return "boolean"; 249 250 case SIGNATURE_ENDFUNC: 251 case SIGNATURE_FUNC: 252 return nextTypeName(); 253 254 default: 255 throw new IllegalArgumentException( 256 "Invalid JNI signature character '" + key + "'"); 257 } 258 } 259 }