AttributeDefinitionBands.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.pack200;

  18. import java.io.IOException;
  19. import java.io.OutputStream;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.HashMap;
  23. import java.util.List;
  24. import java.util.Map;

  25. import org.objectweb.asm.Attribute;

  26. /**
  27.  * Attribute Definition bands define how any unknown attributes should be read by the decompressor.
  28.  */
  29. public class AttributeDefinitionBands extends BandSet {

  30.     public static class AttributeDefinition {

  31.         public int index;
  32.         public int contextType;
  33.         public CPUTF8 name;
  34.         public CPUTF8 layout;

  35.         public AttributeDefinition(final int index, final int contextType, final CPUTF8 name, final CPUTF8 layout) {
  36.             this.index = index;
  37.             this.contextType = contextType;
  38.             this.name = name;
  39.             this.layout = layout;
  40.         }

  41.     }

  42.     /**
  43.      * {@value}
  44.      */
  45.     public static final int CONTEXT_CLASS = 0;

  46.     /**
  47.      * {@value}
  48.      */
  49.     public static final int CONTEXT_CODE = 3;

  50.     /**
  51.      * {@value}
  52.      */
  53.     public static final int CONTEXT_FIELD = 1;

  54.     /**
  55.      * {@value}
  56.      */
  57.     public static final int CONTEXT_METHOD = 2;

  58.     private final List<AttributeDefinition> classAttributeLayouts = new ArrayList<>();
  59.     private final List<AttributeDefinition> methodAttributeLayouts = new ArrayList<>();
  60.     private final List<AttributeDefinition> fieldAttributeLayouts = new ArrayList<>();

  61.     private final List<AttributeDefinition> codeAttributeLayouts = new ArrayList<>();

  62.     private final List<AttributeDefinition> attributeDefinitions = new ArrayList<>();
  63.     private final CpBands cpBands;

  64.     private final Segment segment;

  65.     public AttributeDefinitionBands(final Segment segment, final int effort, final Attribute[] attributePrototypes) {
  66.         super(effort, segment.getSegmentHeader());
  67.         this.cpBands = segment.getCpBands();
  68.         this.segment = segment;
  69.         final Map<String, String> classLayouts = new HashMap<>();
  70.         final Map<String, String> methodLayouts = new HashMap<>();
  71.         final Map<String, String> fieldLayouts = new HashMap<>();
  72.         final Map<String, String> codeLayouts = new HashMap<>();

  73.         for (final Attribute attributePrototype : attributePrototypes) {
  74.             final NewAttribute newAttribute = (NewAttribute) attributePrototype;
  75.             if (!(newAttribute instanceof NewAttribute.ErrorAttribute) && !(newAttribute instanceof NewAttribute.PassAttribute)
  76.                     && !(newAttribute instanceof NewAttribute.StripAttribute)) {
  77.                 if (newAttribute.isContextClass()) {
  78.                     classLayouts.put(newAttribute.type, newAttribute.getLayout());
  79.                 }
  80.                 if (newAttribute.isContextMethod()) {
  81.                     methodLayouts.put(newAttribute.type, newAttribute.getLayout());
  82.                 }
  83.                 if (newAttribute.isContextField()) {
  84.                     fieldLayouts.put(newAttribute.type, newAttribute.getLayout());
  85.                 }
  86.                 if (newAttribute.isContextCode()) {
  87.                     codeLayouts.put(newAttribute.type, newAttribute.getLayout());
  88.                 }
  89.             }
  90.         }
  91.         if (classLayouts.size() > 7) {
  92.             segmentHeader.setHave_class_flags_hi(true);
  93.         }
  94.         if (methodLayouts.size() > 6) {
  95.             segmentHeader.setHave_method_flags_hi(true);
  96.         }
  97.         if (fieldLayouts.size() > 10) {
  98.             segmentHeader.setHave_field_flags_hi(true);
  99.         }
  100.         if (codeLayouts.size() > 15) {
  101.             segmentHeader.setHave_code_flags_hi(true);
  102.         }
  103.         int[] availableClassIndices = { 25, 26, 27, 28, 29, 30, 31 };
  104.         if (classLayouts.size() > 7) {
  105.             availableClassIndices = addHighIndices(availableClassIndices);
  106.         }
  107.         addAttributeDefinitions(classLayouts, availableClassIndices, CONTEXT_CLASS);
  108.         int[] availableMethodIndices = { 26, 27, 28, 29, 30, 31 };
  109.         if (methodAttributeLayouts.size() > 6) {
  110.             availableMethodIndices = addHighIndices(availableMethodIndices);
  111.         }
  112.         addAttributeDefinitions(methodLayouts, availableMethodIndices, CONTEXT_METHOD);
  113.         int[] availableFieldIndices = { 18, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
  114.         if (fieldAttributeLayouts.size() > 10) {
  115.             availableFieldIndices = addHighIndices(availableFieldIndices);
  116.         }
  117.         addAttributeDefinitions(fieldLayouts, availableFieldIndices, CONTEXT_FIELD);
  118.         int[] availableCodeIndices = { 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
  119.         if (codeAttributeLayouts.size() > 15) {
  120.             availableCodeIndices = addHighIndices(availableCodeIndices);
  121.         }
  122.         addAttributeDefinitions(codeLayouts, availableCodeIndices, CONTEXT_CODE);
  123.     }

  124.     private void addAttributeDefinitions(final Map<String, String> layoutMap, final int[] availableIndices, final int contextType) {
  125.         final int i = 0;
  126.         layoutMap.forEach((name, layout) -> {
  127.             final int index = availableIndices[i];
  128.             final AttributeDefinition definition = new AttributeDefinition(index, contextType, cpBands.getCPUtf8(name), cpBands.getCPUtf8(layout));
  129.             attributeDefinitions.add(definition);
  130.             switch (contextType) {
  131.             case CONTEXT_CLASS:
  132.                 classAttributeLayouts.add(definition);
  133.                 break;
  134.             case CONTEXT_METHOD:
  135.                 methodAttributeLayouts.add(definition);
  136.                 break;
  137.             case CONTEXT_FIELD:
  138.                 fieldAttributeLayouts.add(definition);
  139.                 break;
  140.             case CONTEXT_CODE:
  141.                 codeAttributeLayouts.add(definition);
  142.             }
  143.         });
  144.     }

  145.     private int[] addHighIndices(final int[] availableIndices) {
  146.         final int[] temp = Arrays.copyOf(availableIndices, availableIndices.length + 32);
  147.         int j = 32;
  148.         for (int i = availableIndices.length; i < temp.length; i++) {
  149.             temp[i] = j;
  150.             j++;
  151.         }
  152.         return temp;
  153.     }

  154.     private void addSyntheticDefinitions() {
  155.         final boolean anySytheticClasses = segment.getClassBands().isAnySyntheticClasses();
  156.         final boolean anySyntheticMethods = segment.getClassBands().isAnySyntheticMethods();
  157.         final boolean anySyntheticFields = segment.getClassBands().isAnySyntheticFields();
  158.         if (anySytheticClasses || anySyntheticMethods || anySyntheticFields) {
  159.             final CPUTF8 syntheticUTF = cpBands.getCPUtf8("Synthetic");
  160.             final CPUTF8 emptyUTF = cpBands.getCPUtf8("");
  161.             if (anySytheticClasses) {
  162.                 attributeDefinitions.add(new AttributeDefinition(12, CONTEXT_CLASS, syntheticUTF, emptyUTF));
  163.             }
  164.             if (anySyntheticMethods) {
  165.                 attributeDefinitions.add(new AttributeDefinition(12, CONTEXT_METHOD, syntheticUTF, emptyUTF));
  166.             }
  167.             if (anySyntheticFields) {
  168.                 attributeDefinitions.add(new AttributeDefinition(12, CONTEXT_FIELD, syntheticUTF, emptyUTF));
  169.             }
  170.         }
  171.     }

  172.     /**
  173.      * All input classes for the segment have now been read in, so this method is called so that this class can calculate/complete anything it could not do
  174.      * while classes were being read.
  175.      */
  176.     public void finaliseBands() {
  177.         addSyntheticDefinitions();
  178.         segmentHeader.setAttribute_definition_count(attributeDefinitions.size());
  179.     }

  180.     public List<AttributeDefinition> getClassAttributeLayouts() {
  181.         return classAttributeLayouts;
  182.     }

  183.     public List<AttributeDefinition> getCodeAttributeLayouts() {
  184.         return codeAttributeLayouts;
  185.     }

  186.     public List<AttributeDefinition> getFieldAttributeLayouts() {
  187.         return fieldAttributeLayouts;
  188.     }

  189.     public List<AttributeDefinition> getMethodAttributeLayouts() {
  190.         return methodAttributeLayouts;
  191.     }

  192.     @Override
  193.     public void pack(final OutputStream out) throws IOException, Pack200Exception {
  194.         PackingUtils.log("Writing attribute definition bands...");
  195.         final int[] attributeDefinitionHeader = new int[attributeDefinitions.size()];
  196.         final int[] attributeDefinitionName = new int[attributeDefinitions.size()];
  197.         final int[] attributeDefinitionLayout = new int[attributeDefinitions.size()];
  198.         for (int i = 0; i < attributeDefinitionLayout.length; i++) {
  199.             final AttributeDefinition def = attributeDefinitions.get(i);
  200.             attributeDefinitionHeader[i] = def.contextType | def.index + 1 << 2;
  201.             attributeDefinitionName[i] = def.name.getIndex();
  202.             attributeDefinitionLayout[i] = def.layout.getIndex();
  203.         }

  204.         byte[] encodedBand = encodeBandInt("attributeDefinitionHeader", attributeDefinitionHeader, Codec.BYTE1);
  205.         out.write(encodedBand);
  206.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from attributeDefinitionHeader[" + attributeDefinitionHeader.length + "]");

  207.         encodedBand = encodeBandInt("attributeDefinitionName", attributeDefinitionName, Codec.UNSIGNED5);
  208.         out.write(encodedBand);
  209.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from attributeDefinitionName[" + attributeDefinitionName.length + "]");

  210.         encodedBand = encodeBandInt("attributeDefinitionLayout", attributeDefinitionLayout, Codec.UNSIGNED5);
  211.         out.write(encodedBand);
  212.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from attributeDefinitionLayout[" + attributeDefinitionLayout.length + "]");
  213.     }
  214. }