AnnotationsAttribute.java

  1. /*
  2.  *  Licensed to the Apache Software Foundation (ASF) under one or more
  3.  *  contributor license agreements.  See the NOTICE file distributed with
  4.  *  this work for additional information regarding copyright ownership.
  5.  *  The ASF licenses this file to You under the Apache License, Version 2.0
  6.  *  (the "License"); you may not use this file except in compliance with
  7.  *  the License.  You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */
  17. package org.apache.commons.compress.harmony.unpack200.bytecode;

  18. import java.io.DataOutputStream;
  19. import java.io.IOException;
  20. import java.util.ArrayList;
  21. import java.util.List;

  22. /**
  23.  * Abstract superclass for Annotations attributes
  24.  */
  25. public abstract class AnnotationsAttribute extends Attribute {

  26.     /**
  27.      * Class to represent the annotation structure for class file attributes
  28.      */
  29.     public static class Annotation {

  30.         private final int numPairs;
  31.         private final CPUTF8[] elementNames;
  32.         private final ElementValue[] elementValues;
  33.         private final CPUTF8 type;

  34.         // Resolved values
  35.         private int typeIndex;
  36.         private int[] nameIndexes;

  37.         public Annotation(final int numPairs, final CPUTF8 type, final CPUTF8[] elementNames, final ElementValue[] elementValues) {
  38.             this.numPairs = numPairs;
  39.             this.type = type;
  40.             this.elementNames = elementNames;
  41.             this.elementValues = elementValues;
  42.         }

  43.         public List<Object> getClassFileEntries() {
  44.             final List<Object> entries = new ArrayList<>();
  45.             for (int i = 0; i < elementNames.length; i++) {
  46.                 entries.add(elementNames[i]);
  47.                 entries.addAll(elementValues[i].getClassFileEntries());
  48.             }
  49.             entries.add(type);
  50.             return entries;
  51.         }

  52.         public int getLength() {
  53.             int length = 4;
  54.             for (int i = 0; i < numPairs; i++) {
  55.                 length += 2;
  56.                 length += elementValues[i].getLength();
  57.             }
  58.             return length;
  59.         }

  60.         public void resolve(final ClassConstantPool pool) {
  61.             type.resolve(pool);
  62.             typeIndex = pool.indexOf(type);
  63.             nameIndexes = new int[numPairs];
  64.             for (int i = 0; i < elementNames.length; i++) {
  65.                 elementNames[i].resolve(pool);
  66.                 nameIndexes[i] = pool.indexOf(elementNames[i]);
  67.                 elementValues[i].resolve(pool);
  68.             }
  69.         }

  70.         public void writeBody(final DataOutputStream dos) throws IOException {
  71.             dos.writeShort(typeIndex);
  72.             dos.writeShort(numPairs);
  73.             for (int i = 0; i < numPairs; i++) {
  74.                 dos.writeShort(nameIndexes[i]);
  75.                 elementValues[i].writeBody(dos);
  76.             }
  77.         }
  78.     }

  79.     public static class ElementValue {

  80.         private final Object value;
  81.         private final int tag;

  82.         // resolved value index if it's a constant
  83.         private int constantValueIndex = -1;

  84.         public ElementValue(final int tag, final Object value) {
  85.             this.tag = tag;
  86.             this.value = value;
  87.         }

  88.         public List<Object> getClassFileEntries() {
  89.             final List<Object> entries = new ArrayList<>(1);
  90.             if (value instanceof CPNameAndType) {
  91.                 // used to represent enum, so don't include the actual CPNameAndType
  92.                 entries.add(((CPNameAndType) value).name);
  93.                 entries.add(((CPNameAndType) value).descriptor);
  94.             } else if (value instanceof ClassFileEntry) {
  95.                 // TODO? ClassFileEntry is an Object
  96.                 entries.add(value);
  97.             } else if (value instanceof ElementValue[]) {
  98.                 final ElementValue[] values = (ElementValue[]) value;
  99.                 for (final ElementValue value2 : values) {
  100.                     entries.addAll(value2.getClassFileEntries());
  101.                 }
  102.             } else if (value instanceof Annotation) {
  103.                 entries.addAll(((Annotation) value).getClassFileEntries());
  104.             }
  105.             return entries;
  106.         }

  107.         public int getLength() {
  108.             switch (tag) {
  109.             case 'B':
  110.             case 'C':
  111.             case 'D':
  112.             case 'F':
  113.             case 'I':
  114.             case 'J':
  115.             case 'S':
  116.             case 'Z':
  117.             case 'c':
  118.             case 's':
  119.                 return 3;
  120.             case 'e':
  121.                 return 5;
  122.             case '[':
  123.                 int length = 3;
  124.                 final ElementValue[] nestedValues = (ElementValue[]) value;
  125.                 for (final ElementValue nestedValue : nestedValues) {
  126.                     length += nestedValue.getLength();
  127.                 }
  128.                 return length;
  129.             case '@':
  130.                 return 1 + ((Annotation) value).getLength();
  131.             }
  132.             return 0;
  133.         }

  134.         public void resolve(final ClassConstantPool pool) {
  135.             if (value instanceof CPConstant) {
  136.                 ((CPConstant) value).resolve(pool);
  137.                 constantValueIndex = pool.indexOf((CPConstant) value);
  138.             } else if (value instanceof CPClass) {
  139.                 ((CPClass) value).resolve(pool);
  140.                 constantValueIndex = pool.indexOf((CPClass) value);
  141.             } else if (value instanceof CPUTF8) {
  142.                 ((CPUTF8) value).resolve(pool);
  143.                 constantValueIndex = pool.indexOf((CPUTF8) value);
  144.             } else if (value instanceof CPNameAndType) {
  145.                 ((CPNameAndType) value).resolve(pool);
  146.             } else if (value instanceof Annotation) {
  147.                 ((Annotation) value).resolve(pool);
  148.             } else if (value instanceof ElementValue[]) {
  149.                 final ElementValue[] nestedValues = (ElementValue[]) value;
  150.                 for (final ElementValue nestedValue : nestedValues) {
  151.                     nestedValue.resolve(pool);
  152.                 }
  153.             }
  154.         }

  155.         public void writeBody(final DataOutputStream dos) throws IOException {
  156.             dos.writeByte(tag);
  157.             if (constantValueIndex != -1) {
  158.                 dos.writeShort(constantValueIndex);
  159.             } else if (value instanceof CPNameAndType) {
  160.                 ((CPNameAndType) value).writeBody(dos);
  161.             } else if (value instanceof Annotation) {
  162.                 ((Annotation) value).writeBody(dos);
  163.             } else if (value instanceof ElementValue[]) {
  164.                 final ElementValue[] nestedValues = (ElementValue[]) value;
  165.                 dos.writeShort(nestedValues.length);
  166.                 for (final ElementValue nestedValue : nestedValues) {
  167.                     nestedValue.writeBody(dos);
  168.                 }
  169.             } else {
  170.                 throw new Error("");
  171.             }
  172.         }
  173.     }

  174.     public AnnotationsAttribute(final CPUTF8 attributeName) {
  175.         super(attributeName);
  176.     }

  177. }