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 
  21 package com.sun.org.apache.bcel.internal.generic;
  22 
  23 import java.io.DataInput;
  24 import java.io.DataOutputStream;
  25 import java.io.IOException;
  26 
  27 import com.sun.org.apache.bcel.internal.classfile.AnnotationElementValue;
  28 import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry;
  29 import com.sun.org.apache.bcel.internal.classfile.ArrayElementValue;
  30 import com.sun.org.apache.bcel.internal.classfile.ClassElementValue;
  31 import com.sun.org.apache.bcel.internal.classfile.ElementValue;
  32 import com.sun.org.apache.bcel.internal.classfile.EnumElementValue;
  33 import com.sun.org.apache.bcel.internal.classfile.SimpleElementValue;
  34 
  35 /**
  36  * @since 6.0
  37  * @LastModified: Jan 2020
  38  */
  39 public abstract class ElementValueGen
  40 {
  41     private final int type;
  42     private final ConstantPoolGen cpGen;
  43 
  44     protected ElementValueGen(final int type, final ConstantPoolGen cpGen)
  45     {
  46         this.type = type;
  47         this.cpGen = cpGen;
  48     }
  49 
  50     /**
  51      * Subtypes return an immutable variant of the ElementValueGen
  52      */
  53     public abstract ElementValue getElementValue();
  54 
  55     public int getElementValueType()
  56     {
  57         return type;
  58     }
  59 
  60     public abstract String stringifyValue();
  61 
  62     public abstract void dump(DataOutputStream dos) throws IOException;
  63 
  64     public static final int STRING = 's';
  65 
  66     public static final int ENUM_CONSTANT = 'e';
  67 
  68     public static final int CLASS = 'c';
  69 
  70     public static final int ANNOTATION = '@';
  71 
  72     public static final int ARRAY = '[';
  73 
  74     public static final int PRIMITIVE_INT = 'I';
  75 
  76     public static final int PRIMITIVE_BYTE = 'B';
  77 
  78     public static final int PRIMITIVE_CHAR = 'C';
  79 
  80     public static final int PRIMITIVE_DOUBLE = 'D';
  81 
  82     public static final int PRIMITIVE_FLOAT = 'F';
  83 
  84     public static final int PRIMITIVE_LONG = 'J';
  85 
  86     public static final int PRIMITIVE_SHORT = 'S';
  87 
  88     public static final int PRIMITIVE_BOOLEAN = 'Z';
  89 
  90     public static ElementValueGen readElementValue(final DataInput dis,
  91             final ConstantPoolGen cpGen) throws IOException
  92     {
  93         final int type = dis.readUnsignedByte();
  94         switch (type)
  95         {
  96         case 'B': // byte
  97             return new SimpleElementValueGen(PRIMITIVE_BYTE, dis
  98                     .readUnsignedShort(), cpGen);
  99         case 'C': // char
 100             return new SimpleElementValueGen(PRIMITIVE_CHAR, dis
 101                     .readUnsignedShort(), cpGen);
 102         case 'D': // double
 103             return new SimpleElementValueGen(PRIMITIVE_DOUBLE, dis
 104                     .readUnsignedShort(), cpGen);
 105         case 'F': // float
 106             return new SimpleElementValueGen(PRIMITIVE_FLOAT, dis
 107                     .readUnsignedShort(), cpGen);
 108         case 'I': // int
 109             return new SimpleElementValueGen(PRIMITIVE_INT, dis
 110                     .readUnsignedShort(), cpGen);
 111         case 'J': // long
 112             return new SimpleElementValueGen(PRIMITIVE_LONG, dis
 113                     .readUnsignedShort(), cpGen);
 114         case 'S': // short
 115             return new SimpleElementValueGen(PRIMITIVE_SHORT, dis
 116                     .readUnsignedShort(), cpGen);
 117         case 'Z': // boolean
 118             return new SimpleElementValueGen(PRIMITIVE_BOOLEAN, dis
 119                     .readUnsignedShort(), cpGen);
 120         case 's': // String
 121             return new SimpleElementValueGen(STRING, dis.readUnsignedShort(),
 122                     cpGen);
 123         case 'e': // Enum constant
 124             return new EnumElementValueGen(dis.readUnsignedShort(), dis
 125                     .readUnsignedShort(), cpGen);
 126         case 'c': // Class
 127             return new ClassElementValueGen(dis.readUnsignedShort(), cpGen);
 128         case '@': // Annotation
 129             // TODO: isRuntimeVisible ??????????
 130             // FIXME
 131             return new AnnotationElementValueGen(ANNOTATION,
 132                     new AnnotationEntryGen(AnnotationEntry.read(dis, cpGen
 133                             .getConstantPool(), true), cpGen, false), cpGen);
 134         case '[': // Array
 135             final int numArrayVals = dis.readUnsignedShort();
 136             final ElementValue[] evalues = new ElementValue[numArrayVals];
 137             for (int j = 0; j < numArrayVals; j++)
 138             {
 139                 evalues[j] = ElementValue.readElementValue(dis, cpGen
 140                         .getConstantPool());
 141             }
 142             return new ArrayElementValueGen(ARRAY, evalues, cpGen);
 143         default:
 144             throw new RuntimeException("Unexpected element value kind in annotation: " + type);
 145         }
 146     }
 147 
 148     protected ConstantPoolGen getConstantPool()
 149     {
 150         return cpGen;
 151     }
 152 
 153     /**
 154      * Creates an (modifiable) ElementValueGen copy of an (immutable)
 155      * ElementValue - constant pool is assumed correct.
 156      */
 157     public static ElementValueGen copy(final ElementValue value,
 158             final ConstantPoolGen cpool, final boolean copyPoolEntries)
 159     {
 160         switch (value.getElementValueType())
 161         {
 162         case 'B': // byte
 163         case 'C': // char
 164         case 'D': // double
 165         case 'F': // float
 166         case 'I': // int
 167         case 'J': // long
 168         case 'S': // short
 169         case 'Z': // boolean
 170         case 's': // String
 171             return new SimpleElementValueGen((SimpleElementValue) value, cpool,
 172                     copyPoolEntries);
 173         case 'e': // Enum constant
 174             return new EnumElementValueGen((EnumElementValue) value, cpool,
 175                     copyPoolEntries);
 176         case '@': // Annotation
 177             return new AnnotationElementValueGen(
 178                     (AnnotationElementValue) value, cpool, copyPoolEntries);
 179         case '[': // Array
 180             return new ArrayElementValueGen((ArrayElementValue) value, cpool,
 181                     copyPoolEntries);
 182         case 'c': // Class
 183             return new ClassElementValueGen((ClassElementValue) value, cpool,
 184                     copyPoolEntries);
 185         default:
 186             throw new RuntimeException("Not implemented yet! (" + value.getElementValueType() + ")");
 187         }
 188     }
 189 }