1 /*
   2  * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 package com.sun.org.apache.bcel.internal.classfile;
  21 
  22 import java.io.DataInput;
  23 import java.io.DataOutputStream;
  24 import java.io.IOException;
  25 import java.util.Objects;
  26 
  27 import com.sun.org.apache.bcel.internal.Const;
  28 import com.sun.org.apache.bcel.internal.util.BCELComparator;
  29 
  30 /**
  31  * Abstract superclass for classes to represent the different constant types
  32  * in the constant pool of a class file. The classes keep closely to
  33  * the JVM specification.
  34  *
  35  * @LastModified: Jan 2020
  36  */
  37 public abstract class Constant implements Cloneable, Node {
  38 
  39     private static BCELComparator bcelComparator = new BCELComparator() {
  40 
  41         @Override
  42         public boolean equals( final Object o1, final Object o2 ) {
  43             final Constant THIS = (Constant) o1;
  44             final Constant THAT = (Constant) o2;
  45             return Objects.equals(THIS.toString(), THAT.toString());
  46         }
  47 
  48 
  49         @Override
  50         public int hashCode( final Object o ) {
  51             final Constant THIS = (Constant) o;
  52             return THIS.toString().hashCode();
  53         }
  54     };
  55 
  56     /* In fact this tag is redundant since we can distinguish different
  57      * `Constant' objects by their type, i.e., via `instanceof'. In some
  58      * places we will use the tag for switch()es anyway.
  59      *
  60      * First, we want match the specification as closely as possible. Second we
  61      * need the tag as an index to select the corresponding class name from the
  62      * `CONSTANT_NAMES' array.
  63      */
  64     private byte tag;
  65 
  66     Constant(final byte tag) {
  67         this.tag = tag;
  68     }
  69 
  70     /**
  71      * Called by objects that are traversing the nodes of the tree implicitely
  72      * defined by the contents of a Java class. I.e., the hierarchy of methods,
  73      * fields, attributes, etc. spawns a tree of objects.
  74      *
  75      * @param v Visitor object
  76      */
  77     @Override
  78     public abstract void accept( Visitor v );
  79 
  80     public abstract void dump( DataOutputStream file ) throws IOException;
  81 
  82     /**
  83      * @return Tag of constant, i.e., its type. No setTag() method to avoid
  84      * confusion.
  85      */
  86     public final byte getTag() {
  87         return tag;
  88     }
  89 
  90     /**
  91      * @return String representation.
  92      */
  93     @Override
  94     public String toString() {
  95         return Const.getConstantName(tag) + "[" + tag + "]";
  96     }
  97 
  98     /**
  99      * @return deep copy of this constant
 100      */
 101     public Constant copy() {
 102         try {
 103             return (Constant) super.clone();
 104         } catch (final CloneNotSupportedException e) {
 105             // TODO should this throw?
 106         }
 107         return null;
 108     }
 109 
 110     @Override
 111     public Object clone() {
 112         try {
 113             return super.clone();
 114         } catch (final CloneNotSupportedException e) {
 115             throw new Error("Clone Not Supported"); // never happens
 116         }
 117     }
 118 
 119     /**
 120      * Reads one constant from the given input, the type depends on a tag byte.
 121      *
 122      * @param dataInput Input stream
 123      * @return Constant object
 124      * @throws IOException if an I/O error occurs reading from the given {@code dataInput}.
 125      * @throws ClassFormatException if the next byte is not recognized
 126      * @since 6.0 made public
 127      */
 128     public static Constant readConstant(final DataInput dataInput) throws IOException, ClassFormatException {
 129         final byte b = dataInput.readByte(); // Read tag byte
 130         switch (b) {
 131         case Const.CONSTANT_Class:
 132             return new ConstantClass(dataInput);
 133         case Const.CONSTANT_Fieldref:
 134             return new ConstantFieldref(dataInput);
 135         case Const.CONSTANT_Methodref:
 136             return new ConstantMethodref(dataInput);
 137         case Const.CONSTANT_InterfaceMethodref:
 138             return new ConstantInterfaceMethodref(dataInput);
 139         case Const.CONSTANT_String:
 140             return new ConstantString(dataInput);
 141         case Const.CONSTANT_Integer:
 142             return new ConstantInteger(dataInput);
 143         case Const.CONSTANT_Float:
 144             return new ConstantFloat(dataInput);
 145         case Const.CONSTANT_Long:
 146             return new ConstantLong(dataInput);
 147         case Const.CONSTANT_Double:
 148             return new ConstantDouble(dataInput);
 149         case Const.CONSTANT_NameAndType:
 150             return new ConstantNameAndType(dataInput);
 151         case Const.CONSTANT_Utf8:
 152             return ConstantUtf8.getInstance(dataInput);
 153         case Const.CONSTANT_MethodHandle:
 154             return new ConstantMethodHandle(dataInput);
 155         case Const.CONSTANT_MethodType:
 156             return new ConstantMethodType(dataInput);
 157         case Const.CONSTANT_Dynamic:
 158             return new ConstantDynamic(dataInput);
 159         case Const.CONSTANT_InvokeDynamic:
 160             return new ConstantInvokeDynamic(dataInput);
 161         case Const.CONSTANT_Module:
 162             return new ConstantModule(dataInput);
 163         case Const.CONSTANT_Package:
 164             return new ConstantPackage(dataInput);
 165         default:
 166             throw new ClassFormatException("Invalid byte tag in constant pool: " + b);
 167         }
 168     }
 169 
 170     /**
 171      * @return Comparison strategy object
 172      */
 173     public static BCELComparator getComparator() {
 174         return bcelComparator;
 175     }
 176 
 177     /**
 178      * @param comparator Comparison strategy object
 179      */
 180     public static void setComparator( final BCELComparator comparator ) {
 181         bcelComparator = comparator;
 182     }
 183 
 184     /**
 185      * Returns value as defined by given BCELComparator strategy.
 186      * By default two Constant objects are said to be equal when
 187      * the result of toString() is equal.
 188      *
 189      * @see java.lang.Object#equals(java.lang.Object)
 190      */
 191     @Override
 192     public boolean equals( final Object obj ) {
 193         return bcelComparator.equals(this, obj);
 194     }
 195 
 196     /**
 197      * Returns value as defined by given BCELComparator strategy.
 198      * By default return the hashcode of the result of toString().
 199      *
 200      * @see java.lang.Object#hashCode()
 201      */
 202     @Override
 203     public int hashCode() {
 204         return bcelComparator.hashCode(this);
 205     }
 206 }