    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 */
    017package org.apache.bcel.classfile;
    018
    019import java.io.DataInput;
    020import java.io.DataOutputStream;
    021import java.io.IOException;
    022import java.util.Arrays;
    023
    024import org.apache.bcel.Const;
    025
    026/**
    027 * This class represents a reference to an unknown (i.e., application-specific) attribute of a class. It is instantiated
    028 * from the {@link Attribute#readAttribute(java.io.DataInput, ConstantPool)} method. Applications that need to read in
    029 * application-specific attributes should create an {@link UnknownAttributeReader} implementation and attach it via
    030 * {@link Attribute#addAttributeReader(String, UnknownAttributeReader)}.
    031 *
    032 * @see Attribute
    033 * @see UnknownAttributeReader
    034 */
    035public final class Unknown extends Attribute {
    036
    037    private byte[] bytes;
    038
    039    private final String name;
    040
    041    /**
    042     * Constructs a new instance for a non-standard attribute.
    043     *
    044     * @param nameIndex Index in constant pool
    045     * @param length Content length in bytes
    046     * @param bytes Attribute contents
    047     * @param constantPool Array of constants
    048     */
    049    public Unknown(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
    050        super(Const.ATTR_UNKNOWN, nameIndex, length, constantPool);
    051        this.bytes = bytes;
    052        this.name = constantPool.getConstantUtf8(nameIndex).getBytes();
    053    }
    054
    055    /**
    056     * Constructs a new instance from an input stream.
    057     *
    058     * @param nameIndex Index in constant pool
    059     * @param length Content length in bytes
    060     * @param input Input stream
    061     * @param constantPool Array of constants
    062     * @throws IOException if an I/O error occurs.
    063     */
    064    Unknown(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
    065        this(nameIndex, length, (byte[]) null, constantPool);
    066        if (length > 0) {
    067            bytes = new byte[length];
    068            input.readFully(bytes);
    069        }
    070    }
    071
    072    /**
    073     * Constructs a new instance from another instance. Note that both objects use the same references (shallow copy). Use clone() for a physical copy.
    074     *
    075     * @param unknown Source.
    076     */
    077    public Unknown(final Unknown unknown) {
    078        this(unknown.getNameIndex(), unknown.getLength(), unknown.getBytes(), unknown.getConstantPool());
    079    }
    080
    081    /**
    082     * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
    083     * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
    084     *
    085     * @param v Visitor object
    086     */
    087    @Override
    088    public void accept(final Visitor v) {
    089        v.visitUnknown(this);
    090    }
    091
    092    /**
    093     * @return deep copy of this attribute
    094     */
    095    @Override
    096    public Attribute copy(final ConstantPool constantPool) {
    097        final Unknown c = (Unknown) clone();
    098        if (bytes != null) {
    099            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}