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  * @see Attribute
  42  * @see UnknownAttributeReader
  43  */
  44 public final class Unknown extends Attribute {
  45 
  46     private byte[] bytes;
  47     private final String name;
  48     private static final Map<String, Unknown> unknown_attributes = new HashMap<>();
  49 
  50 
  51     /** @return array of unknown attributes, but just one for each kind.
  52      */
  53     static Unknown[] getUnknownAttributes() {
  54         final Unknown[] unknowns = new Unknown[unknown_attributes.size()];
  55         unknown_attributes.values().toArray(unknowns);
  56         unknown_attributes.clear();
  57         return unknowns;
  58     }
  59 
  60 
  61     /**
  62      * Initialize from another object. Note that both objects use the same
  63      * references (shallow copy). Use clone() for a physical copy.
  64      */
  65     public Unknown(final Unknown c) {
  66         this(c.getNameIndex(), c.getLength(), c.getBytes(), c.getConstantPool());
  67     }
  68 
  69 
  70     /**
  71      * Create a non-standard attribute.
  72      *
  73      * @param name_index Index in constant pool
  74      * @param length Content length in bytes
  75      * @param bytes Attribute contents
  76      * @param constant_pool Array of constants
  77      */
  78     public Unknown(final int name_index, final int length, final byte[] bytes, final ConstantPool constant_pool) {
  79         super(Const.ATTR_UNKNOWN, name_index, length, constant_pool);
  80         this.bytes = bytes;
  81         name = ((ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8))
  82                 .getBytes();
  83         unknown_attributes.put(name, this);
  84     }
  85 
  86 
  87     /**
  88      * Construct object from input stream.
  89      *
  90      * @param name_index Index in constant pool
  91      * @param length Content length in bytes
  92      * @param input Input stream
  93      * @param constant_pool Array of constants
  94      * @throws IOException
  95      */
  96     Unknown(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
  97             throws IOException {
  98         this(name_index, length, (byte[]) null, constant_pool);
  99         if (length > 0) {
 100             bytes = new byte[length];
 101             input.readFully(bytes);
 102         }
 103     }
 104 
 105 
 106     /**
 107      * Called by objects that are traversing the nodes of the tree implicitely
 108      * defined by the contents of a Java class. I.e., the hierarchy of methods,
 109      * fields, attributes, etc. spawns a tree of objects.
 110      *
 111      * @param v Visitor object
 112      */
 113     @Override
 114     public void accept( final Visitor v ) {
 115         v.visitUnknown(this);
 116     }
 117 
 118 
 119     /**
 120      * Dump unknown bytes to file stream.
 121      *
 122      * @param file Output file stream
 123      * @throws IOException
 124      */
 125     @Override
 126     public void dump( final DataOutputStream file ) throws IOException {
 127         super.dump(file);
 128         if (super.getLength() > 0) {
 129             file.write(bytes, 0, super.getLength());
 130         }
 131     }
 132 
 133 
 134     /**
 135      * @return data bytes.
 136      */
 137     public byte[] getBytes() {
 138         return bytes;
 139     }
 140 
 141 
 142     /**
 143      * @return name of attribute.
 144      */
 145     @Override
 146     public String getName() {
 147         return name;
 148     }
 149 
 150 
 151     /**
 152      * @param bytes the bytes to set
 153      */
 154     public void setBytes( final byte[] bytes ) {
 155         this.bytes = bytes;
 156     }
 157 
 158 
 159     /**
 160      * @return String representation.
 161      */
 162     @Override
 163     public String toString() {
 164         if (super.getLength() == 0 || bytes == null) {
 165             return "(Unknown attribute " + name + ")";
 166         }
 167         String hex;
 168         if (super.getLength() > 10) {
 169             final byte[] tmp = new byte[10];
 170             System.arraycopy(bytes, 0, tmp, 0, 10);
 171             hex = Utility.toHexString(tmp) + "... (truncated)";
 172         } else {
 173             hex = Utility.toHexString(bytes);
 174         }
 175         return "(Unknown attribute " + name + ": " + hex + ")";
 176     }
 177 
 178 
 179     /**
 180      * @return deep copy of this attribute
 181      */
 182     @Override
 183     public Attribute copy( final ConstantPool _constant_pool ) {
 184         final Unknown c = (Unknown) clone();
 185         if (bytes != null) {
 186             c.bytes = new byte[bytes.length];
 187             System.arraycopy(bytes, 0, c.bytes, 0, bytes.length);
 188         }
 189         c.setConstantPool(_constant_pool);
 190         return c;
 191     }
 192 }