001: /*
002: * ProGuard -- shrinking, optimization, obfuscation, and preverification
003: * of Java bytecode.
004: *
005: * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
006: *
007: * This program is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License as published by the Free
009: * Software Foundation; either version 2 of the License, or (at your option)
010: * any later version.
011: *
012: * This program is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
015: * more details.
016: *
017: * You should have received a copy of the GNU General Public License along
018: * with this program; if not, write to the Free Software Foundation, Inc.,
019: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021: package proguard.classfile.util;
022:
023: import proguard.classfile.ClassConstants;
024:
025: /**
026: * An <code>InternalTypeEnumeration</code> provides an enumeration of all
027: * parameter types listed in a given internal method descriptor or signature.
028: * The signature can also be a class signature. The return type of a method
029: * descriptor can retrieved separately.
030: *
031: * @author Eric Lafortune
032: */
033: public class InternalTypeEnumeration {
034: private String descriptor;
035: private int index;
036:
037: /**
038: * Creates a new InternalTypeEnumeration for the given method descriptor.
039: */
040: public InternalTypeEnumeration(String descriptor) {
041: this .descriptor = descriptor;
042: this .index = descriptor
043: .indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN) + 1;
044: }
045:
046: /**
047: * Returns whether the enumeration can provide more types from the method
048: * descriptor.
049: */
050: public boolean hasMoreTypes() {
051: return index < descriptor.length()
052: && descriptor.charAt(index) != ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE;
053: }
054:
055: /**
056: * Returns the next type from the method descriptor.
057: */
058: public String nextType() {
059: int startIndex = index;
060:
061: int nestingLevel = 0;
062: boolean parsingRawType = true;
063: boolean parsingArrayPrefix;
064: do {
065: parsingArrayPrefix = false;
066:
067: char c = descriptor.charAt(index++);
068:
069: if (parsingRawType) {
070: // Parse an array character, primitive type, or a token
071: // marking the beginning of an identifier (for a class or
072: // a variable type).
073: switch (c) {
074: case ClassConstants.INTERNAL_TYPE_GENERIC_START: {
075: parsingRawType = false;
076: nestingLevel++;
077: break;
078: }
079: case ClassConstants.INTERNAL_TYPE_GENERIC_END: {
080: parsingRawType = false;
081: nestingLevel--;
082: break;
083: }
084: case ClassConstants.INTERNAL_TYPE_ARRAY: {
085: parsingArrayPrefix = true;
086: break;
087: }
088: case ClassConstants.INTERNAL_TYPE_CLASS_START:
089: case ClassConstants.INTERNAL_TYPE_GENERIC_VARIABLE_START: {
090: parsingRawType = false;
091: nestingLevel += 2;
092: break;
093: }
094: }
095: } else {
096: // Parse the identifier, or a token marking its end.
097: switch (c) {
098: case ClassConstants.INTERNAL_TYPE_CLASS_END:
099: parsingRawType = true;
100: nestingLevel -= 2;
101:
102: // Are we at the start of a type parameter?
103: if (nestingLevel == 1
104: && descriptor.charAt(index) != ClassConstants.INTERNAL_TYPE_GENERIC_END) {
105: parsingRawType = false;
106: }
107: break;
108: case ClassConstants.INTERNAL_TYPE_GENERIC_START:
109: parsingRawType = true;
110: nestingLevel++;
111: break;
112: case ClassConstants.INTERNAL_TYPE_GENERIC_BOUND:
113: parsingRawType = true;
114: break;
115: }
116: }
117: } while (nestingLevel > 0 || parsingArrayPrefix);
118:
119: return descriptor.substring(startIndex, index);
120: }
121:
122: /**
123: * Returns the return type from the descriptor, assuming it's a method
124: * descriptor.
125: */
126: public String returnType() {
127: return descriptor
128: .substring(descriptor
129: .indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE) + 1);
130: }
131:
132: /**
133: * A main method for testing the type enumeration.
134: */
135: public static void main(String[] args) {
136: try {
137: System.out.println("Descriptor [" + args[0] + "]");
138: InternalTypeEnumeration enumeration = new InternalTypeEnumeration(
139: args[0]);
140:
141: while (enumeration.hasMoreTypes()) {
142: System.out.println(" Type [" + enumeration.nextType()
143: + "]");
144: }
145:
146: System.out.println(" Return type ["
147: + enumeration.returnType() + "]");
148: } catch (Exception ex) {
149: ex.printStackTrace();
150: }
151: }
152: }
|