1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 Eric Lafortune (eric (at) graphics.cornell.edu) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 package proguard.classfile.util; 22 23 import proguard.classfile.ClassConstants; 24 25 26 /** 27 * An <code>InternalTypeEnumeration</code> provides an enumeration of all 28 * parameter types listed in a given internal method descriptor or signature. 29 * The signature can also be a class signature. The return type of a method 30 * descriptor can be retrieved separately. 31 * 32 * @author Eric Lafortune 33 */ 34 public class InternalTypeEnumeration 35 { 36 private String descriptor; 37 private int firstIndex; 38 private int lastIndex; 39 private int index; 40 41 42 /** 43 * Creates a new InternalTypeEnumeration for the given method descriptor. 44 */ 45 public InternalTypeEnumeration(String descriptor) 46 { 47 this.descriptor = descriptor; 48 this.firstIndex = descriptor.indexOf(ClassConstants.METHOD_ARGUMENTS_OPEN); 49 this.lastIndex = descriptor.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE); 50 this.index = firstIndex + 1; 51 52 if (lastIndex < 0) 53 { 54 lastIndex = descriptor.length(); 55 } 56 } 57 58 59 /** 60 * Returns whether the type is a method signature. 61 */ 62 public boolean isMethodSignature() 63 { 64 return firstIndex >= 0; 65 } 66 67 68 /** 69 * Returns the formal type parameters from the descriptor, assuming it's a 70 * method descriptor. 71 */ 72 public String formalTypeParameters() 73 { 74 return descriptor.substring(0, firstIndex); 75 } 76 77 78 /** 79 * Returns whether the enumeration can provide more types from the method 80 * descriptor. 81 */ 82 public boolean hasMoreTypes() 83 { 84 return index < lastIndex; 85 } 86 87 88 /** 89 * Returns the next type from the method descriptor. 90 */ 91 public String nextType() 92 { 93 int startIndex = index; 94 95 skipArray(); 96 97 char c = descriptor.charAt(index++); 98 switch (c) 99 { 100 case ClassConstants.TYPE_CLASS_START: 101 case ClassConstants.TYPE_GENERIC_VARIABLE_START: 102 { 103 skipClass(); 104 break; 105 } 106 case ClassConstants.TYPE_GENERIC_START: 107 { 108 skipGeneric(); 109 break; 110 } 111 } 112 113 return descriptor.substring(startIndex, index); 114 } 115 116 117 /** 118 * Returns the return type from the descriptor, assuming it's a method 119 * descriptor. 120 */ 121 public String returnType() 122 { 123 return descriptor.substring(lastIndex + 1); 124 } 125 126 127 // Small utility methods. 128 129 private void skipArray() 130 { 131 while (descriptor.charAt(index) == ClassConstants.TYPE_ARRAY) 132 { 133 index++; 134 } 135 } 136 137 138 private void skipClass() 139 { 140 while (true) 141 { 142 char c = descriptor.charAt(index++); 143 switch (c) 144 { 145 case ClassConstants.TYPE_GENERIC_START: 146 skipGeneric(); 147 break; 148 149 case ClassConstants.TYPE_CLASS_END: 150 return; 151 } 152 } 153 } 154 155 156 private void skipGeneric() 157 { 158 int nestingLevel = 1; 159 160 do 161 { 162 char c = descriptor.charAt(index++); 163 switch (c) 164 { 165 case ClassConstants.TYPE_GENERIC_START: 166 nestingLevel++; 167 break; 168 169 case ClassConstants.TYPE_GENERIC_END: 170 nestingLevel--; 171 break; 172 } 173 } 174 while (nestingLevel > 0); 175 } 176 177 178 /** 179 * A main method for testing the type enumeration. 180 */ 181 public static void main(String[] args) 182 { 183 try 184 { 185 for (int index = 0; index < args.length; index++) 186 { 187 String descriptor = args[index]; 188 189 System.out.println("Descriptor ["+descriptor+"]"); 190 InternalTypeEnumeration enumeration = new InternalTypeEnumeration(descriptor); 191 192 if (enumeration.firstIndex >= 0) 193 { 194 System.out.println(" Formal type parameters ["+enumeration.formalTypeParameters()+"]"); 195 } 196 197 while (enumeration.hasMoreTypes()) 198 { 199 System.out.println(" Type ["+enumeration.nextType()+"]"); 200 } 201 202 if (enumeration.lastIndex < descriptor.length()) 203 { 204 System.out.println(" Return type ["+enumeration.returnType()+"]"); 205 } 206 } 207 } 208 catch (Exception ex) 209 { 210 ex.printStackTrace(); 211 } 212 } 213 } 214