AttributeLayout.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;

  18. import org.apache.commons.compress.harmony.pack200.Codec;
  19. import org.apache.commons.compress.harmony.pack200.Pack200Exception;
  20. import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry;

  21. /**
  22.  * AttributeLayout defines a layout that describes how an attribute will be transmitted.
  23.  */
  24. public class AttributeLayout implements IMatcher {

  25.     /**
  26.      * {@value}
  27.      */
  28.     public static final String ACC_ABSTRACT = "ACC_ABSTRACT"; //$NON-NLS-1$

  29.     /**
  30.      * {@value}
  31.      */
  32.     public static final String ACC_ANNOTATION = "ACC_ANNOTATION"; //$NON-NLS-1$

  33.     /**
  34.      * {@value}
  35.      */
  36.     public static final String ACC_ENUM = "ACC_ENUM"; //$NON-NLS-1$

  37.     /**
  38.      * {@value}
  39.      */
  40.     public static final String ACC_FINAL = "ACC_FINAL"; //$NON-NLS-1$

  41.     /**
  42.      * {@value}
  43.      */
  44.     public static final String ACC_INTERFACE = "ACC_INTERFACE"; //$NON-NLS-1$

  45.     /**
  46.      * {@value}
  47.      */
  48.     public static final String ACC_NATIVE = "ACC_NATIVE"; //$NON-NLS-1$

  49.     /**
  50.      * {@value}
  51.      */
  52.     public static final String ACC_PRIVATE = "ACC_PRIVATE"; //$NON-NLS-1$

  53.     /**
  54.      * {@value}
  55.      */
  56.     public static final String ACC_PROTECTED = "ACC_PROTECTED"; //$NON-NLS-1$

  57.     /**
  58.      * {@value}
  59.      */
  60.     public static final String ACC_PUBLIC = "ACC_PUBLIC"; //$NON-NLS-1$

  61.     /**
  62.      * {@value}
  63.      */
  64.     public static final String ACC_STATIC = "ACC_STATIC"; //$NON-NLS-1$

  65.     /**
  66.      * {@value}
  67.      */
  68.     public static final String ACC_STRICT = "ACC_STRICT"; //$NON-NLS-1$

  69.     /**
  70.      * {@value}
  71.      */
  72.     public static final String ACC_SYNCHRONIZED = "ACC_SYNCHRONIZED"; //$NON-NLS-1$

  73.     /**
  74.      * {@value}
  75.      */
  76.     public static final String ACC_SYNTHETIC = "ACC_SYNTHETIC"; //$NON-NLS-1$

  77.     /**
  78.      * {@value}
  79.      */
  80.     public static final String ACC_TRANSIENT = "ACC_TRANSIENT"; //$NON-NLS-1$

  81.     /**
  82.      * {@value}
  83.      */
  84.     public static final String ACC_VOLATILE = "ACC_VOLATILE"; //$NON-NLS-1$

  85.     /**
  86.      * {@value}
  87.      */
  88.     public static final String ATTRIBUTE_ANNOTATION_DEFAULT = "AnnotationDefault"; //$NON-NLS-1$

  89.     /**
  90.      * {@value}
  91.      */
  92.     public static final String ATTRIBUTE_CLASS_FILE_VERSION = "class-file version"; //$NON-NLS-1$

  93.     /**
  94.      * {@value}
  95.      */
  96.     public static final String ATTRIBUTE_CODE = "Code"; //$NON-NLS-1$

  97.     /**
  98.      * {@value}
  99.      */
  100.     public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue"; //$NON-NLS-1$

  101.     /**
  102.      * {@value}
  103.      */
  104.     public static final String ATTRIBUTE_DEPRECATED = "Deprecated"; //$NON-NLS-1$

  105.     /**
  106.      * {@value}
  107.      */

  108.     /**
  109.      * {@value}
  110.      */
  111.     public static final String ATTRIBUTE_ENCLOSING_METHOD = "EnclosingMethod"; //$NON-NLS-1$

  112.     /**
  113.      * {@value}
  114.      */
  115.     public static final String ATTRIBUTE_EXCEPTIONS = "Exceptions"; //$NON-NLS-1$

  116.     /**
  117.      * {@value}
  118.      */
  119.     public static final String ATTRIBUTE_INNER_CLASSES = "InnerClasses"; //$NON-NLS-1$

  120.     /**
  121.      * {@value}
  122.      */
  123.     public static final String ATTRIBUTE_LINE_NUMBER_TABLE = "LineNumberTable"; //$NON-NLS-1$

  124.     /**
  125.      * {@value}
  126.      */
  127.     public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable"; //$NON-NLS-1$

  128.     /**
  129.      * {@value}
  130.      */
  131.     public static final String ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable"; //$NON-NLS-1$

  132.     /**
  133.      * {@value}
  134.      */
  135.     public static final String ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations"; //$NON-NLS-1$

  136.     /**
  137.      * {@value}
  138.      */
  139.     public static final String ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations"; //$NON-NLS-1$

  140.     /**
  141.      * {@value}
  142.      */
  143.     public static final String ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"; //$NON-NLS-1$

  144.     /**
  145.      * {@value}
  146.      */
  147.     public static final String ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations"; //$NON-NLS-1$

  148.     /**
  149.      * {@value}
  150.      */
  151.     public static final String ATTRIBUTE_SIGNATURE = "Signature"; //$NON-NLS-1$

  152.     /**
  153.      * {@value}
  154.      */
  155.     public static final String ATTRIBUTE_SOURCE_FILE = "SourceFile"; //$NON-NLS-1$

  156.     /**
  157.      * {@value}
  158.      */
  159.     public static final int CONTEXT_CLASS = 0;

  160.     /**
  161.      * {@value}
  162.      */
  163.     public static final int CONTEXT_CODE = 3;

  164.     /**
  165.      * {@value}
  166.      */
  167.     public static final int CONTEXT_FIELD = 1;

  168.     /**
  169.      * {@value}
  170.      */
  171.     public static final int CONTEXT_METHOD = 2;

  172.     /**
  173.      * Context names.
  174.      */
  175.     public static final String[] contextNames = { "Class", "Field", "Method", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  176.             "Code", }; //$NON-NLS-1$

  177.     private static ClassFileEntry getValue(final String layout, long value, final SegmentConstantPool pool) throws Pack200Exception {
  178.         if (layout.startsWith("R")) { //$NON-NLS-1$
  179.             // references
  180.             if (layout.indexOf('N') != -1) {
  181.                 value--;
  182.             }
  183.             if (layout.startsWith("RU")) { //$NON-NLS-1$
  184.                 return pool.getValue(SegmentConstantPool.UTF_8, value);
  185.             }
  186.             if (layout.startsWith("RS")) { //$NON-NLS-1$
  187.                 return pool.getValue(SegmentConstantPool.SIGNATURE, value);
  188.             }
  189.         } else if (layout.startsWith("K")) { //$NON-NLS-1$
  190.             final char type = layout.charAt(1);
  191.             switch (type) {
  192.             case 'S': // String
  193.                 return pool.getValue(SegmentConstantPool.CP_STRING, value);
  194.             case 'I': // Int (or byte or short)
  195.             case 'C': // Char
  196.                 return pool.getValue(SegmentConstantPool.CP_INT, value);
  197.             case 'F': // Float
  198.                 return pool.getValue(SegmentConstantPool.CP_FLOAT, value);
  199.             case 'J': // Long
  200.                 return pool.getValue(SegmentConstantPool.CP_LONG, value);
  201.             case 'D': // Double
  202.                 return pool.getValue(SegmentConstantPool.CP_DOUBLE, value);
  203.             }
  204.         }
  205.         throw new Pack200Exception("Unknown layout encoding: " + layout);
  206.     }

  207.     private final int context;

  208.     private final int index;

  209.     private final String layout;

  210.     private long mask;

  211.     private final String name;
  212.     private final boolean isDefault;
  213.     private int backwardsCallCount;

  214.     /**
  215.      * Constructs a default AttributeLayout (equivalent to {@code new AttributeLayout(name, context, layout, index, true);})
  216.      *
  217.      * @param name    TODO
  218.      * @param context TODO
  219.      * @param layout  TODO
  220.      * @param index   TODO
  221.      * @throws Pack200Exception Attribute context out of range.
  222.      * @throws Pack200Exception Cannot have a null layout.
  223.      * @throws Pack200Exception Cannot have an unnamed layout.
  224.      */
  225.     public AttributeLayout(final String name, final int context, final String layout, final int index) throws Pack200Exception {
  226.         this(name, context, layout, index, true);
  227.     }

  228.     public AttributeLayout(final String name, final int context, final String layout, final int index, final boolean isDefault) throws Pack200Exception {
  229.         this.index = index;
  230.         this.context = context;
  231.         if (index >= 0) {
  232.             this.mask = 1L << index;
  233.         } else {
  234.             this.mask = 0;
  235.         }
  236.         if (context != CONTEXT_CLASS && context != CONTEXT_CODE && context != CONTEXT_FIELD && context != CONTEXT_METHOD) {
  237.             throw new Pack200Exception("Attribute context out of range: " + context);
  238.         }
  239.         if (layout == null) {
  240.             throw new Pack200Exception("Cannot have a null layout");
  241.         }
  242.         if (name == null || name.length() == 0) {
  243.             throw new Pack200Exception("Cannot have an unnamed layout");
  244.         }
  245.         this.name = name;
  246.         this.layout = layout;
  247.         this.isDefault = isDefault;
  248.     }

  249.     public Codec getCodec() {
  250.         if (layout.indexOf('O') >= 0) {
  251.             return Codec.BRANCH5;
  252.         }
  253.         if (layout.indexOf('P') >= 0) {
  254.             return Codec.BCI5;
  255.         }
  256.         if (layout.indexOf('S') >= 0 && !layout.contains("KS") //$NON-NLS-1$
  257.                 && !layout.contains("RS")) { //$NON-NLS-1$
  258.             return Codec.SIGNED5;
  259.         }
  260.         if (layout.indexOf('B') >= 0) {
  261.             return Codec.BYTE1;
  262.         }
  263.         return Codec.UNSIGNED5;
  264.     }

  265.     public int getContext() {
  266.         return context;
  267.     }

  268.     public int getIndex() {
  269.         return index;
  270.     }

  271.     public String getLayout() {
  272.         return layout;
  273.     }

  274.     public String getName() {
  275.         return name;
  276.     }

  277.     public ClassFileEntry getValue(final long value, final SegmentConstantPool pool) throws Pack200Exception {
  278.         return getValue(layout, value, pool);
  279.     }

  280.     public ClassFileEntry getValue(final long value, final String type, final SegmentConstantPool pool) throws Pack200Exception {
  281.         // TODO This really needs to be better tested, esp. the different types
  282.         // TODO This should have the ability to deal with RUN stuff too, and
  283.         // unions
  284.         if (!layout.startsWith("KQ")) {
  285.             return getValue(layout, value, pool);
  286.         }
  287.         if (type.equals("Ljava/lang/String;")) { //$NON-NLS-1$
  288.             return getValue("KS", value, pool);
  289.         }
  290.         return getValue("K" + type + layout.substring(2), value, //$NON-NLS-1$
  291.                 pool);
  292.     }

  293.     @Override
  294.     public int hashCode() {
  295.         final int PRIME = 31;
  296.         int r = 1;
  297.         if (name != null) {
  298.             r = r * PRIME + name.hashCode();
  299.         }
  300.         if (layout != null) {
  301.             r = r * PRIME + layout.hashCode();
  302.         }
  303.         r = r * PRIME + index;
  304.         r = r * PRIME + context;
  305.         return r;
  306.     }

  307.     public boolean isDefaultLayout() {
  308.         return isDefault;
  309.     }

  310.     /*
  311.      * (non-Javadoc)
  312.      *
  313.      * @see org.apache.commons.compress.harmony.unpack200.IMatches#matches(long)
  314.      */
  315.     @Override
  316.     public boolean matches(final long value) {
  317.         return (value & mask) != 0;
  318.     }

  319.     public int numBackwardsCallables() {
  320.         if ("*".equals(layout)) {
  321.             return 1;
  322.         }
  323.         return backwardsCallCount;
  324.     }

  325.     public void setBackwardsCallCount(final int backwardsCallCount) {
  326.         this.backwardsCallCount = backwardsCallCount;
  327.     }

  328.     @Override
  329.     public String toString() {
  330.         return contextNames[context] + ": " + name;
  331.     }

  332. }