001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 */
018 package org.apache.bcel.classfile;
019
020 import java.io.DataInputStream;
021 import java.io.DataOutputStream;
022 import java.io.IOException;
023 import java.util.HashMap;
024 import java.util.Map;
025 import org.apache.bcel.Constants;
026
027 /**
028 * This class represents a reference to an unknown (i.e.,
029 * application-specific) attribute of a class. It is instantiated from the
030 * <em>Attribute.readAttribute()</em> method. Applications that need to
031 * read in application-specific attributes should create an <a
032 * href="./AttributeReader.html">AttributeReader</a> implementation and
033 * attach it via <a
034 * href="./Attribute.html#addAttributeReader(java.lang.String,
035 * org.apache.bcel.classfile.AttributeReader)">Attribute.addAttributeReader</a>.
036
037 *
038 * @version $Id: Unknown.java 1152072 2011-07-29 01:54:05Z dbrosius $
039 * @see org.apache.bcel.classfile.Attribute
040 * @see org.apache.bcel.classfile.AttributeReader
041 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
042 */
043 public final class Unknown extends Attribute {
044
045 private static final long serialVersionUID = -4099655108069755015L;
046 private byte[] bytes;
047 private String name;
048 private static final Map<String, Unknown> unknown_attributes = new HashMap<String, Unknown>();
049
050
051 /** @return array of unknown attributes, but just one for each kind.
052 */
053 static Unknown[] getUnknownAttributes() {
054 Unknown[] unknowns = new Unknown[unknown_attributes.size()];
055 unknown_attributes.values().toArray(unknowns);
056 unknown_attributes.clear();
057 return unknowns;
058 }
059
060
061 /**
062 * Initialize from another object. Note that both objects use the same
063 * references (shallow copy). Use clone() for a physical copy.
064 */
065 public Unknown(Unknown c) {
066 this(c.getNameIndex(), c.getLength(), c.getBytes(), c.getConstantPool());
067 }
068
069
070 /**
071 * Create a non-standard attribute.
072 *
073 * @param name_index Index in constant pool
074 * @param length Content length in bytes
075 * @param bytes Attribute contents
076 * @param constant_pool Array of constants
077 */
078 public Unknown(int name_index, int length, byte[] bytes, ConstantPool constant_pool) {
079 super(Constants.ATTR_UNKNOWN, name_index, length, constant_pool);
080 this.bytes = bytes;
081 name = ((ConstantUtf8) constant_pool.getConstant(name_index, Constants.CONSTANT_Utf8))
082 .getBytes();
083 unknown_attributes.put(name, this);
084 }
085
086
087 /**
088 * Construct object from file stream.
089 * @param name_index Index in constant pool
090 * @param length Content length in bytes
091 * @param file Input stream
092 * @param constant_pool Array of constants
093 * @throws IOException
094 */
095 Unknown(int name_index, int length, DataInputStream file, ConstantPool constant_pool)
096 throws IOException {
097 this(name_index, length, (byte[]) null, constant_pool);
098 if (length > 0) {
099 bytes = new byte[length];
100 file.readFully(bytes);
101 }
102 }
103
104
105 /**
106 * Called by objects that are traversing the nodes of the tree implicitely
107 * defined by the contents of a Java class. I.e., the hierarchy of methods,
108 * fields, attributes, etc. spawns a tree of objects.
109 *
110 * @param v Visitor object
111 */
112 @Override
113 public void accept( Visitor v ) {
114 v.visitUnknown(this);
115 }
116
117
118 /**
119 * Dump unknown bytes to file stream.
120 *
121 * @param file Output file stream
122 * @throws IOException
123 */
124 @Override
125 public final void dump( DataOutputStream file ) throws IOException {
126 super.dump(file);
127 if (length > 0) {
128 file.write(bytes, 0, length);
129 }
130 }
131
132
133 /**
134 * @return data bytes.
135 */
136 public final byte[] getBytes() {
137 return bytes;
138 }
139
140
141 /**
142 * @return name of attribute.
143 */
144 @Override
145 public final String getName() {
146 return name;
147 }
148
149
150 /**
151 * @param bytes the bytes to set
152 */
153 public final void setBytes( byte[] bytes ) {
154 this.bytes = bytes;
155 }
156
157
158 /**
159 * @return String representation.
160 */
161 @Override
162 public final String toString() {
163 if (length == 0 || bytes == null) {
164 return "(Unknown attribute " + name + ")";
165 }
166 String hex;
167 if (length > 10) {
168 byte[] tmp = new byte[10];
169 System.arraycopy(bytes, 0, tmp, 0, 10);
170 hex = Utility.toHexString(tmp) + "... (truncated)";
171 } else {
172 hex = Utility.toHexString(bytes);
173 }
174 return "(Unknown attribute " + name + ": " + hex + ")";
175 }
176
177
178 /**
179 * @return deep copy of this attribute
180 */
181 @Override
182 public Attribute copy( ConstantPool _constant_pool ) {
183 Unknown c = (Unknown) clone();
184 if (bytes != null) {
185 c.bytes = new byte[bytes.length];
186 System.arraycopy(bytes, 0, c.bytes, 0, bytes.length);
187 }
188 c.constant_pool = _constant_pool;
189 return c;
190 }
191 }