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