Unknown.java

  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. package org.apache.bcel.classfile;

  18. import java.io.DataInput;
  19. import java.io.DataOutputStream;
  20. import java.io.IOException;
  21. import java.util.Arrays;

  22. import org.apache.bcel.Const;

  23. /**
  24.  * This class represents a reference to an unknown (i.e., application-specific) attribute of a class. It is instantiated
  25.  * from the {@link Attribute#readAttribute(java.io.DataInput, ConstantPool)} method. Applications that need to read in
  26.  * application-specific attributes should create an {@link UnknownAttributeReader} implementation and attach it via
  27.  * {@link Attribute#addAttributeReader(String, UnknownAttributeReader)}.
  28.  *
  29.  * @see Attribute
  30.  * @see UnknownAttributeReader
  31.  */
  32. public final class Unknown extends Attribute {

  33.     private byte[] bytes;

  34.     private final String name;

  35.     /**
  36.      * Constructs a new instance for a non-standard attribute.
  37.      *
  38.      * @param nameIndex Index in constant pool
  39.      * @param length Content length in bytes
  40.      * @param bytes Attribute contents
  41.      * @param constantPool Array of constants
  42.      */
  43.     public Unknown(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
  44.         super(Const.ATTR_UNKNOWN, nameIndex, length, constantPool);
  45.         this.bytes = bytes;
  46.         this.name = constantPool.getConstantUtf8(nameIndex).getBytes();
  47.     }

  48.     /**
  49.      * Constructs a new instance from an input stream.
  50.      *
  51.      * @param nameIndex Index in constant pool
  52.      * @param length Content length in bytes
  53.      * @param input Input stream
  54.      * @param constantPool Array of constants
  55.      * @throws IOException if an I/O error occurs.
  56.      */
  57.     Unknown(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
  58.         this(nameIndex, length, (byte[]) null, constantPool);
  59.         if (length > 0) {
  60.             bytes = new byte[length];
  61.             input.readFully(bytes);
  62.         }
  63.     }

  64.     /**
  65.      * Constructs a new instance from another instance. Note that both objects use the same references (shallow copy). Use clone() for a physical copy.
  66.      *
  67.      * @param unknown Source.
  68.      */
  69.     public Unknown(final Unknown unknown) {
  70.         this(unknown.getNameIndex(), unknown.getLength(), unknown.getBytes(), unknown.getConstantPool());
  71.     }

  72.     /**
  73.      * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
  74.      * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
  75.      *
  76.      * @param v Visitor object
  77.      */
  78.     @Override
  79.     public void accept(final Visitor v) {
  80.         v.visitUnknown(this);
  81.     }

  82.     /**
  83.      * @return deep copy of this attribute
  84.      */
  85.     @Override
  86.     public Attribute copy(final ConstantPool constantPool) {
  87.         final Unknown c = (Unknown) clone();
  88.         if (bytes != null) {
  89.             c.bytes = bytes.clone();
  90.         }
  91.         c.setConstantPool(constantPool);
  92.         return c;
  93.     }

  94.     /**
  95.      * Dumps unknown bytes to file stream.
  96.      *
  97.      * @param file Output file stream
  98.      * @throws IOException if an I/O error occurs.
  99.      */
  100.     @Override
  101.     public void dump(final DataOutputStream file) throws IOException {
  102.         super.dump(file);
  103.         if (super.getLength() > 0) {
  104.             file.write(bytes, 0, super.getLength());
  105.         }
  106.     }

  107.     /**
  108.      * @return data bytes.
  109.      */
  110.     public byte[] getBytes() {
  111.         return bytes;
  112.     }

  113.     /**
  114.      * @return name of attribute.
  115.      */
  116.     @Override
  117.     public String getName() {
  118.         return name;
  119.     }

  120.     /**
  121.      * @param bytes the bytes to set
  122.      */
  123.     public void setBytes(final byte[] bytes) {
  124.         this.bytes = bytes;
  125.     }

  126.     /**
  127.      * @return String representation.
  128.      */
  129.     @Override
  130.     public String toString() {
  131.         if (super.getLength() == 0 || bytes == null) {
  132.             return "(Unknown attribute " + name + ")";
  133.         }
  134.         String hex;
  135.         final int limit = 10;
  136.         if (super.getLength() > limit) {
  137.             final byte[] tmp = Arrays.copyOf(bytes, limit);
  138.             hex = Utility.toHexString(tmp) + "... (truncated)";
  139.         } else {
  140.             hex = Utility.toHexString(bytes);
  141.         }
  142.         return "(Unknown attribute " + name + ": " + hex + ")";
  143.     }
  144. }