1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2009 Eric Lafortune (eric@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 */ 21package proguard.classfile.util; 22 23import 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 retrieved separately. 31 * 32 * @author Eric Lafortune 33 */ 34public 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.INTERNAL_METHOD_ARGUMENTS_OPEN); 49 this.lastIndex = descriptor.indexOf(ClassConstants.INTERNAL_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 the formal type parameters from the descriptor, assuming it's a 61 * method descriptor. 62 */ 63 public String formalTypeParameters() 64 { 65 return descriptor.substring(0, firstIndex); 66 } 67 68 69 /** 70 * Returns whether the enumeration can provide more types from the method 71 * descriptor. 72 */ 73 public boolean hasMoreTypes() 74 { 75 return index < lastIndex; 76 } 77 78 79 /** 80 * Returns the next type from the method descriptor. 81 */ 82 public String nextType() 83 { 84 int startIndex = index; 85 86 skipArray(); 87 88 char c = descriptor.charAt(index++); 89 switch (c) 90 { 91 case ClassConstants.INTERNAL_TYPE_CLASS_START: 92 case ClassConstants.INTERNAL_TYPE_GENERIC_VARIABLE_START: 93 { 94 skipClass(); 95 break; 96 } 97 case ClassConstants.INTERNAL_TYPE_GENERIC_START: 98 { 99 skipGeneric(); 100 break; 101 } 102 } 103 104 return descriptor.substring(startIndex, index); 105 } 106 107 108 /** 109 * Returns the return type from the descriptor, assuming it's a method 110 * descriptor. 111 */ 112 public String returnType() 113 { 114 return descriptor.substring(lastIndex + 1); 115 } 116 117 118 // Small utility methods. 119 120 private void skipArray() 121 { 122 while (descriptor.charAt(index) == ClassConstants.INTERNAL_TYPE_ARRAY) 123 { 124 index++; 125 } 126 } 127 128 129 private void skipClass() 130 { 131 while (true) 132 { 133 char c = descriptor.charAt(index++); 134 switch (c) 135 { 136 case ClassConstants.INTERNAL_TYPE_GENERIC_START: 137 skipGeneric(); 138 break; 139 140 case ClassConstants.INTERNAL_TYPE_CLASS_END: 141 return; 142 } 143 } 144 } 145 146 147 private void skipGeneric() 148 { 149 int nestingLevel = 1; 150 151 do 152 { 153 char c = descriptor.charAt(index++); 154 switch (c) 155 { 156 case ClassConstants.INTERNAL_TYPE_GENERIC_START: 157 nestingLevel++; 158 break; 159 160 case ClassConstants.INTERNAL_TYPE_GENERIC_END: 161 nestingLevel--; 162 break; 163 } 164 } 165 while (nestingLevel > 0); 166 } 167 168 169 /** 170 * A main method for testing the type enumeration. 171 */ 172 public static void main(String[] args) 173 { 174 try 175 { 176 for (int index = 0; index < args.length; index++) 177 { 178 String descriptor = args[index]; 179 180 System.out.println("Descriptor ["+descriptor+"]"); 181 InternalTypeEnumeration enumeration = new InternalTypeEnumeration(descriptor); 182 183 if (enumeration.firstIndex >= 0) 184 { 185 System.out.println(" Formal type parameters ["+enumeration.formalTypeParameters()+"]"); 186 } 187 188 while (enumeration.hasMoreTypes()) 189 { 190 System.out.println(" Type ["+enumeration.nextType()+"]"); 191 } 192 193 if (enumeration.lastIndex < descriptor.length()) 194 { 195 System.out.println(" Return type ["+enumeration.returnType()+"]"); 196 } 197 } 198 } 199 catch (Exception ex) 200 { 201 ex.printStackTrace(); 202 } 203 } 204} 205