View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.harmony.unpack200;
20  
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.Iterator;
24  import java.util.List;
25  
26  import org.apache.commons.compress.harmony.unpack200.bytecode.AnnotationDefaultAttribute;
27  import org.apache.commons.compress.harmony.unpack200.bytecode.AnnotationsAttribute.Annotation;
28  import org.apache.commons.compress.harmony.unpack200.bytecode.AnnotationsAttribute.ElementValue;
29  import org.apache.commons.compress.harmony.unpack200.bytecode.Attribute;
30  import org.apache.commons.compress.harmony.unpack200.bytecode.CPDouble;
31  import org.apache.commons.compress.harmony.unpack200.bytecode.CPFloat;
32  import org.apache.commons.compress.harmony.unpack200.bytecode.CPInteger;
33  import org.apache.commons.compress.harmony.unpack200.bytecode.CPLong;
34  import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
35  import org.apache.commons.compress.harmony.unpack200.bytecode.RuntimeVisibleorInvisibleAnnotationsAttribute;
36  import org.apache.commons.compress.harmony.unpack200.bytecode.RuntimeVisibleorInvisibleParameterAnnotationsAttribute;
37  import org.apache.commons.compress.harmony.unpack200.bytecode.RuntimeVisibleorInvisibleParameterAnnotationsAttribute.ParameterAnnotation;
38  
39  /**
40   * A group of metadata bands, such as class_RVA_bands, method_AD_bands etc.
41   */
42  public class MetadataBandGroup {
43  
44      private static CPUTF8 rvaUTF8;
45      private static CPUTF8 riaUTF8;
46  
47      private static CPUTF8 rvpaUTF8;
48      private static CPUTF8 ripaUTF8;
49  
50      public static void setRiaAttributeName(final CPUTF8 cpUTF8Value) {
51          riaUTF8 = cpUTF8Value;
52      }
53  
54      public static void setRipaAttributeName(final CPUTF8 cpUTF8Value) {
55          ripaUTF8 = cpUTF8Value;
56      }
57  
58      public static void setRvaAttributeName(final CPUTF8 cpUTF8Value) {
59          rvaUTF8 = cpUTF8Value;
60      }
61  
62      public static void setRvpaAttributeName(final CPUTF8 cpUTF8Value) {
63          rvpaUTF8 = cpUTF8Value;
64      }
65  
66      private final String type;
67  
68      private final CpBands cpBands;
69  
70      private List<Attribute> attributes;
71  
72      public int[] param_NB;
73  
74      public int[] anno_N;
75      public CPUTF8[][] type_RS;
76      public int[][] pair_N;
77      public CPUTF8[] name_RU;
78      public int[] T;
79      public CPInteger[] caseI_KI;
80      public CPDouble[] caseD_KD;
81      public CPFloat[] caseF_KF;
82      public CPLong[] caseJ_KJ;
83      public CPUTF8[] casec_RS;
84      public String[] caseet_RS;
85      public String[] caseec_RU;
86      public CPUTF8[] cases_RU;
87      public int[] casearray_N;
88      public CPUTF8[] nesttype_RS;
89      public int[] nestpair_N;
90      public CPUTF8[] nestname_RU;
91      private int caseI_KI_Index;
92  
93      private int caseD_KD_Index;
94  
95      private int caseF_KF_Index;
96  
97      private int caseJ_KJ_Index;
98  
99      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 }