001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.commons.compress.harmony.unpack200;
020
021import java.util.ArrayList;
022import java.util.Arrays;
023import java.util.Iterator;
024import java.util.List;
025
026import org.apache.commons.compress.harmony.unpack200.bytecode.AnnotationDefaultAttribute;
027import org.apache.commons.compress.harmony.unpack200.bytecode.AnnotationsAttribute.Annotation;
028import org.apache.commons.compress.harmony.unpack200.bytecode.AnnotationsAttribute.ElementValue;
029import org.apache.commons.compress.harmony.unpack200.bytecode.Attribute;
030import org.apache.commons.compress.harmony.unpack200.bytecode.CPDouble;
031import org.apache.commons.compress.harmony.unpack200.bytecode.CPFloat;
032import org.apache.commons.compress.harmony.unpack200.bytecode.CPInteger;
033import org.apache.commons.compress.harmony.unpack200.bytecode.CPLong;
034import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
035import org.apache.commons.compress.harmony.unpack200.bytecode.RuntimeVisibleorInvisibleAnnotationsAttribute;
036import org.apache.commons.compress.harmony.unpack200.bytecode.RuntimeVisibleorInvisibleParameterAnnotationsAttribute;
037import org.apache.commons.compress.harmony.unpack200.bytecode.RuntimeVisibleorInvisibleParameterAnnotationsAttribute.ParameterAnnotation;
038
039/**
040 * A group of metadata bands, such as class_RVA_bands, method_AD_bands etc.
041 */
042public class MetadataBandGroup {
043
044    private static CPUTF8 rvaUTF8;
045    private static CPUTF8 riaUTF8;
046
047    private static CPUTF8 rvpaUTF8;
048    private static CPUTF8 ripaUTF8;
049
050    public static void setRiaAttributeName(final CPUTF8 cpUTF8Value) {
051        riaUTF8 = cpUTF8Value;
052    }
053
054    public static void setRipaAttributeName(final CPUTF8 cpUTF8Value) {
055        ripaUTF8 = cpUTF8Value;
056    }
057
058    public static void setRvaAttributeName(final CPUTF8 cpUTF8Value) {
059        rvaUTF8 = cpUTF8Value;
060    }
061
062    public static void setRvpaAttributeName(final CPUTF8 cpUTF8Value) {
063        rvpaUTF8 = cpUTF8Value;
064    }
065
066    private final String type;
067
068    private final CpBands cpBands;
069
070    private List<Attribute> attributes;
071
072    public int[] param_NB;
073
074    public int[] anno_N;
075    public CPUTF8[][] type_RS;
076    public int[][] pair_N;
077    public CPUTF8[] name_RU;
078    public int[] T;
079    public CPInteger[] caseI_KI;
080    public CPDouble[] caseD_KD;
081    public CPFloat[] caseF_KF;
082    public CPLong[] caseJ_KJ;
083    public CPUTF8[] casec_RS;
084    public String[] caseet_RS;
085    public String[] caseec_RU;
086    public CPUTF8[] cases_RU;
087    public int[] casearray_N;
088    public CPUTF8[] nesttype_RS;
089    public int[] nestpair_N;
090    public CPUTF8[] nestname_RU;
091    private int caseI_KI_Index;
092
093    private int caseD_KD_Index;
094
095    private int caseF_KF_Index;
096
097    private int caseJ_KJ_Index;
098
099    private int casec_RS_Index;
100
101    private int caseet_RS_Index;
102
103    private int caseec_RU_Index;
104
105    private int cases_RU_Index;
106
107    private int casearray_N_Index;
108
109    private int T_index;
110
111    private int nesttype_RS_Index;
112
113    private int nestpair_N_Index;
114
115    private Iterator<CPUTF8> nestname_RU_Iterator;
116
117    private int anno_N_Index;
118
119    private int pair_N_Index;
120
121    public MetadataBandGroup(final String type, final CpBands cpBands) {
122        this.type = type;
123        this.cpBands = cpBands;
124    }
125
126    /**
127     * Gets a new Annotation.
128     *
129     * @param numPairs      Number of pairs, matches the lengths of {@code elementNames} and {@code elementValues} in the new Annotation.
130     * @param type          Type.
131     * @param namesIterator Iterates names to create pairs.
132     */
133    private Annotation getAnnotation(final CPUTF8 type, final int pairCount, final Iterator<CPUTF8> namesIterator) {
134        final CPUTF8[] elementNames = new CPUTF8[pairCount];
135        final ElementValue[] elementValues = new ElementValue[pairCount];
136        for (int j = 0; j < elementNames.length; j++) {
137            elementNames[j] = namesIterator.next();
138            final int t = T[T_index++];
139            elementValues[j] = new ElementValue(t, getNextValue(t));
140        }
141        return new Annotation(pairCount, type, elementNames, elementValues);
142    }
143
144    private Attribute getAttribute(final int numAnnotations, final CPUTF8[] types, final int[] pairCounts, final Iterator<CPUTF8> namesIterator) {
145        final Annotation[] annotations = new Annotation[numAnnotations];
146        Arrays.setAll(annotations, i -> getAnnotation(types[i], pairCounts[i], namesIterator));
147        return new RuntimeVisibleorInvisibleAnnotationsAttribute(type.equals("RVA") ? rvaUTF8 : riaUTF8, annotations);
148    }
149
150    public List<Attribute> getAttributes() {
151        // TODO: Optimize iterators!
152        if (attributes == null) {
153            attributes = new ArrayList<>();
154            if (name_RU != null) {
155                final Iterator<CPUTF8> name_RU_Iterator = Arrays.asList(name_RU).iterator();
156                if (!type.equals("AD")) {
157                    T_index = 0;
158                }
159                caseI_KI_Index = 0;
160                caseD_KD_Index = 0;
161                caseF_KF_Index = 0;
162                caseJ_KJ_Index = 0;
163                casec_RS_Index = 0;
164                caseet_RS_Index = 0;
165                caseec_RU_Index = 0;
166                cases_RU_Index = 0;
167                casearray_N_Index = 0;
168                nesttype_RS_Index = 0;
169                nestpair_N_Index = 0;
170                nestname_RU_Iterator = Arrays.asList(nestname_RU).iterator();
171                if (type.equals("RVA") || type.equals("RIA")) {
172                    for (int i = 0; i < anno_N.length; i++) {
173                        attributes.add(getAttribute(anno_N[i], type_RS[i], pair_N[i], name_RU_Iterator));
174                    }
175                } else if (type.equals("RVPA") || type.equals("RIPA")) {
176                    anno_N_Index = 0;
177                    pair_N_Index = 0;
178                    for (final int element : param_NB) {
179                        attributes.add(getParameterAttribute(element, name_RU_Iterator));
180                    }
181                }
182            } else if (type.equals("AD")) {
183                for (final int element : T) {
184                    attributes.add(new AnnotationDefaultAttribute(new ElementValue(element, getNextValue(element))));
185                }
186            }
187        }
188        return attributes;
189    }
190
191    private Object getNextValue(final int t) {
192        switch (t) {
193        case 'B':
194        case 'C':
195        case 'I':
196        case 'S':
197        case 'Z':
198            return caseI_KI[caseI_KI_Index++];
199        case 'D':
200            return caseD_KD[caseD_KD_Index++];
201        case 'F':
202            return caseF_KF[caseF_KF_Index++];
203        case 'J':
204            return caseJ_KJ[caseJ_KJ_Index++];
205        case 'c':
206            return casec_RS[casec_RS_Index++];
207        case 'e':
208            // TODO: check this - it may not work if the first string already
209            // has a colon in it
210            final String enumString = caseet_RS[caseet_RS_Index++] + ":" + caseec_RU[caseec_RU_Index++];
211            return cpBands.cpNameAndTypeValue(enumString);
212        case 's':
213            return cases_RU[cases_RU_Index++];
214        case '[':
215            final int arraySize = casearray_N[casearray_N_Index++];
216            final ElementValue[] nestedArray = new ElementValue[arraySize];
217            for (int i = 0; i < arraySize; i++) {
218                final int nextT = T[T_index++];
219                nestedArray[i] = new ElementValue(nextT, getNextValue(nextT));
220            }
221            return nestedArray;
222        case '@':
223            final CPUTF8 type = nesttype_RS[nesttype_RS_Index++];
224            final int numPairs = nestpair_N[nestpair_N_Index++];
225
226            return getAnnotation(type, numPairs, nestname_RU_Iterator);
227        }
228        return null;
229    }
230
231    private Attribute getParameterAttribute(final int numParameters, final Iterator<CPUTF8> namesIterator) {
232        final ParameterAnnotation[] parameterAnnotations = new ParameterAnnotation[numParameters];
233        for (int i = 0; i < numParameters; i++) {
234            final int numAnnotations = anno_N[anno_N_Index++];
235            final int[] pairCounts = pair_N[pair_N_Index++];
236            final Annotation[] annotations = new Annotation[numAnnotations];
237            Arrays.setAll(annotations, j -> getAnnotation(type_RS[anno_N_Index - 1][j], pairCounts[j], namesIterator));
238            parameterAnnotations[i] = new ParameterAnnotation(annotations);
239        }
240        return new RuntimeVisibleorInvisibleParameterAnnotationsAttribute(type.equals("RVPA") ? rvpaUTF8 : ripaUTF8, parameterAnnotations);
241    }
242
243}