Home | History | Annotate | Download | only in classfile
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  */
     18 package org.apache.bcel.classfile;
     19 
     20 import java.io.DataInput;
     21 import java.io.DataOutputStream;
     22 import java.io.IOException;
     23 import java.util.HashMap;
     24 import java.util.Map;
     25 
     26 import org.apache.bcel.Const;
     27 
     28 /**
     29  * This class represents a reference to an unknown (i.e.,
     30  * application-specific) attribute of a class.  It is instantiated from the
     31  * {@link Attribute#readAttribute(java.io.DataInput, ConstantPool)} method.
     32  * Applications that need to read in application-specific attributes should create an
     33  * {@link UnknownAttributeReader} implementation and attach it via
     34  * {@link Attribute#addAttributeReader(String, UnknownAttributeReader)}.
     35 
     36  *
     37  * @version $Id$
     38  * @see Attribute
     39  * @see UnknownAttributeReader
     40  */
     41 public final class Unknown extends Attribute {
     42 
     43     private byte[] bytes;
     44     private final String name;
     45     private static final Map<String, Unknown> unknown_attributes = new HashMap<>();
     46 
     47 
     48     /** @return array of unknown attributes, but just one for each kind.
     49      */
     50     static Unknown[] getUnknownAttributes() {
     51         final Unknown[] unknowns = new Unknown[unknown_attributes.size()];
     52         unknown_attributes.values().toArray(unknowns);
     53         unknown_attributes.clear();
     54         return unknowns;
     55     }
     56 
     57 
     58     /**
     59      * Initialize from another object. Note that both objects use the same
     60      * references (shallow copy). Use clone() for a physical copy.
     61      */
     62     public Unknown(final Unknown c) {
     63         this(c.getNameIndex(), c.getLength(), c.getBytes(), c.getConstantPool());
     64     }
     65 
     66 
     67     /**
     68      * Create a non-standard attribute.
     69      *
     70      * @param name_index Index in constant pool
     71      * @param length Content length in bytes
     72      * @param bytes Attribute contents
     73      * @param constant_pool Array of constants
     74      */
     75     public Unknown(final int name_index, final int length, final byte[] bytes, final ConstantPool constant_pool) {
     76         super(Const.ATTR_UNKNOWN, name_index, length, constant_pool);
     77         this.bytes = bytes;
     78         name = ((ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8))
     79                 .getBytes();
     80         unknown_attributes.put(name, this);
     81     }
     82 
     83 
     84     /**
     85      * Construct object from input stream.
     86      *
     87      * @param name_index Index in constant pool
     88      * @param length Content length in bytes
     89      * @param input Input stream
     90      * @param constant_pool Array of constants
     91      * @throws IOException
     92      */
     93     Unknown(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
     94             throws IOException {
     95         this(name_index, length, (byte[]) null, constant_pool);
     96         if (length > 0) {
     97             bytes = new byte[length];
     98             input.readFully(bytes);
     99         }
    100     }
    101 
    102 
    103     /**
    104      * Called by objects that are traversing the nodes of the tree implicitely
    105      * defined by the contents of a Java class. I.e., the hierarchy of methods,
    106      * fields, attributes, etc. spawns a tree of objects.
    107      *
    108      * @param v Visitor object
    109      */
    110     @Override
    111     public void accept( final Visitor v ) {
    112         v.visitUnknown(this);
    113     }
    114 
    115 
    116     /**
    117      * Dump unknown bytes to file stream.
    118      *
    119      * @param file Output file stream
    120      * @throws IOException
    121      */
    122     @Override
    123     public final void dump( final DataOutputStream file ) throws IOException {
    124         super.dump(file);
    125         if (super.getLength() > 0) {
    126             file.write(bytes, 0, super.getLength());
    127         }
    128     }
    129 
    130 
    131     /**
    132      * @return data bytes.
    133      */
    134     public final byte[] getBytes() {
    135         return bytes;
    136     }
    137 
    138 
    139     /**
    140      * @return name of attribute.
    141      */
    142     @Override
    143     public final String getName() {
    144         return name;
    145     }
    146 
    147 
    148     /**
    149      * @param bytes the bytes to set
    150      */
    151     public final void setBytes( final byte[] bytes ) {
    152         this.bytes = bytes;
    153     }
    154 
    155 
    156     /**
    157      * @return String representation.
    158      */
    159     @Override
    160     public final String toString() {
    161         if (super.getLength() == 0 || bytes == null) {
    162             return "(Unknown attribute " + name + ")";
    163         }
    164         String hex;
    165         if (super.getLength() > 10) {
    166             final byte[] tmp = new byte[10];
    167             System.arraycopy(bytes, 0, tmp, 0, 10);
    168             hex = Utility.toHexString(tmp) + "... (truncated)";
    169         } else {
    170             hex = Utility.toHexString(bytes);
    171         }
    172         return "(Unknown attribute " + name + ": " + hex + ")";
    173     }
    174 
    175 
    176     /**
    177      * @return deep copy of this attribute
    178      */
    179     @Override
    180     public Attribute copy( final ConstantPool _constant_pool ) {
    181         final Unknown c = (Unknown) clone();
    182         if (bytes != null) {
    183             c.bytes = new byte[bytes.length];
    184             System.arraycopy(bytes, 0, c.bytes, 0, bytes.length);
    185         }
    186         c.setConstantPool(_constant_pool);
    187         return c;
    188     }
    189 }
    190