View Javadoc
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  
19  import java.io.DataInput;
20  import java.io.DataOutputStream;
21  import java.io.IOException;
22  import java.util.Arrays;
23  
24  import org.apache.bcel.Const;
25  
26  /**
27   * This class represents a reference to an unknown (i.e., application-specific) attribute of a class. It is instantiated
28   * from the {@link Attribute#readAttribute(java.io.DataInput, ConstantPool)} method. Applications that need to read in
29   * application-specific attributes should create an {@link UnknownAttributeReader} implementation and attach it via
30   * {@link Attribute#addAttributeReader(String, UnknownAttributeReader)}.
31   *
32   * @see Attribute
33   * @see UnknownAttributeReader
34   */
35  public final class Unknown extends Attribute {
36  
37      private byte[] bytes;
38  
39      private final String name;
40  
41      /**
42       * Constructs a new instance for a non-standard attribute.
43       *
44       * @param nameIndex Index in constant pool
45       * @param length Content length in bytes
46       * @param bytes Attribute contents
47       * @param constantPool Array of constants
48       */
49      public Unknown(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
50          super(Const.ATTR_UNKNOWN, nameIndex, length, constantPool);
51          this.bytes = bytes;
52          this.name = constantPool.getConstantUtf8(nameIndex).getBytes();
53      }
54  
55      /**
56       * Constructs a new instance from an input stream.
57       *
58       * @param nameIndex Index in constant pool
59       * @param length Content length in bytes
60       * @param input Input stream
61       * @param constantPool Array of constants
62       * @throws IOException if an I/O error occurs.
63       */
64      Unknown(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
65          this(nameIndex, length, (byte[]) null, constantPool);
66          if (length > 0) {
67              bytes = new byte[length];
68              input.readFully(bytes);
69          }
70      }
71  
72      /**
73       * Constructs a new instance from another instance. Note that both objects use the same references (shallow copy). Use clone() for a physical copy.
74       *
75       * @param unknown Source.
76       */
77      public Unknown(final Unknown unknown) {
78          this(unknown.getNameIndex(), unknown.getLength(), unknown.getBytes(), unknown.getConstantPool());
79      }
80  
81      /**
82       * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
83       * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
84       *
85       * @param v Visitor object
86       */
87      @Override
88      public void accept(final Visitor v) {
89          v.visitUnknown(this);
90      }
91  
92      /**
93       * @return deep copy of this attribute
94       */
95      @Override
96      public Attribute copy(final ConstantPool constantPool) {
97          final Unknown c = (Unknown) clone();
98          if (bytes != null) {
99              c.bytes = bytes.clone();
100         }
101         c.setConstantPool(constantPool);
102         return c;
103     }
104 
105     /**
106      * Dumps unknown bytes to file stream.
107      *
108      * @param file Output file stream
109      * @throws IOException if an I/O error occurs.
110      */
111     @Override
112     public void dump(final DataOutputStream file) throws IOException {
113         super.dump(file);
114         if (super.getLength() > 0) {
115             file.write(bytes, 0, super.getLength());
116         }
117     }
118 
119     /**
120      * @return data bytes.
121      */
122     public byte[] getBytes() {
123         return bytes;
124     }
125 
126     /**
127      * @return name of attribute.
128      */
129     @Override
130     public String getName() {
131         return name;
132     }
133 
134     /**
135      * @param bytes the bytes to set
136      */
137     public void setBytes(final byte[] bytes) {
138         this.bytes = bytes;
139     }
140 
141     /**
142      * @return String representation.
143      */
144     @Override
145     public String toString() {
146         if (super.getLength() == 0 || bytes == null) {
147             return "(Unknown attribute " + name + ")";
148         }
149         String hex;
150         final int limit = 10;
151         if (super.getLength() > limit) {
152             final byte[] tmp = Arrays.copyOf(bytes, limit);
153             hex = Utility.toHexString(tmp) + "... (truncated)";
154         } else {
155             hex = Utility.toHexString(bytes);
156         }
157         return "(Unknown attribute " + name + ": " + hex + ")";
158     }
159 }