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    }