Signature.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.bcel.classfile;
- import java.io.ByteArrayInputStream;
- import java.io.DataInput;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.nio.charset.StandardCharsets;
- import java.util.Objects;
- import org.apache.bcel.Const;
- import org.apache.bcel.util.Args;
- /**
- * This class is derived from <em>Attribute</em> and represents a reference to a GJ attribute.
- *
- * @see Attribute
- */
- public final class Signature extends Attribute {
- /**
- * Extends ByteArrayInputStream to make 'unreading' chars possible.
- */
- private static final class MyByteArrayInputStream extends ByteArrayInputStream {
- MyByteArrayInputStream(final String data) {
- super(data.getBytes(StandardCharsets.UTF_8));
- }
- String getData() {
- return new String(buf, StandardCharsets.UTF_8);
- }
- void unread() {
- if (pos > 0) {
- pos--;
- }
- }
- }
- private static boolean identStart(final int ch) {
- return ch == 'T' || ch == 'L';
- }
- // @since 6.0 is no longer final
- public static boolean isActualParameterList(final String s) {
- return s.startsWith("L") && s.endsWith(">;");
- }
- // @since 6.0 is no longer final
- public static boolean isFormalParameterList(final String s) {
- return s.startsWith("<") && s.indexOf(':') > 0;
- }
- private static void matchGJIdent(final MyByteArrayInputStream in, final StringBuilder buf) {
- int ch;
- matchIdent(in, buf);
- ch = in.read();
- if (ch == '<' || ch == '(') { // Parameterized or method
- // System.out.println("Enter <");
- buf.append((char) ch);
- matchGJIdent(in, buf);
- while ((ch = in.read()) != '>' && ch != ')') { // List of parameters
- if (ch == -1) {
- throw new IllegalArgumentException("Illegal signature: " + in.getData() + " reaching EOF");
- }
- // System.out.println("Still no >");
- buf.append(", ");
- in.unread();
- matchGJIdent(in, buf); // Recursive call
- }
- // System.out.println("Exit >");
- buf.append((char) ch);
- } else {
- in.unread();
- }
- ch = in.read();
- if (identStart(ch)) {
- in.unread();
- matchGJIdent(in, buf);
- } else if (ch == ')') {
- in.unread();
- } else if (ch != ';') {
- throw new IllegalArgumentException("Illegal signature: " + in.getData() + " read " + (char) ch);
- }
- }
- private static void matchIdent(final MyByteArrayInputStream in, final StringBuilder buf) {
- int ch;
- if ((ch = in.read()) == -1) {
- throw new IllegalArgumentException("Illegal signature: " + in.getData() + " no ident, reaching EOF");
- }
- // System.out.println("return from ident:" + (char) ch);
- if (!identStart(ch)) {
- final StringBuilder buf2 = new StringBuilder();
- int count = 1;
- while (Character.isJavaIdentifierPart((char) ch)) {
- buf2.append((char) ch);
- count++;
- ch = in.read();
- }
- if (ch == ':') { // Ok, formal parameter
- final int skipExpected = "Ljava/lang/Object".length();
- final long skipActual = in.skip(skipExpected);
- if (skipActual != skipExpected) {
- throw new IllegalStateException(String.format("Unexpected skip: expected=%,d, actual=%,d", skipExpected, skipActual));
- }
- buf.append(buf2);
- ch = in.read();
- in.unread();
- // System.out.println("so far:" + buf2 + ":next:" +(char) ch);
- } else {
- for (int i = 0; i < count; i++) {
- in.unread();
- }
- }
- return;
- }
- final StringBuilder buf2 = new StringBuilder();
- ch = in.read();
- do {
- buf2.append((char) ch);
- ch = in.read();
- // System.out.println("within ident:"+ (char) ch);
- } while (ch != -1 && (Character.isJavaIdentifierPart((char) ch) || ch == '/'));
- buf.append(Utility.pathToPackage(buf2.toString()));
- // System.out.println("regular return ident:"+ (char) ch + ":" + buf2);
- if (ch != -1) {
- in.unread();
- }
- }
- public static String translate(final String s) {
- // System.out.println("Sig:" + s);
- final StringBuilder buf = new StringBuilder();
- matchGJIdent(new MyByteArrayInputStream(s), buf);
- return buf.toString();
- }
- private int signatureIndex;
- /**
- * Constructs object from file stream.
- *
- * @param nameIndex Index in constant pool to CONSTANT_Utf8
- * @param length Content length in bytes
- * @param input Input stream
- * @param constantPool Array of constants
- * @throws IOException if an I/O error occurs.
- */
- Signature(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
- this(nameIndex, length, input.readUnsignedShort(), constantPool);
- }
- /**
- * @param nameIndex Index in constant pool to CONSTANT_Utf8
- * @param length Content length in bytes
- * @param signatureIndex Index in constant pool to CONSTANT_Utf8
- * @param constantPool Array of constants
- */
- public Signature(final int nameIndex, final int length, final int signatureIndex, final ConstantPool constantPool) {
- super(Const.ATTR_SIGNATURE, nameIndex, Args.require(length, 2, "Signature length attribute"), constantPool);
- this.signatureIndex = signatureIndex;
- // validate:
- Objects.requireNonNull(constantPool.getConstantUtf8(signatureIndex), "constantPool.getConstantUtf8(signatureIndex)");
- }
- /**
- * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
- * physical copy.
- *
- * @param c Source to copy.
- */
- public Signature(final Signature c) {
- this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool());
- }
- /**
- * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
- * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
- *
- * @param v Visitor object
- */
- @Override
- public void accept(final Visitor v) {
- // System.err.println("Visiting non-standard Signature object");
- v.visitSignature(this);
- }
- /**
- * @return deep copy of this attribute
- */
- @Override
- public Attribute copy(final ConstantPool constantPool) {
- return (Attribute) clone();
- }
- /**
- * Dump source file attribute to file stream in binary format.
- *
- * @param file Output file stream
- * @throws IOException if an I/O error occurs.
- */
- @Override
- public void dump(final DataOutputStream file) throws IOException {
- super.dump(file);
- file.writeShort(signatureIndex);
- }
- /**
- * @return GJ signature.
- */
- public String getSignature() {
- return super.getConstantPool().getConstantUtf8(signatureIndex).getBytes();
- }
- /**
- * @return Index in constant pool of source file name.
- */
- public int getSignatureIndex() {
- return signatureIndex;
- }
- /**
- * @param signatureIndex the index info the constant pool of this signature
- */
- public void setSignatureIndex(final int signatureIndex) {
- this.signatureIndex = signatureIndex;
- }
- /**
- * @return String representation
- */
- @Override
- public String toString() {
- return "Signature: " + getSignature();
- }
- }