MetadataBandGroup.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements. See the NOTICE file distributed with this
  4.  * work for additional information regarding copyright ownership. The ASF
  5.  * licenses this file to You under the Apache License, Version 2.0 (the
  6.  * "License"); you may not use this file except in compliance with the License.
  7.  * 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, WITHOUT
  13.  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  14.  * License for the specific language governing permissions and limitations under
  15.  * 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.Iterator;
  22. import java.util.List;

  23. /**
  24.  * A group of metadata (annotation) bands, such as class_RVA_bands, method_AD_bands etc.
  25.  */
  26. public class MetadataBandGroup extends BandSet {

  27.     public static final int CONTEXT_CLASS = 0;
  28.     public static final int CONTEXT_FIELD = 1;
  29.     public static final int CONTEXT_METHOD = 2;

  30.     private final String type;
  31.     private int numBackwardsCalls;

  32.     public IntList param_NB = new IntList(); // TODO: Lazy instantiation?
  33.     public IntList anno_N = new IntList();
  34.     public List<CPSignature> type_RS = new ArrayList<>();
  35.     public IntList pair_N = new IntList();
  36.     public List<CPUTF8> name_RU = new ArrayList<>();
  37.     public List<String> T = new ArrayList<>();
  38.     public List<CPConstant<?>> caseI_KI = new ArrayList<>();
  39.     public List<CPConstant<?>> caseD_KD = new ArrayList<>();
  40.     public List<CPConstant<?>> caseF_KF = new ArrayList<>();
  41.     public List<CPConstant<?>> caseJ_KJ = new ArrayList<>();
  42.     public List<CPSignature> casec_RS = new ArrayList<>();
  43.     public List<CPSignature> caseet_RS = new ArrayList<>();
  44.     public List<CPUTF8> caseec_RU = new ArrayList<>();
  45.     public List<CPUTF8> cases_RU = new ArrayList<>();
  46.     public IntList casearray_N = new IntList();
  47.     public List<CPSignature> nesttype_RS = new ArrayList<>();
  48.     public IntList nestpair_N = new IntList();
  49.     public List<CPUTF8> nestname_RU = new ArrayList<>();

  50.     private final CpBands cpBands;
  51.     private final int context;

  52.     /**
  53.      * Constructs a new MetadataBandGroup
  54.      *
  55.      * @param type          must be either AD, RVA, RIA, RVPA or RIPA.
  56.      * @param context       {@code CONTEXT_CLASS}, {@code CONTEXT_METHOD} or {@code CONTEXT_FIELD}
  57.      * @param cpBands       constant pool bands
  58.      * @param segmentHeader segment header
  59.      * @param effort        packing effort
  60.      */
  61.     public MetadataBandGroup(final String type, final int context, final CpBands cpBands, final SegmentHeader segmentHeader, final int effort) {
  62.         super(effort, segmentHeader);
  63.         this.type = type;
  64.         this.cpBands = cpBands;
  65.         this.context = context;
  66.     }

  67.     /**
  68.      * Add an annotation to this set of bands
  69.      *
  70.      * @param desc       TODO
  71.      * @param nameRU     TODO
  72.      * @param tags       TODO
  73.      * @param values     TODO
  74.      * @param caseArrayN TODO
  75.      * @param nestTypeRS TODO
  76.      * @param nestNameRU TODO
  77.      * @param nestPairN  TODO
  78.      */
  79.     public void addAnnotation(final String desc, final List<String> nameRU, final List<String> tags, final List<Object> values, final List<Integer> caseArrayN,
  80.             final List<String> nestTypeRS, final List<String> nestNameRU, final List<Integer> nestPairN) {
  81.         type_RS.add(cpBands.getCPSignature(desc));
  82.         pair_N.add(nameRU.size());
  83.         nameRU.forEach(name -> name_RU.add(cpBands.getCPUtf8(name)));

  84.         final Iterator<Object> valuesIterator = values.iterator();
  85.         for (final String tag : tags) {
  86.             T.add(tag);
  87.             switch (tag) {
  88.             case "B":
  89.             case "C":
  90.             case "I":
  91.             case "S":
  92.             case "Z": {
  93.                 caseI_KI.add(cpBands.getConstant(valuesIterator.next()));
  94.                 break;
  95.             }
  96.             case "D": {
  97.                 caseD_KD.add(cpBands.getConstant(valuesIterator.next()));
  98.                 break;
  99.             }
  100.             case "F": {
  101.                 caseF_KF.add(cpBands.getConstant(valuesIterator.next()));
  102.                 break;
  103.             }
  104.             case "J": {
  105.                 caseJ_KJ.add(cpBands.getConstant(valuesIterator.next()));
  106.                 break;
  107.             }
  108.             case "c": {
  109.                 casec_RS.add(cpBands.getCPSignature(nextString(valuesIterator)));
  110.                 break;
  111.             }
  112.             case "e": {
  113.                 caseet_RS.add(cpBands.getCPSignature(nextString(valuesIterator)));
  114.                 caseec_RU.add(cpBands.getCPUtf8(nextString(valuesIterator)));
  115.                 break;
  116.             }
  117.             case "s": {
  118.                 cases_RU.add(cpBands.getCPUtf8(nextString(valuesIterator)));
  119.                 break;
  120.             }
  121.             }
  122.             // do nothing here for [ or @ (handled below)
  123.         }
  124.         for (final Integer element : caseArrayN) {
  125.             final int arraySize = element.intValue();
  126.             casearray_N.add(arraySize);
  127.             numBackwardsCalls += arraySize;
  128.         }
  129.         nestTypeRS.forEach(element -> nesttype_RS.add(cpBands.getCPSignature(element)));
  130.         nestNameRU.forEach(element -> nestname_RU.add(cpBands.getCPUtf8(element)));
  131.         for (final Integer numPairs : nestPairN) {
  132.             nestpair_N.add(numPairs.intValue());
  133.             numBackwardsCalls += numPairs.intValue();
  134.         }
  135.     }

  136.     /**
  137.      * Add an annotation to this set of bands.
  138.      *
  139.      * @param numParams  TODO
  140.      * @param annoN      TODO
  141.      * @param pairN      TODO
  142.      * @param typeRS     TODO
  143.      * @param nameRU     TODO
  144.      * @param tags       TODO
  145.      * @param values     TODO
  146.      * @param caseArrayN TODO
  147.      * @param nestTypeRS TODO
  148.      * @param nestNameRU TODO
  149.      * @param nestPairN  TODO
  150.      */
  151.     public void addParameterAnnotation(final int numParams, final int[] annoN, final IntList pairN, final List<String> typeRS, final List<String> nameRU,
  152.             final List<String> tags, final List<Object> values, final List<Integer> caseArrayN, final List<String> nestTypeRS, final List<String> nestNameRU,
  153.             final List<Integer> nestPairN) {
  154.         param_NB.add(numParams);
  155.         for (final int element : annoN) {
  156.             anno_N.add(element);
  157.         }
  158.         pair_N.addAll(pairN);
  159.         typeRS.forEach(desc -> type_RS.add(cpBands.getCPSignature(desc)));
  160.         nameRU.forEach(name -> name_RU.add(cpBands.getCPUtf8(name)));
  161.         final Iterator<Object> valuesIterator = values.iterator();
  162.         for (final String tag : tags) {
  163.             T.add(tag);
  164.             switch (tag) {
  165.             case "B":
  166.             case "C":
  167.             case "I":
  168.             case "S":
  169.             case "Z": {
  170.                 caseI_KI.add(cpBands.getConstant(valuesIterator.next()));
  171.                 break;
  172.             }
  173.             case "D": {
  174.                 caseD_KD.add(cpBands.getConstant(valuesIterator.next()));
  175.                 break;
  176.             }
  177.             case "F": {
  178.                 caseF_KF.add(cpBands.getConstant(valuesIterator.next()));
  179.                 break;
  180.             }
  181.             case "J": {
  182.                 caseJ_KJ.add(cpBands.getConstant(valuesIterator.next()));
  183.                 break;
  184.             }
  185.             case "c": {
  186.                 casec_RS.add(cpBands.getCPSignature(nextString(valuesIterator)));
  187.                 break;
  188.             }
  189.             case "e": {
  190.                 caseet_RS.add(cpBands.getCPSignature(nextString(valuesIterator)));
  191.                 caseec_RU.add(cpBands.getCPUtf8(nextString(valuesIterator)));
  192.                 break;
  193.             }
  194.             case "s": {
  195.                 cases_RU.add(cpBands.getCPUtf8(nextString(valuesIterator)));
  196.                 break;
  197.             }
  198.             }
  199.             // do nothing here for [ or @ (handled below)
  200.         }
  201.         for (final Integer element : caseArrayN) {
  202.             final int arraySize = element.intValue();
  203.             casearray_N.add(arraySize);
  204.             numBackwardsCalls += arraySize;
  205.         }
  206.         nestTypeRS.forEach(type -> nesttype_RS.add(cpBands.getCPSignature(type)));
  207.         nestNameRU.forEach(name -> nestname_RU.add(cpBands.getCPUtf8(name)));
  208.         for (final Integer numPairs : nestPairN) {
  209.             nestpair_N.add(numPairs.intValue());
  210.             numBackwardsCalls += numPairs.intValue();
  211.         }
  212.     }

  213.     /**
  214.      * Returns true if any annotations have been added to this set of bands.
  215.      *
  216.      * @return true if any annotations have been added to this set of bands.
  217.      */
  218.     public boolean hasContent() {
  219.         return type_RS.size() > 0;
  220.     }

  221.     public void incrementAnnoN() {
  222.         anno_N.increment(anno_N.size() - 1);
  223.     }

  224.     public void newEntryInAnnoN() {
  225.         anno_N.add(1);
  226.     }

  227.     private String nextString(final Iterator<Object> valuesIterator) {
  228.         return (String) valuesIterator.next();
  229.     }

  230.     public int numBackwardsCalls() {
  231.         return numBackwardsCalls;
  232.     }

  233.     /*
  234.      * (non-Javadoc)
  235.      *
  236.      * @see org.apache.commons.compress.harmony.pack200.BandSet#pack(java.io.OutputStream)
  237.      */
  238.     @Override
  239.     public void pack(final OutputStream out) throws IOException, Pack200Exception {
  240.         PackingUtils.log("Writing metadata band group...");
  241.         if (hasContent()) {
  242.             String contextStr;
  243.             if (context == CONTEXT_CLASS) {
  244.                 contextStr = "Class";
  245.             } else if (context == CONTEXT_FIELD) {
  246.                 contextStr = "Field";
  247.             } else {
  248.                 contextStr = "Method";
  249.             }
  250.             byte[] encodedBand;
  251.             if (!type.equals("AD")) {
  252.                 if (type.indexOf('P') != -1) {
  253.                     // Parameter annotation so we need to transmit param_NB
  254.                     encodedBand = encodeBandInt(contextStr + "_" + type + " param_NB", param_NB.toArray(), Codec.BYTE1);
  255.                     out.write(encodedBand);
  256.                     PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " anno_N[" + param_NB.size() + "]");
  257.                 }
  258.                 encodedBand = encodeBandInt(contextStr + "_" + type + " anno_N", anno_N.toArray(), Codec.UNSIGNED5);
  259.                 out.write(encodedBand);
  260.                 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " anno_N[" + anno_N.size() + "]");

  261.                 encodedBand = encodeBandInt(contextStr + "_" + type + " type_RS", cpEntryListToArray(type_RS), Codec.UNSIGNED5);
  262.                 out.write(encodedBand);
  263.                 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " type_RS[" + type_RS.size() + "]");

  264.                 encodedBand = encodeBandInt(contextStr + "_" + type + " pair_N", pair_N.toArray(), Codec.UNSIGNED5);
  265.                 out.write(encodedBand);
  266.                 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " pair_N[" + pair_N.size() + "]");

  267.                 encodedBand = encodeBandInt(contextStr + "_" + type + " name_RU", cpEntryListToArray(name_RU), Codec.UNSIGNED5);
  268.                 out.write(encodedBand);
  269.                 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " name_RU[" + name_RU.size() + "]");
  270.             }
  271.             encodedBand = encodeBandInt(contextStr + "_" + type + " T", tagListToArray(T), Codec.BYTE1);
  272.             out.write(encodedBand);
  273.             PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " T[" + T.size() + "]");

  274.             encodedBand = encodeBandInt(contextStr + "_" + type + " caseI_KI", cpEntryListToArray(caseI_KI), Codec.UNSIGNED5);
  275.             out.write(encodedBand);
  276.             PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseI_KI[" + caseI_KI.size() + "]");

  277.             encodedBand = encodeBandInt(contextStr + "_" + type + " caseD_KD", cpEntryListToArray(caseD_KD), Codec.UNSIGNED5);
  278.             out.write(encodedBand);
  279.             PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseD_KD[" + caseD_KD.size() + "]");

  280.             encodedBand = encodeBandInt(contextStr + "_" + type + " caseF_KF", cpEntryListToArray(caseF_KF), Codec.UNSIGNED5);
  281.             out.write(encodedBand);
  282.             PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseF_KF[" + caseF_KF.size() + "]");

  283.             encodedBand = encodeBandInt(contextStr + "_" + type + " caseJ_KJ", cpEntryListToArray(caseJ_KJ), Codec.UNSIGNED5);
  284.             out.write(encodedBand);
  285.             PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseJ_KJ[" + caseJ_KJ.size() + "]");

  286.             encodedBand = encodeBandInt(contextStr + "_" + type + " casec_RS", cpEntryListToArray(casec_RS), Codec.UNSIGNED5);
  287.             out.write(encodedBand);
  288.             PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " casec_RS[" + casec_RS.size() + "]");

  289.             encodedBand = encodeBandInt(contextStr + "_" + type + " caseet_RS", cpEntryListToArray(caseet_RS), Codec.UNSIGNED5);
  290.             out.write(encodedBand);
  291.             PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseet_RS[" + caseet_RS.size() + "]");

  292.             encodedBand = encodeBandInt(contextStr + "_" + type + " caseec_RU", cpEntryListToArray(caseec_RU), Codec.UNSIGNED5);
  293.             out.write(encodedBand);
  294.             PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseec_RU[" + caseec_RU.size() + "]");

  295.             encodedBand = encodeBandInt(contextStr + "_" + type + " cases_RU", cpEntryListToArray(cases_RU), Codec.UNSIGNED5);
  296.             out.write(encodedBand);
  297.             PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " cases_RU[" + cases_RU.size() + "]");

  298.             encodedBand = encodeBandInt(contextStr + "_" + type + " casearray_N", casearray_N.toArray(), Codec.UNSIGNED5);
  299.             out.write(encodedBand);
  300.             PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " casearray_N[" + casearray_N.size() + "]");

  301.             encodedBand = encodeBandInt(contextStr + "_" + type + " nesttype_RS", cpEntryListToArray(nesttype_RS), Codec.UNSIGNED5);
  302.             out.write(encodedBand);
  303.             PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " nesttype_RS[" + nesttype_RS.size() + "]");

  304.             encodedBand = encodeBandInt(contextStr + "_" + type + " nestpair_N", nestpair_N.toArray(), Codec.UNSIGNED5);
  305.             out.write(encodedBand);
  306.             PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " nestpair_N[" + nestpair_N.size() + "]");

  307.             encodedBand = encodeBandInt(contextStr + "_" + type + " nestname_RU", cpEntryListToArray(nestname_RU), Codec.UNSIGNED5);
  308.             out.write(encodedBand);
  309.             PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " nestname_RU[" + nestname_RU.size() + "]");
  310.         }
  311.     }

  312.     /**
  313.      * Remove the latest annotation that was added to this group
  314.      */
  315.     public void removeLatest() {
  316.         final int latest = anno_N.remove(anno_N.size() - 1);
  317.         for (int i = 0; i < latest; i++) {
  318.             type_RS.remove(type_RS.size() - 1);
  319.             final int pairs = pair_N.remove(pair_N.size() - 1);
  320.             for (int j = 0; j < pairs; j++) {
  321.                 removeOnePair();
  322.             }
  323.         }
  324.     }

  325.     /*
  326.      * Convenience method for removeLatest
  327.      */
  328.     private void removeOnePair() {
  329.         final String tag = T.remove(T.size() - 1);
  330.         switch (tag) {
  331.         case "B":
  332.         case "C":
  333.         case "I":
  334.         case "S":
  335.         case "Z":
  336.             caseI_KI.remove(caseI_KI.size() - 1);
  337.             break;
  338.         case "D":
  339.             caseD_KD.remove(caseD_KD.size() - 1);
  340.             break;
  341.         case "F":
  342.             caseF_KF.remove(caseF_KF.size() - 1);
  343.             break;
  344.         case "J":
  345.             caseJ_KJ.remove(caseJ_KJ.size() - 1);
  346.             break;
  347.         case "e":
  348.             caseet_RS.remove(caseet_RS.size() - 1);
  349.             caseec_RU.remove(caseet_RS.size() - 1);
  350.             break;
  351.         case "s":
  352.             cases_RU.remove(cases_RU.size() - 1);
  353.             break;
  354.         case "[":
  355.             final int arraySize = casearray_N.remove(casearray_N.size() - 1);
  356.             numBackwardsCalls -= arraySize;
  357.             for (int k = 0; k < arraySize; k++) {
  358.                 removeOnePair();
  359.             }
  360.             break;
  361.         case "@":
  362.             nesttype_RS.remove(nesttype_RS.size() - 1);
  363.             final int numPairs = nestpair_N.remove(nestpair_N.size() - 1);
  364.             numBackwardsCalls -= numPairs;
  365.             for (int i = 0; i < numPairs; i++) {
  366.                 removeOnePair();
  367.             }
  368.             break;
  369.         }
  370.     }

  371.     private int[] tagListToArray(final List<String> list) {
  372.         return list.stream().mapToInt(s -> s.charAt(0)).toArray();
  373.     }

  374. }