1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.bcel.internal.classfile;
  23 
  24 import java.io.DataInput;
  25 import java.io.DataOutputStream;
  26 import java.io.IOException;
  27 import java.util.HashMap;
  28 import java.util.Map;
  29 
  30 import com.sun.org.apache.bcel.internal.Const;
  31 
  32 /**
  33  * This class represents a reference to an unknown (i.e.,
  34  * application-specific) attribute of a class.  It is instantiated from the
  35  * {@link Attribute#readAttribute(java.io.DataInput, ConstantPool)} method.
  36  * Applications that need to read in application-specific attributes should create an
  37  * {@link UnknownAttributeReader} implementation and attach it via
  38  * {@link Attribute#addAttributeReader(String, UnknownAttributeReader)}.
  39 
  40  *
  41  * @version $Id$
  42  * @see Attribute
  43  * @see UnknownAttributeReader
  44  */
  45 public final class Unknown extends Attribute {
  46 
  47     private byte[] bytes;
  48     private final String name;
  49     private static final Map<String, Unknown> unknown_attributes = new HashMap<>();
  50 
  51 
  52     /** @return array of unknown attributes, but just one for each kind.
  53      */
  54     static Unknown[] getUnknownAttributes() {
  55         final Unknown[] unknowns = new Unknown[unknown_attributes.size()];
  56         unknown_attributes.values().toArray(unknowns);
  57         unknown_attributes.clear();
  58         return unknowns;
  59     }
  60 
  61 
  62     /**
  63      * Initialize from another object. Note that both objects use the same
  64      * references (shallow copy). Use clone() for a physical copy.
  65      */
  66     public Unknown(final Unknown c) {
  67         this(c.getNameIndex(), c.getLength(), c.getBytes(), c.getConstantPool());
  68     }
  69 
  70 
  71     /**
  72      * Create a non-standard attribute.
  73      *
  74      * @param name_index Index in constant pool
  75      * @param length Content length in bytes
  76      * @param bytes Attribute contents
  77      * @param constant_pool Array of constants
  78      */
  79     public Unknown(final int name_index, final int length, final byte[] bytes, final ConstantPool constant_pool) {
  80         super(Const.ATTR_UNKNOWN, name_index, length, constant_pool);
  81         this.bytes = bytes;
  82         name = ((ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8))
  83                 .getBytes();
  84         unknown_attributes.put(name, this);
  85     }
  86 
  87 
  88     /**
  89      * Construct object from input stream.
  90      *
  91      * @param name_index Index in constant pool
  92      * @param length Content length in bytes
  93      * @param input Input stream
  94      * @param constant_pool Array of constants
  95      * @throws IOException
  96      */
  97     Unknown(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
  98             throws IOException {
  99         this(name_index, length, (byte[]) null, constant_pool);
 100         if (length > 0) {
 101             bytes = new byte[length];
 102             input.readFully(bytes);
 103         }
 104     }
 105 
 106 
 107     /**
 108      * Called by objects that are traversing the nodes of the tree implicitely
 109      * defined by the contents of a Java class. I.e., the hierarchy of methods,
 110      * fields, attributes, etc. spawns a tree of objects.
 111      *
 112      * @param v Visitor object
 113      */
 114     @Override
 115     public void accept( final Visitor v ) {
 116         v.visitUnknown(this);
 117     }
 118 
 119 
 120     /**
 121      * Dump unknown bytes to file stream.
 122      *
 123      * @param file Output file stream
 124      * @throws IOException
 125      */
 126     @Override
 127     public final void dump( final DataOutputStream file ) throws IOException {
 128         super.dump(file);
 129         if (super.getLength() > 0) {
 130             file.write(bytes, 0, super.getLength());
 131         }
 132     }
 133 
 134 
 135     /**
 136      * @return data bytes.
 137      */
 138     public final byte[] getBytes() {
 139         return bytes;
 140     }
 141 
 142 
 143     /**
 144      * @return name of attribute.
 145      */
 146     @Override
 147     public final String getName() {
 148         return name;
 149     }
 150 
 151 
 152     /**
 153      * @param bytes the bytes to set
 154      */
 155     public final void setBytes( final byte[] bytes ) {
 156         this.bytes = bytes;
 157     }
 158 
 159 
 160     /**
 161      * @return String representation.
 162      */
 163     @Override
 164     public final String toString() {
 165         if (super.getLength() == 0 || bytes == null) {
 166             return "(Unknown attribute " + name + ")";
 167         }
 168         String hex;
 169         if (super.getLength() > 10) {
 170             final byte[] tmp = new byte[10];
 171             System.arraycopy(bytes, 0, tmp, 0, 10);
 172             hex = Utility.toHexString(tmp) + "... (truncated)";
 173         } else {
 174             hex = Utility.toHexString(bytes);
 175         }
 176         return "(Unknown attribute " + name + ": " + hex + ")";
 177     }
 178 
 179 
 180     /**
 181      * @return deep copy of this attribute
 182      */
 183     @Override
 184     public Attribute copy( final ConstantPool _constant_pool ) {
 185         final Unknown c = (Unknown) clone();
 186         if (bytes != null) {
 187             c.bytes = new byte[bytes.length];
 188             System.arraycopy(bytes, 0, c.bytes, 0, bytes.length);
 189         }
 190         c.setConstantPool(_constant_pool);
 191         return c;
 192     }
 193 }