    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements. See the NOTICE file distributed with this
    004 * work for additional information regarding copyright ownership. The ASF
    005 * licenses this file to You under the Apache License, Version 2.0 (the
    006 * "License"); you may not use this file except in compliance with the License.
    007 * You may obtain a copy of the License at
    008 *
    009 * http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    014 * License for the specific language governing permissions and limitations under
    015 * the License.
    016 */
    017package org.apache.commons.compress.harmony.pack200;
    018
    019import java.io.IOException;
    020import java.io.OutputStream;
    021import java.util.ArrayList;
    022import java.util.Iterator;
    023import java.util.List;
    024
    025/**
    026 * A group of metadata (annotation) bands, such as class_RVA_bands, method_AD_bands etc.
    027 */
    028public class MetadataBandGroup extends BandSet {
    029
    030    public static final int CONTEXT_CLASS = 0;
    031    public static final int CONTEXT_FIELD = 1;
    032    public static final int CONTEXT_METHOD = 2;
    033
    034    private final String type;
    035    private int numBackwardsCalls = 0;
    036
    037    public IntList param_NB = new IntList(); // TODO: Lazy instantiation?
    038    public IntList anno_N = new IntList();
    039    public List type_RS = new ArrayList();
    040    public IntList pair_N = new IntList();
    041    public List name_RU = new ArrayList();
    042    public List T = new ArrayList();
    043    public List caseI_KI = new ArrayList();
    044    public List caseD_KD = new ArrayList();
    045    public List caseF_KF = new ArrayList();
    046    public List caseJ_KJ = new ArrayList();
    047    public List casec_RS = new ArrayList();
    048    public List caseet_RS = new ArrayList();
    049    public List caseec_RU = new ArrayList();
    050    public List cases_RU = new ArrayList();
    051    public IntList casearray_N = new IntList();
    052    public List nesttype_RS = new ArrayList();
    053    public IntList nestpair_N = new IntList();
    054    public List nestname_RU = new ArrayList();
    055
    056    private final CpBands cpBands;
    057    private final int context;
    058
    059    /**
    060     * Constructs a new MetadataBandGroup
    061     *
    062     * @param type must be either AD, RVA, RIA, RVPA or RIPA.
    063     * @param context <code>CONTEXT_CLASS</code>, <code>CONTEXT_METHOD</code> or <code>CONTEXT_FIELD</code>
    064     * @param cpBands constant pool bands
    065     * @param segmentHeader segment header
    066     * @param effort packing effort
    067     */
    068    public MetadataBandGroup(final String type, final int context, final CpBands cpBands,
    069        final SegmentHeader segmentHeader, final int effort) {
    070        super(effort, segmentHeader);
    071        this.type = type;
    072        this.cpBands = cpBands;
    073        this.context = context;
    074    }
    075
    076    /*
    077     * (non-Javadoc)
    078     *
    079     * @see org.apache.commons.compress.harmony.pack200.BandSet#pack(java.io.OutputStream)
    080     */
    081    @Override
    082    public void pack(final OutputStream out) throws IOException, Pack200Exception {
    083        PackingUtils.log("Writing metadata band group...");
    084        if (hasContent()) {
    085            String contextStr;
    086            if (context == CONTEXT_CLASS) {
    087                contextStr = "Class";
    088            } else if (context == CONTEXT_FIELD) {
    089                contextStr = "Field";
    090            } else {
    091                contextStr = "Method";
    092            }
    093            byte[] encodedBand = null;
    094            if (!type.equals("AD")) {
    095                if (type.indexOf('P') != -1) {
    096                    // Parameter annotation so we need to transmit param_NB
    097                    encodedBand = encodeBandInt(contextStr + "_" + type + " param_NB", param_NB.toArray(), Codec.BYTE1);
    098                    out.write(encodedBand);
    099                    PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type
    100                        + " anno_N[" + param_NB.size() + "]");
    101                }
    102                encodedBand = encodeBandInt(contextStr + "_" + type + " anno_N", anno_N.toArray(), Codec.UNSIGNED5);
    103                out.write(encodedBand);
    104                PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " anno_N["
    105                    + anno_N.size() + "]");
    106
    107                encodedBand = encodeBandInt(contextStr + "_" + type + " type_RS", cpEntryListToArray(type_RS),
    108                    Codec.UNSIGNED5);
    109                out.write(encodedBand);
    110                PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " type_RS["
    111                    + type_RS.size() + "]");
    112
    113                encodedBand = encodeBandInt(contextStr + "_" + type + " pair_N", pair_N.toArray(), Codec.UNSIGNED5);
    114                out.write(encodedBand);
    115                PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " pair_N["
    116                    + pair_N.size() + "]");
    117
    118                encodedBand = encodeBandInt(contextStr + "_" + type + " name_RU", cpEntryListToArray(name_RU),
    119                    Codec.UNSIGNED5);
    120                out.write(encodedBand);
    121                PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " name_RU["
    122                    + name_RU.size() + "]");
    123            }
    124            encodedBand = encodeBandInt(contextStr + "_" + type + " T", tagListToArray(T), Codec.BYTE1);
    125            out.write(encodedBand);
    126            PackingUtils
    127                .log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " T[" + T.size() + "]");
    128
    129            encodedBand = encodeBandInt(contextStr + "_" + type + " caseI_KI", cpEntryListToArray(caseI_KI),
    130                Codec.UNSIGNED5);
    131            out.write(encodedBand);
    132            PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseI_KI["
    133                + caseI_KI.size() + "]");
    134
    135            encodedBand = encodeBandInt(contextStr + "_" + type + " caseD_KD", cpEntryListToArray(caseD_KD),
    136                Codec.UNSIGNED5);
    137            out.write(encodedBand);
    138            PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseD_KD["
    139                + caseD_KD.size() + "]");
    140
    141            encodedBand = encodeBandInt(contextStr + "_" + type + " caseF_KF", cpEntryListToArray(caseF_KF),
    142                Codec.UNSIGNED5);
    143            out.write(encodedBand);
    144            PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseF_KF["
    145                + caseF_KF.size() + "]");
    146
    147            encodedBand = encodeBandInt(contextStr + "_" + type + " caseJ_KJ", cpEntryListToArray(caseJ_KJ),
    148                Codec.UNSIGNED5);
    149            out.write(encodedBand);
    150            PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseJ_KJ["
    151                + caseJ_KJ.size() + "]");
    152
    153            encodedBand = encodeBandInt(contextStr + "_" + type + " casec_RS", cpEntryListToArray(casec_RS),
    154                Codec.UNSIGNED5);
    155            out.write(encodedBand);
    156            PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " casec_RS["
    157                + casec_RS.size() + "]");
    158
    159            encodedBand = encodeBandInt(contextStr + "_" + type + " caseet_RS", cpEntryListToArray(caseet_RS),
    160                Codec.UNSIGNED5);
    161            out.write(encodedBand);
    162            PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseet_RS["
    163                + caseet_RS.size() + "]");
    164
    165            encodedBand = encodeBandInt(contextStr + "_" + type + " caseec_RU", cpEntryListToArray(caseec_RU),
    166                Codec.UNSIGNED5);
    167            out.write(encodedBand);
    168            PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseec_RU["
    169                + caseec_RU.size() + "]");
    170
    171            encodedBand = encodeBandInt(contextStr + "_" + type + " cases_RU", cpEntryListToArray(cases_RU),
    172                Codec.UNSIGNED5);
    173            out.write(encodedBand);
    174            PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " cases_RU["
    175                + cases_RU.size() + "]");
    176
    177            encodedBand = encodeBandInt(contextStr + "_" + type + " casearray_N", casearray_N.toArray(),
    178                Codec.UNSIGNED5);
    179            out.write(encodedBand);
    180            PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " casearray_N["
    181                + casearray_N.size() + "]");
    182
    183            encodedBand = encodeBandInt(contextStr + "_" + type + " nesttype_RS", cpEntryListToArray(nesttype_RS),
    184                Codec.UNSIGNED5);
    185            out.write(encodedBand);
    186            PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " nesttype_RS["
    187                + nesttype_RS.size() + "]");
    188
    189            encodedBand = encodeBandInt(contextStr + "_" + type + " nestpair_N", nestpair_N.toArray(), Codec.UNSIGNED5);
    190            out.write(encodedBand);
    191            PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " nestpair_N["
    192                + nestpair_N.size() + "]");
    193
    194            encodedBand = encodeBandInt(contextStr + "_" + type + " nestname_RU", cpEntryListToArray(nestname_RU),
    195                Codec.UNSIGNED5);
    196            out.write(encodedBand);
    197            PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " nestname_RU["
    198                + nestname_RU.size() + "]");
    199        }
    200    }
    201
    202    private int[] tagListToArray(final List t2) {
    203        final int[] ints = new int[t2.size()];
    204        for (int i = 0; i < ints.length; i++) {
    205            ints[i] = ((String) t2.get(i)).charAt(0);
    206        }
    207        return ints;
    208    }
    209
    210    /**
    211     * Add an annotation to this set of bands.
    212     *
    213     * @param numParams TODO
    214     * @param annoN TODO
    215     * @param pairN TODO
    216     * @param typeRS TODO
    217     * @param nameRU TODO
    218     * @param t TODO
    219     * @param values TODO
    220     * @param caseArrayN TODO
    221     * @param nestTypeRS TODO
    222     * @param nestNameRU TODO
    223     * @param nestPairN TODO
    224     */
    225    public void addParameterAnnotation(final int numParams, final int[] annoN, final IntList pairN, final List typeRS,
    226        final List nameRU, final List t, final List values, final List caseArrayN, final List nestTypeRS,
    227        final List nestNameRU, final List nestPairN) {
    228        param_NB.add(numParams);
    229        for (int i = 0; i < annoN.length; i++) {
    230            anno_N.add(annoN[i]);
    231        }
    232        pair_N.addAll(pairN);
    233        for (final Iterator iterator = typeRS.iterator(); iterator.hasNext();) {
    234            final String desc = (String) iterator.next();
    235            type_RS.add(cpBands.getCPSignature(desc));
    236        }
    237        for (final Iterator iterator = nameRU.iterator(); iterator.hasNext();) {
    238            final String name = (String) iterator.next();
    239            name_RU.add(cpBands.getCPUtf8(name));
    240        }
    241        final Iterator valuesIterator = values.iterator();
    242        for (final Iterator iterator = t.iterator(); iterator.hasNext();) {
    243            final String tag = (String) iterator.next();
    244            T.add(tag);
    245            if (tag.equals("B") || tag.equals("C") || tag.equals("I") || tag.equals("S") || tag.equals("Z")) {
    246                final Integer value = (Integer) valuesIterator.next();
    247                caseI_KI.add(cpBands.getConstant(value));
    248            } else if (tag.equals("D")) {
    249                final Double value = (Double) valuesIterator.next();
    250                caseD_KD.add(cpBands.getConstant(value));
    251            } else if (tag.equals("F")) {
    252                final Float value = (Float) valuesIterator.next();
    253                caseF_KF.add(cpBands.getConstant(value));
    254            } else if (tag.equals("J")) {
    255                final Long value = (Long) valuesIterator.next();
    256                caseJ_KJ.add(cpBands.getConstant(value));
    257            } else if (tag.equals("c")) {
    258                final String value = (String) valuesIterator.next();
    259                casec_RS.add(cpBands.getCPSignature(value));
    260            } else if (tag.equals("e")) {
    261                final String value = (String) valuesIterator.next();
    262                final String value2 = (String) valuesIterator.next();
    263                caseet_RS.add(cpBands.getCPSignature(value));
    264                caseec_RU.add(cpBands.getCPUtf8(value2));
    265            } else if (tag.equals("s")) {
    266                final String value = (String) valuesIterator.next();
    267                cases_RU.add(cpBands.getCPUtf8(value));
    268            }
    269            // do nothing here for [ or @ (handled below)
    270        }
    271        for (final Iterator iterator = caseArrayN.iterator(); iterator.hasNext();) {
    272            final int arraySize = ((Integer) iterator.next()).intValue();
    273            casearray_N.add(arraySize);
    274            numBackwardsCalls += arraySize;
    275        }
    276        for (final Iterator iterator = nestTypeRS.iterator(); iterator.hasNext();) {
    277            final String type = (String) iterator.next();
    278            nesttype_RS.add(cpBands.getCPSignature(type));
    279        }
    280        for (final Iterator iterator = nestNameRU.iterator(); iterator.hasNext();) {
    281            final String name = (String) iterator.next();
    282            nestname_RU.add(cpBands.getCPUtf8(name));
    283        }
    284        for (final Iterator iterator = nestPairN.iterator(); iterator.hasNext();) {
    285            final Integer numPairs = (Integer) iterator.next();
    286            nestpair_N.add(numPairs.intValue());
    287            numBackwardsCalls += numPairs.intValue();
    288        }
    289    }
    290
    291    /**
    292     * Add an annotation to this set of bands
    293     *
    294     * @param desc TODO
    295     * @param nameRU TODO
    296     * @param t TODO
    297     * @param values TODO
    298     * @param caseArrayN TODO
    299     * @param nestTypeRS TODO
    300     * @param nestNameRU TODO
    301     * @param nestPairN TODO
    302     */
    303    public void addAnnotation(final String desc, final List nameRU, final List t, final List values,
    304        final List caseArrayN, final List nestTypeRS, final List nestNameRU, final List nestPairN) {
    305        type_RS.add(cpBands.getCPSignature(desc));
    306        pair_N.add(nameRU.size());
    307
    308        for (final Iterator iterator = nameRU.iterator(); iterator.hasNext();) {
    309            final String name = (String) iterator.next();
    310            name_RU.add(cpBands.getCPUtf8(name));
    311        }
    312
    313        final Iterator valuesIterator = values.iterator();
    314        for (final Iterator iterator = t.iterator(); iterator.hasNext();) {
    315            final String tag = (String) iterator.next();
    316            T.add(tag);
    317            if (tag.equals("B") || tag.equals("C") || tag.equals("I") || tag.equals("S") || tag.equals("Z")) {
    318                final Integer value = (Integer) valuesIterator.next();
    319                caseI_KI.add(cpBands.getConstant(value));
    320            } else if (tag.equals("D")) {
    321                final Double value = (Double) valuesIterator.next();
    322                caseD_KD.add(cpBands.getConstant(value));
    323            } else if (tag.equals("F")) {
    324                final Float value = (Float) valuesIterator.next();
    325                caseF_KF.add(cpBands.getConstant(value));
    326            } else if (tag.equals("J")) {
    327                final Long value = (Long) valuesIterator.next();
    328                caseJ_KJ.add(cpBands.getConstant(value));
    329            } else if (tag.equals("c")) {
    330                final String value = (String) valuesIterator.next();
    331                casec_RS.add(cpBands.getCPSignature(value));
    332            } else if (tag.equals("e")) {
    333                final String value = (String) valuesIterator.next();
    334                final String value2 = (String) valuesIterator.next();
    335                caseet_RS.add(cpBands.getCPSignature(value));
    336                caseec_RU.add(cpBands.getCPUtf8(value2));
    337            } else if (tag.equals("s")) {
    338                final String value = (String) valuesIterator.next();
    339                cases_RU.add(cpBands.getCPUtf8(value));
    340            }
    341            // do nothing here for [ or @ (handled below)
    342        }
    343        for (final Iterator iterator = caseArrayN.iterator(); iterator.hasNext();) {
    344            final int arraySize = ((Integer) iterator.next()).intValue();
    345            casearray_N.add(arraySize);
    346            numBackwardsCalls += arraySize;
    347        }
    348        for (final Iterator iterator = nestTypeRS.iterator(); iterator.hasNext();) {
    349            final String type = (String) iterator.next();
    350            nesttype_RS.add(cpBands.getCPSignature(type));
    351        }
    352        for (final Iterator iterator = nestNameRU.iterator(); iterator.hasNext();) {
    353            final String name = (String) iterator.next();
    354            nestname_RU.add(cpBands.getCPUtf8(name));
    355        }
    356        for (final Iterator iterator = nestPairN.iterator(); iterator.hasNext();) {
    357            final Integer numPairs = (Integer) iterator.next();
    358            nestpair_N.add(numPairs.intValue());
    359            numBackwardsCalls += numPairs.intValue();
    360        }
    361    }
    362
    363    /**
    364     * Returns true if any annotations have been added to this set of bands.
    365     *
    366     * @return true if any annotations have been added to this set of bands.
    367     */
    368    public boolean hasContent() {
    369        return type_RS.size() > 0;
    370    }
    371
    372    public int numBackwardsCalls() {
    373        return numBackwardsCalls;
    374    }
    375
    376    public void incrementAnnoN() {
    377        anno_N.increment(anno_N.size() - 1);
    378    }
    379
    380    public void newEntryInAnnoN() {
    381        anno_N.add(1);
    382    }
    383
    384    /**
    385     * Remove the latest annotation that was added to this group
    386     */
    387    public void removeLatest() {
    388        final int latest = anno_N.remove(anno_N.size() - 1);
    389        for (int i = 0; i < latest; i++) {
    390            type_RS.remove(type_RS.size() - 1);
    391            final int pairs = pair_N.remove(pair_N.size() - 1);
    392            for (int j = 0; j < pairs; j++) {
    393                removeOnePair();
    394            }
    395        }
    396    }
    397
    398    /*
    399     * Convenience method for removeLatest
    400     */
    401    private void removeOnePair() {
    402        final String tag = (String) T.remove(T.size() - 1);
    403        if (tag.equals("B") || tag.equals("C") || tag.equals("I") || tag.equals("S") || tag.equals("Z")) {
    404            caseI_KI.remove(caseI_KI.size() - 1);
    405        } else if (tag.equals("D")) {
    406            caseD_KD.remove(caseD_KD.size() - 1);
    407        } else if (tag.equals("F")) {
    408            caseF_KF.remove(caseF_KF.size() - 1);
    409        } else if (tag.equals("J")) {
    410            caseJ_KJ.remove(caseJ_KJ.size() - 1);
    411        } else if (tag.equals("C")) {
    412            casec_RS.remove(casec_RS.size() - 1);
    413        } else if (tag.equals("e")) {
    414            caseet_RS.remove(caseet_RS.size() - 1);
    415            caseec_RU.remove(caseet_RS.size() - 1);
    416        } else if (tag.equals("s")) {
    417            cases_RU.remove(cases_RU.size() - 1);
    418        } else if (tag.equals("[")) {
    419            final int arraySize = casearray_N.remove(casearray_N.size() - 1);
    420            numBackwardsCalls -= arraySize;
    421            for (int k = 0; k < arraySize; k++) {
    422                removeOnePair();
    423            }
    424        } else if (tag.equals("@")) {
    425            nesttype_RS.remove(nesttype_RS.size() - 1);
    426            final int numPairs = nestpair_N.remove(nestpair_N.size() - 1);
    427            numBackwardsCalls -= numPairs;
    428            for (int i = 0; i < numPairs; i++) {
    429                removeOnePair();
    430            }
    431        }
    432    }
    433
    434}